第七章opengl文字显示

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
OpenGL文字显示 (一)显示英文
OpenGL并没有直接提供显示文字的功能,并且,OpenGL也没有自 带专门的字库。因此,要显示文字,就必须依赖操作系统所提供的功能 了。 各种流行的图形操作系统,例如Windows系统和Linux系统,都提供 了一些功能,以便能够在OpenGL程序中方便的显示文字。 最常见的方法就是,我们给出一个字符,给出一个显示列表编号, 然后操作系统由把绘制这个字符的OpenGL命令装到指定的显示列表 中。当需要绘制字符的时候,我们只需要调用这个显示列表即可。假如 我们要显示的文字全部是ASCII字符,则总共只有0到127这128种可能, 因此可以预先把所有的字符分别装到对应的显示列表中,然后在需要时 调用这些显示列表。 Windows系统中,可以使用wglUseFontBitmaps函数来批量的产生显示 字符用的显示列表。函数有四个参数: 第一个参数是HDC,这是Windows GDI的里的东西,调 用wglGetCurrentDC函数,就可以得到一个HDC了。 第二个参数表示第一个要产生的字符,因为我们要产生0到127的字符 的显示列表,所以这里填0。 第三个参数表示要产生字符的总个数,因为我们要产生0到127的字符 的显示列表,总共有128个字符,所以这里填128。 第四个参数表示第一个字符所对应显示列表的编号。假如这里 填1000,则第一个字符的绘制命令将被装到第1000号显示列表,第二个 字符的绘制命令将被装到第1001号显示列表,依次类推。我们可以先 用glGenLists申请128个连续的显示列表编号,然后把第一个显示列表编号 填在这里。 我们为了简化view中的代码,特建立字符显示类COpenGLFont(后面给 出): #define MAX_CHAR 128
(三)三维汉字的显示
在OpenGL中输出文本有两个函数:wglUseFontBitmaps和 wglUseFontOutlines,前者用来输出2维文字,后者用来输出3维文字, 项目需要
采用unicode编码方式.
void COpenGLFont::draw3DString(_TCHAR* str) { GLYPHMETRICSFLOAT pgmf[1]; DWORD dwChar; int list; HDC hDC=wglGetCurrentDC(); for(size_t i=0;i<_tcslen(str);i++) { dwChar=str[i]; list=glGenLists(1); //取出一个字符的显示列表 wglUseFontOutlines(hDC,//设备环境句柄 dwChar,//要转换为显示列表的第一个字符 1, //要转换为显示列表的字符数 list,//显示列表的基数 0.0,//指定与实际轮廓的最大偏移量,显示精度
Байду номын сангаас
// 计算字符的个数 // 如果是双字节字符的(比如中文字符),两个字节才算一个字符 // 否则一个字节算一个字符 len = 0; for(i=0; str[i]!='\0'; ++i) { if( IsDBCSLeadByte(str[i]) ) ++i; ++len; } // 将混合字符转化为宽字符 wstring = (wchar_t*)malloc((len+1) * sizeof(wchar_t)); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstring, len); wstring[len] = L'\0'; // 用完后记得释放内存 free(wstring); 加上前面所讲到的wglUseFontBitmaps函数,即可显示中文字符了。在 字体类中添加显示中文字符函数: void COpenGLFont::drawCNString(const char* str) { int len, i; wchar_t* wstring; HDC hDC = wglGetCurrentDC(); GLuint list = glGenLists(1); // 计算字符的个数 // 如果是双字节字符的(比如中文字符),两个字节才算一个字符 // 否则一个字节算一个字符 len = 0; for(i=0; str[i]!='\0'; ++i)
return; // TODO: 在此处为本机数据添加绘制代码 glClearColor(0.0f,0.0f,0.7f,1.0f); //背景设置 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0,0,10,0,0, 0,0,1,0); glColor3f(1,0,0); glRasterPos4s(-2,0,0,1); //指定位置 COpenGLFont font; font.drawString("chinese character show test!12345"); glFinish(); SwapBuffers(wglGetCurrentDC()); } 指定字体: 在产生显示列表前,Windows允许选择字体。在COpenGLFont类中定义 一个selectFont函数来实现它,大家可以看看代码。 void COpenGLFont::selectFont(int size, int charset, const char* face) { HFONT hFont = CreateFontA(size, //指定字高 0, //指定字宽 0, //指定角度(1/10度) 45, //指定字符的基线与x轴的角度(1/10度) FW_BOLD, //指定字体的重量(FW_BOLD=700) 0, //指定是否斜体 0, //指定是否有下划线 0, //指定是否是StrikeOut字体
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0,0,10,0,0, 0,0,1,0); glColor3f(1,0,0); glRasterPos4s(-5,0,0,1); //指定位置 COpenGLFont font; font.selectFont(48,DEFAULT_CHARSET, "黑体"); font.drawCNString("汉字显示测试!chinese character show test!12345"); glFinish(); SwapBuffers(wglGetCurrentDC()); }
charset, OUT_DEFAULT_PRECIS, //指定输出精度 CLIP_DEFAULT_PRECIS,//指定裁剪精度 DEFAULT_QUALITY, //指定输出质量 DEFAULT_PITCH | FF_SWISS, //指定字体的定位和外观 face); HFONT hOldFont = (HFONT)SelectObject(wglGetCurrentDC(), hFont); DeleteObject(hOldFont); } 在调用wglUseFontBitmaps之前使用selectFont函数即可指定字体。函 数的三个参数分别表示了字体大小、字符集(英文字 体ANSI_CHARSET,简体中文字体GB2312_CHARSET,繁体中文字 体CHINESEBIG5_CHARSET ,对于中文的Windows系统,也可以直接 用DEFAULT_CHARSET表示默认字符集)、字体名称。
{ if( IsDBCSLeadByte(str[i]) ) ++i; ++len; } // 将混合字符转化为宽字符 wstring = (wchar_t*)malloc((len+1) * sizeof(wchar_t)); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstring, len); wstring[len] = L'\0'; // 逐个输出字符 for(i=0; i<len; ++i) { wglUseFontBitmapsW(hDC,wstring[i], 1, list); glCallList(list); } // 回收所有临时资源 free(wstring); glDeleteLists(list, 1); } 注意我用了wglUseFontBitmapsW函数,而不 是wglUseFontBitmaps。wglUseFontBitmapsW是wglUseFontBitmaps函数 的宽字符版本,它认为字符都占两个字节。因为这里使用了 MultiByteToWideChar,每个字符其实是占两个字节的,所以应该 用wglUseFontBitmapsW。 void CMFCOpenGLView::OnDraw(CDC* /*pDC*/) { CMFCOpenGLDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 glClearColor(0.0f,0.0f,0.7f,1.0f); //背景设置
(二)显示中文
原则上,显示中文和显示英文并无不同,同样是把要显示的字符做 成显示列表,然后进行调用。但是有一个问题,英文字母很少,最多只 有几百个,为每个字母创建一个显示列表,没有问题。但是汉字有非常 多个,如果每个汉字都产生一个显示列表,这是不切实际的。我们不能 在初始化时就为每个字符建立一个显示列表,那就只有在每次绘制字符 时创建它了。当我们需要绘制一个字符时,创建对应的显示列表,等绘 制完毕后,再将它销毁。 这里还经常涉及到中文乱码的问题,在网上流传的版本中,使用了 MultiByteToWideChar这个函数的,基本上都没有出现乱码,所以我们 也准备用这个函数。通常我们在C语言里面使用的字符串,如果中英文 混合的话,例如“this is 中文字符.”,则英文字符只占用一个字节,而中 文字符则占用两个字节。用MultiByteToWideChar函数,可以转化为所 有的字符都占两个字节(同时解决了前面所说的乱码问题:))。 转化的代码如下:
wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, lists); 在字符类中添加显示字符函数: void COpenGLFont::drawString(const char* str) { static int isFirstCall = 1; static GLuint lists; if( isFirstCall ) { // 如果是第一次调用,执行初始化 // 为每一个ASCII字符产生一个显示列表 isFirstCall = 0; // 申请MAX_CHAR个连续的显示列表编号 lists = glGenLists(MAX_CHAR); //编号分别是lists, lists + 1, lists + 2, lists + MAX_CHAR -1 // 把每个字符的绘制命令都装到对应的显示列表中 wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, lists); //从 基数lists开始依次显示各个字符 } // 调用每个字符对应的显示列表,绘制每个字符 for(; *str!='\0'; ++str) glCallList(lists + *str); } 显示列表一旦产生就一直存在(除非调用glDeleteLists销毁),所以 我们只需要在第一次调用的时候初始化,以后就可以很方便的调用这些 显示列表来绘制字符了。 绘制字符的时候,可以先用glColor*等指定颜色,然后用glRasterPos*指 定位置,最后调用显示列表来绘制。 #include"OpenGLFont.h" void CMFCOpenGLView::OnDraw(CDC* /*pDC*/) { CMFCOpenGLDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc)
相关文档
最新文档