OpenGL进行文字显示的方法_第1页
OpenGL进行文字显示的方法_第2页
OpenGL进行文字显示的方法_第3页
OpenGL进行文字显示的方法_第4页
OpenGL进行文字显示的方法_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、任何一个DEMO、仿真项目、游戏,都少不了文字这种媒体。这不可不说是对图形视觉媒体的补充我们还有一些无法超越文字来向观众表达的心事,或是补充说明,或是感悟,或是感激。 ZwqX一般的文字不属于图形渲染部分,而属于用户界面部分,这在游戏引擎中看或许一目了然,但是在底层的图形渲染APIOPENGL或D3D中,文字的显示“并不是必须”,但它是多么深深地被需要着口牙。所以,把字体设置、文字显示作为一种图形学技术而非单纯的完全我属或他属,我是这么想的。(同样,拾取也算是这样吧?乱弹OpenGL选择-拾取机制)本文来源于 ZwqXin ( 转载请注明  &

2、#160;   原文地址:怎么表达文字呢?在OpenGL中,我们没有什么现成的东西可用,但确实有办法让我们“得到这种技术”。让我最记忆深刻的是NEHE的两三篇教程(貌似都是十几课吧),讲述的就是今天的这个主题。可以到NEHE网站或者在DANCINGWIND的中文翻译(见搜集的优良OpenGL教程 )看看。而我所知道的这三种方法,前两种应该就是来自那里吧(记得),当时要努力完成课程DEMO,于是胡胡混混地就把相应的那两三课学了,而且把它的文字显示方法应用到自己的程序中(还经历了一段艰辛的探索史.连我当时的MyFont类也记录了这份小辛酸,现在看来,是因为当时的知识水

3、平不够理解吧)。然后后来又一个课程DEMO,老师后来觉得我应该“写中文”,于是我又去探索中文字体显示方法了,并在一个开源DEMO中找到,分析代码段后就拿来主义了,至昨不曾好好考究这就是我所知的第三种方法。三种方法都是三步曲:在初始化的时候“创建字体”Build,在渲染阶段“应用字体”(显示文字)Print,在程序结束或不再需要文字显示的时候“销毁字体”kill。其中前两步比较重要,着重讨论讨论哈1. 常规的屏幕字体打印(NormalFont)应用得比较广,大名鼎鼎的AZURE以前的DEMO就是用这个的。NEHE教程中作为首次出现的字体显示方法,介绍应该比较全面,大家想仔细了解的话请务必从上面网

4、址进入学习(当然还有因为我理解不透不敢乱讲的缘由)。1.  /一般的英语字体打印2. void MyFont:BuildGLFont(int fontHeight)3. 4.    HDC   hDC =:GetDC(HWND_DESKTOP);    /就是这里搞晕了半晚5.    6.    int tFontHeight = -1 * fon

5、tHeight;7.  8.    NormalFontBase = glGenLists(96);                         / Storage For 96 Characters9.    HF

6、ONT font = CreateFont( -tFontHeight,                   / Height Of Font10.                 

7、;              0,                            / Width Of Font11.   

8、;                            0,                     

9、60;      / Angle Of Escapement12.                               0,      

10、60;                     / Orientation Angle13.                        

11、       FW_BOLD,                      / Font Weight14.                &

12、#160;              TRUE,                         / Italic15.       

13、60;                       FALSE,                        / Un

14、derline16.                               FALSE,                 &

15、#160;      / Strikeout17.                               ANSI_CHARSET,       

16、0;         / Character Set Identifier18.                               OUT_TT_PRECIS, 

17、;               / Output Precision19.                              

18、60;CLIP_DEFAULT_PRECIS,          / Clipping Precision20.                               ANT

19、IALIASED_QUALITY,          / Output Quality21.                               FF_DONTCARE|D

20、EFAULT_PITCH,    / Family And Pitch22.                               "Georgia");    &

21、#160;              / Font Name23.  24.     HFONT oldfont = (HFONT)SelectObject(hDC, font);         / Selects The Fo

22、nt We Want25.     26.     wglUseFontBitmaps(hDC, 32, 96, NormalFontBase);         / Builds 96 Characters Starting At Character 3227.    

23、0;28.     SelectObject(hDC, oldfont);                         / Selects The Font We Want to return to29.  

24、;   DeleteObject(font);                                 / Delete The Font30.     31.

25、    SetBkMode(hDC,TRANSPARENT);   32.  33.     NormalFont = true; 34. 其中bUild的时候首先用到的是GDI的CreateFont函数创建字体这应该是比较常用的方法,设置了关于字体的一切并选入字体后,有一步重要的操作:wglUseFontBitmaps。1.  2. wglUseFontBitmap3. 为当前选中的GDI字体创建一组OpenGL显示列表位图字体

26、60;4. BOOL wglUseFontBitmap(HDC hDC, DWORD dwFirst, DWORD dwCount, DWORD dwListBase); 5.  6. 参数7. hDC8. 设备环境句柄9.  10. dwFirst11. 用于创建显示列表字体的第一个字符的ASCII值12.  13. dwCount14. 字符数15.  16. dwListBase17. 第一个显示列表的名称18.  19. 返回值20. 成功返回TR

27、UE,否则返回FALSE 21.  输入为DC,32,96以及创建的96个新显示列表的base列表。函数绘制从ASCII码为32-128的字符进入显示列表,依赖OPENGL显示列表的高速显示能力(直接从硬件拿存储区),可以方便进行字符的切换。在Print过程中,调用glCallLists就能调动起这些列表了,但是怎么决定具体要“调动”哪些字母呢(96个之中)?1. void MyFont:PrintGLText(GLint x, GLint y, const char *string, .)&#

28、160;2.     char  text256;3.     va_list pArguments;4.  5.     if (string = NULL)6.         return;7.  8.     va_start(pArguments, strin

29、g);9.     vsprintf(text, string, pArguments);10.     va_end(pArguments);11.  12.  13.     glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT |  GL_ENABLE_BIT | GL_LIGHTING_BIT);14.   &

30、#160; glDisable(GL_DEPTH_TEST);15.     glDisable(GL_LIGHTING);16.     glDisable(GL_TEXTURE_2D);17.     glColor4f(mColor0, mColor1, mColor2, mColor3);18.  19.     glWindowPos2i(x, y);20. 

31、0;21.     glListBase(NormalFontBase - 32);22.     glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);23.     glPopAttrib();24. 首先看函数形式printf形式,若想有个详细了解,可到这里看看。简单来说,就是C时代的可变参数列。va_start - vsprintf - (va_arg)- va_end这套机制就是为

32、了把可变参数列的内容,通过va_list (char*指针)一个一个从栈中取出来赋予他者我们的glCallLists所要接受的所有“具体字符”,通过base为基础的索引快速寻觅而取得对应ASCII字符的字体信息(实际是位图字体),并依照期望使其形成为“具体字符串”印入屏幕。另外着重介绍的是我所添加的两个优化它们贯穿三种文字显示方法之中。其一是glPushAttrib,它与glPopAttrib配合,保证了其之间的OPENGL状态设置的独立性,使其不影响该代码逻辑的前后的具体渲染状态。当然参数取GL_ALL_ATTRIB_BITS是保险点,但只要你弄清楚自己的需要,像上面这样给予特定的

33、状态作为参数效率会更高。恩,颜色,光照,深度测试,混合选择与当前方法最匹配的状态而没有对状态机的后顾之忧,如同文字本身一样作为对象完全独立于图形渲染“模块”。另一是glWindowPos2i(x, y),按OpenGL编程指南第8章所说,它取代我们以前用的glRasterPos2i,不再让作为描绘对象的物体承受模型-视图-投影变换之苦乱弹OpenGL中的矩阵变换(上) ,而是直接独立到OPENGL世界的出口屏幕坐标系,如GDI般用窗口坐标(根据屏幕像素数)来描述文字的起点位置。这同样是赋予文字的独立性,而且意义重大可知道,当时我用glRasterPos2i多么狼狈,好难才让文字不在场

34、景“里面”乱窜。在具体应用中,在初始化调用BuildGLFont.,在渲染阶段调用PrintGLText。譬如:1. /CMAINFRAME2. MyFont mFont;3.  4. /初始化:5. mFont.BuildGLFont(25);/25是字体字高,控制字体大小6.  7. /渲染阶段(RenderGLScene)8.  9. mFont.PrintGLText(530, 710, "http:/www.Z - My 3D Graphics");10. 

35、0;11. /将在坐标X = 530, Y =710位置开始绘制文字。对1024*768大小的渲染窗口中,即在右上角注意,OpenGL窗口坐标系的原点在窗口的左下角,横坐标为X,竖坐标为Y,最大值在右上角。(同见乱弹OpenGL选择-拾取机制 )浏览一下效果,第一行就是了,因为我默认用的是Georgia字体(应该一般人电脑都有),所以很漂亮接下来会谈及其余两种方法,并比较之。真正的纹理文字是怎样弄的呢?怎样让中文字体乖乖显示?什么时候用哪种方法?我集成的MyFont类是怎样个怪样?听下回分解:在OpenGL上设置字体和显示文字(下)本文来源于 

36、ZwqXin ( 转载请注明      原文地址:Tags: OpenGL  代码  工具类  C  分类:OpenGL技术 | 评论:1 | 引用:0 | 浏览:7399« 水效果 - 水池在OpenGL上设置字体和显示文字(下) »分享到新浪微博QQ空间腾讯微博人人网豆瓣0· 点击这里获取该日志的TrackBack引用地址· 相关文章:· 乱弹OpenGL选择-拾取机制(下

37、)  (2009-6-14 23:3:8)乱弹OpenGL选择-拾取机制(上)  (2009-6-13 16:54:2)子类调用父类的纯虚函数之问题  (2009-6-8 23:18:32)视锥类CFrustum .zwqxin ver  (2009-6-2 22:39:52)标准MFC在OpenGL  (2009-5-31 17:46:47)QuickSort 快速排序的实现  (2009-5-6 1:21:55)全屏反锯齿 - 多重采样  (2009-

38、5-3 19:50:7)全屏反锯齿 - 多重采样  (2009-5-2 16:21:56)图像处理里的空间域滤波  (2009-4-27 23:53:18)一年前,首次献给OpenGL之夜.雷达追踪  (2009-4-5 22:18:52)在OpenGL上设置字体和显示文字(下)2009-8-6 10:22:27 | 发布:zwqxin本篇紧随上篇,继续说一下鄙人所了解的在OpenGL进行文字显示的方法,也方便不知从哪个次元来到这里的学习者提供一点这方面的信息。上一篇见:在OpenGL上设置字体和显示文字(上) ZwqX本文来源于&#

39、160;ZwqXin ( 转载请注明      原文地址:2. 纹理字体最近接触Irrlicht引擎,里面的GUI模块涉及的字体设置就是用了这种纹理字体的方法。事实上,上篇的方法最后多少了涉及到了位图字体,但是这里所说的,是直接从一张“写着各个英文字符和其他常用字符”的纹理上,按对此纹理上的图案“结构”的先验知识而获取字符对应的“纹理部分”,显示到屏幕上。换句话来说,这就是真正的纹理贴图了,因此必须结合一张特定设计的“字体纹理”。要显示一个字符,需要你绘制一个一定大小的矩形(这个长度值相当于之前的字体高度它控制最后出来的文字

40、的大小),然后找到你所需字符在该纹理上的纹理坐标,作为索引检索出纹理上的对应字符部分的小纹理,贴到该矩形上。1.  2. /从字体集纹理中取出的字符3. void MyFont:BuildTextureFont(GLuint fonttex, int fontHeight, int screenWidth, int screenHeight)4. 5.     TextureFontFont = fonttex;6.  7.  

41、;   float   cx;                                         / Ho

42、lds Our X Character Coord8.     float   cy;                                 

43、0;       / Holds Our Y Character Coord9.  10.     glEnable(GL_TEXTURE_2D);11.  12.     TextureFontBase = glGenLists(256);          

44、;        / Creating 256 Display Lists13.  14.     glBindTexture(GL_TEXTURE_2D, TextureFontFont);      / Select Our Font Texture15.  16.    &

45、#160;for(int loop=0; loop<256; loop+)                    / Loop Through All 256 Lists17.     18.       

46、0; cx=float(loop%16)/16.0f;                        / X Position Of Current Character19.         cy=float(loop/

47、16)/16.0f;                        / Y Position Of Current Character20.  21.         glNewList(TextureFontBase&

48、#160;+ loop, GL_COMPILE);  / Start Building A List22.             glBegin(GL_QUADS);                   &#

49、160;      / Use A Quad For Each Character23.                 glTexCoord2f(cx,1-cy-0.0625f);          / Te

50、xture Coord (Bottom Left)24.                 glVertex2i(0,0);                        

51、/ Vertex Coord (Bottom Left)25.                 glTexCoord2f(cx+0.0625f,1-cy-0.0625f);  / Texture Coord (Bottom Right)26.         

52、        glVertex2i(fontHeight, 0);              / Vertex Coord (Bottom Right)27.               

53、  glTexCoord2f(cx+0.0625f,1-cy);          / Texture Coord (Top Right)28.                 glVertex2i(fontHeight,fontHeight);   

54、;   / Vertex Coord (Top Right)29.                 glTexCoord2f(cx,1-cy);                  /

55、0;Texture Coord (Top Left)30.                 glVertex2i(0, fontHeight);              / Vertex Coord (Top Left

56、)31.             glEnd();                                    

57、;/ Done Building Our Quad (Character)32.             glTranslated(fontHeight,0,0);               / Move To The Right

58、0;Of The Character33.         glEndList();                                  

59、0; / Done Building The Display List34.                                       

60、60;                / Loop Until All 256 Are Built35.  36.     glDisable(GL_TEXTURE_2D);37.  38.     ScreenWidth = screenWidth;39.

61、    ScreenHeight = screenHeight;40.  41.     TextureFont = true;42. 这在BUILD阶段就做的必要是没有的,但是一次过导入纹理中256个字符,生成256个小纹理,并在每帧都选择对应的纹理索引检索纹理,且每个字符如此这样的重复不变而低效的事情,还是由OpenGL的显示列表技术来做比较好一次过在初始化时做好,放入显示列表。在 PRINT阶段只要调用显示列表就好。关于显示列表,eastcowboy在他的OP

62、ENGL入门学习中详细提及过,有兴趣的朋友可看看他的文章:OpenGL入门学习第八课-使用显示列表 。比起最时兴的VBO,显示列表在重复劳动上还是有一定优势的额最后的结果是按glTranslated进行排列的256个具有纹理字符的矩形。为什么要得到渲染窗口的大小呢?因为这些矩形要保证在屏幕最前方,就应该让它突破矩阵变换啊。在上篇在OpenGL上设置字体和显示文字(上) 也提过glWindowPos2i(x, y),但这里对实际的矩形它不是很适用。因此我还是选择原来的路子,来给予文字以独立于图形的属性在屏幕最前而位置只由屏幕坐标XY决定。方法就是,或许很多人也熟悉的,glOrtho正交

63、投影变换。因此,屏幕大小(这里指渲染窗口的大小)是需要的。1.  2. void MyFont:PrintTextureText(GLint x, GLint y, char *string, int TextureSet)3. 4.     if (TextureSet > 1)TextureSet = 1;5.     if (TextureSet 

64、;< 0)TextureSet = 0;6.  7.     glPushAttrib(GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_ENABLE_BIT|  GL_LIST_BIT);8.     glDisable(GL_LIGHTING); 9.  10.     glEnable(GL_TEXTURE_2D);11

65、.     glBindTexture(GL_TEXTURE_2D, TextureFontFont);      / Select Our Font Texture12.  13.     glDisable(GL_DEPTH_TEST);             &

66、#160;             / Disables Depth Testing14.     glEnable(GL_BLEND);15.     glBlendFunc(GL_SRC_ALPHA,GL_ONE);16.  17.     glColor4f(mColor0, mColor1,

67、 mColor2, mColor3);  18.  19.     glMatrixMode(GL_PROJECTION);                        / Select The Projection Matri

68、x20.     glPushMatrix();                                     / Store The Project

69、ion Matrix21.     22.     glLoadIdentity();                                   /&

70、#160;Reset The Projection Matrix23.     glOrtho(0,ScreenWidth,0,ScreenHeight,-1,1);         / Set Up An Ortho Screen24.  25.     glMatrixMode(GL_MODELVIEW);  &#

71、160;                      / Select The Modelview Matrix26.     glPushMatrix();            

72、                         / Store The Modelview Matrix27.     28.     glLoadIdentity();     

73、;                              / Reset The Modelview Matrix29.     glTranslated(x,y,0);    

74、;                            / Position The Text (0,0 - Bottom Left)30.     31.     g

75、lListBase(TextureFontBase-32 + (128 * TextureSet);/ Choose The Font Set (0 or 1)32.     glCallLists(strlen(string),GL_UNSIGNED_BYTE,string);/ Write The Text To The Screen33.    

76、60;34.     glMatrixMode(GL_PROJECTION);                        / Select The Projection Matrix35.     glPopMatrix(); 

77、;                                     / Restore The Old Projection Matrix36.   &

78、#160; glMatrixMode(GL_MODELVIEW);                         / Select The Modelview Matrix37.     glPopMatrix();   

79、60;                                  / Restore The Old Projection Matrix38.     39. &

80、#160;   glDisable(GL_BLEND);40.     glEnable(GL_DEPTH_TEST);                            / Enables Depth Testin

81、g41.     glDisable(GL_TEXTURE_2D);42.  43.     glPopAttrib();44. TextureSet选择字符集,因为字符纹理里面每个字符对应两种字体,用0/1选择。glPushAttrib的作用前面说过了。之后我们用glPushMatrix保存当前的投影/模型视图矩阵,在弄好一切好就马上切换回去。弄什么呢?新的坐标变换。文字(glCallLists绘制)是脱离我们OPENGL图形世界的,因此单独给予它一套变换在屏幕最前方且不受视觉透视影响。glOrtho(

82、0,ScreenWidth,0,ScreenHeight,-1,1)这样的投影变换设置配合glTranslated这样的模型变换就能满足我的要求了。因为创建的正交投影是与渲染窗口大小一致的,所以glTranslated的X,Y的单位与像素pixel对应这不也就是GDI那种设置方式了么哈。具体应用:1. /CMAINFRAME 2. MyFont mFont; 3.   4. /初始化: 5. mFont.BuildTextureFont(FontTextureID, 25, VB_WIDTH, VB_HE

83、IGHT);6. /25是字体字高,控制字体大小 ,FontTextureID字体纹理的纹理ID7.   8. /渲染阶段(RenderGLScene) 9.   10. mFont.PrintTextureText(790,645,"Font Test",1);11.   12. /将在坐标X = 790, Y =645位置开始绘制文字。对1024*768大小的渲染窗口中,13. /即在右上角偏下3.GDI字体事实上第一种方法也可以说是GDI的

84、方法,但是这里更明显,结合GDI字体创建和位图创建。而且它不涉及显示列表。它是在渲染时动态创建包容文字的设备相关位图(具体可参考我的一篇旧文认识HBITMAP与Bmp操作(整内存拷贝版) ),再把此位图定位而成的。因此,它是很慢的(抽)。但是为了中文字体,一点点的性能损失算得了什么呢。1. /GDI, 位图字体 可设中文字体2. void MyFont:BuildGDIFont(LPCTSTR lpszFacename, int fontWeights, int fontHeight)3. 4.  

85、60;int tfontHeight = -1 * fontHeight;5.       hGDIFont = CreateFont(tfontHeight, 0, 0, 0, fontWeights, 0, 0, 0, GB2312_CHARSET,6.            

86、;             0, 0, 0, FF_MODERN, lpszFacename);7.       GDIFont = true;8. BUILD部分就不多说了,就是CreateFontfontWeights表示字体的重量,在0900内可选,直接设置FW_BOLD之类的也行,这里给出这个参数不过是多给它一些可控性而已。首参数是字体,譬

87、如可以是"黑体","宋体"等等,也可以是英文字体。当然这里应该是取你电脑的字库里的字体,所以考虑程序的通用性,别搞些另类的字体或只有自己有的字体GB2312_CHARSET你该知道啦哈。1. void MyFont:PrintfChtext(int x, int y, LPCTSTR lpszText)2. 3.       CBitmap bitmap;4.      

88、60;BITMAP bm;5.       SIZE size;6.       7.       HDC MDC = :CreateCompatibleDC(NULL);8.       SelectObject(MDC, hGDIFont);9.     

89、  10.       :GetTextExtentPoint32(MDC,lpszText,strlen(lpszText),&size);11.  12.       bitmap.CreateBitmap(size.cx, size.cy, 1, 1, NULL);13.  14.       HBITMAP ol

90、dBmp=(HBITMAP)SelectObject(MDC,bitmap);15.  16.       SetBkColor  (MDC, RGB(0,     0,   0);17.       SetTextColor(MDC, RGB(255, 255, 255);18.  19.   &

91、#160;   TextOut(MDC, 0, 0, lpszText, strlen(lpszText);20.  21.       bitmap.GetBitmap(&bm);22.       size.cx = (bm.bmWidth + 31) & (31);23.  24.   

92、    int bufsize = size.cy * size.cx;25.  26.       struct   27.               BITMAPINFOHEADER bih;28.     

93、60;         RGBQUAD col2;29.              bic; 30.  31.       BITMAPINFO *binf = (BITMAPINFO *)&bic; 32.   

94、;    binf->bmiHeader.biSize     = sizeof(binf->bmiHeader);33.       binf->bmiHeader.biWidth    = bm.bmWidth;34.       binf->bmiHeader.biHeight  

95、; = bm.bmHeight;35.       binf->bmiHeader.biPlanes   = 1;   36.       binf->bmiHeader.biBitCount = 1;37.       binf->bmiHeader.biCompression 

96、= BI_RGB;38.       binf->bmiHeader.biSizeImage   = bufsize; 39.  40.       UCHAR* Bits = new UCHARbufsize; 41.       :GetDIBits(MDC,bitmap, 0, bm.bmHeight, Bits, binf, DIB_RGB_COLORS); 42.                           

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论