基於DirectX的簡單UI介面製作
阿新 • • 發佈:2018-12-30
程式碼裡註釋寫的比較清楚,有點DirectX基礎的就能簡單看懂,
謹以此文記錄那些年寫過的程式碼,和分享給那些需要的朋友o(∩_∩)o
//D3DComMacro.h
/*-------------------------------------------------------------- 【標頭檔案】:D3DComMacro.h Create by Beyond Ray,2014年2月 (描述):公共輔助巨集的定義 ----------------------------------------------------------------*/ #pragma once #ifndef HR #define HR(hr) {if(FAILED(hr)) return E_FAIL ;} //定義HR巨集,便於錯誤檢測 #endif #ifndef SAFE_RELEASE #define SAFE_RELEASE(p) {if(p) { (p)->Release(); p = NULL ;}} //定義一個安全釋放巨集,便於COM介面的釋放 #endif #ifndef SAFE_DELETE #define SAFE_DELETE(p) {if(p) {delete(p); p = NULL ;}} //定義一個安全刪除巨集,便於new分配記憶體的刪除 #endif #ifndef SAFE_DELETE_ARRAY #define SAFE_DELETE_ARRAY(p) {if(p) {delete [] (p); p = NULL ;}} //定義一個安全刪除巨集,便於new[]分配記憶體的刪除 #endif #ifndef IF #define IF(p) {if(p != D3D_OK) return false;} //定義一個IF巨集,用於返回BOOL型的檢測 #endif
//GUIClass.h
/*-------------------------------------------------------------- 【標頭檔案】:GUIClass.h Created by Beyond Ray,2014年2月 (描述):一個封裝了控制元件物件的類和控制元件處理函式 ----------------------------------------------------------------*/ #pragma once #include"D3DComMacro.h" #include<d3d9.h> #include<d3dx9.h> //定義控制元件型別 #define UGP_GUI_STATIC_TEXT 1 #define UGP_GUI_BUTTON 2 //定義滑鼠按鍵及指標的狀態 #define GUI_LBUTTON_DOWN 1 #define GUI_LBUTTON_UP 2 #define GUI_MOUSE_OVER 3 //定義選單頁面切換的巨集 #define GUI_BKGROUND_MAIN 1 #define GUI_BKGROUND_START 2 #define GUI_BKGROUND_LOAD 3 #define GUI_BKGROUND_OPTION 4 //具體的控制元件型別ID #define GUI_STATIC_TEXT 0 #define GUI_BUTTON_START 1 #define GUI_BUTTON_LOAD 2 #define GUI_BUTTON_OPTION 3 #define GUI_BUTTON_QUIT 4 #define GUI_BUTTON_BACK 5 //定義控制元件型別ID最大上限編號 #define GUI_TEXT_MAX 0 #define GUI_BUTTON_MAX 5 //靈活頂點格式的結構 typedef struct { float x, y, z, rhw; //頂點座標 float u, v; //紋理貼圖 //DWORD color; } GUIVERTEX, * LPGUIVERTEX; #define D3DFVF_GUI (D3DFVF_XYZRHW | D3DFVF_TEX1 ) //控制元件屬性結構體 struct GUICONTROL { int type; //控制元件的型別(文字、按鈕) int controlID; //控制元件的具體型別ID WORD index; //文字:對字型物件的索引,按鈕:對頂點快取的索引 WORD x; //控制元件相對於視窗客戶區左上角的X位置 WORD y; //控制元件相對於視窗客戶區左上角的Y位置 WORD width; //控制元件的寬度 WORD height; //控制元件的高度 TCHAR * text; //文字的內容 unsigned long color; //文字的顏色 LPDIRECT3DTEXTURE9 textureUP, textureDown, textureOver; //(只相對於按鈕)表示滑鼠按下,釋放,經過時的紋理貼圖 }; //【定義一個GUI物件類】 class GUIClass { private: LPDIRECT3DDEVICE9 m_pd3dDevice9; //Direct3D裝置物件(COM介面物件) LPDIRECT3DTEXTURE9 m_pBackGround; //控制元件物件的背景貼圖(COM介面物件) LPDIRECT3DVERTEXBUFFER9 m_pBkBuffer; //背景圖快取物件(COM介面物件) LPD3DXFONT * m_pFont; //指向字型物件的指標(COM介面物件陣列) LPDIRECT3DVERTEXBUFFER9 * m_pCtrlBuffer; //控制元件按鈕快取物件的指標(COM介面物件陣列) GUICONTROL * m_pControl; //控制元件的陣列物件 int m_iFontNums; //字型種類的數目 int m_iTextNums; //文字物件的數目 int m_iButtonNums; //按鈕物件的數目 int m_iControlNums; //控制元件物件的數目 WORD m_wBackgroundWidth; //貼圖背景的寬度 WORD m_wBackgroundHeight; //貼圖背景的高度 BOOL m_bIsBKBufferUsed; //用一個標識來判斷是否使用了背景(以緩衝區的建立為標誌) public: GUIClass(LPDIRECT3DDEVICE9 pd3dDevice9, WORD Width, WORD Height); //建構函式 ~GUIClass(){ CleanUp(); } //解構函式 public: LPDIRECT3DDEVICE9 GetDevice(){ return m_pd3dDevice9; } //返回裝置物件 int GetFontNums(){ return m_iFontNums; } //返回字型種類的數目 int GetTextNums(){ return m_iTextNums; } //返回文字物件的數目 int GetButtonNums(){ return m_iButtonNums; } //返回按鈕物件的數目 int GetControlNums(){ return m_iControlNums; } //返回控制元件物件的數目 WORD GetBackgroundWidth(){ return m_wBackgroundWidth; } //返回貼圖背景的寬度 WORD GetBackgroundHeight(){ return m_wBackgroundHeight; } //返回貼圖背景的高度 VOID SetBackgroundWidth(WORD Width){ m_wBackgroundWidth = Width; } //設定貼圖背景的寬度 VOID SetBackgroundHeight(WORD Height){ m_wBackgroundHeight = Height; } //設定貼圖背景的高度 LPDIRECT3DTEXTURE9 GetBkTexture(){ return m_pBackGround; } //返回背景紋理貼圖 LPDIRECT3DVERTEXBUFFER9 GetBkBuffer(){ return m_pBkBuffer; } //返回背景頂點快取 BOOL IsBKBufferUsed(){ return m_bIsBKBufferUsed; } //判斷是否使用了背景(以緩衝區的建立為標誌) //用索引分別得到字型,按鈕頂點快取,控制元件的物件 LPD3DXFONT GetFont(WORD Index) { if (Index >= m_iFontNums) return NULL; return m_pFont[Index]; } LPDIRECT3DVERTEXBUFFER9 GetCtrlBuffer(WORD Index) { if (Index >= m_iButtonNums) return NULL; return m_pCtrlBuffer[Index]; } GUICONTROL* GetControl(WORD Index) { if (Index >= m_iControlNums) return NULL; return &m_pControl[Index]; } BOOL AddBackground(TCHAR * pBackgroundName); //新增背景 BOOL CreateTextFont(TCHAR * FontName, DWORD SIZE, WORD *Index); //增加字型 BOOL AddStaticText(TCHAR * TextContent, UINT ControlID, DWORD Color, WORD x, WORD y, WORD Index);//增加文字 BOOL AddButton(UINT ControlID, WORD x, WORD y, //增加按鈕 TCHAR* TextureDown, TCHAR* TextureUp, TCHAR* TextureOver); VOID CleanUp(); //資源的清理 }; BOOL ProcessGUI(GUIClass * GUI, BOOL LMBDown, WORD MouseX, WORD MouseY, void(CALLBACK *GUIProc)(int Id, int State)); //回撥函式作形參
//GUIClass.cpp
/*-------------------------------------------------------------- 【Cpp檔案】:GUIClass.cpp Created by Beyond Ray,2014年2月 (描述):一個封裝了控制元件物件的類和控制元件處理函式的實現 ----------------------------------------------------------------*/ #include"GUIClass.h" //-------------------------------------------【GUIClass()函式】-------------------------------------------------- // Desc:建構函式(初始化) //--------------------------------------------------------------------------------------------------------------- GUIClass::GUIClass(LPDIRECT3DDEVICE9 pd3dDevice9, WORD Width, WORD Height) { m_pd3dDevice9 = pd3dDevice9; m_pBackGround = NULL; m_pBkBuffer = NULL; m_pControl = NULL; m_pCtrlBuffer = NULL; m_pFont = NULL; m_iFontNums = 0; m_iTextNums = 0; m_iControlNums = 0; m_iButtonNums = 0; m_wBackgroundWidth = Width; m_wBackgroundHeight = Height; m_bIsBKBufferUsed = FALSE; } //-------------------------------------------【AddBackground()函式】--------------------------------------------- // Desc:新增GUIClass物件的唯一背景圖片 //--------------------------------------------------------------------------------------------------------------- BOOL GUIClass::AddBackground(TCHAR * pBackgroundName) { if (!pBackgroundName) return FALSE; IF(D3DXCreateTextureFromFile(m_pd3dDevice9, pBackgroundName, &m_pBackGround)); IF(m_pd3dDevice9->CreateVertexBuffer(4 * sizeof(GUIVERTEX), D3DUSAGE_WRITEONLY, D3DFVF_GUI, D3DPOOL_DEFAULT, &m_pBkBuffer, NULL)); float w = (float)m_wBackgroundWidth; float h = (float)m_wBackgroundHeight; GUIVERTEX Vertices[] = { { 0, h, 0.0f, 1.0f, 0.0f, 1.0f }, { 0, 0, 0.0f, 1.0f, 0.0f, 0.0f }, { w, h, 0.0f, 1.0f, 1.0f, 1.0f }, { w, 0, 0.0f, 1.0f, 1.0f, 0.0f } }; VOID *pVertices = NULL; IF(m_pBkBuffer->Lock(0, 0, &pVertices, NULL)); memcpy(pVertices, Vertices, sizeof(Vertices)); m_pBkBuffer->Unlock(); m_bIsBKBufferUsed = true; return TRUE; } //--------------------------------------------【CreateTextFont()函式】------------------------------------------- // Desc:建立並增加字型物件 //--------------------------------------------------------------------------------------------------------------- BOOL GUIClass::CreateTextFont(TCHAR * FontName, DWORD SIZE, WORD *Index) { if (!m_pFont) { m_pFont = new LPD3DXFONT[1]; if (!m_pFont) return FALSE; } else { LPD3DXFONT * pTempFont = new LPD3DXFONT[m_iFontNums + 1]; if (!pTempFont) return FALSE; memset(pTempFont, 0, sizeof(pTempFont)); memcpy(pTempFont, m_pFont, sizeof(m_pFont)); SAFE_DELETE_ARRAY(m_pFont); m_pFont = pTempFont; } IF(D3DXCreateFont(m_pd3dDevice9, SIZE, 0, 1000, 0, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, FontName, &m_pFont[m_iFontNums])); *Index = m_iFontNums; m_iFontNums++; return TRUE; } //-------------------------------------------【AddText()函式】--------------------------------------------------- // Desc:增加文字控制元件 //--------------------------------------------------------------------------------------------------------------- BOOL GUIClass::AddStaticText(TCHAR * TextContent, UINT ControlID, DWORD Color, WORD x, WORD y, WORD Index) { //對形參作檢測判斷 if ( ControlID > GUI_TEXT_MAX || Index >= m_iFontNums) return FALSE; //為m_pControl分配新的記憶體空間 if (!m_pControl) { m_pControl = new GUICONTROL[1]; if (!m_pControl) return FALSE; } else { GUICONTROL * pTempCtrl = new GUICONTROL[m_iControlNums + 1]; if (!pTempCtrl) return FALSE; memset(pTempCtrl, 0, (m_iControlNums + 1) * sizeof(GUICONTROL)); memcpy(pTempCtrl, m_pControl, m_iControlNums * sizeof(GUICONTROL)); SAFE_DELETE_ARRAY(m_pControl); m_pControl = pTempCtrl; } //填充新資料的引數 m_pControl[m_iControlNums].type = UGP_GUI_STATIC_TEXT; m_pControl[m_iControlNums].controlID = ControlID; m_pControl[m_iControlNums].x = x; m_pControl[m_iControlNums].y = y; m_pControl[m_iControlNums].index = Index; m_pControl[m_iControlNums].color = Color; //新文字的複製 int iChars = lstrlen(TextContent); m_pControl[m_iControlNums].text = new TCHAR[iChars + 1]; if (!m_pControl[m_iControlNums].text) return FALSE; lstrcpy(m_pControl[m_iControlNums].text, TextContent); m_pControl[m_iControlNums].text[iChars] = '\0'; //通過描述欄位讀取並計算寬和高 D3DXFONT_DESC desc; m_pFont[Index]->GetDesc(&desc); m_pControl[m_iControlNums].height = desc.Height; m_pControl[m_iControlNums].width = desc.Width * iChars; //控制元件數量和文字數量的增加 m_iControlNums++; m_iTextNums++; return TRUE; } //-------------------------------------------【AddButton()函式】---------------------------------------------- // Desc:增加按鈕控制元件 //------------------------------------------------------------------------------------------------------------ BOOL GUIClass::AddButton(UINT ControlID, WORD x, WORD y, TCHAR* TextureDown, TCHAR* TextureUp, TCHAR* TextureOver) { //對形參作檢測判斷 if (ControlID <= GUI_TEXT_MAX || ControlID > GUI_BUTTON_MAX) return FALSE; //為m_pControl分配新的記憶體空間 if (!m_pControl) { m_pControl = new GUICONTROL[1]; if (!m_pControl) return FALSE; } else { GUICONTROL * pTempCtrl = new GUICONTROL[m_iControlNums + 1]; if (!pTempCtrl) return FALSE; memset(pTempCtrl, 0, (m_iControlNums + 1) * sizeof(GUICONTROL)); memcpy(pTempCtrl, m_pControl, m_iControlNums * sizeof(GUICONTROL)); SAFE_DELETE_ARRAY(m_pControl); m_pControl = pTempCtrl; } //填充新資料的引數 m_pControl[m_iControlNums].type = UGP_GUI_BUTTON; m_pControl[m_iControlNums].controlID = ControlID; IF(D3DXCreateTextureFromFile(m_pd3dDevice9, TextureDown, &m_pControl[m_iControlNums].textureDown)); IF(D3DXCreateTextureFromFile(m_pd3dDevice9, TextureUp, &m_pControl[m_iControlNums].textureUP)); IF(D3DXCreateTextureFromFile(m_pd3dDevice9, TextureOver, &m_pControl[m_iControlNums].textureOver)); D3DSURFACE_DESC desc; m_pControl[m_iControlNums].textureDown->GetLevelDesc(0, &desc); m_pControl[m_iControlNums].x = x; m_pControl[m_iControlNums].y = y; m_pControl[m_iControlNums].height = desc.Height; m_pControl[m_iControlNums].width = desc.Width; //為m_pCtrlBuffer分配新的記憶體 if (!m_pCtrlBuffer) { m_pCtrlBuffer = new LPDIRECT3DVERTEXBUFFER9[1]; if (!m_pCtrlBuffer) return FALSE; } else { LPDIRECT3DVERTEXBUFFER9 * pTempCtrlBuffer = new LPDIRECT3DVERTEXBUFFER9[m_iButtonNums + 1]; if (!pTempCtrlBuffer) return FALSE; memcpy(pTempCtrlBuffer, m_pCtrlBuffer, m_iButtonNums * sizeof(LPDIRECT3DVERTEXBUFFER9));//指標的賦值 SAFE_DELETE_ARRAY(m_pCtrlBuffer); m_pCtrlBuffer = pTempCtrlBuffer; } //建立頂點緩衝區 IF(m_pd3dDevice9->CreateVertexBuffer(4 * sizeof(GUIVERTEX), 0, D3DFVF_GUI, D3DPOOL_MANAGED, &m_pCtrlBuffer[m_iButtonNums], NULL)); GUIVERTEX Vertics[] = { { x, y + desc.Height, 0, 1.0f, 0.0f, 1.0f }, { x, y, 0, 1.0f, 0.0f, 0.0f }, { x + desc.Width, y + desc.Height, 0, 1.0f, 1.0f, 1.0f }, { x + desc.Width, y, 0, 1.0f, 1.0f, 0.0f } }; VOID *pVertices = NULL; IF(m_pCtrlBuffer[m_iButtonNums]->Lock(0, 0, (void **)&pVertices, NULL)); memcpy(pVertices, Vertics, sizeof(Vertics)); m_pCtrlBuffer[m_iButtonNums]->Unlock(); m_pControl[m_iControlNums].index = m_iButtonNums; //增加控制元件和按鈕的數目 m_iButtonNums++; m_iControlNums++; return TRUE; } //-------------------------------------------【CleanUp()函式】--------------------------------------------------- // Desc:資源的清理 //--------------------------------------------------------------------------------------------------------------- VOID GUIClass::CleanUp() { if (m_bIsBKBufferUsed) { SAFE_RELEASE(m_pBackGround); SAFE_RELEASE(m_pBkBuffer); } for (int i = 0; i < m_iFontNums; i++) SAFE_RELEASE(m_pFont[i]); SAFE_DELETE_ARRAY(m_pFont); for (int i = 0; i < m_iButtonNums; i++) { SAFE_RELEASE(m_pCtrlBuffer[i]); } SAFE_DELETE_ARRAY(m_pCtrlBuffer); for (int i = 0; i < m_iControlNums; i++) { SAFE_RELEASE(m_pControl[i].textureDown); SAFE_RELEASE(m_pControl[i].textureUP); SAFE_RELEASE(m_pControl[i].textureOver); SAFE_DELETE_ARRAY(m_pControl[i].text); } SAFE_DELETE_ARRAY(m_pControl); } //----------------------------------------【ProcessGUI()函式】--------------------------------------------- // Desc:進行GUI的渲染 //--------------------------------------------------------------------------------------------------------- BOOL ProcessGUI(GUIClass * GUI, BOOL LMBDown, WORD MouseX, WORD MouseY, void(CALLBACK *GUIProc)(int Id, int State)) { if (!GUI) return FALSE; LPDIRECT3DDEVICE9 pd3dDevice9 = GUI->GetDevice(); if (!pd3dDevice9) return FALSE; if (!(GUI->IsBKBufferUsed() && GUI->GetBkBuffer() && GUI->GetBkTexture())) return FALSE; //渲染GUI背景 //pd3dDevice9->SetRenderState(D3DRS_LIGHTING, false); pd3dDevice9->SetTexture(0, GUI->GetBkTexture()); pd3dDevice9->SetStreamSource(0, GUI->GetBkBuffer(), 0, sizeof(GUIVERTEX)); pd3dDevice9->SetFVF(D3DFVF_GUI); pd3dDevice9->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); //用來顯示文字的物件 LPD3DXFONT pFont = NULL; RECT rect = { 0, 0, GUI->GetBackgroundWidth(), GUI->GetBackgroundHeight() }; // 建立一個頂點快取物件用於按鈕的渲染 LPDIRECT3DVERTEXBUFFER9 pVertexBuffer = NULL; int iState = GUI_LBUTTON_UP; //渲染控制元件 GUICONTROL *pGUIControl = NULL; for (WORD i = 0; i < GUI->GetControlNums(); i++) { iState = GUI_LBUTTON_UP; pGUIControl = GUI->GetControl(i); if (!pGUIControl) continue; switch (pGUIControl->type) { case UGP_GUI_STATIC_TEXT: pFont = GUI->GetFont(pGUIControl->index); if (!pFont) continue; //設定起始位置並輸出文字 rect.left = pGUIControl->x; rect.top = pGUIControl->y; pFont->DrawText(NULL, pGUIControl->text, -1, &rect, DT_LEFT | DT_SINGLELINE, pGUIControl->color); break; case UGP_GUI_BUTTON: pVertexBuffer = GUI->GetCtrlBuffer(pGUIControl->index); if (!pVertexBuffer) continue; //開啟Alpha混合 pd3dDevice9->SetRenderState(D3DRS_ALPHABLENDENABLE, true); pd3dDevice9->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); pd3dDevice9->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); if (MouseX >= pGUIControl->x && MouseX <= (pGUIControl->x + pGUIControl->width) && MouseY >= pGUIControl->y && MouseY <= (pGUIControl->y + pGUIControl->height)) { if (LMBDown) iState = GUI_LBUTTON_DOWN; else iState = GUI_MOUSE_OVER; } //開始渲染按鈕 if (iState == GUI_LBUTTON_DOWN) pd3dDevice9->SetTexture(0, pGUIControl->textureDown); if (iState == GUI_LBUTTON_UP) pd3dDevice9->SetTexture(0, pGUIControl->textureUP); if (iState == GUI_MOUSE_OVER) pd3dDevice9->SetTexture(0, pGUIControl->textureOver); pd3dDevice9->SetStreamSource(0, pVertexBuffer, 0, sizeof(GUIVERTEX)); pd3dDevice9->SetFVF(D3DFVF_GUI); pd3dDevice9->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); //關閉Alpha混合 pd3dDevice9->SetRenderState(D3DRS_ALPHABLENDENABLE, false); } if (GUIProc) GUIProc(pGUIControl->controlID, iState); } return TRUE; }
//main.cpp
/*----------------------------------------------------------------
【Cpp檔案】:main.cpp Create by Beyond Ray,2014年2月
(描述):簡單的GUI介面實現
------------------------------------------------------------------*/
//【標頭檔案】
#include"D3DComMacro.h"
#include"GUIClass.h"
#include <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
//【庫檔案】
#pragma comment (lib, "winmm.lib") //為呼叫 PlaySound 函式
#pragma comment (lib, "d3d9.lib") //Direct3D9相關庫檔案
#pragma comment (lib, "d3dx9.lib") //ID3DX相關庫檔案
#pragma comment (lib, "dxguid.lib") //GUID相關識別
#pragma comment (lib, "dinput8.lib") //DirectInput相關庫檔案
//【巨集定義】
#define WINDOW_TITLE L"致我們永不熄滅的遊戲夢想----【Beyond我愛楊】" //視窗標題
//【全域性變數宣告】
TCHAR lpClassName[] = TEXT("GDIDemo"); //宣告類名
HINSTANCE g_hInst = NULL; //例項控制代碼
LPDIRECT3DDEVICE9 g_pd3dDevice9 = NULL; //Direct3D裝置物件(COM介面物件)
LPD3DXFONT g_pFont = NULL; //字型物件(COM介面物件)
wchar_t g_str[50]; //用於輸出的字串陣列
int g_cxClient = 1280; //視窗客戶區的寬度
int g_cyClient = 775; //視窗客戶區的高度
//-----------------------------------【GUI相關的全域性變數宣告】---------------------------------------
int g_cxMouse = 0; //滑鼠指標X位置
int g_cyMouse = 0; //滑鼠指標Y位置
BOOL g_bLMBDown = false; //判斷滑鼠左鍵是否按下的標誌
GUIClass * g_pGUIMain = NULL;
GUIClass * g_pGUIStart = NULL;
GUIClass * g_pGUILoad = NULL;
GUIClass * g_pGUIOption = NULL; //4個GUI類的物件
int g_currentGUI = GUI_BKGROUND_MAIN; //預設的GUI標識
WORD g_GUIMainFont = -1; //GUI字型物件的索引
//--------------------------------------------------------------------------------------------------
//【全域性函式宣告】
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //視窗過程函式
HRESULT Direct3D_Init(HWND hwnd); //在該函式中進行Direct3D初始化
HRESULT Object_Init(HWND hwnd); //在該函式中進行繪製物體資源的初始化
VOID Direct3D_Render(HWND hwnd); //在該函式中進行Direct3D的渲染
VOID Direct3D_CleanUp(); //在該函式中進行COM資源及其他資源的清理
VOID HelpText_Render(HWND); //在該函式中渲染幫助文字
VOID CALLBACK GUICallBack(int Id, int State); //GUI回撥函式
VOID Light_Set(LPDIRECT3DDEVICE9, int); //在該函式中進行光源的設定
VOID ClipClient(HWND hwnd); //該函式將限制滑鼠在客戶區中
float GetFPS(); //得到每秒的幀率(Frame Per Second)
//----------------------------------------【WinMain主函式】-------------------------------------------
// 描述:Windows程式的入口函式,程式從這裡開始
//----------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wndclass;
HWND hwnd;
MSG msg = { 0 };
g_hInst = hInstance;
//【設計視窗類】
wndclass.cbSize = sizeof (WNDCLASSEX); //結構大小
wndclass.style = CS_HREDRAW | CS_VREDRAW; //視窗風格樣式
wndclass.lpfnWndProc = WndProc; //設定視窗過程地址
wndclass.cbClsExtra = 0; //額外的視窗類記憶體空間
wndclass.cbWndExtra = 0; //額外的視窗記憶體空間
wndclass.hInstance = hInstance; //視窗的例項控制代碼
wndclass.hIcon = (HICON)::LoadImage(NULL, L"pictures/icon.ico", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
//載入圖示
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //載入滑鼠指標
wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //載入視窗背景
wndclass.lpszMenuName = NULL; //視窗選單名稱
wndclass.lpszClassName = lpClassName; //視窗類名稱
wndclass.hIconSm = 0; //工作列中的小圖示
//【註冊視窗類】
if (!RegisterClassEx(&wndclass))
{
MessageBox(NULL, TEXT("視窗類註冊失敗"), lpClassName, MB_OK | MB_ICONEXCLAMATION);
return -1;
}
//【建立視窗】
hwnd = CreateWindow(lpClassName, WINDOW_TITLE,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, g_cxClient, g_cyClient,
NULL, NULL, hInstance, NULL); //父視窗控制代碼,選單控制代碼,例項控制代碼,額外欄位
if (S_OK != Direct3D_Init(hwnd))
{
MessageBox(hwnd, _T("Direct3D初始化資源失敗!!"), _T("我愛楊的訊息視窗"), MB_OK);
return E_FAIL;
}
//【移動,顯示和更新視窗】
MoveWindow(hwnd, 0, 0, g_cxClient, g_cyClient, TRUE);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
//播放背景音樂
PlaySound(_T("GUI/天下貳 - 太古銅門.wav"), NULL, SND_ASYNC | SND_FILENAME);
//進入遊戲訊息迴圈
static FLOAT fCurrentTime = (float)timeGetTime();
static FLOAT fLastTime = (float)timeGetTime();
static FLOAT fElapsedTime = 0.0f;
while (msg.message != WM_QUIT)
{
fLastTime = fCurrentTime;
fCurrentTime = (float)timeGetTime();
fElapsedTime = (fCurrentTime - fLastTime) / 1000.0f;
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Direct3D_Render(hwnd);
}
}
//登出視窗類
UnregisterClass(lpClassName, wndclass.hInstance);
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_SIZE:
g_cxClient = LOWORD(lParam);
g_cyClient = HIWORD(lParam);
if (g_cxClient == 0 || g_cyClient == 0)
return 0;
ClipClient(hwnd);
return 0;
case WM_MOUSEMOVE:
g_cxMouse = LOWORD(lParam) + GetSystemMetrics(SM_CXBORDER);
g_cyMouse = HIWORD(lParam) + GetSystemMetrics(SM_CYCAPTION);
return 0;
case WM_LBUTTONDOWN:
g_bLMBDown = TRUE;
return 0;
case WM_LBUTTONUP:
g_bLMBDown = FALSE;
return 0;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
DestroyWindow(hwnd);
return 0;
case WM_PAINT:
Direct3D_Render(hwnd);
ValidateRect(hwnd, NULL);
return 0;
case WM_DESTROY:
Direct3D_CleanUp();
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
//--------------------------------------------【Direct3D_Init】---------------------------------------------
// 描述:在該函式中進行Direct3D初始化
//----------------------------------------------------------------------------------------------------------
HRESULT Direct3D_Init(HWND hwnd)
{
//--------------------------------------------------------------------------------------
// 【創介面】:建立Direct3D介面物件, 以便用該Direct3D物件建立Direct3D裝置物件
//--------------------------------------------------------------------------------------
LPDIRECT3D9 pD3D9; //建立Direct3D介面物件
if (FAILED(pD3D9 = Direct3DCreate9(D3D_SDK_VERSION))) //初始化Direct3D介面物件,並與DirectX_SDK版本協商,
return E_FAIL; //以便包含的標頭檔案與DirectX Runtime匹配
//--------------------------------------------------------------------------------------
// 【取資訊】:獲取硬體裝置資訊
//--------------------------------------------------------------------------------------
D3DCAPS9 caps; int vp = 0;
if (FAILED(pD3D9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps)))
{
return E_FAIL;
}
if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; //支援硬體頂點運算方式
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //支援軟體頂點運算方式
//--------------------------------------------------------------------------------------
// 【填內容】:填充D3DPRESENT_PARAMETERS結構體
//--------------------------------------------------------------------------------------
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferWidth = g_cxClient; //後臺緩衝區寬度
d3dpp.BackBufferHeight = g_cyClient; //後臺緩衝區高度
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; //後臺緩衝區儲存畫素格式
d3dpp.BackBufferCount = 2; //後臺緩衝區數量
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; //多重取樣的型別
d3dpp.MultiSampleQuality = 0; //多重取樣的格式
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; //指定如何將後臺緩衝區內容複製到前臺的快取中
d3dpp.hDeviceWindow = hwnd; //當前與裝置關聯的視窗,被啟用的視窗
d3dpp.Windowed = true; //對啟用視窗表示是否使用視窗模式
d3dpp.EnableAutoDepthStencil = true; //自動管理深度快取,模版快取
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; //深度快取,模版快取格式,(這裡為24位深度,8位模版)
d3dpp.Flags = 0; //附加屬性
d3dpp.FullScreen_RefreshRateInHz = 0; //全屏模式時的螢幕重新整理率
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; //後臺緩衝區和前臺緩衝區的最大交換頻率
//--------------------------------------------------------------------------------------
// 【創裝置】:建立Direct3D裝置介面
//--------------------------------------------------------------------------------------
if (FAILED(pD3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, vp, &d3dpp, &g_pd3dDevice9)))
{
SAFE_RELEASE(pD3D9);
return E_FAIL;
}
SAFE_RELEASE(pD3D9); //Direct3D介面物件使命完成,我們將其釋放掉
if (S_OK != Object_Init(hwnd))
return E_FAIL;
return S_OK;
}
//--------------------------------------------【Object_Init】------------------------------------------------
// 描述:在該函式中進行繪製物體資源的初始化
//-----------------------------------------------------------------------------------------------------------
HRESULT Object_Init(HWND hwnd)
{
//建立字型
HR(D3DXCreateFont(g_pd3dDevice9, 36, 0, 0, 0, FALSE, DEFAULT_CHARSET, //建立微軟雅黑字型
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, _T("Clambria"), &g_pFont));
srand(GetTickCount()); //用作業系統啟動到現在的時間來初始化隨機種子
//----------------------------------------【GUI相關資源的新增】----------------------------------------------
//GUI物件的初始化
g_pGUIMain = new GUIClass(g_pd3dDevice9, g_cxClient, g_cyClient);
g_pGUIStart = new GUIClass(g_pd3dDevice9, g_cxClient, g_cyClient);
g_pGUILoad = new GUIClass(g_pd3dDevice9, g_cxClient, g_cyClient);
g_pGUIOption = new GUIClass(g_pd3dDevice9, g_cxClient, g_cyClient);
//新增GUI字型物件
g_pGUIMain->CreateTextFont(_T("微軟雅黑"), 36, &g_GUIMainFont);
//新增背景圖片
if (!g_pGUIMain->AddBackground(TEXT("GUI/main.jpg"))) return E_FAIL;
if (!g_pGUIStart->AddBackground(TEXT("GUI/startgame.jpg"))) return E_FAIL;
if (!g_pGUILoad->AddBackground(TEXT("GUI/loadgame.jpg"))) return E_FAIL;
if (!g_pGUIOption->AddBackground(TEXT("GUI/option.jpg"))) return E_FAIL;
//---------------------------------【主選單main頁面相關的頁面佈局程式碼】---------------------------------
// 新增靜態文字到頁面中
if (!g_pGUIMain->AddStaticText(TEXT("Version 我愛楊V2.0傾情製造版"), GUI_STATIC_TEXT,
D3DCOLOR_RGBA(255, 255, 255, 210), 850, 720, g_GUIMainFont)) return false;
// 新增4個按鈕,分別是開始遊戲,載入進度,選項和退出遊戲,每個按鈕對應3幅圖
if (!g_pGUIMain->AddButton(GUI_BUTTON_START, 585, 340, TEXT("GUI\\startDown.png"),
TEXT("GUI\\StartUp.png"), TEXT("GUI\\startOver.png"))) return false;
if (!g_pGUIMain->AddButton(GUI_BUTTON_LOAD, 585, 385, TEXT("GUI\\loadDown.png"),
TEXT("GUI\\loadUp.png"),TEXT("GUI\\loadOver.png"))) return false;
if (!g_pGUIMain->AddButton(GUI_BUTTON_OPTION, 585, 430, L"GUI\\optionsDown.png",
L"GUI\\optionsUp.png", L"GUI\\optionsOver.png")) return false;
if (!g_pGUIMain->AddButton(GUI_BUTTON_QUIT, 585, 475, L"GUI\\quitDown.png",
L"GUI\\quitUp.png", L"GUI\\quitOver.png")) return false;
//------------------------【開始新遊戲start頁面相關的頁面佈局程式碼】------------------------
// 新增按鈕到頁面中
if (!g_pGUIStart->AddButton(GUI_BUTTON_BACK, 750, 400, L"GUI/backDown.png", L"GUI/backUp.png",
L"GUI/backOver.png")) return false;
if (!g_pGUIStart->AddButton(GUI_BUTTON_BACK, 300, 200, L"GUI/飛航模式down.png", L"GUI/飛航模式up.png",
L"GUI/飛航模式over.png")) return false;
//------------------------【載入遊戲load頁面相關的頁面佈局程式碼】------------------------
// 新增按鈕到頁面中
if (!g_pGUILoad->AddButton(GUI_BUTTON_BACK, 750, 400, L"GUI/backDown.png", L"GUI/backUp.png",
L"GUI/backOver.png")) return false;
//------------------------【遊戲設定option頁面相關的頁面佈局程式碼】------------------------
// 新增按鈕到頁面中
if (!g_pGUIOption->AddButton(GUI_BUTTON_BACK, 750, 400, L"GUI/backDown.png", L"GUI/backUp.png",
L"GUI/backOver.png")) return false;
return S_OK;
}
//--------------------------------------------【Direct3D_Render】--------------------------------------------
// 描述:在該函式中進行Direct3D的渲染
//-----------------------------------------------------------------------------------------------------------
VOID Direct3D_Render(HWND hwnd)
{
//----------------------------------------------------------------------------------
//【清屏操作】
//----------------------------------------------------------------------------------
g_pd3dDevice9->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_XRGB(0, 100, 200), 1.0f, 0);
//----------------------------------------------------------------------------------
//【開始場景】
//----------------------------------------------------------------------------------
g_pd3dDevice9->BeginScene();
//----------------------------------------------------------------------------------
//【正式繪製】
//----------------------------------------------------------------------------------
switch (g_currentGUI)
{
case GUI_BKGROUND_MAIN:
ProcessGUI(g_pGUIMain, g_bLMBDown, g_cxMouse, g_cyMouse, GUICallBack);
break;
case GUI_BKGROUND_START:
ProcessGUI(g_pGUIStart, g_bLMBDown, g_cxMouse, g_cyMouse, GUICallBack);
break;
case GUI_BKGROUND_LOAD:
ProcessGUI(g_pGUILoad, g_bLMBDown, g_cxMouse, g_cyMouse, GUICallBack);
break;
case GUI_BKGROUND_OPTION:
ProcessGUI(g_pGUIOption, g_bLMBDown, g_cxMouse, g_cyMouse, GUICallBack);
break;
}
//渲染幫助文字:
HelpText_Render(hwnd);
//----------------------------------------------------------------------------------
//【結束場景】
//----------------------------------------------------------------------------------
g_pd3dDevice9->EndScene();
//----------------------------------------------------------------------------------
//【翻轉與顯示】
//----------------------------------------------------------------------------------
g_pd3dDevice9->Present(NULL, NULL, NULL, NULL);
//源矩形區域,目標矩形區域,當前繪製的視窗,最小更新區域
}
//--------------------------------------------【Game_CleanUp】------------------------------------------------
// 描述:在該函式中進行COM資源及其他資源的清理
//------------------------------------------------------------------------------------------------------------
VOID Direct3D_CleanUp()
{
SAFE_RELEASE(g_pd3dDevice9); //釋放Direct3D裝置介面
SAFE_RELEASE(g_pFont); //釋放字型介面物件
}
//----------------------------------------【HelpText_Render()函式】-------------------------------------------
// Desc:幫助文字資訊的輸出
//------------------------------------------------------------------------------------------------------------
VOID HelpText_Render(HWND hwnd)
{
RECT rect;
GetClientRect(hwnd, &rect);
//在視窗右上角輸出幀率
int icharCount = swprintf_s(g_str, 20, _T("FPS:%0.3f"), GetFPS());
g_pFont->DrawText(NULL, g_str, icharCount, &rect, DT_RIGHT | DT_TOP, D3DCOLOR_XRGB(255, 10, 10));
}
//-----------------------------------------------【GUICallBack()函式】----------------------------------------
// Desc:GUI回撥函式(更改GUI物件標識和滑鼠狀態)
//------------------------------------------------------------------------------------------------------------
VOID CALLBACK GUICallBack(int Id, int State)
{
switch (Id)
{
case GUI_BUTTON_BACK:
if (State == GUI_LBUTTON_DOWN)
g_currentGUI = GUI_BKGROUND_MAIN;
break;
case GUI_BUTTON_START:
if (State == GUI_LBUTTON_DOWN)
g_currentGUI = GUI_BKGROUND_START;
break;
case GUI_BUTTON_LOAD:
if (State == GUI_LBUTTON_DOWN)
g_currentGUI = GUI_BKGROUND_LOAD;
break;
case GUI_BUTTON_OPTION:
if (State == GUI_LBUTTON_DOWN)
g_currentGUI = GUI_BKGROUND_OPTION;
break;
case GUI_BUTTON_QUIT:
if (State == GUI_LBUTTON_DOWN)
PostQuitMessage(0);
break;
}
}
//-----------------------------------------------【ClipClient()函式】-----------------------------------------
// Desc:該函式將限制滑鼠在客戶區中
//------------------------------------------------------------------------------------------------------------
VOID ClipClient(HWND hwnd)
{
POINT lt, rb;
RECT rect;
GetClientRect(hwnd, &rect);
lt.x = rect.left;
lt.y = rect.top;
rb.x = rect.right;
rb.y = rect.bottom;
ClientToScreen(hwnd, <);
ClientToScreen(hwnd, &rb);
rect.left = lt.x;
rect.top = lt.y;
rect.right = rb.x;
rect.bottom = rb.y;
ClipCursor(&rect);
//ShowCursor(false);
}
//--------------------------------------------【GetFPS()函式】-----------------------------------------------
// 描述:計算每秒畫面重新整理的幀數
//-----------------------------------------------------------------------------------------------------------
float GetFPS()
{
static float fps = 0; //每秒的幀率
static int iframeCount = 0; //圖形繪製的幀數
static DWORD dwlastTime = 0; //上次獲取的時間
static DWORD dwcurrentTime; //當前獲取的時間
iframeCount++;
dwcurrentTime = timeGetTime();
if (dwcurrentTime - dwlastTime >= 1000.0f)
{
fps = (float)iframeCount * 1000.0f / (dwcurrentTime - dwlastTime);
dwlastTime = dwcurrentTime;
iframeCount = 0;
}
return fps;
}
此專案總共4個檔案,一個定義了巨集的標頭檔案,一個主體GUIClass類的.h檔案以及一個Cpp檔案,最後是一個包含了框架和執行過程的main.cpp
下面是GUI介面截圖:
主介面:
start game:
load game:
options:
最後給個資源連結的傳送門:點選開啟連結