【游戏程序设计】Direct 3D 图形用户界面
运行结果:
D3DGUIClass.h:
#pragma once
//====================================================
//一个游戏GUI系统类的头文件
//====================================================
#include <d3d9.h>
#include <d3dx9.h>
#include "D3DUtil.h"
//所支持的空间类型宏
#define UGP_GUI_STATICTEXT 1
#define UGP_GUI_BUTTON 2
#define UGP_GUI_BACKGROUND 3
//鼠标按键状态宏
#define UGP_BUTTON_UP 1
#define UGP_BUTTON_DOWN 2
#define UGP_BUTTON_OVER 3
//设置一些GUI用到的控件ID
#define STATIC_TEXT_ID 1
#define BUTTON_START_ID 2
#define BUTTON_LOAD_ID 3
#define BUTTON_OPTION_ID 4
#define BUTTON_QUIT_ID 5
#define BUTTON_BACK_ID 6
#define BUTTON_LEVEL_1_ID 7
//菜单页面的宏定义
#define GUI_MAIN_SCREEN 1
#define GUI_START_SCREEN 2
#define GUI_LOAD_SCREEN 3
#define GUI_OPTION_SCREEN 4
//FVF灵活顶点格式的结构体
struct GUIVERTEX
{
float x, y, z;
float rhw;
unsigned long color;
float u, v;
};
#define D3DFVF_GUIVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
//控件属性结构体
struct GUICONTROL
{
int m_id; //控件id
int m_type; //操作类型
unsigned long m_color; //控件颜色
int m_listID; //如果是文字的话,表示字体,否则表示顶点缓存
float m_xPos; //控件的起始位置
float m_yPos;
float m_width; //控件的宽度与高度
float m_height;
wchar_t *m_text; //文字内容
LPDIRECT3DTEXTURE9 m_Background; //控件背景的填充图像
LPDIRECT3DTEXTURE9 m_upTex, m_downTex, m_overTex; //存放按钮弹起,按下和鼠标经过时的纹理图
};
class D3DGUIClass
{
private:
LPDIRECT3DDEVICE9 m_pd3dDevice; //D3D设备对象
LPD3DXFONT *m_pFonts; //D3D字体对象
LPDIRECT3DVERTEXBUFFER9 *m_pVertexBuffers; //顶点缓存对象指针
GUICONTROL *m_pControls; //控件对象
GUICONTROL m_Background; //背景图对象
LPDIRECT3DVERTEXBUFFER9 m_pBackgroundBuffer; //背景图缓冲区对象
bool m_bIsBackgroundUsed; //一个标识,用于标识是否用了背景
int m_nTotalControlNum; //控件数目计数器
int m_nTotalFontNum; //字体数目计数器
int m_nTotalBufferNum; //缓冲区数目计数器
int m_nWindowHeight; //窗口宽度
int m_nWindowWidth; //窗口高度
public:
D3DGUIClass(LPDIRECT3DDEVICE9 device, int w, int h); //构造函数
~D3DGUIClass(void); //析构函数
LPDIRECT3DDEVICE9 GetD3DDevice() {return m_pd3dDevice;} //返回D3D设备对象的函数
GUICONTROL *GetBackground() {return &m_Background;} //返回背景的函数
LPDIRECT3DVERTEXBUFFER9 GetBackgroundBuffer() {return m_pBackgroundBuffer;} //返回背景缓冲区对象的函数
int GetTotalFontNum() {return m_nTotalFontNum;} //返回所有字体数目的函数
int GetTotalControlNum() {return m_nTotalControlNum;} //返回所有控件数目的函数
int GetTotalBufferNun() {return m_nTotalBufferNum;} //返回总的缓冲区数目的函数
int GetWindowWidth() {return m_nWindowWidth;} //返回窗口宽度的函数
int GetWindowHeight() {return m_nWindowHeight;} //返回窗口高度的函数
bool IsBackgroundUsed() {return m_bIsBackgroundUsed;} //返回背景是否在使用的bool值的函数
void SetWindowSize(int w, int h) {m_nWindowWidth = w; m_nWindowHeight = h;} //设置窗口宽度和高度的函数
LPD3DXFONT GetFont(int id) //返回字体ID函数
{
if(id < 0 || id >= m_nTotalFontNum)
return NULL;
return m_pFonts[id];
}
GUICONTROL *GetGUIControl(int id) //返回GUI控件函数
{
if(id < 0 || id >= m_nTotalControlNum)
return NULL;
return &m_pControls[id];
}
LPDIRECT3DVERTEXBUFFER9 GetVertexBuffer(int id) //返回顶点缓存ID函数
{
if(id < 0 || id >= m_nTotalBufferNum)
return NULL;
return m_pVertexBuffers[id];
}
HRESULT CreateTextFont(wchar_t *fontName, int size); //字体创建函数
HRESULT AddBackground(wchar_t *filename); //GUI背景添加函数
void AddStaticText(int id, wchar_t *text, float x, float y, unsigned long color, int fontID); //添加静态文本
HRESULT AddButton(int id, float x, float y, wchar_t *up, wchar_t *over, wchar_t *down); //添加按钮函数
};
void ProcessGUI(D3DGUIClass *gui, bool LMBDown, int MouseX, int MouseY, void (*funcPtr)(int id, int state)); //回调函数
D3DGUIClass.cpp:
//====================================================
//一个游戏GUI系统的类的源文件
//====================================================
#include "D3DGUIClass.h"
//-----------------------------------------------------------------------------
//构造函数
//-----------------------------------------------------------------------------
D3DGUIClass::D3DGUIClass(LPDIRECT3DDEVICE9 device, int w, int h)
{
m_pd3dDevice = device;
m_nWindowWidth = w;
m_nWindowHeight = h;
m_pFonts = NULL;
m_pControls = NULL;
m_pVertexBuffers = NULL;
memset(&m_Background, 0, sizeof(m_Background));
m_bIsBackgroundUsed = false;
m_nTotalFontNum = 0;
m_nTotalControlNum = 0;
m_nTotalBufferNum = 0;
m_pBackgroundBuffer = NULL;
}
//-----------------------------------------------------------------------------
//析构函数
//-----------------------------------------------------------------------------
D3DGUIClass::~D3DGUIClass(void)
{
for(int i = 0; i < m_nTotalFontNum; ++i)
SAFE_RELEASE(m_pFonts[i]);
SAFE_DELETE_ARRAY(m_pFonts);
for(int i = 0; i < m_nTotalControlNum; ++i)
{
SAFE_DELETE_ARRAY(m_pControls[i].m_text);
SAFE_RELEASE(m_pControls[i].m_Background);
SAFE_RELEASE(m_pControls[i].m_upTex);
SAFE_RELEASE(m_pControls[i].m_downTex);
SAFE_RELEASE(m_pControls[i].m_overTex);
}
SAFE_DELETE_ARRAY(m_pControls);
for(int i = 0; i < m_nTotalBufferNum; ++i)
SAFE_RELEASE(m_pVertexBuffers[i]);
SAFE_DELETE_ARRAY(m_pVertexBuffers);
SAFE_RELEASE(m_Background.m_Background);
SAFE_RELEASE(m_pBackgroundBuffer);
}
//-----------------------------------------------------------------------------
//字体创建函数
//-----------------------------------------------------------------------------
HRESULT D3DGUIClass::CreateTextFont(wchar_t *fontName, int size)
{
if(!m_pFonts)
m_pFonts = new LPD3DXFONT[1];
else
{
LPD3DXFONT *temp = new LPD3DXFONT[m_nTotalFontNum + 1];
//不能直接sizeof(temp),因为是动态数组!
memcpy(temp, m_pFonts, sizeof(LPD3DXFONT) * m_nTotalFontNum);
SAFE_DELETE_ARRAY(m_pFonts);
m_pFonts = temp;
}
//调用D3DXCreateFont函数创建字体
HRESULT hr;
HR(D3DXCreateFont(m_pd3dDevice, size, 0, 0, 1000, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, fontName, &m_pFonts[m_nTotalFontNum]));
++m_nTotalFontNum;
return S_OK;
}
//-----------------------------------------------------------------------------
//创建保存背景图的缓存函数
//-----------------------------------------------------------------------------
HRESULT D3DGUIClass::AddBackground(wchar_t *filename)
{
if(!filename)
return E_FAIL;
m_bIsBackgroundUsed = true;
m_Background.m_type = UGP_GUI_BACKGROUND;
m_Background.m_width = m_nWindowWidth;
m_Background.m_height = m_nWindowHeight;
//从文件载入纹理图片
HRESULT hr;
HR(D3DXCreateTextureFromFile(m_pd3dDevice, filename, &m_Background.m_Background));
//获取窗口宽度和高度 以便稍后的背景铺满窗口
float w = m_nWindowWidth;
float h = m_nWindowHeight;
//创建顶点缓存
HR(m_pd3dDevice->CreateVertexBuffer(4*sizeof(GUIVERTEX), 0, D3DFVF_GUIVERTEX, D3DPOOL_MANAGED, &m_pBackgroundBuffer, 0));
GUIVERTEX vertices[] =
{
{w, 0, 0.0f, 1, D3DCOLOR_XRGB(255,255,255), 1.0f, 0.0f},
{w, h, 0.0f, 1, D3DCOLOR_XRGB(255,255,255), 1.0f, 1.0f},
{0, 0, 0.0f, 1, D3DCOLOR_XRGB(255,255,255), 0.0f, 0.0f},
{0, h, 0.0f, 1, D3DCOLOR_XRGB(255,255,255), 0.0f, 1.0f},
};
//填充顶点缓存
void *pVertices = NULL;
HR(m_pBackgroundBuffer->Lock(0, sizeof(vertices), &pVertices, 0));
memcpy(pVertices, vertices, sizeof(vertices));
m_pBackgroundBuffer->Unlock();
return S_OK;
}
//-----------------------------------------------------------------------------
//创建静态文本控件
//-----------------------------------------------------------------------------
void D3DGUIClass::AddStaticText(int id, wchar_t *text, float x, float y, unsigned long color, int fontID)
{
//下面的代码创建一个控件
if(!m_pControls)
{
m_pControls = new GUICONTROL[1];
memset(m_pControls, 0, sizeof(GUICONTROL));
}
else
{
GUICONTROL *temp = new GUICONTROL[m_nTotalControlNum + 1];
//初始化数组
memset(temp, 0, sizeof(GUICONTROL) * (m_nTotalControlNum + 1));
memcpy(temp, m_pControls, sizeof(GUICONTROL) * m_nTotalControlNum);
SAFE_DELETE_ARRAY(m_pControls);
m_pControls = temp;
}
//填充我们需要的静态文本信息
m_pControls[m_nTotalControlNum].m_id = id;
m_pControls[m_nTotalControlNum].m_type = UGP_GUI_STATICTEXT;
m_pControls[m_nTotalControlNum].m_color = color;
m_pControls[m_nTotalControlNum].m_listID = fontID;
m_pControls[m_nTotalControlNum].m_xPos = x;
m_pControls[m_nTotalControlNum].m_yPos = y;
//复制文本数据
int len = wcslen(text);
m_pControls[m_nTotalControlNum].m_text = new wchar_t[len+1];
wcscpy(m_pControls[m_nTotalControlNum].m_text, text);
//增量总数的计算
++m_nTotalControlNum;
}
//-----------------------------------------------------------------------------
//创建按钮控件的函数
//-----------------------------------------------------------------------------
HRESULT D3DGUIClass::AddButton(int id, float x, float y, wchar_t *up, wchar_t *over, wchar_t *down)
{
if(!up || !over || !down)
return E_FAIL;
if(!m_pControls)
{
m_pControls = new GUICONTROL[1];
memset(&m_pControls[0], 0, sizeof(GUICONTROL));
}
else
{
GUICONTROL *temp = new GUICONTROL[m_nTotalControlNum + 1];
memset(temp, 0, sizeof(GUICONTROL) * (m_nTotalControlNum + 1));
memcpy(temp, m_pControls, sizeof(GUICONTROL) * m_nTotalControlNum);
SAFE_DELETE_ARRAY(m_pControls);
m_pControls = temp;
}
m_pControls[m_nTotalControlNum].m_id = id;
m_pControls[m_nTotalControlNum].m_type = UGP_GUI_BUTTON;
m_pControls[m_nTotalControlNum].m_listID = m_nTotalBufferNum;
m_pControls[m_nTotalControlNum].m_xPos = x;
m_pControls[m_nTotalControlNum].m_yPos = y;
//从文件加载纹理
HRESULT hr;
HR(D3DXCreateTextureFromFile(m_pd3dDevice, up, &m_pControls[m_nTotalControlNum].m_upTex));
HR(D3DXCreateTextureFromFile(m_pd3dDevice, over, &m_pControls[m_nTotalControlNum].m_overTex));
HR(D3DXCreateTextureFromFile(m_pd3dDevice, down, &m_pControls[m_nTotalControlNum].m_downTex));
//获取一下图形的宽度和高度
D3DSURFACE_DESC desc;
m_pControls[m_nTotalControlNum].m_upTex->GetLevelDesc(0, &desc);
float w = desc.Width;
float h = desc.Height;
m_pControls[m_nTotalControlNum].m_width = w;
m_pControls[m_nTotalControlNum].m_height = h;
++m_nTotalControlNum;
if(!m_pVertexBuffers)
m_pVertexBuffers = new LPDIRECT3DVERTEXBUFFER9[1];
else
{
LPDIRECT3DVERTEXBUFFER9 *temp = new LPDIRECT3DVERTEXBUFFER9[m_nTotalBufferNum + 1];
memcpy(temp, m_pVertexBuffers, sizeof(LPDIRECT3DVERTEXBUFFER9) * m_nTotalBufferNum);
SAFE_DELETE_ARRAY(m_pVertexBuffers);
m_pVertexBuffers = temp;
}
//创建顶点缓存
HR(m_pd3dDevice->CreateVertexBuffer(4*sizeof(GUIVERTEX), 0, D3DFVF_GUIVERTEX,
D3DPOOL_MANAGED, &m_pVertexBuffers[m_nTotalBufferNum], 0));
GUIVERTEX vertices[] =
{
{w + x, 0 + y, 0.0f, 1, D3DCOLOR_XRGB(255,255,255), 1.0f, 0.0f},
{w + x, y + h, 0.0f, 1, D3DCOLOR_XRGB(255,255,255), 1.0f, 1.0f},
{0 + x, 0 + y, 0.0f, 1, D3DCOLOR_XRGB(255,255,255), 0.0f, 0.0f},
{0 + x, y + h, 0.0f, 1, D3DCOLOR_XRGB(255,255,255), 0.0f, 1.0f}
};
//填充顶点缓存
void *pVertices = NULL;
HR(m_pVertexBuffers[m_nTotalBufferNum]->Lock(0, sizeof(vertices), &pVertices, 0));
memcpy(pVertices, vertices, sizeof(vertices));
m_pVertexBuffers[m_nTotalBufferNum]->Unlock();
//自增
++m_nTotalBufferNum;
return S_OK;
}
//-----------------------------------------------------------------------------
//全局函数,封装渲染整个GUI系统,同时还为控件调用回调函数
//-----------------------------------------------------------------------------
void ProcessGUI(D3DGUIClass *gui, bool LMBDown, int MouseX, int MouseY, void (*funcPtr)(int id, int state))
{
if(!gui)
return;
LPDIRECT3DDEVICE9 device = gui->GetD3DDevice();
if(!device)
return;
//绘制背景
GUICONTROL *Background = gui->GetBackground();
LPDIRECT3DVERTEXBUFFER9 bgBuffer = gui->GetBackgroundBuffer();
//已经创建的才绘制
if(gui->IsBackgroundUsed() && Background && bgBuffer)
{
device->SetStreamSource(0, bgBuffer, 0, sizeof(GUIVERTEX));
device->SetFVF(D3DFVF_GUIVERTEX);
device->SetTexture(0, Background->m_Background);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
device->SetTexture(0, NULL);
}
//用来显示文本的对象
LPD3DXFONT pFont = NULL;
RECT fontRect = {0, 0, gui->GetWindowWidth(), gui->GetWindowHeight()};
//各个控件的渲染
for(int i = 0; i < gui->GetTotalControlNum(); ++i)
{
//获取当前控件
GUICONTROL *pControl = gui->GetGUIControl(i);
int listId = pControl->m_listID;
//根据不同的类型做不同的操作
switch(pControl->m_type)
{
case UGP_GUI_STATICTEXT:
//获取字体对象
pFont = gui->GetFont(listId);
if(!pFont)
return;
//设置文字位置
fontRect.left = pControl->m_xPos;
fontRect.top = pControl->m_yPos;
//显示文字
pFont->DrawText(0, pControl->m_text, -1, &fontRect, DT_LEFT, pControl->m_color);
break;
case UGP_GUI_BUTTON:
int status = UGP_BUTTON_UP;
//创建一个顶点缓存用于按钮的渲染 获取按钮的对应的顶点缓存对象
LPDIRECT3DVERTEXBUFFER9 pBuffer = gui->GetVertexBuffer(listId);
if(!pBuffer)
return;
//检查鼠标是否悬停或者点击了按钮
if(MouseX > pControl->m_xPos && MouseX < pControl->m_xPos + pControl->m_width &&
MouseY > pControl->m_yPos && MouseY < pControl->m_yPos + pControl->m_height)
{
if(LMBDown)
status = UGP_BUTTON_DOWN;
else
status = UGP_BUTTON_OVER;
}
//设置纹理的Alpha透明选项
device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
//根据不同的鼠标与按钮状态 准备不同的纹理图
if(status == UGP_BUTTON_UP)
device->SetTexture(0, pControl->m_upTex);
else if(status == UGP_BUTTON_DOWN)
device->SetTexture(0, pControl->m_downTex);
else
device->SetTexture(0, pControl->m_overTex);
//渲染按钮
device->SetStreamSource(0, pBuffer, 0, sizeof(GUIVERTEX));
device->SetFVF(D3DFVF_GUIVERTEX);
device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
device->SetTexture(0, NULL);
//关闭Alpha混合
device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
//根据回调函数处理控件消息
if(funcPtr)
funcPtr(pControl->m_id, status);
break;
}
}
}
WinMain.cpp:
#include <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
#include "D3DGUIClass.h"
#define WINDOW_TITLE L"Direct 3D 图形用户界面"
//---------------------------------------【全局变量声明部分】------------------------------------------------
//描述:全局变量的声明
//-----------------------------------------------------------------------------------------------------------
LPDIRECT3DDEVICE9 g_pd3dDevice; //Direct 3D设备对象
LPD3DXFONT g_pTextAdapterName; //显卡名字的2D文本
LPD3DXFONT g_pTextHelper; //帮助文本的2D文本
LPD3DXFONT g_pTextInfor; //绘制信息的2D文本
LPD3DXFONT g_pTextFPS; //FPS文本的2D文本
wchar_t g_strAdapterName[60]; //包括显卡名字的字符串
wchar_t g_strFPS[50]; //包含帧频率的字符数组
D3DGUIClass *g_mainGUI; //主窗口
D3DGUIClass *g_startGUI; //游戏开始窗口
D3DGUIClass *g_loadGUI; //游戏载入窗口
D3DGUIClass *g_optionGUI; //游戏设置窗口
bool g_LMBDown; //GUI中的鼠标状态信息,鼠标左键是否按下的标识
int g_MouseX, g_MouseY; //存储鼠标坐标的两个变量
int g_currentGUI; //一个当前的GUI标识
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT Direct3D_Init(HWND); //在这个函数中继续Direct3D的初始化
HRESULT Objects_Init(HWND); //在这个函数中进行要绘制的物体的资源初始化
void Direct3D_Render(HWND, float); //在这个函数中进行Direct3D渲染代码的书写
void Direct3D_ClearUp(); //在这个函数中清理COM资源以及其他资源
float Get_FPS();
void Direct3D_Update(float);
void HelpText_Render(HWND);
void GUICallback(int, int);
//----------------------------------------【WinMain()函数】-------------------------------------------------
//描述:Windows应用程序的入口函数
//-------------------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wndClass = {0};
wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = (WNDPROC)WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = (HICON)LoadImage(NULL, L"icon.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = L"3DGameBase";
if(!RegisterClassEx(&wndClass))
return -1;
HWND hWnd = CreateWindow(L"3DGameBase", WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
MoveWindow(hWnd, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, true);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
PlaySound(L"Final Fantasy XIII.wav", NULL, SND_LOOP | SND_ASYNC | SND_FILENAME);
if(FAILED(Direct3D_Init(hWnd)))
MessageBox(hWnd, L"Direct3D 初始化失败!", L"消息窗口", 0);
MSG msg = {0};
while(msg.message != WM_QUIT)
{
static float fLastTime = (float)timeGetTime(); //上帧渲染时间
static float fCurrTime = (float)timeGetTime(); //此帧渲染时间
static float fTimeDelta = 0.0f;
fCurrTime = (float)timeGetTime();
fTimeDelta = (fCurrTime - fLastTime) / 1000.0f; //上帧到此帧经过的时间
fLastTime = fCurrTime; //把此次渲染时间赋给上次渲染时间
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Direct3D_Update(fTimeDelta);
Direct3D_Render(hWnd, fTimeDelta);
}
}
UnregisterClass(L"3DGameBase", wndClass.hInstance);
return 0;
}
//---------------------------------------------【WndProc()函数】-----------------------------------------
//描述:窗口过程函数WndProc,对窗口消息进行处理
//---------------------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_PAINT:
ValidateRect(hWnd, NULL); //使窗口区域生效
break;
case WM_KEYDOWN:
if(wParam == VK_ESCAPE)
DestroyWindow(hWnd);
break;
case WM_LBUTTONDOWN:
g_LMBDown = true;
break;
case WM_LBUTTONUP:
g_LMBDown = false;
break;
case WM_MOUSEMOVE:
g_MouseX = LOWORD(lParam);
g_MouseY = HIWORD(lParam);
break;
case WM_DESTROY:
//调用自定义的资源清理函数Direct3D_ClearUp();进行退出前的资源清理
Direct3D_ClearUp();
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
//---------------------------------------------【Direct3D_Init()函数】-----------------------------------------
//描述:Direct3D初始化函数,进行Direct3D的初始化
//---------------------------------------------------------------------------------------------------------------
HRESULT Direct3D_Init(HWND hWnd)
{
//---------------------------------------------------------------------------------------------------------------
//【Direct3D初始化步骤一】:创建Direct3D接口对象,以便用该Direct3D对象创建Direct3D设备对象
//---------------------------------------------------------------------------------------------------------------
LPDIRECT3D9 pD3D = NULL; //Direct3D接口对象的创建。
if((pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) //初始化Direct3D接口对象,并进行DirectX版本协商。
return E_FAIL;
//---------------------------------------------------------------------------------------------------------------
//【Direct3D初始化步骤二】:获取硬件设备信息
//---------------------------------------------------------------------------------------------------------------
D3DCAPS9 caps;
int vp = 0;
if(FAILED(pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps)))
return E_FAIL;
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; //支持硬件顶点运算,采用硬件顶点运算
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //不支持硬件顶点运算,采用软件顶点运算
//---------------------------------------------------------------------------------------------------------------
//【Direct3D初始化步骤三】:填充D3DPRESENT_PARAMETERS结构体
//---------------------------------------------------------------------------------------------------------------
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferWidth = WINDOW_WIDTH;
d3dpp.BackBufferHeight = WINDOW_HEIGHT;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.Windowed = true;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = 0;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
//---------------------------------------------------------------------------------------------------------------
//【Direct3D初始化步骤四】:创建Direct3D设备接口。
//---------------------------------------------------------------------------------------------------------------
if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, vp, &d3dpp, &g_pd3dDevice)))
return E_FAIL;
//获取显卡信息到g_strAdapterName中,并在显卡名称前加上“当前显卡型号:”字符串
//定义一个D3DADAPTER_IDENTIFIER9结构体,用于存储显卡信息
D3DADAPTER_IDENTIFIER9 Adapter;
//调用GetAdapterIdentifier,获取显卡信息
if(FAILED(pD3D->GetAdapterIdentifier(0, 0, &Adapter)))
return E_FAIL;
//显卡名称现在已经在Adapter.Description中了,但是其为char类型,我们要将其转为wchar_t类型
int len = MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, NULL, 0);
//这步操作完成后,g_strAdapterName中就为当前我们的显卡类型名的wchar_t型字符串了
MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, g_strAdapterName, len);
//定义一个临时字符串,且方便了把"当前显卡型号:"字符串引入我们的目的字符串中
wchar_t tempName[50] = L"当前显卡型号:";
//把当前我们的显卡名加到“当前显卡型号:”字符串后面,结果存在TempName中
wcscat_s(tempName, g_strAdapterName);
//把TempName中的结果拷贝到全局变量g_strAdapterName中
wcscpy_s(g_strAdapterName, tempName);
SAFE_RELEASE(pD3D); //LPDIRECT3D9接口对象的使命完成,将其释放掉
if(FAILED(Objects_Init(hWnd))) // 调用一次Objects_Init,进行渲染资源的初始化
return E_FAIL;
return S_OK;
}
//------------------------------------------【Objects_Init()】函数---------------------------------------------
//描述:渲染资源初始化函数,在此函数中进行要被渲染的物体的资源的初始化
//---------------------------------------------------------------------------------------------------------------
HRESULT Objects_Init(HWND hWnd)
{
//创建字体
if(FAILED(D3DXCreateFont(g_pd3dDevice, 36, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0, L"Calibri", &g_pTextFPS)))
return E_FAIL;
if(FAILED(D3DXCreateFont(g_pd3dDevice, 20, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0, L"华文中宋", &g_pTextAdapterName)))
return E_FAIL;
if(FAILED(D3DXCreateFont(g_pd3dDevice, 23, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0, L"微软雅黑", &g_pTextHelper)))
return E_FAIL;
if(FAILED(D3DXCreateFont(g_pd3dDevice, 26, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0, L"黑体", &g_pTextInfor)))
return E_FAIL;
HRESULT hr;
//创建GUI系统
g_mainGUI = new D3DGUIClass(g_pd3dDevice, WINDOW_WIDTH, WINDOW_HEIGHT);
g_loadGUI = new D3DGUIClass(g_pd3dDevice, WINDOW_WIDTH, WINDOW_HEIGHT);
g_startGUI = new D3DGUIClass(g_pd3dDevice, WINDOW_WIDTH, WINDOW_HEIGHT);
g_optionGUI = new D3DGUIClass(g_pd3dDevice, WINDOW_WIDTH, WINDOW_HEIGHT);
//添加背景图片
HR(g_mainGUI->AddBackground(L"Textures\\mainGUI.jpg"));
HR(g_loadGUI->AddBackground(L"Textures\\loadGUI.jpg"));
HR(g_startGUI->AddBackground(L"Textures\\startGUI.jpg"));
HR(g_optionGUI->AddBackground(L"Textures\\optionGUI.jpg"));
//添加字体
HR(g_mainGUI->CreateTextFont(L"微软雅黑", 28));
HR(g_loadGUI->CreateTextFont(L"微软雅黑", 38));
HR(g_startGUI->CreateTextFont(L"微软雅黑", 38));
HR(g_optionGUI->CreateTextFont(L"微软雅黑", 38));
//添加静态文本到GUI中
g_mainGUI->AddStaticText(STATIC_TEXT_ID, L"Version 2.0", 1170, 735, D3DCOLOR_XRGB(55,155,255), 0);
g_mainGUI->AddStaticText(STATIC_TEXT_ID, L"打造游戏GUI界面", 500, 150, D3DCOLOR_XRGB(255,255,255), 0);
//添加4个按钮,分别是开始游戏,载入进度,选项和退出游戏,每个按钮对应三幅图
HR(g_mainGUI->AddButton(BUTTON_START_ID, 650, 340, L"Textures\\startUp.png",L"Textures\\startOver.png", L"Textures\\startDown.png"));
HR(g_mainGUI->AddButton(BUTTON_LOAD_ID, 650, 385, L"Textures\\loadUp.png",L"Textures\\loadOver.png", L"Textures\\loadDown.png"));
HR(g_mainGUI->AddButton(BUTTON_OPTION_ID, 650, 430, L"Textures\\optionsUp.png",L"Textures\\optionsOver.png", L"Textures\\optionsDown.png"));
HR(g_mainGUI->AddButton(BUTTON_QUIT_ID, 650, 475, L"Textures\\quitUp.png",L"Textures\\quitOver.png", L"Textures\\quitDown.png"));
//添加按钮到页面中
HR(g_startGUI->AddButton(BUTTON_LEVEL_1_ID, 550, 380, L"Textures\\level1Up.png",L"Textures\\level1Over.png", L"Textures\\level1Down.png"));
HR(g_startGUI->AddButton(BUTTON_BACK_ID, 750, 350, L"Textures\\backUp.png",L"Textures\\backOver.png", L"Textures\\backDown.png"));
//添加静态文本到页面中
g_loadGUI->AddStaticText(STATIC_TEXT_ID, L"这里是load game页面", 411, 340, D3DCOLOR_XRGB(33,255,55), 0);
//添加按钮到页面中
HR(g_loadGUI->AddButton(BUTTON_BACK_ID, 750, 400, L"Textures\\backUp.png",L"Textures\\backOver.png", L"Textures\\backDown.png"));
//添加静态文本到页面中
g_optionGUI->AddStaticText(STATIC_TEXT_ID, L"这里是Option页面", 540, 60, D3DCOLOR_XRGB(33,255,55), 0);
//添加按钮到页面中
HR(g_optionGUI->AddButton(BUTTON_BACK_ID, 750, 450, L"Textures\\backUp.png",L"Textures\\backOver.png", L"Textures\\backDown.png"));
return S_OK;
}
//------------------------------------------【GUICallback()】函数---------------------------------------------
//描述:GUI系统的回调函数,填写按钮按下的相关处理代码
//---------------------------------------------------------------------------------------------------------------
void GUICallback(int id, int state)
{
switch(id)
{
case BUTTON_START_ID: //开始游戏按钮
if(state == UGP_BUTTON_DOWN)
g_currentGUI = GUI_START_SCREEN;
break;
case BUTTON_LOAD_ID: //载入游戏按钮
if(state == UGP_BUTTON_DOWN)
g_currentGUI = GUI_LOAD_SCREEN;
break;
case BUTTON_OPTION_ID: //设置按钮
if(state == UGP_BUTTON_DOWN)
g_currentGUI = GUI_OPTION_SCREEN;
break;
case BUTTON_BACK_ID: //返回按钮
if(state == UGP_BUTTON_DOWN)
g_currentGUI = GUI_MAIN_SCREEN;
break;
case BUTTON_LEVEL_1_ID: //开始游戏页面中,Level1按钮
//等级1的游戏从这里写代码
break;
case BUTTON_QUIT_ID:
//如果点击了退出按钮,就退出程序
if(state == UGP_BUTTON_DOWN)
PostQuitMessage(0);
break;
}
}
//-----------------------------------------【Get_FPS()函数】---------------------------------------------------
//描述:不是即时渲染代码但是需要实时调用的,如按键后的坐标的更改,都放在这里
//---------------------------------------------------------------------------------------------------------------
void Direct3D_Update(float fTimeDelta)
{
}
//----------------------------------------【Direct3D_Render()函数】--------------------------------------------
//描述:使用Direct3D进行渲染
//---------------------------------------------------------------------------------------------------------------
void Direct3D_Render(HWND hWnd, float fTimeDelta)
{
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤一】:清屏操作
//---------------------------------------------------------------------------------------------------------------
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤二】:开始绘制
//---------------------------------------------------------------------------------------------------------------
g_pd3dDevice->BeginScene(); //开始绘制
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤三】:正式绘制
//---------------------------------------------------------------------------------------------------------------
//处理和渲染GUI系统
if(g_currentGUI == GUI_MAIN_SCREEN)
ProcessGUI(g_mainGUI, g_LMBDown, g_MouseX, g_MouseY, GUICallback);
else if(g_currentGUI == GUI_START_SCREEN)
ProcessGUI(g_startGUI, g_LMBDown, g_MouseX, g_MouseY, GUICallback);
else if(g_currentGUI == GUI_LOAD_SCREEN)
ProcessGUI(g_loadGUI, g_LMBDown, g_MouseX, g_MouseY, GUICallback);
else if(g_currentGUI == GUI_OPTION_SCREEN)
ProcessGUI(g_optionGUI, g_LMBDown, g_MouseX, g_MouseY, GUICallback);
else
ProcessGUI(g_mainGUI, g_LMBDown, g_MouseX, g_MouseY, GUICallback);
//绘制文字信息
HelpText_Render(hWnd);
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤四】:结束绘制
//---------------------------------------------------------------------------------------------------------------
g_pd3dDevice->EndScene(); //结束绘制
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤五】:显示翻转
//---------------------------------------------------------------------------------------------------------------
g_pd3dDevice->Present(NULL, NULL, NULL, NULL); //翻转与显示
}
//----------------------------------------【HelpText_Render()函数】--------------------------------------------
//描述:封装了帮助信息的函数
//---------------------------------------------------------------------------------------------------------------
void HelpText_Render(HWND hWnd)
{
//定义一个矩形,用来获取主窗口矩形
RECT formatRect;
GetClientRect(hWnd, &formatRect);
//在窗口右上角处,显示每秒帧数
swprintf_s(g_strFPS, L"FPS:%.3f", Get_FPS());
g_pTextFPS->DrawText(0, g_strFPS, -1, &formatRect, DT_TOP | DT_RIGHT, D3DCOLOR_XRGB(255,255,255));
//显示显卡类型名
g_pTextAdapterName->DrawText(0, g_strAdapterName, -1, &formatRect, DT_TOP | DT_LEFT, D3DXCOLOR(1.0f, 0.5f, 0.0f, 1.0f));
}
//-----------------------------------------【Get_FPS()函数】---------------------------------------------------
//描述:用于计算帧频率
//---------------------------------------------------------------------------------------------------------------
float Get_FPS()
{
//定义四个静态变量
static int frameCount = 0; //帧数
static float currentTime = 0; //当前时间
static float lastTime = 0; //上次计算帧频率的时间
static float fps = 0; //需要计算的fps值
++frameCount; //每调用一次此函数,帧数加一
//获取系统时间, timeGetTime() 返回系统时间,以毫秒为单位,乘以0.001得到秒
currentTime = timeGetTime() * 0.001f;
//如果当前时间减去之前计算帧频率的时间大于1秒钟,就进行帧频率的更新,并将帧数归零
if(currentTime - lastTime > 1.0f) //将时间控制在1秒钟
{
fps = frameCount / (currentTime - lastTime); //计算这一秒的fps值
frameCount = 0; //将本次帧数清零
lastTime = currentTime; //将当前时间赋给上次计算帧频率的时间,作为下一秒的基准时间
}
return fps;
}
//------------------------------------------------【 Direct3D_ClearUp函数】------------------------------------------
//描述:资源清理函数,在此函数中进行程序退出前资源的清理工作
//-------------------------------------------------------------------------------------------------------------------
void Direct3D_ClearUp()
{
//释放COM接口对象
SAFE_RELEASE(g_pd3dDevice);
SAFE_RELEASE(g_pTextFPS);
SAFE_RELEASE(g_pTextAdapterName);
SAFE_DELETE(g_mainGUI);
SAFE_DELETE(g_startGUI);
SAFE_DELETE(g_optionGUI);
SAFE_DELETE(g_loadGUI);
}