⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 renderer.cpp

📁 3D数学基础:图形与游戏开发书籍源码,里面有很多实用的代码,对做3D的同志很有意义
💻 CPP
📖 第 1 页 / 共 5 页
字号:
		assert(SUCCEEDED(result));
	}
}

/////////////////////////////////////////////////////////////////////////////
//
// class Renderer rendering primitives
//
/////////////////////////////////////////////////////////////////////////////

//---------------------------------------------------------------------------
// Renderer::clear
//
// Clear the screen and/or frame buffer

void	Renderer::clear(int options) {

	// Make sure we have a device

	if (pD3DDevice == NULL) {
		assert(false);
		return;
	}

	// Did they request to clear anything?  I suppose you
	// could call this function without requesting to clear anything,
	// but this is most likely a bug...

	if (!(options & (kClearFrameBuffer | kClearDepthBuffer))) {
		assert(false);
		return;
	}

	// Figure out what color to use.  By default,
	// we use black

	unsigned frameBufferARGB = MAKE_ARGB(0,0,0,0);
	if (options & kClearToConstantColor) {
		frameBufferARGB = constantARGB;
		assert(!(options & kClearToFogColor));
	} else if (options & kClearToFogColor) {
		frameBufferARGB = fogColor;
	}

	// Always slam alpha to zero, if we have alpha in the frame buffer

	frameBufferARGB &= 0x00ffffff;

	// Figure out what to clear

	DWORD	clearWhat = 0;
	if (options & kClearFrameBuffer) {
		clearWhat |= D3DCLEAR_TARGET;
	}
	if (options & kClearDepthBuffer) {
		clearWhat |= D3DCLEAR_ZBUFFER;
	}

	// Clear it

	HRESULT result = pD3DDevice->Clear(
		0,
		NULL,
		clearWhat,
		frameBufferARGB,
		1.0F,
		0
	);
	assert(SUCCEEDED(result));
}

//---------------------------------------------------------------------------
// Renderer::renderTriMesh
//
// Render a triangle mesh, given vertex data in various formats.
//
// The input is a vertex list, and a triangle list.  The vertex list contains
// vertex data in various formats.  (See below.)  The triangle list is a list
// of indices into the vertex list.
//
// A few performance problems with this code:
//
// 1.	The use of DrawIndexedPrimitiveUP, where "UP" stands for "User
//	pointer."  For "ad-hoc" dynamic geometry (i.e. that which is generated
//	procedurally on the frame, this isn't a major problem.  However,
//	for "fixed" geometry that does not change from frame to frame - such
//	as models, static scenery, etc, it would be much better to use
//	vertex buffers.  But that requires exposing much more of the internals
//	to the higher level code than we would want for this "learning"
//	environment.
//
// 2.	We set the shader and lighting mode for every primitive.  Let's
//	hope DirectX is smart enough to not stall needlessly.

void	Renderer::renderTriMesh(const RenderVertex *vertexList, int vertexCount, const RenderTri *triList, int triCount) {
	HRESULT result;

	// Make sure we have something to render

	if (!checkMesh(vertexList, vertexCount, triList, triCount)) {
		return;
	}

	// Make sure we have a device

	if (pD3DDevice == NULL) {
		assert(false);
		return;
	}

	// Enable lighting, if user has enabled it

	setD3DRenderState(D3DRS_LIGHTING, lightEnable);

	// Set the vertex shader using a flexible vertex format

	result = pD3DDevice->SetVertexShader(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1);
	assert(SUCCEEDED(result));

	// Render it using "user pointer" data

	result = pD3DDevice->DrawIndexedPrimitiveUP(
		D3DPT_TRIANGLELIST,
		0,
		vertexCount,
		triCount,
		triList,
		D3DFMT_INDEX16,
		vertexList,
		sizeof(vertexList[0])
	);
	assert(SUCCEEDED(result));
}

void	Renderer::renderTriMesh(const RenderVertexL *vertexList, int vertexCount, const RenderTri *triList, int triCount) {
	HRESULT result;

	// Make sure we have something to render

	if (!checkMesh(vertexList, vertexCount, triList, triCount)) {
		return;
	}

	// Make sure we have a device

	if (pD3DDevice == NULL) {
		assert(false);
		return;
	}

	// These are pre-lit vertices.  Disable D3D lighting

	setD3DRenderState(D3DRS_LIGHTING, FALSE);

	// Set the vertex shader using a flexible vertex format

	result = pD3DDevice->SetVertexShader(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
	assert(SUCCEEDED(result));

	// Render it using "user pointer" data

	result = pD3DDevice->DrawIndexedPrimitiveUP(
		D3DPT_TRIANGLELIST,
		0,
		vertexCount,
		triCount,
		triList,
		D3DFMT_INDEX16,
		vertexList,
		sizeof(vertexList[0])
	);
	assert(SUCCEEDED(result));
}

void	Renderer::renderTriMesh(const RenderVertexTL *vertexList, int vertexCount, const RenderTri *triList, int triCount) {
	HRESULT result;

	// Make sure we have something to render

	if (!checkMesh(vertexList, vertexCount, triList, triCount)) {
		return;
	}

	// Make sure we have a device

	if (pD3DDevice == NULL) {
		assert(false);
		return;
	}

	// These are pre-lit vertices.  Disable D3D lighting

	setD3DRenderState(D3DRS_LIGHTING, FALSE);

	// Set the vertex shader using a flexible vertex format

	result = pD3DDevice->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
	assert(SUCCEEDED(result));

	// Render it using "user pointer" data

	result = pD3DDevice->DrawIndexedPrimitiveUP(
		D3DPT_TRIANGLELIST,
		0,
		vertexCount,
		triCount,
		triList,
		D3DFMT_INDEX16,
		vertexList,
		sizeof(vertexList[0])
	);
	assert(SUCCEEDED(result));
}

//---------------------------------------------------------------------------
// Renderer::dot
//
// Plots a 2D dot at the given integer coordinates using the current constant
// color (including alpha) and blending state.  There is no lighting, fog,
// or z-buffering.

void	Renderer::dot(int x, int y) {

	// !KLUDGE! Just draw a 1x1 box.  Hey, it works!

	boxFill(x, y, x+1, y+1);
}

//---------------------------------------------------------------------------
// Renderer::line
//
// Plots an arbitrarily-oriented line from (x1,y1) to (x2,y2), using the
// current constant color (including alpha) and blending state.  There is no
// lighting, fog, or z-buffering.

void	Renderer::line(int x1, int y1, int x2, int y2) {

	// !FIXME!

	assert(false);
}

//---------------------------------------------------------------------------
// Renderer::boxFill
//
// Plots a filled rectangle.  The x2 and y2 coordinates specify "one past"
// the last pixel to be plotted.  (Similar to the Win32 convention.)  In
// other words, the width of the rectangle is given by x2-x1.  Some people
// find this convention to be "weird" or "off by one."  However, it is
// actually much more elegant and usually avoids countless +1's and -1's that
// eventually cancel each other out.  This also more closely matches how
// it would work if floating point coordinates were used.

void	Renderer::boxFill(int x1, int y1, int x2, int y2) {

	// Clip to window

	if (x1 < windowX1) {
		x1 = windowX1;
	}
	if (y1 < windowY1) {
		y1 = windowY1;
	}
	if (x2 > windowX2) {
		x2 = windowX2;
	}
	if (y2 > windowY2) {
		y2 = windowY2;
	}

	// Check for empty rectangle

	if (x1 >= x2 || y1 >= y2) {
		return;
	}

	// !FIXME!

	assert(false);
}

void	Renderer::videoSave() {
}

void	Renderer::videoRestore() {
}

/////////////////////////////////////////////////////////////////////////////
//
// class Renderer texture cache functions
//
//---------------------------------------------------------------------------
//
// Some notes about the design of the texture cache:
//
// The texture cache is not actually a "cache" per se, since no texture
// is ever automatically ejected from the cache.  It's actually just a
// "manager" which keeps track of all the textures that are loaded.
//
// Each texture in the cache is accessible by a "handle."  This is a simple
// integer value that the upper level code knows nothing about, other than
// zero is never returned as a texture handle.
//
// In addition, textures may be given a text "name."  If a texture does
// not have a name, it is "anonymous" and is only accessible via handle.
// All named textures must have a unique name - there will never be two
// textures with the same name in the cache.  Use the findTexture()
// function to search the cache for a texture with a given name and
// retreive its handle.  Be warned that this function is slow.  Texture
// names are never case sensitive.
//
// A special texture always exists in the cache with the handle
// kWhiteTexture.  This texture is a solid white texture, very useful
// for rendering debugging objects, etc.  It effectively can be used
// to render an "untextured" object.  (For simplicity, we didn't
// support "untextured" rendering - you always must use a texture.)
//
// You can create a texture manually by calling allocTexture() and then
// setTextureImage().  This way, textures can be made procedurally in code.
// Or, you can load a texture from disk using the cacheTexture() function.
// For disk textures, the "name" of the texture is the exact same
// as the filename (including any path and extension.)
//
// You select a texture into the rendering context by handle.  You
// may re-allocate, free, or otherwise manipulate the currently selected
// texture.  However, in this case, the graphics system may deselect your
// texture and select another texture (like the white texture).
//
// The "name" and "handle" interfaces provide a simple and relatively flexible
// low-level interface to texture cache.  A much easier but less flexible
// interface is also provided using the TextureReference structure.  This
// interface is the "lazy man's" interface.  The TextureReference struct
// keeps track of the texture name and handle in a single struct.  What's
// more, you don't even have to maintain the handle yourself - the graphics
// system will do everything for you.  All you have to do is fill in the
// name, and then you can cache or select the texture easily.  In fact,
// you don't even have to cache the texture before rendering.  When you
// select the texture into the rendering context, if it isn't already
// selected, the graphics system will automatically "demand cache" it
// for you.  This is not the best for performance, but it will always
// function properly.
//
// Note that to use TextureReference efficiently, they must be kept around
// between frames.  Otherwise, the texture must be located by name every
// time it is used - which is going to be slow.  For example, don't do this:
//
//	void	renderSomething() {
//
//		// Fill in local texture structure
//
//		TextureReference tex;
//		strcpy(tex.name, "mytexture.tga");
//
//		// Select the texture.  YIKES!  This works, but will be
//		slow.
//
//		gRenderer.selectTexture(tex);
//
//		// ... render something here using that texture
//	}
//
// For best performance, keep the texture reference around persistently,
// either as a class member, global variable, or static local variable.
//
/////////////////////////////////////////////////////////////////////////////

//---------------------------------------------------------------------------
// Renderer::resetTextureCache
//
// Resets texture cache to default state - only containing a single,
// white texture.

void	Renderer::resetTextureCache() {

	// Free all textures

	freeAllTextures();

	// Create a small white texture

	const int	kSz = 32;
	int	whiteTextureHandle = allocTexture("white", kSz, kSz);

	// It should have gone into the reserved "white texture" slot

	assert(whiteTextureHandle == kWhiteTexture);

	// Set the data

	unsigned *whiteImage = new unsigned[kSz*kSz];
	memset(whiteImage, 0xff, kSz*kSz*4);
	setTextureImage(whiteTextureHandle, whiteImage);
	delete [] whiteImage;

	// Select it

	currentTextureHandle = 0;
	selectTexture(kWhiteTexture);
}

//---------------------------------------------------------------------------
// Renderer::findTexture
//
// Locates a texture, by name.  Returns the handle to the texture, or 0
// if not found.  The search is not case sensitive.  "Anonymous" textures
// (those with no name) cannot be located with this function.

int	Renderer::findTexture(const char *name) {

	// Can't search using an empty name.

	assert(name != NULL);
	assert(name[0] != '\0');

	// Search list linearly.  We could implement some sort
	// of hash table or binary search to make this fast,
	// but this function probably won't be called in speed
	// critical situations, so we're going to keep it simple.

	for (int i = 1 ; i < nextTextureSlot ; ++i) {
		if (stricmp(name, textureCacheList[i].name) == 0) {
			return i;
		}
	}

	// Not found

	return 0;
}

//---------------------------------------------------------------------------
// Renderer::allocTexture
//
// Creates a texture and optionally gives it a name.  If the name
// is specified, then it must be unique - any texture currently
// existing with that name is replaced, and the same handle is returned.
//
// If no name is specified, then the texture is "anonymous" and may only
// be accessed by handle.
//
// The return value is a handle that you can use to reference the texture.
// Texture handles are always > 0.
//
// Currently, this function never returns failure - if there is a problem,
// it will abort the program.

int	Renderer::allocTexture(const char *name, int xSize, int ySize) {
	TextureCacheEntry *t;

	// Can't do this without a device

	assert(pD3DDevice != NULL);

	// Verify texture size.  We require a power of two,

	co

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -