main.h头文件包含了用于GUI系统和控件的define语句。这里将在游戏源文件中添加3个新函数,它们分别是InitializeMainMenu()、MainMenuCallback()和MainMenuRender()。其中InitializeMainMenu()由GameInitialize()函数调用,将整个GUI的主菜单加载到内存中。MainMenuRender()由GameLoop()函数调用,借助渲染系统将主菜单显示在屏幕上。函数MainMenuCallback()是GUI系统的回调函数,对按钮动作做出响应。
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(); // Menu functions. bool InitializeMainMenu(); void MainMenuCallback(int id, int state); void MainMenuRender(); // Main game functions. bool GameInitialize(); void GameLoop(); void GameShutdown(); // Main menu defines. GUI_FRAME #define GUI_MAIN_SCREEN 1 #define GUI_START_SCREEN 2 #define GUI_CREDITS_SCREEN 3 // ids for our GUI controls. #define STATIC_TEXT_ID 1 #define BUTTON_START_ID 2 #define BUTTON_CREDITS_ID 3 #define BUTTON_QUIT_ID 4 #define BUTTON_BACK_ID 5 #define BUTTON_LEVEL_1_ID 6 #endif
main.cpp
#include"main.h" // Globals... HWND g_hwnd; CRenderInterface *g_Render = NULL; // GUI ids. int g_mainGui = -1; int g_startGui = -1; int g_creditsGui = -1; int g_currentGUI = GUI_MAIN_SCREEN; // Font id. int g_arialID = -1; // Temp Mouse state information. bool LMBDown = false; int mouseX = 0, mouseY = 0; 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; case WM_LBUTTONDOWN: LMBDown = true; break; case WM_LBUTTONUP: LMBDown = false; break; case WM_MOUSEMOVE: mouseY = HIWORD (lp); mouseX = LOWORD (lp); 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); // 创建渲染静态文本用的字体 if(!g_Render->CreateText("Arial", 0, true, 18, g_arialID)) return false; return true; } void ShutdownEngine() { if(g_Render) { g_Render->Shutdown(); delete g_Render; g_Render = NULL; } } bool InitializeMainMenu() { // Create gui screens. if(!g_Render->CreateGUI(g_mainGui)) return false; if(!g_Render->CreateGUI(g_startGui)) return false; if(!g_Render->CreateGUI(g_creditsGui)) return false; // Load backdrops. if(!g_Render->AddGUIBackdrop(g_mainGui, "menu/mainMenu.jpg")) return false; if(!g_Render->AddGUIBackdrop(g_startGui, "menu/startMenu.jpg")) return false; if(!g_Render->AddGUIBackdrop(g_creditsGui, "menu/creditsMenu.jpg")) return false; // Set main screen elements. if(!g_Render->AddGUIStaticText(g_mainGui, STATIC_TEXT_ID, "Version: 1.0", PERCENT_OF(WIN_WIDTH, 0.85), PERCENT_OF(WIN_WIDTH, 0.05), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIButton(g_mainGui, BUTTON_START_ID, PERCENT_OF(WIN_WIDTH, 0.05), PERCENT_OF(WIN_HEIGHT, 0.40), "menu/startUp.png", "menu/StartOver.png", "menu/startDown.png")) return false; if(!g_Render->AddGUIButton(g_mainGui, BUTTON_CREDITS_ID, PERCENT_OF(WIN_WIDTH, 0.05), PERCENT_OF(WIN_HEIGHT, 0.50), "menu/creditsUp.png", "menu/creditsOver.png", "menu/creditsDown.png")) return false; if(!g_Render->AddGUIButton(g_mainGui, BUTTON_QUIT_ID, PERCENT_OF(WIN_WIDTH, 0.05), PERCENT_OF(WIN_HEIGHT, 0.60), "menu/quitUp.png", "menu/quitOver.png", "menu/quitDown.png")) return false; // Set start screen elements. if(!g_Render->AddGUIButton(g_startGui, BUTTON_LEVEL_1_ID, PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.15), "menu/level1Up.png", "menu/level1Over.png", "menu/level1Down.png")) return false; if(!g_Render->AddGUIButton(g_startGui, BUTTON_BACK_ID, PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.80), "menu/backUp.png", "menu/backOver.png", "menu/backDown.png")) return false; // Set credits screen elements. if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, "Game Design -", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.15), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, " Allen Sherrod", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.20), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, "Programming -", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.25), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, " Allen Sherrod", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.30), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, "Sound -", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.35), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, " Allen Sherrod", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.40), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, "Level Design -", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.45), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, " Allen Sherrod", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.50), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, "Speical Thanks -", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.55), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, " Jenifer Niles", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.60), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, " Bryan Davidson", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.65), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, " Charles River Media", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.70), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIStaticText(g_creditsGui, STATIC_TEXT_ID, " Readers of this book", PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.75), UGPCOLOR_ARGB(255,255,255,255), g_arialID)) return false; if(!g_Render->AddGUIButton(g_creditsGui, BUTTON_BACK_ID, PERCENT_OF(WIN_WIDTH, 0.1), PERCENT_OF(WIN_HEIGHT, 0.80), "menu/backUp.png", "menu/backOver.png", "menu/backDown.png")) return false; return true; } void MainMenuCallback(int id, int state) { switch(id) { case BUTTON_START_ID: if(state == UGP_BUTTON_DOWN) g_currentGUI = GUI_START_SCREEN; break; case BUTTON_CREDITS_ID: if(state == UGP_BUTTON_DOWN) g_currentGUI = GUI_CREDITS_SCREEN; break; case BUTTON_BACK_ID: if(state == UGP_BUTTON_DOWN) g_currentGUI = GUI_MAIN_SCREEN; break; case BUTTON_QUIT_ID: if(state == UGP_BUTTON_DOWN) PostQuitMessage(0); break; case BUTTON_LEVEL_1_ID: // Start first level. break; } } void MainMenuRender() { if(!g_Render) return; g_Render->StartRender(1, 1, 0); if(g_currentGUI == GUI_MAIN_SCREEN) g_Render->ProcessGUI(g_mainGui, LMBDown, mouseX, mouseY, MainMenuCallback); else if(g_currentGUI == GUI_START_SCREEN) g_Render->ProcessGUI(g_startGui, LMBDown, mouseX, mouseY, MainMenuCallback); else g_Render->ProcessGUI(g_creditsGui, LMBDown, mouseX, mouseY, MainMenuCallback); g_Render->EndRendering(); } bool GameInitialize() { if(!InitializeMainMenu()) return false; return true; } void GameLoop() { MainMenuRender(); } void GameShutdown() { }
defines.h
#ifndef _UGP_DEFINES_H_ #define _UGP_DEFINES_H_ #include#define PERCENT_OF(a, b) (int)(a * b) // Boolean values. #define UGP_INVALID -1 #define UGP_OK 1 #define UGP_FAIL 0 // Vertex formats. GUI控件矩形的灵活顶点格式 #define GUI_FVF 2 // Types of controls we support. #define UGP_GUI_STATICTEXT 1 #define UGP_GUI_BUTTON 2 #define UGP_GUI_BACKDROP 3 // Mouse button states. #define UGP_BUTTON_UP 1 #define UGP_BUTTON_OVER 2 #define UGP_BUTTON_DOWN 3 // Light type defines. #define LIGHT_POINT 1 #define LIGHT_DIRECTIONAL 2 #define LIGHT_SPOT 3 // 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 }; enum RenderState { CULL_NONE, CULL_CW, CULL_CCW, DEPTH_NONE, DEPTH_READONLY, DEPTH_READWRITE, SHADE_POINTS, SHADE_SOLIDTRI, SHADE_WIRETRI, SHADE_WIREPOLY, TRANSPARENCY_NONE, TRANSPARENCY_ENABLE }; enum TransState { TRANS_ZERO = 1, TRANS_ONE, TRANS_SRCCOLOR, TRANS_INVSRCCOLOR, TRANS_SRCALPHA, TRANS_INVSRCALPHA, TRANS_DSTALPHA, TRANS_INVDSTALPHA, TRANS_DSTCOLOR, TRANS_INVDSTCOLOR, TRANS_SRCALPHASAT, TRANS_BOTHSRCALPHA, TRANS_INVBOTHSRCALPHA, TRANS_BLENDFACTOR, TRANS_INVBLENDFACTOR }; enum TextureState { MIN_FILTER, MAG_FILTER, MIP_FILTER }; enum FilterType { POINT_TYPE, LINEAR_TYPE, ANISOTROPIC_TYPE }; // Color defines. #define UGPCOLOR_ARGB(a,r,g,b) ((unsigned long)((((a)&0xff)<<24)|\ (((r)&0xff)<<16)|(((g)&0xff)<<8)|\ ((b)&0xff))) #endif
engine.h
#ifndef _UGP_ENGINE_H_ #define _UGP_ENGINE_H_ #include"structs.h" #include"RenderInterface.h" #include"D3DRenderer.h" #include"light.h" #include"material.h" #endif
structs.h
#ifndef _UGP_STRUCTS_H_ #define _UGP_STRUCTS_H_ // A structure for our custom vertex type. struct stGUIVertex { float x, y, z, rhw; unsigned long color; float tu, tv; }; #endif
GUI.h
#ifndef _UGP_D3D_GUI_H_ #define _UGP_D3D_GUI_H_ #include"defines.h" struct stGUIControl { // 控件类型 int m_type; // 控件id int m_id; // 控件颜色(仅用于静态文本) unsigned long m_color; // 静态文本:字体id;按钮,背景图:静态几何图形缓存中的id int m_listID; // 左上角的x,y坐标(用于静态文本和按钮) int m_xPos, m_yPos; // 按钮的宽高(仅用于按钮) int m_width, m_height; //静态文本的内容 char *m_text; // 按钮弹起、按下、鼠标在按钮上时分别显示的纹理的id; // 当控件类型是背景图时,用m_upTex存储纹理id int m_upTex, m_downTex, m_overTex; }; // 渲染系统将负责字体和静态几何图形缓存的创建、删除和管理。 class CGUISystem { public: CGUISystem() : m_controls(0), m_totalControls(0), m_backDropID(-1) {} ~CGUISystem() { Shutdown(); } // 向控件链表中加一个空的控件对象 int IncreaseControls(); // 添加背景图 // @texID 背景图的纹理ID // @staticID 存储背景图几何形状的静态缓存ID bool AddBackdrop(int texID, int staticID); // 添加静态文本控件 // @id 控件id // @text 文本内容 // @x 文本的起始x坐标 // @y 文本的起始y坐标 // @color 文本颜色 // @fontID 文本用到的字体id(在字体链表中的索引) bool AddStaticText(int id, char *text, int x, int y, unsigned long color, int fontID); // @id 控件id // @x 左上角的x坐标 // @y 左上角的y坐标 // @width 按钮宽度 // @height 按钮高度 // @ upID 按钮弹起时的纹理id // @overID 鼠标在按钮上时的纹理id // @downID 按钮按下时的纹理id // @staticID 显示按钮几何形状的静态缓存ID bool AddButton(int id, int x, int y, int width, int height, int upID, int overID, int downID, unsigned int staticID); // 清理资源 void Shutdown(); stGUIControl *GetGUIControl(int id) { if(id < 0 || id >= m_totalControls) return NULL; return &m_controls[id]; } int GetTotalControls() { return m_totalControls; } stGUIControl *GetBackDrop() { if(m_backDropID >= 0 && m_totalControls) return &m_controls[m_backDropID]; return NULL; } private: // 控件链表头指针 stGUIControl *m_controls; // 控件总数 int m_totalControls; // 背景纹理的id(索引) int m_backDropID; }; #endif
GUI.cpp
#include"GUI.h" int CGUISystem::IncreaseControls() { if(!m_controls) { m_controls = new stGUIControl[1]; if(!m_controls) return UGP_FAIL; memset(&m_controls[0], 0, sizeof(stGUIControl)); } else { stGUIControl *temp; temp = new stGUIControl[m_totalControls + 1]; if(!temp) return UGP_FAIL; memset(temp, 0, sizeof(stGUIControl) * (m_totalControls + 1)); memcpy(temp, m_controls,sizeof(stGUIControl) * m_totalControls); delete[] m_controls; m_controls = temp; } return UGP_OK; } bool CGUISystem::AddBackdrop(int texID, int sID) { if(texID < 0 || sID < 0) return false; // 若之前没背景图则把texID当做背景图,否则直接修改原来的背景图的id if(m_backDropID < 0) { // Create a blank control. if(!IncreaseControls()) return false; // Fill in necessary info. m_controls[m_totalControls].m_type = UGP_GUI_BACKDROP; m_controls[m_totalControls].m_upTex = texID; m_controls[m_totalControls].m_listID = sID; // Keep track which index is backdrop. // Allows us to render backdrop first without // having to have added it first. m_backDropID = m_totalControls; // Increment total. m_totalControls++; } else { // Else just override the tex id and static buffer id. m_controls[m_backDropID].m_upTex = texID; m_controls[m_backDropID].m_listID = sID; } return true; } bool CGUISystem::AddStaticText(int id, char *text, int x, int y, unsigned long color, int fontID) { if(!text || fontID < 0) return false; // Create a blank control. if(!IncreaseControls()) return false; // Fill it with all the info we need for static text. m_controls[m_totalControls].m_type = UGP_GUI_STATICTEXT; m_controls[m_totalControls].m_id = id; m_controls[m_totalControls].m_color = color; m_controls[m_totalControls].m_xPos = x; m_controls[m_totalControls].m_yPos = y; m_controls[m_totalControls].m_listID = fontID; // Copy text data. int len = strlen(text); m_controls[m_totalControls].m_text = new char[len + 1]; if(!m_controls[m_totalControls].m_text) return false; memcpy(m_controls[m_totalControls].m_text, text, len); m_controls[m_totalControls].m_text[len] = '\0'; // Increment total. m_totalControls++; return true; } bool CGUISystem::AddButton(int id, int x, int y, int width, int height, int upID, int overID, int downID, unsigned int staticID) { // Create a blank control. if(!IncreaseControls()) return false; // Set all the data needed to render/process a button. m_controls[m_totalControls].m_type = UGP_GUI_BUTTON; m_controls[m_totalControls].m_id = id; m_controls[m_totalControls].m_xPos = x; m_controls[m_totalControls].m_yPos = y; m_controls[m_totalControls].m_width = width; m_controls[m_totalControls].m_height = height; m_controls[m_totalControls].m_upTex = upID; m_controls[m_totalControls].m_overTex = overID; m_controls[m_totalControls].m_downTex = downID; m_controls[m_totalControls].m_listID = staticID; // Increment total. m_totalControls++; return true; } void CGUISystem::Shutdown() { // Release all resources. for(int s = 0; s < m_totalControls; s++) { if(m_controls[s].m_text) { delete[] m_controls[s].m_text; m_controls[s].m_text = NULL; } } m_totalControls = 0; if(m_controls) delete[] m_controls; m_controls = NULL; }
RenderInterface.h
#ifndef _UGP_RENDERINTERFACE_H_ #define _UGP_RENDERINTERFACE_H_ #include"defines.h" #include"material.h" #include"light.h" #include"GUI.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 SetMaterial(stMaterial *mat) = 0; virtual void SetLight(stLight *light, int index) = 0; virtual void DisableLight(int index) = 0; virtual void SetDepthTesting(RenderState state) = 0; virtual void SetTransparency(RenderState state, TransState src, TransState dst) = 0; virtual int AddTexture2D(char *file, int *texId) = 0; virtual void SetTextureFilter(int index, int filter, int val) = 0; virtual void SetMultiTexture() = 0; virtual void ApplyTexture(int index, int texId) = 0; virtual void SaveScreenShot(char *file) = 0; virtual void EnablePointSprites(float size, float min, float a, float b, float c) = 0; virtual void DisablePointSprites() = 0; // 创建新字体 // @font 字体名称 // @weight 字体权重 // @italic 是否为斜体 // @size 字体大小 // @id 字体在字体数组中的索引 virtual bool CreateText(char *font, int weight, bool italic, int size, int &id) = 0; // 渲染静态文本 // @id 字体的索引id // @x 文本起始x坐标 // @y 文本的起始y坐标 // @r,g,b 文本的颜色 // @text 文本的内容 virtual void DisplayText(int id, long x, long y, int r, int g, int b, char *text, ...) = 0; virtual void DisplayText(int id, long x, long y, unsigned long color, char *text, ...) = 0; // 创建一个新的GUI Frame // @id 新创建的GUI Frame在GUI数组中的索引id bool CreateGUI(int &id) { if(!m_guiList) { m_guiList = new CGUISystem[1]; if(!m_guiList) return UGP_FAIL; } else { CGUISystem *temp; temp = new CGUISystem[m_totalGUIs + 1]; memcpy(temp, m_guiList, sizeof(CGUISystem) * m_totalGUIs); delete[] m_guiList; m_guiList = temp; } id = m_totalGUIs; m_totalGUIs++; return true; } // 向某gui中添加背景图 // @guiId 目标gui的索引 // @fileName 背景图索引 virtual bool AddGUIBackdrop(int guiId, char *fileName) = 0; // 向某gui中添加静态文本 // @guiId 目标gui的索引 // @id 控件的id // @text 文本内容 // @x 文本起始x坐标 // @y 文本起始y坐标 // @color 文本颜色 // @fontID 用到的字体的索引id virtual bool AddGUIStaticText(int guiId, int id, char *text, int x, int y, unsigned long color, int fontID) = 0; // @guiId 目标gui的索引 // @id 控件的id // @x 起始x坐标 // @y 起始y坐标 // @up 按钮弹起时的纹理的路径 // @over 鼠标在按钮上时的纹理的路径 // @down 按钮按下时的纹理的路径 virtual bool AddGUIButton(int guiId, int id, int x, int y, char *up, char *over, char *down) = 0; // Render GUI // 函数以GUI对象ID为参数。并将GUI显示到屏幕上。该函数也要处理按钮状态,将GUI元素显示到屏幕上。 // @guiId 目标gui的索引 // @LMBDown 左键是否按下 // @mouseX 鼠标当前位置的x坐标 // @mouseY 鼠标当前位置的Y坐标 // @funcPtr 回调函数指针 // @id gui上的按钮控件的id // @state 按钮控件状态 virtual void ProcessGUI(int guiID, bool LMBDown, int mouseX, int mouseY, void(*funcPtr)(int id, int state)) = 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; // 字体总数 int m_totalFonts; // GUI Frame的数组头指针 CGUISystem *m_guiList; // GUI Frame的总数 int m_totalGUIs; WinHWND m_mainHandle; float m_near; float m_far; }; #endif
D3DRenderer.h
#ifndef _D3D_RENDERER_H_ #define _D3D_RENDERER_H_ #include#include #include #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; }; struct stD3DTexture { stD3DTexture() : fileName(0), image(0), width(0), height(0) {} char *fileName; int width, height; LPDIRECT3DTEXTURE9 image; }; 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 SetMaterial(stMaterial *mat); void SetLight(stLight *light, int index); void DisableLight(int index); void SetDepthTesting(RenderState state); void SetTransparency(RenderState state, TransState src, TransState dst); int AddTexture2D(char *file, int *texId); void SetTextureFilter(int index, int filter, int val); void SetMultiTexture(); void ApplyTexture(int index, int texId); void SaveScreenShot(char *file); void EnablePointSprites(float size, float min, float a, float b, float c); void DisablePointSprites(); // bool CreateText(char *font, int weight, bool italic, int size, int &id); void DisplayText(int id, long x, long y, int r, int g, int b, char *text, ...); void DisplayText(int id, long x, long y, unsigned long color, char *text, ...); bool AddGUIBackdrop(int guiId, char *fileName); bool AddGUIStaticText(int guiId, int id, char *text, int x, int y, unsigned long color, int fontID); bool AddGUIButton(int guiId, int id, int x, int y, char *up, char *over, char *down); void ProcessGUI(int guiID, bool LMBDown, int mouseX, int mouseY, void(*funcPtr)(int id, int state)); 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; // 字体数组头指针 LPD3DXFONT *m_fonts; // Total fonts in base class. stD3DStaticBuffer *m_staticBufferList; int m_numStaticBuffers; int m_activeStaticBuffer; stD3DTexture *m_textureList; int m_numTextures; }; bool CreateD3DRenderer(CRenderInterface **pObj); #endif
D3DRenderer.cpp
bool CD3DRenderer::CreateText(char *font, int weight, bool italic, int size, int &id) { if(!m_fonts) { m_fonts = new LPD3DXFONT[1]; if(!m_fonts) return UGP_FAIL; } else { LPD3DXFONT *temp; temp = new LPD3DXFONT[m_totalFonts + 1]; memcpy(temp, m_fonts, sizeof(LPD3DXFONT) * m_totalFonts); delete[] m_fonts; m_fonts = temp; } if(FAILED(D3DXCreateFont(m_Device, size, 0, weight, 1, italic, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, font, &m_fonts[m_totalFonts]))) return false; id = m_totalFonts; m_totalFonts++; return true; } void CD3DRenderer::DisplayText(int id, long x, long y, int r, int g, int b, char *text, ...) { RECT FontPosition = {x, y, m_screenWidth, m_screenWidth}; char message[1024]; va_list argList; if(id >= m_totalFonts) return; va_start(argList, text); vsprintf(message, text, argList); va_end(argList); m_fonts[id]->DrawText(NULL, message, -1, &FontPosition, DT_SINGLELINE, D3DCOLOR_ARGB(255, r, g, b)); } void CD3DRenderer::DisplayText(int id, long x, long y, unsigned long color, char *text, ...) { RECT FontPosition = {x, y, m_screenWidth, m_screenWidth}; char message[1024]; va_list argList; if(id >= m_totalFonts) return; va_start(argList, text); vsprintf(message, text, argList); va_end(argList); m_fonts[id]->DrawText(NULL, message, -1, &FontPosition, DT_SINGLELINE, color); } bool CD3DRenderer::AddGUIBackdrop(int guiId, char *fileName) { if(guiId >= m_totalGUIs) return false; int texID = -1, staticID = -1; if(!AddTexture2D(fileName, &texID)) return false; unsigned long col = D3DCOLOR_XRGB(255,255,255); stGUIVertex obj[] = { {(float)m_screenWidth, 0, 0, 1, col, 1, 0}, {(float)m_screenWidth, (float)m_screenHeight, 0, 1, col, 1, 1}, { 0, 0, 0, 1, col, 0, 0}, { 0, (float)m_screenHeight, 0, 1, col, 0, 1}, }; if(!CreateStaticBuffer(GUI_FVF, TRIANGLE_STRIP, 4, 0, sizeof(stGUIVertex), (void**)&obj, NULL, &staticID)) return false; return m_guiList[guiId].AddBackdrop(texID, staticID); } bool CD3DRenderer::AddGUIStaticText(int guiId, int id, char *text, int x, int y, unsigned long color, int fontID) { if(guiId >= m_totalGUIs) return false; return m_guiList[guiId].AddStaticText(id, text, x, y, color, fontID); } bool CD3DRenderer::AddGUIButton(int guiId, int id, int x, int y, char *up, char *over, char *down) { if(guiId >= m_totalGUIs) return false; int upID = -1, overID = -1, downID = -1, staticID = -1; if(!AddTexture2D(up, &upID)) return false; if(!AddTexture2D(over, &overID)) return false; if(!AddTexture2D(down, &downID)) return false; unsigned long col = D3DCOLOR_XRGB(255,255,255); int w = m_textureList[upID].width; int h = m_textureList[upID].height; stGUIVertex obj[] = { {(float)(w + x), (float)(0 + y), 0, 1, col, 1, 0}, {(float)(w + x), (float)(h + y), 0, 1, col, 1, 1}, {(float)(0 + x), (float)(0 + y), 0, 1, col, 0, 0}, {(float)(0 + x), (float)(h + y), 0, 1, col, 0, 1}, }; if(!CreateStaticBuffer(GUI_FVF, TRIANGLE_STRIP, 4, 0, sizeof(stGUIVertex), (void**)&obj, NULL, &staticID)) return false; return m_guiList[guiId].AddButton(id, x, y, w, h, upID, overID, downID, staticID); } void CD3DRenderer::ProcessGUI(int guiId, bool LMBDown, int mouseX, int mouseY, void(*funcPtr)(int id, int state)) { if(guiId >= m_totalGUIs || !m_Device) return; CGUISystem *gui = &m_guiList[guiId]; if(!gui) return; // 必须先画背景图 stGUIControl *backDrop = gui->GetBackDrop(); // Draw backdrop first to control render order. Don't // want to draw this after buttons in 2D. if(backDrop) { // 设置纹理对象 ApplyTexture(0, backDrop->m_upTex); // 渲染该纹理到m_listID对应的静态缓存对应的几何形状 Render(backDrop->m_listID); // 渲染完该纹理后清空当前纹理对象 ApplyTexture(0, -1); } // Initial button state. int status = UGP_BUTTON_UP; // 遍历GUI控件对象数组,并逐个渲染 Loop through all controls and display them. for(int i = 0; i < gui->GetTotalControls(); i++) { // Get the current control. stGUIControl *pCnt = gui->GetGUIControl(i); if(!pCnt) continue; // Take action depending on what type it is. switch(pCnt->m_type) { case UGP_GUI_STATICTEXT: DisplayText(pCnt->m_listID, pCnt->m_xPos, pCnt->m_yPos, pCnt->m_color, pCnt->m_text); break; case UGP_GUI_BUTTON: status = UGP_BUTTON_UP; // Set alpha transparency on for the texture image. m_Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); m_Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); m_Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); // Check if over the button or pressing it. if(mouseX > pCnt->m_xPos && mouseX < (pCnt->m_xPos + pCnt->m_width) && mouseY > pCnt->m_yPos && mouseY < (pCnt->m_yPos + pCnt->m_height)) { if(LMBDown) status = UGP_BUTTON_DOWN; else status = UGP_BUTTON_OVER; } // State will depend on it's texture. if(status == UGP_BUTTON_UP) ApplyTexture(0, pCnt->m_upTex); if(status == UGP_BUTTON_OVER) ApplyTexture(0, pCnt->m_overTex); if(status == UGP_BUTTON_DOWN) ApplyTexture(0, pCnt->m_downTex); // Render button. Render(pCnt->m_listID); // Turn off alpha. m_Device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); break; } // Process control by calling the callback. 处理空间上的事件 if(funcPtr) funcPtr(pCnt->m_id, status); } } 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; }