在Direct3D渲染中當然也少不了文字。作為所有游戲最重要的一部分,繪制文字的問題也成了非常重要的一個話題。于是咱們接著研究關于文字的繪制。這部分學習完了以后,咱們就會擁有一個有著基本樸實功能的GraphEngine。可以繪制圖片以及文字以后,剩下的事便可以干完了。
作為Direct3D中繪制文字的利器ID3DXFont有著完備的文字繪制功能。可是首先要說明的是,ID3DXFont在繪制文字的時候使用的是GDI的API,眾所周知GDI是效率非常低下的東西。于是在這個基礎上,DXUT提供了一個東西叫做CDXUTTextHelper,它封裝了需要的ID3DXFont以及Sprite,并提高了工作效率。那么具體是怎么提高的呢?那就是它在內(nèi)存中開辟了一塊紋理,將繪制過的文字繪制在這上面,以后再次遇到這個字的時候就直接當做普通紋理處理了。這樣做的代價就是內(nèi)存的開銷變大,經(jīng)過咱的測試,穩(wěn)定下來的大概會占掉200-300MB的內(nèi)存,即使是在目前普及1G-2G內(nèi)存的時代,這樣的開銷也算是非常巨大的,因此汝可以在ID3DXFont和CDXUTTextHelper之間作出選擇,是犧牲空間換來時間還是犧牲時間換來空間。或者汝有更好的方法請回復。
那么接下來就是正題了,這里以ID3DXFont為講解對象,CDXUTTextHelper跟這個類似。
跟以前一樣先來看構(gòu)造ID3DXFont的函數(shù)原型:
HRESULT D3DXCreateFont(
LPDIRECT3DDEVICE9 pDevice,
INT Height,
UINT Width,
UINT Weight,
UINT MipLevels,
BOOL Italic,
DWORD CharSet,
DWORD OutputPrecision,
DWORD Quality,
DWORD PitchAndFamily,
LPCTSTR pFacename,
LPD3DXFONT * ppFont
);
pDevice:Direct3D設備
Height:字符的邏輯單位高度
Weight:字符的邏輯單位寬度
Weight:字符粗細的枚舉量,有以下幾種:
/* Font Weights */
#define FW_DONTCARE 0
#define FW_THIN 100
#define FW_EXTRALIGHT 200
#define FW_LIGHT 300
#define FW_NORMAL 400
#define FW_MEDIUM 500
#define FW_SEMIBOLD 600
#define FW_BOLD 700
#define FW_EXTRABOLD 800
#define FW_HEAVY 900
MipLevels:好吧咱自重咱也不知道這個是干啥的不過也不需要了解它是干啥的填0就好了
Italic:是否斜體
CharSet:字體字符的設置,也就是一些字體的指定,一般填DEFAULT_CHARSET
#define ANSI_CHARSET 0
#define DEFAULT_CHARSET 1
#define SYMBOL_CHARSET 2
#define SHIFTJIS_CHARSET 128
#define HANGEUL_CHARSET 129
#define HANGUL_CHARSET 129
#define GB2312_CHARSET 134
#define CHINESEBIG5_CHARSET 136
#define OEM_CHARSET 255
#if(WINVER >= 0x0400)
#define JOHAB_CHARSET 130
#define HEBREW_CHARSET 177
#define ARABIC_CHARSET 178
#define GREEK_CHARSET 161
#define TURKISH_CHARSET 162
#define VIETNAMESE_CHARSET 163
#define THAI_CHARSET 222
#define EASTEUROPE_CHARSET 238
#define RUSSIAN_CHARSET 204
OutputPrecision:指定Windows如何把指定的字體大小和實際的字體相配,一般填OUT_DEFAULT_PRECIS
#define OUT_DEFAULT_PRECIS 0
#define OUT_STRING_PRECIS 1
#define OUT_CHARACTER_PRECIS 2
#define OUT_STROKE_PRECIS 3
#define OUT_TT_PRECIS 4
#define OUT_DEVICE_PRECIS 5
#define OUT_RASTER_PRECIS 6
#define OUT_TT_ONLY_PRECIS 7
#define OUT_OUTLINE_PRECIS 8
#define OUT_SCREEN_OUTLINE_PRECIS 9
#define OUT_PS_ONLY_PRECIS 10
Quality:指定Windows如何把指定的字體和實際的字體相配,一般填DEFAULT_QUALITY
#define DEFAULT_QUALITY 0
#define DRAFT_QUALITY 1
#define PROOF_QUALITY 2
#if(WINVER >= 0x0400)
#define NONANTIALIASED_QUALITY 3
#define ANTIALIASED_QUALITY 4
PitchAndFamily:
Pitch:一個位圖內(nèi)存地址距下一個位圖內(nèi)存地址的距離,一般填DEFAULT_PITCH
#define DEFAULT_PITCH 0
#define FIXED_PITCH 1
#define VARIABLE_PITCH 2
Family:這個看注釋就知道了,不知道的話就填FF_DONTCARE
/* Font Families */
#define FF_DONTCARE (0<<4) /* Don't care or don't know. */
#define FF_ROMAN (1<<4) /* Variable stroke width, serifed. */
/* Times Roman, Century Schoolbook, etc. */
#define FF_SWISS (2<<4) /* Variable stroke width, sans-serifed. */
/* Helvetica, Swiss, etc. */
#define FF_MODERN (3<<4) /* Constant stroke width, serifed or sans-serifed. */
/* Pica, Elite, Courier, etc. */
#define FF_SCRIPT (4<<4) /* Cursive, etc. */
#define FF_DECORATIVE (5<<4) /* Old English, etc. */
pFacename:字體名稱的寬字符串,例如L”Airia”
ppFont:ID3DXFont類型的指針,傳入進去以此建立字體對象。
用D3DXCreateFont就可以創(chuàng)建各種各樣的字體了。那么如何在實際的程序運行中用多種字體呢?你可以用map來管理,這樣預處理出來是非常好的。
在附件中的工程的GameEngine.cpp的OnCreateDevice中可以看見字體的初始化過程。
字體對象建立好了后便是繪制了,下面看一下ID3DXFont::DrawText:
INT DrawText(
LPD3DXSPRITE pSprite,
LPCTSTR pString,
INT Count,
LPRECT pRect,
DWORD Format,
D3DCOLOR Color
);
pSprite:ID3DXFont要借用Sprite來繪制文字,于是第一個參數(shù)傳入已經(jīng)建立好的sprite
pString:需要繪制的文字的寬字符串
Count:需要繪制的文字的長度,若是-1則整個字符串一起畫,否則按字數(shù)繪制
pRect:指定一個矩形來讓文字按Format格式在此矩形內(nèi)排列
Color:繪制文字的顏色
Format:繪制文字的格式。ID3DFont提供了多樣的繪制格式,見下:
注:我的程序中已經(jīng)將ID3DXFont封裝進graphEngine,具體參見代碼
DT_BOTTOM:指定在矩形底部繪制
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,0,200,200),DT_BOTTOM);
DT_CALCRECT:改變傳入的矩形的長寬,變成剛好能容下需要畫文字的矩形
DT_CENTER:指定在矩形的橫向的中間繪制
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,0,200,200),DT_CENTER);
DT_EXPANDTABS:不忽略制表符繪制(\t),一個TAB占8個位置
graphEngine->DrawTexts(L"\tSumreen",MakeRect(0,0,200,200),DT_EXPANDTABS);
DT_LEFT:指定橫向在矩形的左側(cè)繪制
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,0,200,200),DT_LEFT);
DT_NOCLIP:不作任何格式限制及裁剪,以矩形左上角為繪制點繪制
graphEngine->DrawTexts(L"SumreenSumreenSumreenSumreen",MakeRect(0,0,50,200),DT_NOCLIP);
DT_RIGHT:指定在矩形右側(cè)繪制文字
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,0,200,200),DT_RIGHT);
DT_SINGLELINE:在單行中繪制,忽略換行等
graphEngine->DrawTexts(L"Sumreen\nSumreen",MakeRect(0,0,200,200),DT_SINGLELINE);
DT_TOP:指定縱向在矩形頂部繪制
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,0,200,200),DT_TOP);
DT_VCENTER:指定縱向在矩形中間繪制
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,0,200,200),DT_VCENTER);
DT_WORDBREAK:指定在矩形中自動換行繪制,還可以智能換行以不切斷單詞
graphEngine->DrawTexts(L"Sumreen Sumreen Sumreen Sumreen Sumreen Sumreen Sumreen Sumreen",MakeRect(0,0,200,200),DT_WORDBREAK);
以上為常用的一些標示符,如果需要更多信息請參考DirectX SDK。
其中汝覺得標示符不沖突就可以用或運算同時使用:
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,0,200,200),DT_RIGHT|DT_BOTTOM);
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,0,200,200),DT_CENTER|DT_VCENTER);
其中常用的就是DT_NOCLIP了,即不作任何限制
最后要注意的是因為ID3DXFont是用Sprite在繪制內(nèi)存中的紋理式的文字,也就是相當于普通的繪制紋理,于是一定要在Device和Sprite的Begin以及End之間再調(diào)用DrawText。
以上就是利用ID3DXFont繪制文字的基礎內(nèi)容。雖然說是基礎,卻也提供了非常多的實用的效果。對于制作GALGAME來說已經(jīng)足夠了。
順便再說一個經(jīng)常用到的效果:陰影以及邊框
其實這個也不復雜,就只是平移一兩個單位像素按陰影顏色再繪制一下就行了:
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,1,200,200),D3DCOLOR_ARGB(255,255,0,0),DT_NOCLIP);
graphEngine->DrawTexts(L"Sumreen",MakeRect(1,0,200,200),D3DCOLOR_ARGB(255,255,0,0),DT_NOCLIP);
graphEngine->DrawTexts(L"Sumreen",MakeRect(-1,0,200,200),D3DCOLOR_ARGB(255,255,0,0),DT_NOCLIP);
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,-1,200,200),D3DCOLOR_ARGB(255,255,0,0),DT_NOCLIP);
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,0,200,200),D3DCOLOR_ARGB(255,0,255,0),DT_NOCLIP);
graphEngine->DrawTexts(L"Sumreen",MakeRect(1,1,200,200),D3DCOLOR_ARGB(255,0,0,0),DT_NOCLIP);
graphEngine->DrawTexts(L"Sumreen",MakeRect(0,0,200,200),D3DCOLOR_ARGB(255,0,255,0),DT_NOCLIP);
嘛,文字的繪制就是這樣了。現(xiàn)在繪制東西已經(jīng)不成問題了,于是下一次便開始講整個引擎的框架。
文章中可能會有疏忽和錯誤之處,也請大家不吝賜教。
代碼工程下載(VS2008):
/Files/CK985/Direct3D_2D.rar