【游戏程序设计】Direct 3D 图形用户界面

运行结果:

【游戏程序设计】Direct 3D 图形用户界面

【游戏程序设计】Direct 3D 图形用户界面

【游戏程序设计】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);
}