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

下载本文档

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

文档简介

任何一个DEMO、仿真项目、游戏,都少不了文字这种媒体。这不可不说是对图形视觉媒体的补充一一我们还有一些无法超越文字来向观众表达的心事,或是补充说明,或是感悟,或是感激。ZwqX一般的文字不属于图形渲染部分,而属于用户界面部分,这在游戏引擎中看或许一目了然,但是在底层的图形渲染API——OPENGL或D3D中,文字的显示''并不是必须'',但它是多么深深地被需要着口牙。所以,把字体设置、文字显示作为一种图形学技术而非单纯的完全我属或他属,我是这么想的。(同样,拾取也算是这样吧?[乱弹OpenGL选择拾取机制T])本文来源于ZwqXin(http:〃),转载请注明原文地址:/acbives/opengl/openglfontsettingshowing.htm]怎么表达文字呢?在OpenGL中,我们没有什么现成的东西可用,但确实有办法让我们''得到这种技术"。让我最记忆深刻的是NEHE的两三篇教程(貌似都是十几课吧),讲述的就是今天的这个主题。可以到NEHE网站或者在DANCINGWIND的中文翻译(见[搜集的优良OpenGL教程])看看~。而我所知道的这三种方法,前两种应该就是来自那里吧(记得~~),当时要努力完成课程DEMO,于是胡胡混混地就把相应的那两三课学了,而且把它的文字显示方法应用到自己的程序中(还经历了一段艰辛的探索史…连我当时的MyFont类也记录了这份小辛酸,现在看来,是因为当时的知识水平不够理解吧)。然后后来又一个课程DEMO,老师后来觉得我应该''写中文",于是我又去探索中文字体显示方法了,并在一个开源DEMO中找到,分析代码段后就拿来主义了,至昨不曾好好考究——这就是我所知的第三种方法。三种方法都是三步曲:在初始化的时候''创建字体"[Build],在渲染阶段''应用字体”(显示文字)[Print],在程序结束或不再需要文字显示的时候''销毁字体"[kill]。其中前两步比较重要,着重讨论讨论哈~1.常规的屏幕字体打印(NormalFont)应用得比较广,大名鼎鼎的AZURE以前的DEMO就是用这个的。NEHE教程中作为首次出现的字体显示方法,介绍应该比较全面,大家想仔细了解的话请务必从上面网址进入学习(当然还有因为我理解不透不敢乱讲的缘由)。/////////一般的英语字体打印voidMyFont::BuildGLFont(intfontHeight){HDChDC=::GetDC(HWND_DESKTOP);//////就是这里搞晕了半晚5.inttFontHeight=-1*fontHeight;7.&NormalFontBase=glGenLists(96);//StorageFor96Characters9.HFONTfont=CreateFont(-tFontHeight,//HeightOfFont10.0,//WidthOfFont11.0,//AngleOfEscapement12.0,//OrientationAngle13.FW_BOLD,//FontWeight14.TRUE,//Italic15.FALSE,//Underline16.FALSE,//Strikeout17.ANSI_CHARSET,//CharacterSetIdentifier18.OUT_TT_PRECIS,//OutputPrecision19.CLIP_DEFAULT_PRECIS,//ClippingPrecision20.ANTIALIASED_QUALITY,//OutputQuality21.FF_DONTCARE|DEFAULT_PITCH,//FamilyAndPitch22."Georgia");//FontName23.24.HFONToldfont=(HFONT)SelectObject(hDC,font);//SelectsTheFontWeWant25.26.wglUseFontBitmaps(hDC,32,96,NormalFontBase);//Builds96CharactersStartingAtCharacter3227.28.SelectObject(hDC,oldfont);//SelectsTheFontWeWanttoreturnto29.DeleteObject(font);//DeleteTheFont30.31.SetBkMode(hDC,TRANSPARENT);32.33.NormalFont=true;34.}其中bUild的时候首先用到的是GDI的CreateFont函数创建字体一一应该是比较常用的方法,设置了关于字体的一切并选入字体后,有一步重要的操作:wglUseFontBitmaps。1.wglUseFontBitmap为当前选中的GDI字体创建一组OpenGL显示列表位图字体BOOLwglUseFontBitmap(HDChDC,DWORDdwFirst,DWORDdwCount,DWORDdwListBase);5.参数hDC&设备环境句柄9.dwFirst用于创建显示列表字体的第一个字符的ASCII值12.dwCount字符数15.dwListBase第一个显示列表的名称18.返回值成功返回TRUE,否则返回FALSE21.输入为DC,32,96以及创建的96个新显示列表的base列表。函数绘制从ASCII码为32-128的字符进入显示列表,依赖OPENGL显示列表的高速显示能力(直接从硬件拿存储区),可以方便进行字符的切换。在Print过程中,调用glCallLists就能调动起这些列表了,但是怎么决定具体要''调动''哪些字母呢(96个之中)?voidMyFont::PrintGLText(GLintx,GLinty,constchar*string,...)chartext[256];va_listpArguments;4.if(string==NULL)return;7.va_start(pArguments,string);vsprintf(text,string,pArguments);va_end(pArguments);11.12.glPushAttrib(GL_LIST_BIT|GL_CURRENT_BIT|GL_ENABLE_BIT|GL_LIGHTING_BIT);glDisable(GL_DEPTH_TEST);glDisable(GL_LIGHTING);glDisable(GL_TEXTURE_2D);glColor4f(mColor[0],mColor[1],mColor[2],mColor[3]);18.glWindowPos2i(x,y);20.glListBase(NormalFontBase-32);glCallLists(strlen(text),GL_UNSIGNED_BYTE,text);glPopAttrib();}首先看函数形式——printf形式,若想有个详细了解,可到这里看看。简单来说,就是C时代的可变参数列。va_start-vsprintf-(va_arg)-va_end这套机制就是为了把可变参数列的内容,通过va_list(char*指针)一个一个从栈中取出来赋予他者——我们的glCallLists所要接受的所有''具体字符",通过base为基础的索引快速寻觅而取得对应ASCII字符的字体信息(实际是位图字体),并依照期望使其形成为''具体字符串''印入屏幕。另外着重介绍的是我所添加的两个优化一一它们贯穿三种文字显示方法之中。其一是glPushAttrib,它与glPopAttrib配合,保证了其之间的OPENGL状态设置的独立性,使其不影响该代码逻辑的前后的具体渲染状态。当然参数取GL_ALL_ATTRIB_BITS是保险点,但只要你弄清楚自己的需要,像上面这样给予特定的状态作为参数效率会更高。恩,颜色,光照,深度测试,混合……选择与当前方法最匹配的状态而没有对状态机的后顾之忧,如同文字本身一样一一作为对象完全独立于图形渲染''模块〃。另一是glWindowPos2i(x,y),按《OpenGL编稈指南》第8章所说,它取代我们以前用的glRasterPos2i,不再让作为描绘对象的物体承受模型-视图-投影变换之苦[乱弹OpenGL中的矩阵变换(上),而是直接独立到0PENGL世界的出口一一屏幕坐标系,如GDI般用窗口坐标(根据屏幕像素数)来描述文字的起点位置。这同样是赋予文字的独立性,而且意义重大一一可知道,当时我用glRasterPos2i多么狼狈,好难才让文字不在场景''里面”乱窜。在具体应用中,在初始化调用BuildGLFont.,在渲染阶段调用PrintGLText。譬如://CMAINFRAMEMyFontmFont;3.〃初始化:mFont.BuildGLFont(25);//25是字体字高,控制字体大小6.7.〃渲染阶段(RenderGLScene)&mFont.PrintGLText(530,710,"http://www.Z-My3DGraphics");10.11.//将在坐标X=530,Y=710位置开始绘制文字。对1024*768大小的渲染窗口中,即在右上角注意,OpenGL窗口坐标系的原点在窗口的左下角,横坐标为X,竖坐标为Y,最大值在右上角。(同见[乱弹OpenGL选择-拾取机制II])浏览一下效果,第一行就是了,因为我默认用的是Georgia字体(应该一般人电脑都有),所以很漂亮接下来会谈及其余两种方法,并比较之。真正的纹理文字是怎样弄的呢?怎样让中文字体乖乖显示?什么时候用哪种方法?我集成的MyFont类是怎样个怪样?听下回分解:在OpenGL上设置字体和显示文字(下)本文来源于ZwqXin(http:〃),转载请注明原文地址:httpz//www.zwqxinxom/achivesZopengl/opengl=font=setting=showing.htm]Tags:OpenGL代码工具类C分类:OpenGL技术|评论:1|引用:0|浏览:7399«水效果I-水池在OpenGL上设置字体和显示文字(下)》分享到新浪微博QQ空间腾讯微博人人网豆瓣0点击这里获取该日志的TrackBack引用地址相关文章:

乱弹OpenGI选择-拾取机制(下)(2009-6-1423:3:8)乱弹OpenGI选择-拾取机制(上(2009-6-1316:54:2)子类调用父类的纯虚函数之问题(2009-6-823:18:32)视锥类CFrustum.zwqxinver(2009-6-222:39:52)标准MFC在OpenGL(2009-5-3117:46:47)Quicksort快谏排序的实现,(2009-5-61:21:55)全屏反锯齿-多重采样II(2009-5-319:50:7)全屏反锯齿-多重采样I(2009-5-216:21:56)图像处理里的空间域滤波(2009-4-2723:53:18)一年前,首次献给OpenGI之夜•雷达追踪(2009-4-522:18:52)在OpenGL上设置字体和显示文字(下)2009-8-610:22:27|发布:zwqxin本篇紧随上篇,继续说一下鄙人所了解的在OpenGL进行文字显示的方法,也方便不知从哪个次元来到这里的学习者提供一点这方面的信息。上一篇见:[在OpenGL上设置字体和显示文字(上)一ZwqX本文来源于ZwqXin(),转载请注明原文地址:http:/^^irGhives^>pengl^>pengl-font-setting-showing-2.html2.纹理字体最近接触Irrlicht引擎,里面的GUI模块涉及的字体设置就是用了这种纹理字体的方法。事实上,上篇的方法最后多少了涉及到了位图字体,但是这里所说的,是直接从一张''写着各个英文字符和其他常用字符”的纹理上,按对此纹理上的图案''结构”的先验知识而获取字符对应的''纹理部分",显示到屏幕上。换句话来说,这就是真正的纹理贴图了,因此必须结合一张特定设计的''字体纹理"。要显示一个字符,需要你绘制一个一定大小的矩形(这个长度值相当于之前的字体高度一一它控制最后出来的文字的大小),然后找到你所需字符在该纹理上的纹理坐标,作为索引检索出纹理上的对应字符部分的小纹理,贴到该矩形上。//////////从字体集纹理中取出的字符voidMyFont::BuildTextureFont(GLuintfonttex,intfontHeight,intscreenWidth,intscreenHeight){TextureFontFont=fonttex;floatcx;//HoldsOurXCharacterCoordfloatcy;//HoldsOurYCharacterCoordglEnable(GL_TEXTURE_2D);.5.6.7.&2.//Creating256DisplayListsTextureFontBase=glGenLists(256);//Creating256DisplayLists.2.gIBindTexture(GL_TEXTURE_2D,TextureFontFont);//SelectOurFontTexturefor(intloop=0;Ioopv256;loop++){cx=float(loop%16)/16.0f;for(intloop=0;Ioopv256;loop++){cx=float(loop%16)/16.0f;cy=float(loop/16)/16.0f;//LoopThroughAll256Lists//XPositionOfCurrentCharacter

//YPositionOfCurrentCharacterglNewList(TextureFontBase+loop,GL_COMPILE);//StartBuildingAListglBegin(GL_QUADS);//UseAQuadForEachCharacterglTexCoord2f(cx,1-cy-0.0625f);//TextureCoord(BottomLeft)glVertex2i(0,0);//VertexCoord(BottomLeft)glTexCoord2f(cx+O.O625f,1-cy-0.0625f);//TextureCoord(BottomRight)glVertex2i(fontHeight,0);//VertexCoord(BottomRight)glTexCoord2f(cx+0.0625f,1-cy);//TextureCoord(TopRight)glVertex2i(fontHeight,fontHeight);//VertexCoord(TopRight)glTexCoord2f(cx,1-cy);glVertex2i(0,fontHeight);glEnd();glTranslated(fontHeight,0,0);glEndList();glTexCoord2f(cx,1-cy);glVertex2i(0,fontHeight);glEnd();glTranslated(fontHeight,0,0);glEndList();}//VertexCoord(TopLeft)//DoneBuildingOurQuad(Character)//MoveToTheRightOfTheCharacter//DoneBuildingTheDisplayListLoopUntilAll256AreBuiltglDisable(GL_TEXTURE_2D);ScreenWidth=screenWidth;ScreenHeight=screenHeight;TextureFont=true;}这在BUILD阶段就做的必要是没有的,但是一次过导入纹理中256个字符,生成256个小纹理,并在每帧都选择对应的纹理索引检索纹理,且每个字符如此——这样的重复不变而低效的事情,还是由OpenGL的显示列表技术来做比较好一次过在初始化时做好,放入显示列表。在PRINT阶段只要调用显示列表就好。关于显示列表,eastcowboy在他的OPENGL入门学习中详细提及过,有兴趣的朋友可看看他的文章OpenGL入门学习一—第八课使用显示列表比起最时兴的VBO,显示列表在重复劳动上还是有一定优势的额~最后的结果是按glTranslated进行排列的256个具有纹理字符的矩形。为什么要得到渲染窗口的大小呢?因为这些矩形要保证在屏幕最前方,就应该让它突破矩阵变换啊。在上篇[在0penGL上设置字体和显示文字(上)]也提过glWindowPos2i(x,y),但这里对实际的矩形它不是很适用。因此我还是选择原来的路子,来给予文字以独立于图形的属性——在屏幕最前而位置只由屏幕坐标XY决定。方法就是,或许很多人也熟悉的,glOrtho正交投影变换。因此,屏幕大小(这里指渲染窗口的大小)是需要的。voidMyFont::PrintTextureText(GLintx,GLinty,char*string,intTextureSet)

.7.&2.43.44.if(TextureSet>1)TextureSet=1;if(TextureSet<0)TextureSet=0;glPushAttrib(GL_CURRENT_BIT|GL_LIGHTING_BIT|GL_ENABLE_BIT|GL_LIST_BIT);glDisable(GL_LIGHTING);glEnable(GL_TEXTURE_2D);glBindTexture(GL_TEXTURE_2D,TextureFontFont);//SelectOurFontTextureglDisable(GL_DEPTH_TEST);//DisablesDepthTestingglEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA,GL_ONE);glColor4f(mColor[0],mColor[1],mColor[2],mColor[3]);glMatrixMode(GL_PROJECTION);//SelectTheProjectionMatrixglPushMatrix();//StoreTheProjectionMatrixglLoadIdentity();//ResetTheProjectionMatrixglOrtho(0,ScreenWidth,0,ScreenHeight,-1,1);//SetUpAnOrthoScreenglMatrixMode(GL_MODELVIEW);//SelectTheModelviewMatrixglPushMatrix();//StoreTheModelviewMatrixglLoadIdentity();//ResetTheModelviewMatrixglTranslated(x,y,0);//PositionTheText(0,0-BottomLeft)glListBase(TextureFontBase-32+(128*TextureSet));//ChooseTheFontSet(0or1)glCallLists(strlen(string),GL_UNSIGNED_BYTE,string);//WriteTheTextToTheScreenglMatrixMode(GL_PROJECTION);glPopMatrix();glMatrixMode(GL_MODELVIEW);glPopMatrix();glMatrixMode(GL_PROJECTION);glPopMatrix();glMatrixMode(GL_MODELVIEW);glPopMatrix();glDisable(GL_BLEND);glEnable(GL_DEPTH_TEST);glDisable(GL_TEXTURE_2D);//SelectTheModelviewMatrix//RestoreTheOldProjectionMatrix//EnablesDepthTestingglPopAttrib();}TextureSet选择字符集,因为字符纹理里面每个字符对应两种字体,用0/1选择。glPushAttrib的作用前面说过了。之后我们用glPushMatrix保存当前的投影/模型视图矩阵,在弄好一

切好就马上切换回去。弄什么呢?新的坐标变换。文字(glCallLists绘制)是脱离我们OPENGL图形世界的,因此单独给予它一套变换——在屏幕最前方且不受视觉透视影响。glOrtho(0,ScreenWidth,O,ScreenHeight,-1,1)这样的投影变换设置配合glTranslated这样的模型变换就能满足我的要求了。因为创建的正交投影是与渲染窗口大小一致的,所以glTranslated的X,Y的单位与像素pixel对应——这不也就是GDI那种设置方式了么哈。具体应用://CMAINFRAMEMyFontmFont;3.〃初始化:mFont.BuildTextureFont(FontTexturelD,25,VB_WIDTH,VB_HEIGHT);〃25是字体字高,控制字体大小,FontTexturelD字体纹理的纹理ID7.&〃渲染阶段(RenderGLScene)9.mFont.PrintTextureText(790,645,"FontTest",1);11.〃将在坐标X=790,Y=645位置开始绘制文字。对1024*768大小的渲染窗口中,〃即在右上角偏下3.GDI字体事实上第一种方法也可以说是GDI的方法,但是这里更明显,结合GDI字体创建和位图创建。而且它不涉及显示列表。它是在渲染时动态创建包容文字的设备相关位图(具体可参考我的一篇旧文[认识HBITMAP与Bmp操作(整内存拷贝版)]),再把此位图定位而成的。因此,它是很慢的~(抽)。但是为了中文字体,一点点的性能损失算得了什么呢。///////////GDI,位图字体可设中文字体voidMyFont::BuildGDIFont(LPCTSTRlpszFacename,intfontWeights,intfontHeight){inttfontHeight=-1*fontHeight;hGDIFont=CreateFont(tfontHeight,0,0,0,fontWeights,0,0,0,GB2312_CHARSET,0,0,0,FF_MODERN,lpszFacename);GDIFont=true;&}BUILD部分就不多说了,就是CreateFont~~fontWeights表示字体的重量,在0~900内可选,直接设置FW_BOLD之类的也行,这里给出这个参数不过是多给它一些可控性而已。首参数是字体,譬如可以是"黑体","宋体"等等,也可以是英文字体。当然这里应该是取你电脑的字库里的字体,所以考虑程序的通用性,别搞些另类的字体或只有自己有的字体~GB2312_CHARSET你该知道啦哈。voidMyFont::PrintfChtext(intx,inty,LPCTSTRlpszText){CBitmapbitmap;BITMAPbm;SIZEsize;6.7.HDCMDC=::CreateCompatibleDC(NULL);&SelectObject(MDC,hGDIFont);9.::GetTextExtentPoint32(MDC,lpszText,strlen(lpszText),&size);11.bitmap.CreateBitmap(size.cx,size.cy,1,1,NULL);13.HBITMAPoldBmp=(HBITMAP)SelectObject(MDC,bitmap);15.SetBkColor(MDC,RGB(0,0,0));SetTextColor(MDC,RGB(255,255,255));18.TextOut(MDC,0,0,lpszText,strlen(lpszText));20.bitmap.GetBitmap(&bm);size.cx=(bm.bmWidth+31)&(~31);23.intbufsize=size.cy*size.cx;25.struct{BITMAPINFOHEADERbih;RGBQUADcol[2];}bic;30.BITMAPINFO*binf=(BITMAPINFO*)&bic;binf->bmiHeader.biSize=sizeof(binf->bmiHeader);binf->bmiHeader.biWidth=bm.bmWidth;binf->bmiHeader.biHeight=bm.bmHeight;binf->bmiHeader.biPlanes=1;binf->bmiHeader.biBitCount=1;binf->bmiHeader.biCompression=BI_RGB;binf->bmiHeader.biSizeImage=bufsize;39.UCHAR*Bits=newUCHAR[bufsize];::GetDIBits(MDC,bitmap,0,bm.bmHeight,Bits,binf,DIB_RGB_COLORS);42.glPixelStorei(GL_UNPACK_ALIGNMENE1);44.〃glRasterPos2i(x,y);glWindowPos2i(x,y);glBitmap(size.cx,size.cy,0,0,0,0,Bits);48.deleteBits;SelectObject(MDC,oldBmp);::DeleteDC(MDC);}53.voidMyFont::PrintGDIText(GLintx,GLinty,CStringstr){glLoadldentity();glPushAttrib(GL_CURRENT_BIT|GL_LIGHTING_BIT);58.glDisable(GL_TEXTURE_2D);glDisable(GL_LIGHTING);61.glColor4f(mColor[0],mColor[1],mColor[2],mColor[3]);63.PrintfChtext(x,y,str);65.glPopAttrib();}glPushAttrib和glWindowPos2i的意义不多说了。看主体函数PrintfChtext。几个GDI函数:GetTextExtentPoint32用当前所选字体来计算字符串尺寸,按逻辑单位计算的高和宽都没有考虑裁剪取的情况。CreateBitmap创建单位色位图。函数所做的是依据字符串大小建立一张单色位图,把该位图信息存入UCHAR数组Bits内。类似的操作在[认识HBITMAP与Bmp操作(整内存拷贝版)]也谈过,所以细节部分譬如为什么要取宽度位8倍数等等就略过。重点是要把数组Bits交给谁。恩,glBitmap函数道出了一切。OpenGL里除了几何对象(点、线、多边形)和纹理图像

温馨提示

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

评论

0/150

提交评论