轉自:http://blog.sina.com.cn/s/blog_4d035b080100k3ep.html?retcode=0
opengl文字處理(1) (入門學習十六)(轉)

OpenGL
版的“Hello, World!”
寫完了本課,我的感受是:顯示文字很簡單,顯示文字很復雜??此坪唵蔚墓δ?,背后卻隱藏了深不可測的玄機。
呵呵,別一開始就被嚇住了,讓我們先從“Hello, World!”開始。
前面已經說過了,要顯示字符,就需要通過操作系統,把繪制字符的動作裝到顯示列表中,然后我們調用顯示列表即可繪制字符。
假如我們要顯示的文字全部是ASCII字符,則總共只有0127128種可能,因此可以預先把所有的字符分別裝到對應的顯示列表中,然后在需要時調用這些顯示列表。
Windows系統中,可以使用wglUseFontBitmaps函數來批量的產生顯示字符用的顯示列表。函數有四個參數:
第一個參數是HDC,學過Windows GDI的朋友應該會熟悉這個。如果沒有學過,那也沒關系,只要知道調用wglGetCurrentDC函數,就可以得到一個HDC了。具體的情況可以看下面的代碼。
第二個參數表示第一個要產生的字符,因為我們要產生0127的字符的顯示列表,所以這里填0。
第三個參數表示要產生字符的總個數,因為我們要產生0127的字符的顯示列表,總共有128個字符,所以這里填128。
第四個參數表示第一個字符所對應顯示列表的編號。假如這里填1000,則第一個字符的繪制命令將被裝到第1000號顯示列表,第二個字符的繪制命令將被裝到第1001號顯示列表,依次類推。我們可以先用glGenLists申請128個連續的顯示列表編號,然后把第一個顯示列表編號填在這里。
還要說明一下,因為wglUseFontBitmapsWindows系統特有的函數,所以在使用前需要加入頭文件:#include <windows.h>
現在讓我們來看具體的代碼:

#include <windows.h>

// ASCII
字符總共只有0127,一共128種字符
#define MAX_CHAR       128

void drawString(const char* str) {
    static int isFirstCall 1;
    static GLuint lists;

    if( isFirstCall // 
如果是第一次調用,執行初始化
                        // 為每一個ASCII字符產生一個顯示列表
        isFirstCall 0;

        // 
申請MAX_CHAR個連續的顯示列表編號
        lists glGenLists(MAX_CHAR);

        // 
把每個字符的繪制命令都裝到對應的顯示列表中
        wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, lists);
    }
    // 
調用每個字符對應的顯示列表,繪制每個字符
    for(; *str!='\0'; ++str)
        glCallList(lists *str);
}



顯示列表一旦產生就一直存在(除非調用glDeleteLists銷毀),所以我們只需要在第一次調用的時候初始化,以后就可以很方便的調用這些顯示列表來繪制字符了。
繪制字符的時候,可以先用glColor*等指定顏色,然后用glRasterPos*指定位置,最后調用顯示列表來繪制。

void display(void) {
    glClear(GL_COLOR_BUFFER_BIT);

    glColor3f(1.0f, 0.0f, 0.0f);
    glRasterPos2f(0.0f, 0.0f);
    drawString("Hello, World!");

    glutSwapBuffers();
}

效果如圖:



指定字體
在產生顯示列表前,Windows允許選擇字體。
我做了一個selectFont函數來實現它,大家可以看看代碼。

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


最主要的部分就在于那個參數超多的CreateFont函數,學過Windows GDI的朋友應該不會陌生。沒有學過GDI的朋友,有興趣的話可以自己翻翻MSDN文檔。這里我并不準備仔細講這些參數了,下面的內容還多著呢:(
如果需要在自己的程序中選擇字體的話,把selectFont函數抄下來,在調用glutCreateWindow之后、在調用wglUseFontBitmaps之前使用selectFont函數即可指定字體。函數的三個參數分別表示了字體大小、字符集(英文字體可以用ANSI_CHARSET,簡體中文字體可以用GB2312_CHARSET,繁體中文字體可以用CHINESEBIG5_CHARSET,對于中文的Windows系統,也可以直接用DEFAULT_CHARSET表示默認字符集)、字體名稱。
效果如圖: