轉(zhuǎn)自:http://blog.sina.com.cn/s/blog_4d035b080100k3ep.html?retcode=0
opengl文字處理(1) (入門(mén)學(xué)習(xí)十六)(轉(zhuǎn))
OpenGL版的“Hello, World!”
寫(xiě)完了本課,我的感受是:顯示文字很簡(jiǎn)單,顯示文字很復(fù)雜。看似簡(jiǎn)單的功能,背后卻隱藏了深不可測(cè)的玄機(jī)。
呵呵,別一開(kāi)始就被嚇住了,讓我們先從“Hello, World!”開(kāi)始。
前面已經(jīng)說(shuō)過(guò)了,要顯示字符,就需要通過(guò)操作系統(tǒng),把繪制字符的動(dòng)作裝到顯示列表中,然后我們調(diào)用顯示列表即可繪制字符。
假如我們要顯示的文字全部是ASCII字符,則總共只有0到127這128種可能,因此可以預(yù)先把所有的字符分別裝到對(duì)應(yīng)的顯示列表中,然后在需要時(shí)調(diào)用這些顯示列表。
Windows系統(tǒng)中,可以使用wglUseFontBitmaps函數(shù)來(lái)批量的產(chǎn)生顯示字符用的顯示列表。函數(shù)有四個(gè)參數(shù):
第一個(gè)參數(shù)是HDC,學(xué)過(guò)Windows GDI的朋友應(yīng)該會(huì)熟悉這個(gè)。如果沒(méi)有學(xué)過(guò),那也沒(méi)關(guān)系,只要知道調(diào)用wglGetCurrentDC函數(shù),就可以得到一個(gè)HDC了。具體的情況可以看下面的代碼。
第二個(gè)參數(shù)表示第一個(gè)要產(chǎn)生的字符,因?yàn)槲覀円a(chǎn)生0到127的字符的顯示列表,所以這里填0。
第三個(gè)參數(shù)表示要產(chǎn)生字符的總個(gè)數(shù),因?yàn)槲覀円a(chǎn)生0到127的字符的顯示列表,總共有128個(gè)字符,所以這里填128。
第四個(gè)參數(shù)表示第一個(gè)字符所對(duì)應(yīng)顯示列表的編號(hào)。假如這里填1000,則第一個(gè)字符的繪制命令將被裝到第1000號(hào)顯示列表,第二個(gè)字符的繪制命令將被裝到第1001號(hào)顯示列表,依次類(lèi)推。我們可以先用glGenLists申請(qǐng)128個(gè)連續(xù)的顯示列表編號(hào),然后把第一個(gè)顯示列表編號(hào)填在這里。
還要說(shuō)明一下,因?yàn)?font style="LINE-HEIGHT: 21px; WORD-WRAP: normal; WORD-BREAK: normal" face="Times New Roman">wglUseFontBitmaps是Windows系統(tǒng)特有的函數(shù),所以在使用前需要加入頭文件:#include <windows.h>。
現(xiàn)在讓我們來(lái)看具體的代碼:
#include <windows.h>
// ASCII字符總共只有0到127,一共128種字符
#define MAX_CHAR 128
void drawString(const char* str) {
static int isFirstCall = 1;
static GLuint lists;
if( isFirstCall ) { // 如果是第一次調(diào)用,執(zhí)行初始化
// 為每一個(gè)ASCII字符產(chǎn)生一個(gè)顯示列表
isFirstCall = 0;
// 申請(qǐng)MAX_CHAR個(gè)連續(xù)的顯示列表編號(hào)
lists = glGenLists(MAX_CHAR);
// 把每個(gè)字符的繪制命令都裝到對(duì)應(yīng)的顯示列表中
wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, lists);
}
// 調(diào)用每個(gè)字符對(duì)應(yīng)的顯示列表,繪制每個(gè)字符
for(; *str!='\0'; ++str)
glCallList(lists + *str);
}
顯示列表一旦產(chǎn)生就一直存在(除非調(diào)用glDeleteLists銷(xiāo)毀),所以我們只需要在第一次調(diào)用的時(shí)候初始化,以后就可以很方便的調(diào)用這些顯示列表來(lái)繪制字符了。
繪制字符的時(shí)候,可以先用glColor*等指定顏色,然后用glRasterPos*指定位置,最后調(diào)用顯示列表來(lái)繪制。
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glRasterPos2f(0.0f, 0.0f);
drawString("Hello, World!");
glutSwapBuffers();
}
效果如圖:

指定字體
在產(chǎn)生顯示列表前,Windows允許選擇字體。
我做了一個(gè)selectFont函數(shù)來(lái)實(shí)現(xiàn)它,大家可以看看代碼。
void selectFont(int size, int charset, const char* face) {
HFONT hFont = CreateFontA(size, 0, 0, 0, FW_MEDIUM, 0, 0, 0,
charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, face);
HFONT hOldFont = (HFONT)SelectObject(wglGetCurrentDC(), hFont);
DeleteObject(hOldFont);
}
void display(void) {
selectFont(48, ANSI_CHARSET, "Comic Sans MS");
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glRasterPos2f(0.0f, 0.0f);
drawString("Hello, World!");
glutSwapBuffers();
}
最主要的部分就在于那個(gè)參數(shù)超多的CreateFont函數(shù),學(xué)過(guò)Windows GDI的朋友應(yīng)該不會(huì)陌生。沒(méi)有學(xué)過(guò)GDI的朋友,有興趣的話可以自己翻翻MSDN文檔。這里我并不準(zhǔn)備仔細(xì)講這些參數(shù)了,下面的內(nèi)容還多著呢:(
如果需要在自己的程序中選擇字體的話,把selectFont函數(shù)抄下來(lái),在調(diào)用glutCreateWindow之后、在調(diào)用wglUseFontBitmaps之前使用selectFont函數(shù)即可指定字體。函數(shù)的三個(gè)參數(shù)分別表示了字體大小、字符集(英文字體可以用ANSI_CHARSET,簡(jiǎn)體中文字體可以用GB2312_CHARSET,繁體中文字體可以用CHINESEBIG5_CHARSET,對(duì)于中文的Windows系統(tǒng),也可以直接用DEFAULT_CHARSET表示默認(rèn)字符集)、字體名稱(chēng)。
效果如圖:
