<考古筆記>Hge遊戲引擎(二)Core
HgeCoreFunctions(Core Layer)
1.Hge.h的概要:
/*
概要(個人修改的内容已移除、修改字樣标記)
*/
版本号:HGE_VERSION
為BorlandC編譯提供數學函數支援(不需要,已移除)
基本資料類型:DWORD、WORD、BYTE
句柄類型:HTEXTURE、HTARGET、HEFFECT、HMUSIC、HSTREAM、HCHANNEL
導出dll的設定:EXPORT、CALL
數學常量:M_PI
位色處理宏:ARGB、Set/GetA(R、G、B)
融合方式選項:Color/Alpha/ZWrite
Int設定:螢幕寬高、位深(bpp)、音效相關設定(采樣頻率、fx、music volume)、Fps
String設定:标題名、圖示名、ini/log檔案名
Bool設定:視窗/全屏,開啟/關閉ZBuffer,開啟/關閉TextureFilter、開啟/關閉Sound、是否Suspend(挂起)、顯示/隐藏滑鼠、開啟/關閉Splash(初始的Hge Logo動畫)
Func設定:FrameFunc、RenderFunc、FocusLost/GainFunc、GFXRestoreFunc、ExitFunc
Hwnd狀态:HWND(普通)、HWNDPARENT(父視窗)
電源狀态控制(源碼空定義,已移除)
Fps狀态:是否開啟垂直同步(可移動至Bool設定)
頂點格式:空間坐标(x,y)、depth()、color、紋理坐标(tx, ty)
圖元類型:線段、三角形、四邊形(頂點數組、紋理貼圖句柄、blend方式)
Input事件:事件類型(KeyDown/Up, MButtonDown/Up, MouseMove/Wheel)、Key碼,Flags(Shift, Ctrl, Alt, Capslock, ScrollLock, NumLock, Repeat),鍵盤按鍵(ascii碼)/滑鼠滾輪/滑鼠位置(x, y)
外部接口--純虛類Hge
hgeCreate全局C接口聲明
虛拟鍵值(Virtual Key Cod
2.Hge啟動流程
通過全局的C函數hgeCreate(C++因為提供函數重載,生成的接口函數名會帶有@數字/字元(詳見名稱重整技術,hge.def檔案也是用于解決這個問題的))擷取Hge接口,__stdcall作用為讓函數調用方負責清棧,在使用完Hge接口後調用Release來釋放Hge接口(使用了引用計數技術,Release開銷很小)。
hgeCreate實際工作是new一個Hge_Impl類(public繼承于Hge類),并向上轉型為Hge*傳回。
獲得Hge接口後自行設定一系列Bool、Int、Func、String狀态/開關,然後再使用System_Initiate初始化,初始化過程中Hge會擷取系統目前時間、Hge版本、作業系統版本、實體/虛拟記憶體情況,寫入到log檔案中,再注冊視窗類、建立視窗、初始化Timer、Random、Input、Graphics(GFX)、Sound這些子系統,最後根據是否定義DEMO宏來播放Splash動畫。
Hge_Impl下除了System之外,有Resource、Ini、Random、Timer、Sound(Effect, Music, Stream, Channel)、Input、Graphics(GFX)子系統。值得一提的是,子系統的所有成員變量以及方法全部都放在Hge_Impl類中,以良好的函數命名以及注釋來劃分。
System_Initiate結束之後使用System_Start來執行消息循環。
在收到結束消息,退出循環後使用System_Shutdown關閉各個子系統,最後再使用Release釋放Hge接口。
3.子系統簡介
Random
值得一提的是随機數種子定義的是全局變量,這一點我覺得不如封裝成Singleton類,種子為靜态變量。
/*
Random概要
*/
unsigned int g_seed=;
// 随機數種子的擷取
// 初始化時Random_Seed(0);
void CALL HGE_Impl::Random_Seed(int seed)
{
if(!seed) g_seed=timeGetTime();
else g_seed=seed;
}
// 擷取随機的int數
int CALL HGE_Impl::Random_Int(int min, int max)
{
g_seed=*g_seed+;
return min+(g_seed ^ g_seed>>)%(max-min+);
}
// 擷取随機的float數
float CALL HGE_Impl::Random_Float(float min, float max)
{
g_seed=*g_seed+;
//return min+g_seed*(1.0f/4294967295.0f)*(max-min);
return min+(g_seed>>)*(f/f)*(max-min);
}
Demo
實作方式是将FrameFunc先設定為Demo.cpp中定義的DFrame(RenderFunc設為0,因為DFrame将Render的工作也寫在了一起),貼一張Hge Logo圖(資料在Demo.cpp的hgelogo數組中)到螢幕中心并根據時間修改其alpha值。
/*
splash screen animation
*/
dtime+=pHGE->Timer_GetDelta();
if(dtime<.)
alpha=(BYTE)((dtime*4)*0xFF);
else if(dtime<)
alpha=;
else if(dtime<)
alpha=(BYTE)((f-(dtime-f)*4)*0xFF);
Timer
// 計時器精度由初始化時timeBeginPeriod(1)設定為1ms
// 其他數值初始化如下
// fTime=0.0f;
// t0=t0fps=timeGetTime();
// dt=cfps=0;
// nFPS=0;
float fTime; // 目前時間,可由Timer_GetTime擷取
float fDeltaTime; // 幀之間的時間間隔,可由Timer_GetDelta擷取
DWORD nFixedDelta;
int nFPS; // Fps值,可由Timer_GetFPS擷取
DWORD t0, t0fps, dt;
int cfps;
Log、Ini
log檔案寫入是通過va_list可變長參數和vfprintf實作的:
void CALL HGE_Impl::System_Log(const char *szFormat, ...)
{
FILE *hf = NULL;
va_list ap;
if(!szLogFile[]) return;
hf = fopen(szLogFile, "a");
if(!hf) return;
va_start(ap, szFormat);
vfprintf(hf, szFormat, ap);
va_end(ap);
fprintf(hf, "\n");
fclose(hf);
}
Ini檔案用于儲存本次程式運作的設定參數,使得在下一次程式執行時可直接讀取這些參數。
Ini.cpp提供了對int、float、string三種類型參數的寫入/讀取支援,利用的是Get/WritePrivateProfileString函數。
實際上我覺得可以用lua這樣的腳本語言來做配置參數表,自己封裝Lua與C/C++互動的工具類,開源的庫也有LuaBind。
Sound
// 音頻的資料流使用單連結清單
struct CStreamList
{
HSTREAM hstream;
void* data;
CStreamList* next;
};
Sound系統封裝了Bass庫,支援了采樣頻率、多聲道等進階效果。
Resource
struct CResourceList
{
char filename[_MAX_PATH];
char password[64];
CResourceList* next;
};
Resource系統封裝了Zlib庫,支援解壓打包好的加密/不加密資源包,使用簡單的單連結清單一一讀取需要的資源。
Input
struct CInputEventList
{
hgeInputEvent event;
CInputEventList* next;
};
滑鼠/鍵盤輸入的事件由單連結清單實作的隊列管理。
Graphics
Gfx封裝了DirectX8的API。
Texture
struct CTextureList
{
HTEXTURE tex;
int width;
int height;
CTextureList* next;
};
Target
struct CRenderTargetList
{
int width;
int height;
IDirect3DTexture8* pTex;
IDirect3DSurface8* pDepth;
CRenderTargetList* next;
};