技术文章 > Windows平台下OpenGL汉字处理方法

Windows平台下OpenGL汉字处理方法

2017-10-21 23:43

文档管理软件,文档管理系统,知识管理系统,档案管理系统的技术资料:

基本思想:
用wglUseFontOutlines或wglUseFontBitmaps为每个字生成一个List
为每个字调用glCallList()或为一个字串调用glCallLists()
说明:
  OpenGL设计时考虑了非ascii字符集文字的需求,在OpenGL中使用汉字是没有问题的。由于Windows95/NT4所提供的wgl环境只在单缓冲时可以使用gdi函数,所以即使只是想写一些提示文字也要用这种方法。为此,M$提供了wglUseFont??()函数,它的原型在wingdi.h中可以看到。如果只使用英文字符,那你可以使用类似下面的代码:
在OpenGL初始化的末尾建立字体:
#define LISTBASE 1000
wglUseFontBitmaps(hDC,0,255,LSITBASE);
在需要输出文字的地方调用
char pMyString=“OpenGL Text Info“;
glListBase(LISTBASE);
glCallLists(strlen(pMyString),GL_UNSIGNED_BYTE,pMyString);
  按我们已经习惯的逻辑,只要指定一个中文字体,用同样的方法就应该可以显示中文。但实际上并非如此,这样做会有两个问题:
一.一个中文字体至少有6~7千个字,需要占用很多的内存来保存这些List数据,严重影响程序性能。
二.更重要的是,由于wglUseFont??()函数的M$特色,这样做根本就不能显示汉字!wglUseFont系列函数其实都有asc和widechar两个版本,正如其实的字符串函数一样,这是Windows系统为简化制作国际化程序而设计的,可是,不幸的是,wglUseFont??W()工作并不正常,我真不明白,为什么?在试完这个问题之后,终于明白,正如MSDN MultiMedia Opengl gl3dtext屏保程序作者所说的,a bug.
对于问题一,解决的办法是只生成所用到字的List。
  简单的方法是在字串显示函数中对每个字做一次wglUseFont??(),再call对应的List,用完再删除这个List。显然这个法子性能也不会很好。改进的法子很多,举两个我想到了的例子:1.在程序中建立一个清单,每个字处理之前先到清单里找,如果有就直接CallList,否则生成List并加到清单里。2.对要大量使用文字的程序可以建立一个小字库,甚至可以是以compiled list形式存在的小字库。正如当年我们在Dos下处理汉字一样。
对于问题二,解决的办法是自己处理双字节代码。
  将一个汉字的两个字节组合成一个DWORD传给wglUseFont??()。

--------------------------------------------------------------------------------
示意代码:
//注意,以下代码必须选用中文字体才能工作,
//但可以处理中英文混合字串,Win95/WinNT4下BCB测试通过
void glDrawString(unsigned char *str)
{
GLYPHMETRICSFLOAT pgmf[1];
HDC hDC=wglGetCurrentDC();
DWORD dwChar;
int ListNum;
for(size_t i=0;i<strlen((char *)str);i++)
{
if(IsDBCSLeadByte(str[i]))
{dwChar=(DWORD)((str[i]<<8)|str[i+1]);i++;}
else dwChar=str[i];
ListNum=glGenLists(1);
bool ret=false;
ret=wglUseFontOutlines(hDC,dwChar,1,ListNum,0.0,0.1,WGL_FONT_LINES,pgmf);
glCallList(ListNum);
glDeleteLists(ListNum,1);
}
}

--------------------------------------------------------------------------------
提示:
  在BCB中用Form作OpenGL绘制时,可以利用Form的字体设置信息,在Form初始化或更改字体时显式建立该字体并将它指定给DC,就象这样:
void CreateFont(void)
{
HFONT HFont,HOldFont=0;
LOGFON LogFont;
//取字体信息
GetObject(Form1->Font->Handle,sizeof(LOGFONT),&LogFont);
//建立字体
HFont = CreateFontIndirect(&LogFont);
//选用字体
HOldFont=SelectObject (Form1->hDC, HFont);
//清除已经不用的字体
DeleteObject(HOldFont);
}
样本工程