现在的位置: 首页 > 综合 > 正文

OpenGL系统设计-位图 字体(6) 汉字TrueType字体

2013年09月02日 ⁄ 综合 ⁄ 共 5422字 ⁄ 字号 评论关闭

 

1.1        中文字体

在上一节的程序运行中可以看到,包括Wingdings字体在内的9种字体都正确显示,唯独第10种字体“宋体”虽然可以显示英文字符,但却无法显示中文字符。

这是因为我们的glBuildFont函数仅仅是为英文设计的,它针对每种英文字体生成了128个显示列表,显示某一个字符时只需要调用对应的显示列表即可。

汉字字符和英文字符不同的是,每一个汉字占用两个字节,和汉文、日文都是双字节字符集。并且汉字总数超过8000个,如果每一个汉字也使用一个显示列表来保存的话,资源的消耗是惊人的。

实际上即便能够承受巨大的资源消耗,直接利用wglUseFontBitmapswglUseFontOutlines还是无法显示汉字。其实,这两个函数都有UNICODE版本wglUseFontBitmapsWwglUseFontOutlinesW,目的就是为了处理包括汉字在内的国际所有字符。但是不论在Window 9x/XP还是Windows NT/2000,使用UNICODE版本来处理汉字还是无法实现。

再进一步,我们可以看到,在微软最新的MSDN中,或者在微软的网站上都可以找到如下的信息:

 

PRB: wglUseFontOutlines Does Not Handle DBCSPSS ID Number: Q228099

 

Article Last Modified on 10-29-2001

 

 

--------------------------------------------------------------------------------

The information in this article applies to:

 

Microsoft Win32 Application Programming Interface (API)

Microsoft Windows 98

Microsoft Windows NT Server 4.0

Microsoft Windows NT Workstation 4.0

Microsoft Windows XP Home Edition

Microsoft Windows XP Professional

 

--------------------------------------------------------------------------------

 

 

Symptoms

On Windows 98, the OpenGL function wglUseFontOutlines does not work with DBCS or UNICODE strings. On Windows NT, UNICODE strings work; however, DBCS strings do not.

 

 

 

Cause

DBCS strings are not handled by the glCallLists function, which is used to draw the display list built by wglUseFontOutlines. The reason is that a DBCS string contains characters that are one byte or two bytes each depending on the high byte. Because DBCS strings are not a consistent length, glCallLists does not parse them.

 

以上信息说明了DBCS字符串包含的字符可能是单字节的字符也可能是双字节的字符,这依赖于第一个字节。由于DBCS字符串长度的不确定性,glCallLists根本就不对其进行分析,因此,wglUseFontOutLines不能直接处理双字节字符,包括中文、日文、韩文。简单来说,这是WGL的一个BUG,而且微软也好像没有要解决的意思,因此如果需要在自己的应用程序中显示汉字,就必须自己想办法解决。

 

我们的办法是根据双字节字符集DBCS字符串中每一个字节确定是否双字节字符,针对双字节单独处理,每一个汉字字符生成一个显示列表,显示完毕后就把显示列表释放掉,这样就不会有大量资源消耗了。下面是使用wglUseFontOutLines来实现汉字显示的代码。

 

/*

*   szText:要显示的字符串

*   strFontName:字符串的字体

*/

void glPrintCC(char *szText, LPSTR strFontName)

{

   

    int i, j, ich;

    HFONT hFont;

   

    hFont = CreateFont(

0,                          //缺省高度

        0,                          //缺省宽度

        0,                          //指定移位向量和设备X轴之间的角度,缺省值

        0,                          //字符的基线和设备X轴之间的角度。缺省值

        FW_NORMAL,              //字体的权值,

        FALSE,                      //是否斜体

        FALSE,                      //是否有下划线

        FALSE,                      //是否有删除线

        GB2312_CHARSET,         //汉字字符集

        OUT_TT_PRECIS,              //输出精度

        CLIP_DEFAULT_PRECIS,        //裁减精度

        ANTIALIASED_QUALITY,        //输出质量

        FF_DONTCARE|DEFAULT_PITCH,      //字体间距和字体族

        strFontName);                           //字体名称

   

   

    SelectObject(g_hDC,hFont);

       

    int length = strlen(szText);

 

    //字符串长度为空就返回

    if(length<1)

        return;

   

   

    GLYPHMETRICSFLOAT *gmf;

   

    gmf = new GLYPHMETRICSFLOAT[length];

   

    if(!gmf)

        return;

 

    //显示列表 

    BYTE *CCList;

   

    CCList = new BYTE[length];

    if(!CCList)

    {

        delete [length]gmf;

        return;

    }

   

    char cch;

   

    //生成显示列表集

    GLuint base= glGenLists(length);

   

   

    i=0; j=0;

 

    for(i=0, j=0; i<strlen(szText);)

    {

        if (IsDBCSLeadByte(szText[i]))  ///判断是否为双字节

        {

             

            ich=szText[i];

            ich=(ich<<8)+256;          //256为汉字内码“偏移量”

            ich=ich+szText[i+1];

            i++;i++;

            wglUseFontOutlines(

                g_hDC,              //字体设备上下文DC

                ich,                //要转换为显示列表的第一个字符

                1,                  //要转换为显示列表的字符数

                base+j,             //显示列表的基数

                0.0f,               //指定与实际轮廓的最大偏移量

                0.1f,               //Z轴负方向的值

                WGL_FONT_POLYGONS,  //指定显示列表线段或多边形

                &gmf[j]);           //接受字符的地址

           

CCList[j]=j;

           

            j++;

        }

        else                            //单字节字符

        {

            cch=szText[i];

            i++;

            wglUseFontOutlines(

                g_hDC,

                cch,

                1,

                base+j,

                0.0f,

                0.15f,

                WGL_FONT_POLYGONS,

                &gmf[j]);

           

            CCList[j]=j;

            j++;

        }

    }

   

 

    glPushAttrib(GL_LIST_BIT);

    glListBase(base);

 

    //显示字符串

    glCallLists(strlen(szText),GL_UNSIGNED_BYTE, &CCList[0]);

    glPopAttrib();

   

   

    //显示完毕后删除显示列表

    glDeleteLists(base, length);

    DeleteObject(hFont);

    delete []gmf;

    delete []CCList;

}

 

int glInit()

{

 

    //启用阴影平滑(Smooth Shading)

    glShadeModel(GL_SMOOTH);

   

    glClearColor(1.0f, 1.0f, 1.0f,0.0f);

   

    //设置深度缓冲

    glClearDepth(1.0f);

 

    //启动深度测试

    glEnable(GL_DEPTH_TEST);

 

    //深度测试的类型

    glDepthFunc(GL_LEQUAL);

 

    //进行透视修正

    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

   

    glCreateAllFonts();

 

    //如果将GL_FIL改成GL_LINE,则显示的汉字就是空心字

    glPolygonMode(GL_FRONT_AND_BACK, GL_FIL);

   

    return TRUE;

}

 

 

void glMain()

{

   

    static float angle = 0.0;

    Sleep(300);

 

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();   //加载单位矩阵

    glTranslatef(-8.0f, 3.0f, -15.0f);

 

   

    glColor3f(0.0f, 0.0f, 0.0f);

 

    glPrintCC("楷体字体", "楷体");

    glPrintCC("隶书字体", "隶书");

    glPrintCC("仿宋字体", "仿宋");

    glPrintCC("宋体字体", "宋体");

 

    glTranslatef(-16.0f, -2.0f, 0.0);

    glPrintCC("华文彩云", "华文彩云");

    glPrintCC("华文行楷", "华文行楷");

    glPrintCC("华文新魏", "华文新魏");

    glPrintCC("华文细黑", "华文细黑");

   

    glTranslatef(-15.5f, -2.0f, 0.0);

    glPrintCC("黑体字体", "黑体");

    glPrintCC("幼圆字体", "幼圆");

    glPrintCC("方正舒体", "方正舒体");

    glPrintCC("方正姚体", "方正姚体");

 

    glTranslatef(-15.0f, -2.0f, 0.0);

    glScalef(2.0f, 2.0f, 2.0f);

    glPrintCC("文鼎广告体繁", "文鼎广告体繁");

   

    glTranslatef(-6.0f, -1.5f, 0.0);

    glPrintCC("文鼎海报体繁", "文鼎海报体繁");

    SwapBuffers(g_hDC);

} 

 

 

程序运行结果如图8-7所示,我们需要的汉字都显示出来了。

 

 

8-7   汉字TrueType字体

 

抱歉!评论已关闭.