您的位置:首页 > 产品设计 > UI/UE

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

2009-11-05 21:03 435 查看


1.1 中文字体

在上一节的程序运行中可以看到,包括Wingdings字体在内的9种字体都正确显示,唯独第10种字体“宋体”虽然可以显示英文字符,但却无法显示中文字符。
这是因为我们的glBuildFont函数仅仅是为英文设计的,它针对每种英文字体生成了128个显示列表,显示某一个字符时只需要调用对应的显示列表即可。
汉字字符和英文字符不同的是,每一个汉字占用两个字节,和汉文、日文都是双字节字符集。并且汉字总数超过8000个,如果每一个汉字也使用一个显示列表来保存的话,资源的消耗是惊人的。
实际上即便能够承受巨大的资源消耗,直接利用wglUseFontBitmaps和wglUseFontOutlines还是无法显示汉字。其实,这两个函数都有UNICODE版本wglUseFontBitmapsW和wglUseFontOutlinesW,目的就是为了处理包括汉字在内的国际所有字符。但是不论在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字体
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: