29 GameProject4(+GUI)

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
<windows.h>

#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
<windows.h>
#include
<d3d9.h>
#include
<d3dx9.h>
#include
"RenderInterface.h"

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")


struct stD3DStaticBuffer
{
stD3DStaticBuffer() : vbPtr(
0), ibPtr(0), numVerts(0),
numIndices(
0), stride(0), fvf(0),
primType(NULL_TYPE) {}

LPDIRECT3DVERTEXBUFFER9 vbPtr;
LPDIRECT3DINDEXBUFFER9 ibPtr;
int numVerts;
int numIndices;
int stride;
unsigned
long fvf;
PrimType primType;
};

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;
}

  

posted @ 2011-09-02 18:22  小 楼 一 夜 听 春 雨  阅读(669)  评论(0编辑  收藏  举报