13. GameProjec1_GameEngine

工程GameProject1: main.h, main.cpp这两个文件用于创建游戏Stranded。

工程GameEngine:RenderInterface.h , D3DRenderer.h, D3DRenderer.cpp, engine.h, defines.h.  D3DRenderer.h和D3DRenderer.cpp用于创建Direct3D渲染系统; RenderInterface.h文件是一个基类,D3DRenderer就是从该类派生出来的;engine.h和defines.h包含了游戏引擎中要用到的Define(定义)、Function Prototype(函数原型)、Enumeration(枚举)、Structure(结构)和Include(包含)等语句。

main.h

#ifndef _UGP_MAIN_H_
#define _UGP_MAIN_H_


#include
"StrandedEngine/engine.h"
#pragma comment(lib, "lib/StrandedEngine.lib")

#define WINDOW_CLASS "StrandedGame"
#define WINDOW_NAME "Stranded"
#define WIN_WIDTH 800
#define WIN_HEIGHT 600
#define FULLSCREEN 1

// Function Prototypes...
bool InitializeEngine();
void ShutdownEngine();

// Main game functions.
bool GameInitialize();
void GameLoop();
void GameShutdown();

#endif

  main.cpp

#include"main.h"


// Globals...
HWND g_hwnd;
CRenderInterface
*g_Render = NULL;


LRESULT WINAPI MsgProc(HWND hd, UINT msg, WPARAM wp, LPARAM lp)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(
0);
return 0;
break;

case WM_KEYUP:
if(wp == VK_ESCAPE) PostQuitMessage(0);
break;
}

return DefWindowProc(hd, msg, wp, lp);
}


int WINAPI WinMain(HINSTANCE h, HINSTANCE p, LPSTR cmd, int show)
{
// Register the window class
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc,
0L, 0L, GetModuleHandle(NULL), NULL, NULL,
NULL, NULL, WINDOW_CLASS, NULL };
RegisterClassEx(
&wc);

// Create the application's window
if(FULLSCREEN)
{
g_hwnd
= CreateWindowEx(NULL, WINDOW_CLASS, WINDOW_NAME,
WS_POPUP
| WS_SYSMENU | WS_VISIBLE, 0, 0,
WIN_WIDTH, WIN_HEIGHT,
NULL, NULL, h, NULL);
}
else
{
g_hwnd
= CreateWindowEx(NULL, WINDOW_CLASS, WINDOW_NAME,
WS_OVERLAPPEDWINDOW
| WS_VISIBLE, 0,
0, WIN_WIDTH, WIN_HEIGHT,
NULL, NULL, h, NULL);
}

if(g_hwnd)
{
// Show the window
ShowWindow(g_hwnd, SW_SHOWDEFAULT);
UpdateWindow(g_hwnd);
}

// Initialize the Stranded Engine.
if(InitializeEngine())
{
// Initialize Stranded game.
if(GameInitialize())
{
// Enter the message loop
MSG msg;
ZeroMemory(
&msg, sizeof(msg));

SetCursorPos(
0, 0);

while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
TranslateMessage(
&msg);
DispatchMessage(
&msg);
}
else
GameLoop();
}
}
}

// Release any and all resources.
GameShutdown();
ShutdownEngine();

UnregisterClass(WINDOW_CLASS, wc.hInstance);
return 0;
}


bool InitializeEngine()
{
if(!CreateD3DRenderer(&g_Render)) return false;

if(!g_Render->Initialize(WIN_WIDTH, WIN_HEIGHT,
g_hwnd, FULLSCREEN))
return false;

g_Render
->SetClearCol(0, 0, 0);

return true;
}


void ShutdownEngine()
{
if(g_Render)
{
g_Render
->Shutdown();
delete g_Render;
g_Render
= NULL;
}
}


bool GameInitialize()
{
return true;
}


void GameLoop()
{
if(!g_Render) return;

g_Render
->StartRender(1, 1, 0);

g_Render
->EndRendering();
}


void GameShutdown()
{

}

InitializeEngine()函数调用CreateD3DRenderer()函数为渲染系统分配内存。该函数调用对象的Initialize()函数初始化渲染系统。它将清除色设为黑色。清除色就是在应用程序启动新帧时,清除后台缓存用的颜色。ShutdownEngine()函数只是简单地将所有系统使用的动态内存清除干净。到目前为止,只有一个基本的渲染系统,所以这就是要清除的全部内容。GameInitialize()和GameShutdown()这两个函数都是空的,因为在此还没有创建具体的游戏代码。GameLoop()函数和第1章的render()函数很类似。该函数只是完成渲染一个黑屏的基本功能。

  

defines.h

    defines.h文件包含了游戏使用的大量的定义和枚举变量。defines.h头文件将包含游戏或引擎将用到的常用定义.

#ifndef _UGP_DEFINES_H_
#define _UGP_DEFINES_H_

#include
<windows.h>

// Boolean values.
#define UGP_INVALID -1
#define UGP_OK 1
#define UGP_FAIL 0

// Window handle (need new way if porting to Mac and OpenGL).
#define WinHWND HWND

// Typedefs and enumerations.
typedef long VertexType;

enum PrimType
{
NULL_TYPE,
POINT_LIST,
TRIANGLE_LIST,
TRIANGLE_STRIP,
TRIANGLE_FAN,
LINE_LIST,
LINE_STRIP
};

// Color defines.
#define UGPCOLOR_ARGB(a,r,g,b) ((unsigned long)((((a)&0xff)<<24)|\
(((r)
&0xff)<<16)|(((g)&0xff)<<8)|\
((b)
&0xff)))

#endif

  

RenderInterface.h

RenderInterface.h头文件包含了渲染系统基类的声明。然后派生该类以创建游戏引擎使用的真实渲染系统。

 渲染系统的基类所包含的成员变量有屏幕宽度和高度、一个是否渲染整个屏幕的标识符,Direct3D初始化函数所需要的窗口句柄,以及两个投影矩阵所需的近距离值和远距离值。将变量属性设为受保护的(protected),意味着它们可以是派生类的成员变量,就如同是在那些类中声明的一样。

   这些渲染系统的基类开始先是构造函数和析构函数。这些构造函数只是简单地设置成员变量的默认值,而析构函数什么也不做。析构函数的属性被设置为虚拟的(virtual),因为这样可以确保所有的派生类在析构时可以调用正确的析构函数。如果不这样的话,读者可能就会遇到一些意外错误或是很难发现的内存泄漏问题。在创建基类时,要牢记一定要创建一个虚拟析构函数。

函数的其余部分直接明了。Initialize()函数用于设置Direct3D渲染系统。OneTimeInit()函数调用只需调用代码一次,这就像设置投影矩阵一样。一旦应用程序使用Shutdown()函数,它就会清除渲染系统。在Direct3D中可以释放那些在系统运行过程中用到的Direct3D对象。SetClearCol()函数用于将后台缓存颜色设置为指定的颜色。StartRender()和EndRendering()这两个函数用于启动新场景,结束场景,在渲染场景之前、之后或过程中清除场景。CalculateProjMatrix()和CalculateOrthoMatrix()这两个函数用于设置可以使用立体投影和正交投影的两个矩阵。CreateStaticBuffer()函数用于创建要绘制的静态顶点缓存,Render()函数用于将缓存内容显示在屏幕上。由于OpenGL中没有像Direct3D一样的顶点缓存,因此如果要移植到OpenGL中,就可以设置这些内容,只要用static buffer(静态缓存)类指定浮点数组即可。OpenGL版的Render()函数可以使用顶点数组或OpenGL顶点缓存对象(VBOs)渲染静态缓存内容。唯一的差异在于OpenGL并没有像Direct3D这样创建顶点缓存的结构,但这对于代码移植而言并不是问题。

#ifndef _UGP_RENDERINTERFACE_H_
#define _UGP_RENDERINTERFACE_H_

#include
"defines.h"


class CRenderInterface
{
public:
CRenderInterface() : m_screenWidth(
0),
m_screenHeight(
0), m_near(0), m_far(0) { }
virtual ~CRenderInterface() {}

virtual bool Initialize(int w, int h,
WinHWND mainWin,
bool fullScreen) = 0;
virtual void OneTimeInit() = 0;
virtual void Shutdown() = 0;

virtual void SetClearCol(float r, float g, float b) = 0;
virtual void StartRender(bool bColor, bool bDepth,
bool bStencil) = 0;
virtual void ClearBuffers(bool bColor, bool bDepth,
bool bStencil) = 0;
virtual void EndRendering() = 0;

virtual void CalculateProjMatrix(float fov, float n,
float f) = 0;
virtual void CalculateOrthoMatrix(float n, float f) = 0;

virtual int CreateStaticBuffer(VertexType, PrimType,
int totalVerts, int totalIndices,
int stride, void **data, unsigned int *indices,
int *staticId) = 0;

virtual int Render(int staticId) = 0;

protected:
int m_screenWidth;
int m_screenHeight;
bool m_fullscreen;

WinHWND m_mainHandle;

float m_near;
float m_far;
};

#endif

engine.h

      engine.h文件包含了include语句,这样就可以在一个地方访问游戏引擎的不同内容。这里只包含了渲染系统。诚如所知道的一样,该文件的内容将随着游戏的开发进度而发生变动。

#ifndef _UGP_ENGINE_H_
#define _UGP_ENGINE_H_

#include
"RenderInterface.h"
#include
"D3DRenderer.h"

#endif

  

D3DRenderer.h

D3DRenderer.h头文件定义了本书一直要用到的派生渲染类。除了该类将用于实现具体的渲染功能之外,它的定义与基类没有任何区别。类还声明了几个具体的Direct3D成员变量。

 首先,D3DRenderer.h头文件包含和绑定了具体的Direct3D头和库。接下来是Direct3D静态缓存的声明。该缓存用顶点缓存将静态几何图形(非动画的)绘制到屏幕上。静态缓存结构由顶点缓存、索引缓存(三角形索引)、对顶点和索引的计算、单个顶点尺寸的幅度值、Direct3D顶点FVF以及在渲染静态缓存时要用的图元类型。

       D3D渲染系统为Direct3d9对象详细说明了成员变量、Direct3D设备对象、清除色、一个用于确认它是否位于当前正在渲染的场景中的标识符、保存所有静态缓存的数组链表、静态缓存数目的计数器以及正在使用的当前静态缓存变量。最后一个变量是为了避免设置已经设置过的静态缓存。当有必要在单独一帧中多次渲染相同的对象时,会多次出现这种情况。每次设置相同的静态缓存都要浪费处理时间,都会影响到程序性能。在和纹理图像打交道,尤其是和大纹理图像和对象的多个实例打交道时,更是值得注意。

       文件结尾处声明的最后一个函数原型是CreateD3DRenderer()。实际上并不需要该函数,但是有了该函数,调用它就可以为渲染系统分配内存。当使用动态链接库(DLL),也就是一个用于Direct3D,一个用于OpenGL时,它们会非常有用。如果在这两个动态链接库中都有CreateRenderer()函数,它就会起作用。这样在程序运行期间,就可以为渲染系统分配要用的动态链接库。就可以让程序和渲染系统使用的对象无关。程序并不知道使用的是哪个渲染系统,它只要知道无论它用哪个渲染系统,都要指定它所用的动态链接库。

#ifndef _D3D_RENDERER_H_
#define _D3D_RENDERER_H_

#include
<windows.h>
#include
<d3d9.h>
#include
<d3dx9.h>
#include
"RenderInterface.h"

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")


struct stD3DStaticBuffer
{
stD3DStaticBuffer() : vbPtr(
0), ibPtr(0), numVerts(0),
numIndices(
0), stride(0), fvf(0),
primType(NULL_TYPE) {}

LPDIRECT3DVERTEXBUFFER9 vbPtr;
LPDIRECT3DINDEXBUFFER9 ibPtr;
int numVerts;
int numIndices;
int stride;
unsigned
long fvf;
PrimType primType;
};


class CD3DRenderer : public CRenderInterface
{
public:
CD3DRenderer();
~CD3DRenderer();

bool Initialize(int w, int h, WinHWND mainWin,
bool fullScreen);
void Shutdown();

void SetClearCol(float r, float g, float b);
void StartRender(bool bColor, bool bDepth, bool bStencil);
void ClearBuffers(bool bColor, bool bDepth, bool bStencil);
void EndRendering();

void CalculateProjMatrix(float fov, float n, float f);
void CalculateOrthoMatrix(float n, float f);

int CreateStaticBuffer(VertexType, PrimType,
int totalVerts, int totalIndices,
int stride, void **data, unsigned int *indices,
int *staticId);

int Render(int staticId);

private:
void OneTimeInit();


private:
D3DCOLOR m_Color;
LPDIRECT3D9 m_Direct3D;
LPDIRECT3DDEVICE9 m_Device;
bool m_renderingScene;

stD3DStaticBuffer
*m_staticBufferList;
int m_numStaticBuffers;
int m_activeStaticBuffer;
};

bool CreateD3DRenderer(CRenderInterface **pObj);

#endif

  

D3DRenderer.cpp

 D3DRenderer.cpp源文件开始先声明了CreateD3DRenderer()函数和CD3DRenderer类的构造函数和析构函数。CreateD3DRenderer()函数简单地实现了内存分配,以创建一个新的渲染对象。然后新对象存储在发送给函数的基类指针中。这样游戏只要和基类对象打交道就可以了,而不需要知道该对象是OpenGL还是Direct3D生成的对象。构造函数初始化类成员变量,而析构函数调用Shutdown()函数以确保在销毁对象前系统被清理干净。程序清单2.8显示了前三个函数。

#include"D3DRenderer.h"


bool CreateD3DRenderer(CRenderInterface **pObj)
{
if(!*pObj) *pObj = new CD3DRenderer;
else return false;

return true;
}

unsigned
long CreateD3DFVF(int flags)
{
unsigned
long fvf = 0;

return fvf;
}


CD3DRenderer::CD3DRenderer()
{
m_Direct3D
= NULL;
m_Device
= NULL;
m_renderingScene
= false;
m_numStaticBuffers
= 0;
m_activeStaticBuffer
= UGP_INVALID;
m_staticBufferList
= NULL;
}


CD3DRenderer::
~CD3DRenderer()
{
Shutdown();
}


bool CD3DRenderer::Initialize(int w, int h, WinHWND mainWin,
bool fullScreen)
{
Shutdown();

m_mainHandle
= mainWin;
if(!m_mainHandle) return false;

m_fullscreen
= fullScreen;

D3DDISPLAYMODE mode;
D3DCAPS9 caps;
D3DPRESENT_PARAMETERS Params;

ZeroMemory(
&Params, sizeof(Params));

m_Direct3D
= Direct3DCreate9(D3D_SDK_VERSION);
if(!m_Direct3D) return false;

if(FAILED(m_Direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,
&mode))) return false;

if(FAILED(m_Direct3D->GetDeviceCaps(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
&caps))) return false;

DWORD processing
= 0;
if(caps.VertexProcessingCaps != 0)
processing
= D3DCREATE_HARDWARE_VERTEXPROCESSING |
D3DCREATE_PUREDEVICE;
else
processing
= D3DCREATE_SOFTWARE_VERTEXPROCESSING;

if(m_fullscreen)
{
Params.FullScreen_RefreshRateInHz
= mode.RefreshRate;
Params.PresentationInterval
= D3DPRESENT_INTERVAL_ONE;
}
else
Params.PresentationInterval
= D3DPRESENT_INTERVAL_IMMEDIATE;

Params.Windowed
= !m_fullscreen;
Params.BackBufferWidth
= w;
Params.BackBufferHeight
= h;
Params.hDeviceWindow
= m_mainHandle;
Params.SwapEffect
= D3DSWAPEFFECT_DISCARD;
Params.BackBufferFormat
= mode.Format;
Params.BackBufferCount
= 1;
Params.EnableAutoDepthStencil
= TRUE;
Params.AutoDepthStencilFormat
= D3DFMT_D16;

m_screenWidth
= w;
m_screenHeight
= h;

if(FAILED(m_Direct3D->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, m_mainHandle, processing,
&Params, &m_Device))) return false;

if(m_Device == NULL) return false;

OneTimeInit();
return true;
}


void CD3DRenderer::OneTimeInit()
{
if(!m_Device) return;

m_Device
->SetRenderState(D3DRS_LIGHTING, FALSE);
m_Device
->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

CalculateProjMatrix(D3DX_PI
/ 4, 0.1f, 1000);
}


void CD3DRenderer::Shutdown()
{
for(int s = 0; s < m_numStaticBuffers; s++)
{
if(m_staticBufferList[s].vbPtr)
{
m_staticBufferList[s].vbPtr
->Release();
m_staticBufferList[s].vbPtr
= NULL;
}

if(m_staticBufferList[s].ibPtr)
{
m_staticBufferList[s].ibPtr
->Release();
m_staticBufferList[s].ibPtr
= NULL;
}
}

m_numStaticBuffers
= 0;
if(m_staticBufferList) delete[] m_staticBufferList;
m_staticBufferList
= NULL;

if(m_Device) m_Device->Release();
if(m_Direct3D) m_Direct3D->Release();

m_Device
= NULL;
m_Direct3D
= NULL;
}


void CD3DRenderer::SetClearCol(float r, float g, float b)
{
m_Color
= D3DCOLOR_COLORVALUE(r, g, b, 1.0f);
}


void CD3DRenderer::StartRender(bool bColor, bool bDepth,
bool bStencil)
{
if(!m_Device) return;

unsigned
int buffers = 0;
if(bColor) buffers |= D3DCLEAR_TARGET;
if(bDepth) buffers |= D3DCLEAR_ZBUFFER;
if(bStencil) buffers |= D3DCLEAR_STENCIL;

if(FAILED(m_Device->Clear(0, NULL, buffers, m_Color, 1, 0)))
return;
if(FAILED(m_Device->BeginScene())) return;

m_renderingScene
= true;
}


void CD3DRenderer::ClearBuffers(bool bColor, bool bDepth,
bool bStencil)
{
if(!m_Device) return;

unsigned
int buffers = 0;
if(bColor) buffers |= D3DCLEAR_TARGET;
if(bDepth) buffers |= D3DCLEAR_ZBUFFER;
if(bStencil) buffers |= D3DCLEAR_STENCIL;

if(m_renderingScene) m_Device->EndScene();
if(FAILED(m_Device->Clear(0, NULL, buffers, m_Color, 1, 0)))
return;

if(m_renderingScene)
if(FAILED(m_Device->BeginScene())) return;
}


void CD3DRenderer::EndRendering()
{
if(!m_Device) return;

m_Device
->EndScene();
m_Device
->Present(NULL, NULL, NULL, NULL);

m_renderingScene
= false;
}


void CD3DRenderer::CalculateProjMatrix(float fov, float n, float f)
{
if(!m_Device) return;
D3DXMATRIX projection;

D3DXMatrixPerspectiveFovLH(
&projection, fov,
(
float)m_screenWidth/(float)m_screenHeight, n, f);

m_Device
->SetTransform(D3DTS_PROJECTION, &projection);
}


void CD3DRenderer::CalculateOrthoMatrix(float n, float f)
{
if(!m_Device) return;
D3DXMATRIX ortho;

D3DXMatrixOrthoLH(
&ortho, (float)m_screenWidth,
(
float)m_screenHeight, n, f);
m_Device
->SetTransform(D3DTS_PROJECTION, &ortho);
}


int CD3DRenderer::CreateStaticBuffer(VertexType vType,
PrimType primType,
int totalVerts,
int totalIndices, int stride, void **data,
unsigned
int *indices, int *staticId)
{
void *ptr;
int index = m_numStaticBuffers;

if(!m_staticBufferList)
{
m_staticBufferList
= new stD3DStaticBuffer[1];
if(!m_staticBufferList) return UGP_FAIL;
}
else
{
stD3DStaticBuffer
*temp;
temp
= new stD3DStaticBuffer[m_numStaticBuffers + 1];

memcpy(temp, m_staticBufferList,
sizeof(stD3DStaticBuffer) * m_numStaticBuffers);

delete[] m_staticBufferList;
m_staticBufferList
= temp;
}

m_staticBufferList[index].numVerts
= totalVerts;
m_staticBufferList[index].numIndices
= totalIndices;
m_staticBufferList[index].primType
= primType;
m_staticBufferList[index].stride
= stride;
m_staticBufferList[index].fvf
= CreateD3DFVF(vType);

if(totalIndices > 0)
{
if(FAILED(m_Device->CreateIndexBuffer(sizeof(unsigned int) *
totalIndices, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16,
D3DPOOL_DEFAULT,
&m_staticBufferList[index].ibPtr,
NULL)))
return UGP_FAIL;

if(FAILED(m_staticBufferList[index].ibPtr->Lock(0, 0,
(
void**)&ptr, 0))) return UGP_FAIL;

memcpy(ptr, indices,
sizeof(unsigned int) * totalIndices);
m_staticBufferList[index].ibPtr
->Unlock();
}
else
{
m_staticBufferList[index].ibPtr
= NULL;
}

if(FAILED(m_Device->CreateVertexBuffer(totalVerts * stride,
D3DUSAGE_WRITEONLY, m_staticBufferList[index].fvf,
D3DPOOL_DEFAULT,
&m_staticBufferList[index].vbPtr,
NULL)))
return UGP_FAIL;

if(FAILED(m_staticBufferList[index].vbPtr->Lock(0, 0,
(
void**)&ptr, 0))) return UGP_FAIL;

memcpy(ptr, data, totalVerts
* stride);
m_staticBufferList[index].vbPtr
->Unlock();


*staticId = m_numStaticBuffers;
m_numStaticBuffers
++;

return UGP_OK;
}


int CD3DRenderer::Render(int staticId)
{
if(staticId >= m_numStaticBuffers) return UGP_FAIL;

if(m_activeStaticBuffer != staticId)
{
if(m_staticBufferList[staticId].ibPtr != NULL)
m_Device
->SetIndices(m_staticBufferList[staticId].ibPtr);

m_Device
->SetStreamSource(0,
m_staticBufferList[staticId].vbPtr,
0,
m_staticBufferList[staticId].stride);

m_Device
->SetFVF(m_staticBufferList[staticId].fvf);

m_activeStaticBuffer
= staticId;
}

if(m_staticBufferList[staticId].ibPtr != NULL)
{
switch(m_staticBufferList[staticId].primType)
{
case POINT_LIST:
if(FAILED(m_Device->DrawPrimitive(D3DPT_POINTLIST,
0, m_staticBufferList[staticId].numVerts)))
return UGP_FAIL;
break;

case TRIANGLE_LIST:
if(FAILED(m_Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0,
0, m_staticBufferList[staticId].numVerts / 3,
0, m_staticBufferList[staticId].numIndices)))
return UGP_FAIL;
break;

case TRIANGLE_STRIP:
if(FAILED(m_Device->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0,
0, m_staticBufferList[staticId].numVerts / 2,
0, m_staticBufferList[staticId].numIndices)))
return UGP_FAIL;
break;

case TRIANGLE_FAN:
if(FAILED(m_Device->DrawIndexedPrimitive(D3DPT_TRIANGLEFAN, 0,
0, m_staticBufferList[staticId].numVerts / 2,
0, m_staticBufferList[staticId].numIndices)))
return UGP_FAIL;
break;

case LINE_LIST:
if(FAILED(m_Device->DrawIndexedPrimitive(D3DPT_LINELIST, 0,
0, m_staticBufferList[staticId].numVerts / 2,
0, m_staticBufferList[staticId].numIndices)))
return UGP_FAIL;
break;

case LINE_STRIP:
if(FAILED(m_Device->DrawIndexedPrimitive(D3DPT_LINESTRIP, 0,
0, m_staticBufferList[staticId].numVerts,
0, m_staticBufferList[staticId].numIndices)))
return UGP_FAIL;
break;

default:
return UGP_FAIL;
}
}
else
{
switch(m_staticBufferList[staticId].primType)
{
case POINT_LIST:
if(FAILED(m_Device->DrawPrimitive(D3DPT_POINTLIST,
0, m_staticBufferList[staticId].numVerts)))
return UGP_FAIL;
break;

case TRIANGLE_LIST:
if(FAILED(m_Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0,
(
int)(m_staticBufferList[staticId].numVerts / 3))))
return UGP_FAIL;
break;

case TRIANGLE_STRIP:
if(FAILED(m_Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0,
(
int)(m_staticBufferList[staticId].numVerts / 2))))
return UGP_FAIL;
break;

case TRIANGLE_FAN:
if(FAILED(m_Device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0,
(
int)(m_staticBufferList[staticId].numVerts / 2))))
return UGP_FAIL;
break;

case LINE_LIST:
if(FAILED(m_Device->DrawPrimitive(D3DPT_LINELIST, 0,
m_staticBufferList[staticId].numVerts
/ 2)))
return UGP_FAIL;
break;

case LINE_STRIP:
if(FAILED(m_Device->DrawPrimitive(D3DPT_LINESTRIP, 0,
m_staticBufferList[staticId].numVerts)))
return UGP_FAIL;
break;

default:
return UGP_FAIL;
}
}

return UGP_OK;
}

  Initialize()和OneTimeInit()两个函数。这两个函数就像本书第1章中的演示程序一样用于初始化Direct3D。Initialize()函数像前面一样以相同的方式设置Direct3D,所以该函数没有什么新的东西。该函数的最后部分调用OneTimeInit()函数,以完成附加的初始化工作。Initialize()函数以窗口宽度(w)、高度(h)和窗口句柄(mainWin)以及一个指向窗口是否以全屏形式显示的标识(fullScreen)为参数。OneTimeInit()函数在此设置默认的投影矩阵。

Shutdown()函数主要负责清理所有渲染系统用过的内存。该函数在此循环检查,并释放所有的静态缓存数据,清理静态缓存列表,释放特定的Direct3D对象。

接下来是SetClearCol()、StartRender()、ClearBuffers()和EndRendering()函数。SetClearCol()函数以清屏的红绿蓝三色的浮点值作为参数。StartRender()和ClearBuffers()函数使用三个布尔值指明系统是否清除颜色、深度和stencil缓存。最后一个参数对渲染没有任何作用。StartRender()函数用于启动一个新的场景,而ClearBuffers()用于清理已经启动的场景。EndRendering()函数没有任何参数,用于停止场景的渲染。

下来是CalculateProjMatrix()和CalculateOrthoMatrix()函数。CalculateProjMatrix()函数用于创建平行投影矩阵,它有三个参数:视场(fv)、近距离(n)和远距离值(f)。CalculateOrthoMatrix()函数和CalculateProjMatrix()函数的功能相同,不过它创建的是一个正交投影矩阵,而且他只有两个参数:近距离值(n)和远距离值(f)。

  渲染系统中的倒数第二个函数是CreateStaticBuffer()。该函数的功能是设置静态缓存对象中的一个对象内容,并将其添加到静态缓存列表中。该函数的参数包括:正在使用的顶点类型(本书将在稍后的游戏开发项目中复习该参数)、渲染该几何图形(例如:三角形列表、顶点)的指令、几何图形中的顶点总数和指向新创建的将要保存的静态缓存ID的变量指针。最后一个参数用于保存静态缓存ID,这样就在绘制几何图形时可以将该值传递给Render()函数。 CreateStaticBuffer()函数设置一个静态缓存对象内容,并将其添加到静态缓存列表中。在将该静态缓存添加到列表后,就会创建索引和顶点缓存,并保存静态缓存ID,增加静态缓存总数。使用矩阵列表可以简化对象列表的创建。

// 设置静态缓存对象中的一个对象内容,并将其添加到静态缓存列表中

int CD3DRenderer::CreateStaticBuffer(

   VertexType vType,   // 正在使用的顶点类型

   PrimType primType,  // 渲染该几何图形(例如:三角形列表、顶点)的指令

   int totalVerts,     // 几何图形中的顶点总数

   int totalIndices,   // 几何图形中的索引总数

   int stride,         // 单个顶点尺寸的幅度值

   void **data,     // 保存顶点的数组

   unsigned int *indices, //保存索引的数组

   int *staticId       // 保存静态缓存ID的指针

   );

这里,渲染系统中的最后一个函数是Render()。这个篇幅很长的函数包含了一个参数:静态缓存ID,它会将与该ID相关的几何图形渲染到屏幕上。函数最前面的部分快速检查静态缓存ID以确保其有效。接下来,该函数检查静态缓存ID是否可用。如果可用,它就会调用DrawPrimitive()函数渲染图形。如果静态缓存不可用,它就会调用SetStreamSource()和SetFvF()两个函数。可以像绘制无索引几何图形一样,Render()函数也可以绘制索引几何图形(使用索引的几何图形)。

你可能感兴趣的:(Engine)