OpenGL進行文字顯示的方法_第1頁
OpenGL進行文字顯示的方法_第2頁
OpenGL進行文字顯示的方法_第3頁
OpenGL進行文字顯示的方法_第4頁
OpenGL進行文字顯示的方法_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

任何一個DEMO、仿真項目、游戲,都少不了文字這種媒體。這不可不說是對圖形視覺媒體的補充一一我們還有一些無法超越文字來向觀眾表達的心事,或是補充說明,或是感悟,或是感激。ZwqX一般的文字不屬于圖形渲染部分,而屬于用戶界面部分,這在游戲引擎中看或許一目了然,但是在底層的圖形渲染API——OPENGL或D3D中,文字的顯示''并不是必須'',但它是多么深深地被需要著口牙。所以,把字體設置、文字顯示作為一種圖形學技術而非單純的完全我屬或他屬,我是這么想的。(同樣,拾取也算是這樣吧?[亂彈OpenGL選擇拾取機制T])本文來源于ZwqXin(http:〃),轉(zhuǎn)載請注明原文地址:/acbives/opengl/openglfontsettingshowing.htm]怎么表達文字呢?在OpenGL中,我們沒有什么現(xiàn)成的東西可用,但確實有辦法讓我們''得到這種技術"。讓我最記憶深刻的是NEHE的兩三篇教程(貌似都是十幾課吧),講述的就是今天的這個主題??梢缘絅EHE網(wǎng)站或者在DANCINGWIND的中文翻譯(見[搜集的優(yōu)良OpenGL教程])看看~。而我所知道的這三種方法,前兩種應該就是來自那里吧(記得~~),當時要努力完成課程DEMO,于是胡胡混混地就把相應的那兩三課學了,而且把它的文字顯示方法應用到自己的程序中(還經(jīng)歷了一段艱辛的探索史…連我當時的MyFont類也記錄了這份小辛酸,現(xiàn)在看來,是因為當時的知識水平不夠理解吧)。然后后來又一個課程DEMO,老師后來覺得我應該''寫中文",于是我又去探索中文字體顯示方法了,并在一個開源DEMO中找到,分析代碼段后就拿來主義了,至昨不曾好好考究——這就是我所知的第三種方法。三種方法都是三步曲:在初始化的時候''創(chuàng)建字體"[Build],在渲染階段''應用字體”(顯示文字)[Print],在程序結(jié)束或不再需要文字顯示的時候''銷毀字體"[kill]。其中前兩步比較重要,著重討論討論哈~1.常規(guī)的屏幕字體打?。∟ormalFont)應用得比較廣,大名鼎鼎的AZURE以前的DEMO就是用這個的。NEHE教程中作為首次出現(xiàn)的字體顯示方法,介紹應該比較全面,大家想仔細了解的話請務必從上面網(wǎng)址進入學習(當然還有因為我理解不透不敢亂講的緣由)。/////////一般的英語字體打印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函數(shù)創(chuàng)建字體一一應該是比較常用的方法,設置了關于字體的一切并選入字體后,有一步重要的操作:wglUseFontBitmaps。1.wglUseFontBitmap為當前選中的GDI字體創(chuàng)建一組OpenGL顯示列表位圖字體BOOLwglUseFontBitmap(HDChDC,DWORDdwFirst,DWORDdwCount,DWORDdwListBase);5.參數(shù)hDC&設備環(huán)境句柄9.dwFirst用于創(chuàng)建顯示列表字體的第一個字符的ASCII值12.dwCount字符數(shù)15.dwListBase第一個顯示列表的名稱18.返回值成功返回TRUE,否則返回FALSE21.輸入為DC,32,96以及創(chuàng)建的96個新顯示列表的base列表。函數(shù)繪制從ASCII碼為32-128的字符進入顯示列表,依賴OPENGL顯示列表的高速顯示能力(直接從硬件拿存儲區(qū)),可以方便進行字符的切換。在Print過程中,調(diào)用glCallLists就能調(diào)動起這些列表了,但是怎么決定具體要''調(diào)動''哪些字母呢(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();}首先看函數(shù)形式——printf形式,若想有個詳細了解,可到這里看看。簡單來說,就是C時代的可變參數(shù)列。va_start-vsprintf-(va_arg)-va_end這套機制就是為了把可變參數(shù)列的內(nèi)容,通過va_list(char*指針)一個一個從棧中取出來賦予他者——我們的glCallLists所要接受的所有''具體字符",通過base為基礎的索引快速尋覓而取得對應ASCII字符的字體信息(實際是位圖字體),并依照期望使其形成為''具體字符串''印入屏幕。另外著重介紹的是我所添加的兩個優(yōu)化一一它們貫穿三種文字顯示方法之中。其一是glPushAttrib,它與glPopAttrib配合,保證了其之間的OPENGL狀態(tài)設置的獨立性,使其不影響該代碼邏輯的前后的具體渲染狀態(tài)。當然參數(shù)取GL_ALL_ATTRIB_BITS是保險點,但只要你弄清楚自己的需要,像上面這樣給予特定的狀態(tài)作為參數(shù)效率會更高。恩,顏色,光照,深度測試,混合……選擇與當前方法最匹配的狀態(tài)而沒有對狀態(tài)機的后顧之憂,如同文字本身一樣一一作為對象完全獨立于圖形渲染''模塊〃。另一是glWindowPos2i(x,y),按《OpenGL編稈指南》第8章所說,它取代我們以前用的glRasterPos2i,不再讓作為描繪對象的物體承受模型-視圖-投影變換之苦[亂彈OpenGL中的矩陣變換(上),而是直接獨立到0PENGL世界的出口一一屏幕坐標系,如GDI般用窗口坐標(根據(jù)屏幕像素數(shù))來描述文字的起點位置。這同樣是賦予文字的獨立性,而且意義重大一一可知道,當時我用glRasterPos2i多么狼狽,好難才讓文字不在場景''里面”亂竄。在具體應用中,在初始化調(diào)用BuildGLFont.,在渲染階段調(diào)用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:〃),轉(zhuǎn)載請注明原文地址:httpz//www.zwqxinxom/achivesZopengl/opengl=font=setting=showing.htm]Tags:OpenGL代碼工具類C分類:OpenGL技術|評論:1|引用:0|瀏覽:7399?水效果I-水池在OpenGL上設置字體和顯示文字(下)》分享到新浪微博QQ空間騰訊微博人人網(wǎng)豆瓣0點擊這里獲取該日志的TrackBack引用地址相關文章:

亂彈OpenGI選擇-拾取機制(下)(2009-6-1423:3:8)亂彈OpenGI選擇-拾取機制(上(2009-6-1316:54:2)子類調(diào)用父類的純虛函數(shù)之問題(2009-6-823:18:32)視錐類CFrustum.zwqxinver(2009-6-222:39:52)標準MFC在OpenGL(2009-5-3117:46:47)Quicksort快諫排序的實現(xiàn),(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|發(fā)布:zwqxin本篇緊隨上篇,繼續(xù)說一下鄙人所了解的在OpenGL進行文字顯示的方法,也方便不知從哪個次元來到這里的學習者提供一點這方面的信息。上一篇見:[在OpenGL上設置字體和顯示文字(上)一ZwqX本文來源于ZwqXin(),轉(zhuǎn)載請注明原文地址:http:/^^irGhives^>pengl^>pengl-font-setting-showing-2.html2.紋理字體最近接觸Irrlicht引擎,里面的GUI模塊涉及的字體設置就是用了這種紋理字體的方法。事實上,上篇的方法最后多少了涉及到了位圖字體,但是這里所說的,是直接從一張''寫著各個英文字符和其他常用字符”的紋理上,按對此紋理上的圖案''結(jié)構(gòu)”的先驗知識而獲取字符對應的''紋理部分",顯示到屏幕上。換句話來說,這就是真正的紋理貼圖了,因此必須結(jié)合一張?zhí)囟ㄔO計的''字體紋理"。要顯示一個字符,需要你繪制一個一定大小的矩形(這個長度值相當于之前的字體高度一一它控制最后出來的文字的大小),然后找到你所需字符在該紋理上的紋理坐標,作為索引檢索出紋理上的對應字符部分的小紋理,貼到該矩形上。//////////從字體集紋理中取出的字符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階段只要調(diào)用顯示列表就好。關于顯示列表,eastcowboy在他的OPENGL入門學習中詳細提及過,有興趣的朋友可看看他的文章OpenGL入門學習一—第八課使用顯示列表比起最時興的VBO,顯示列表在重復勞動上還是有一定優(yōu)勢的額~最后的結(jié)果是按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這樣的模型變換就能滿足我的要求了。因為創(chuàng)建的正交投影是與渲染窗口大小一致的,所以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的方法,但是這里更明顯,結(jié)合GDI字體創(chuàng)建和位圖創(chuàng)建。而且它不涉及顯示列表。它是在渲染時動態(tài)創(chuàng)建包容文字的設備相關位圖(具體可參考我的一篇舊文[認識HBITMAP與Bmp操作(整內(nèi)存拷貝版)]),再把此位圖定位而成的。因此,它是很慢的~(抽)。但是為了中文字體,一點點的性能損失算得了什么呢。///////////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內(nèi)可選,直接設置FW_BOLD之類的也行,這里給出這個參數(shù)不過是多給它一些可控性而已。首參數(shù)是字體,譬如可以是"黑體","宋體"等等,也可以是英文字體。當然這里應該是取你電腦的字庫里的字體,所以考慮程序的通用性,別搞些另類的字體或只有自己有的字體~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的意義不多說了??粗黧w函數(shù)PrintfChtext。幾個GDI函數(shù):GetTextExtentPoint32用當前所選字體來計算字符串尺寸,按邏輯單位計算的高和寬都沒有考慮裁剪取的情況。CreateBitmap創(chuàng)建單位色位圖。函數(shù)所做的是依據(jù)字符串大小建立一張單色位圖,把該位圖信息存入UCHAR數(shù)組Bits內(nèi)。類似的操作在[認識HBITMAP與Bmp操作(整內(nèi)存拷貝版)]也談過,所以細節(jié)部分譬如為什么要取寬度位8倍數(shù)等等就略過。重點是要把數(shù)組Bits交給誰。恩,glBitmap函數(shù)道出了一切。OpenGL里除了幾何對象(點、線、多邊形)和紋理圖像

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論