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()函数也可以绘制索引几何图形(使用索引的几何图形)。
13. GameProjec1_GameEngine相关推荐
- mahout安装测试
Mahout 是 Apache Software Foundation(ASF) 旗下的一个开源项目,提供一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建智能应用程序.Apa ...
- ImportError: DLL load failed: 找不到指定的模块。 TensorFlow 1.13
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/zhenlingcn/article/details/88647288 问题描述 问题环境 Tenso ...
- iPhone 14 与iPhone 13
iPhone 14 与iPhone 13 iPhone14Pro配置曝光:感叹号+4800w像素 | 小米12Ultra 最新套壳图 距离下一代iPhone发布还有半年之久,关于iPhone14系列的 ...
- PyTorch 笔记(13)— autograd(0.4 之前和之后版本差异)、Tensor(张量)、Gradient(梯度)
1. 背景简述 torch.autograd 是 PyTorch 中方便用户使用,专门开发的一套自动求导引擎,它能够根据输入和前向传播过程自动构建计算图,并执行反向传播. 计算图是现代深度学习框架 P ...
- 机器学习入门(13)— Affine 仿射层、Softmax 归一化指数函数层实现
1. 一维 Affine 仿射层 我们回顾下之前为了计算加权信号的总和,使用了矩阵的乘积运算 NumPy 中是 np.dot() , 参照代码如下: In [7]: X = np.random.ran ...
- 读书笔记2013第13本:《怎样解题》
<怎样解题>这本书是在看<编程大师访谈录>(中文版第12页)这本书时无意发现的,一个编程大师推荐这本书来指导编程设计,google到这本书后粗略地翻看了一遍,发现是一本教学生如 ...
- [14] 薪酬迅速翻倍的13条跳槽原则
首先,真正的高级人才是不用找工作的,因为只有被工作找的份. 但是,难免有些高级人才厌倦了旧的工作环境,或者遇到天花板,没有了发展空间,或者遇到新老板上任后排除异己来提拔自己的亲信等等,如果您真打算自己 ...
- centos6.5 php5.2,Linux中PHP安装与配置(CentOS-6.5:php-5.2.13)
1 PHP简介 PHP(PHP: Hypertext Preprocessor的缩写,中文名:"超文本预处理器")是一种通用开源脚本语言.语法吸收了C语言.Java和Per ...
- 乐高无限无法进入服务器,乐高无限6.13更新 无法进入游戏问题修复
乐高无限于13日例常更新,那么这次更新了什么内容呢,修复了哪些东西呢,下面就跟随小编一起去了解一下详细内容吧. 生存模式: 1.解决了在玩法模式中使用假日烟花异常的问题; 2.解决了昵称中包含部分特殊 ...
- 福建省2013高职单招计算机类试题,13年福建-高职单招-计算机类试题及答案.doc
计算机类专业基础知识试题 第Ⅰ卷 单项选择题(在每小题的四个备选答案中,选出一个正确答案,并将正确的字母标号填涂在答题卡相应在位置上,每小题3分,共120分) 世界上第一台计算机(ENIAC)诞生的时 ...
最新文章
- 因未发项目奖金,一名程序员决定删代码泄愤
- Redis 热点 Key 如何发现?又该如何解决?
- 【数学与算法】贝塞尔曲线
- android:process=.server,Android启动(三)----开启SystemServer进程
- mysql报错注入实战_MySQL手工注入实战
- 三星:Android之外,技术为王
- python必备基础代码-【Python基础系列】常见的数据预处理方法(附代码)
- 在mysql上发布jbpm4.3
- nginx php上传配置
- 中国单箱梁体最宽矮塔斜拉桥合龙
- 敏捷开发Sprint周期总结
- NXP TJA1043 datasheet 知识点记录
- 推荐一些北京的景点(1简单版)
- autojs切换输入法
- linux swap空间不足,swap空间不足问题解决
- 微信小程序:页面传递中文出现乱码
- 欢迎大家访问我的网站
- <Notes>城市复杂环境的视觉定位与建图(报告人:上交邹丹平教授)
- idea热部署插件JRebel激活(强烈推荐,试试就离不开了)
- MATLAB矩阵变换
热门文章
- Android AlertDialog创建过程详解
- window对象小结
- java导入hbase_如何用java导入hbase.dat文件
- c语言课程性质,c语言课程的特性
- 路由器刷breed web控制台助手_红米AC2100路由器从零认证登录SCUT校园网踩坑经历...
- mysql三台部署_使用三台主机部署LNMP
- mysql实现分布式锁_数据库实现分布式锁
- mysqloffset什么意思_mysql查询时offset过大影响性能的原因和优化详解
- python表格数据过滤复制到另外一个表格
- 帆软Tab控件与控制组件隐藏的异同点