• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

              C++博客 :: 首頁 :: 聯(lián)系 ::  :: 管理
              163 Posts :: 4 Stories :: 350 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(48)

            我參與的團(tuán)隊

            搜索

            •  

            積分與排名

            • 積分 - 401322
            • 排名 - 59

            最新評論

            閱讀排行榜

            評論排行榜

            這節(jié)課繼續(xù)上一節(jié)課課的內(nèi)容。在第13課我們學(xué)習(xí)了如何使用位圖字體,這節(jié)課,我們將學(xué)習(xí)如何使用輪廓字體。
            創(chuàng)建輪廓字體的方法類似于在第13課中我們創(chuàng)建位圖字體的方法。但是,輪廓字體看起來要酷100倍!你可以指定輪廓字體的大小。輪廓字體可以在屏幕中以3D方式運(yùn)動,而且輪廓字體還可以有一定的厚度!而不是平面的2D字符。使用輪廓字體,你可以將你的計算機(jī)中的任何字體轉(zhuǎn)換為OpenGL中的3D字體,加上合適的法線,在有光照的時候,字符就會被很好的照亮了。

            一個小注釋,這段代碼是專門針對Windows寫的,它使用了Windows的wgl函數(shù)來創(chuàng)建字體,顯然,Apple機(jī)系統(tǒng)有agl,X系統(tǒng)有g(shù)lx來支持做同樣事情的,不幸的是,我不能保證這些代碼也是容易使用的。如果哪位有能在屏幕上顯示文字且獨(dú)立于平臺的代碼,請告訴我,我將重寫一個有關(guān)字體的教程。

            我們從第一課的典型代碼開始,添加上stdio.h頭文件以便進(jìn)行標(biāo)準(zhǔn)輸入/輸出操作,另外,stdarg.h頭文件用來解析文字以及把變量轉(zhuǎn)換為文字。最后加上math.h頭文件,這樣我們就可以使用SIN和COS函數(shù)在屏幕中移動文字了。
             
              
              
             另外,我們還要添加2個變量。base將保存我們創(chuàng)建的第一個顯示列表的編號。每個字符都需要有自己的顯示列表。例如,字符‘A’在顯示列表中是65,‘B’是66,‘C’是67,等等。所以,字符‘A’應(yīng)保存在顯示列表中的base + 65這個位置。
            我們再添加一個叫做rot的變量。用它配合SIN和COS函數(shù)在屏幕上旋轉(zhuǎn)文字。我們同時用它來改變文字的顏色。

             
              

            GLuint    base;            // 繪制字體的顯示列表的開始位置
            GLfloat    rot;            // 旋轉(zhuǎn)字體

              
             GLYPHMETRICSFLOAT gmf[256]用來保存256個輪廓字體顯示列表中對應(yīng)的每一個列表的位置和方向的信息。我們通過gmf[num]來選擇字母。num就是我們想要了解的顯示列表的編號。在稍后的代碼中,我將說明如何如何檢查每個字符的寬度,以便自動將文字定位在屏幕中心。切記,每個字符的寬度可以不相同。Glyphmetrics會大大簡化我們的工作。 
              

            GLYPHMETRICSFLOAT gmf[256];    // 記錄256個字符的信息

              
             下面這段用來構(gòu)建真正的字體的代碼類似于我們創(chuàng)建位圖字體的方法。和13課一樣,只是使用wglUseFontOutlines函數(shù)替換wglUseFontBitmaps函數(shù)。
             
              

            base = glGenLists(256);                        // 創(chuàng)建256個顯示列表   
            wglUseFontOutlines(    hDC,                    // 設(shè)置當(dāng)前窗口設(shè)備描述表的句柄
                            0,                // 用于創(chuàng)建顯示列表字體的第一個字符的ASCII值
                            255,                // 字符數(shù)
                            base,                // 第一個顯示列表的名稱

              
             That's not all however. We then set the deviation level. The closer to 0.0f, the smooth the font will look. After we set the deviation, we get to set the font thickness. This describes how thick the font is on the Z axis. 0.0f will produce a flat 2D looking font and 1.0f will produce a font with some depth.

            The parameter WGL_FONT_POLYGONS tells OpenGL to create a solid font using polygons. If we use WGL_FONT_LINES instead, the font will be wireframe (made of lines). It's also important to note that if you use GL_FONT_LINES, normals will not be generated so lighting will not work properly.

            The last parameter gmf points to the address buffer for the display list data.  
              

                            0.0f,                // 字體的光滑度,越小越光滑,0.0為最光滑的狀態(tài)
                            0.2f,                // 在z方向突出的距離
                            WGL_FONT_POLYGONS,            // 使用多邊形來生成字符,每個頂點(diǎn)具有獨(dú)立的法線
                            gmf);                //一個接收字形度量數(shù)據(jù)的數(shù)組的地址,每個數(shù)組元素用它對應(yīng)的顯示列表字符的數(shù)據(jù)填充
            }

              
             The following code is pretty simple. It deletes the 256 display lists from memory starting at the first list specified by base. I'm not sure if Windows would do this for you, but it's better to be safe than sorry :)  
              

            GLvoid KillFont(GLvoid)                        // 刪除顯示列表
            {
                 glDeleteLists(base, 256);                    // 刪除256個顯示列表
            }

              
             下面就是我優(yōu)異的GL文字程序了。你可以通過調(diào)用glPrint(“需要寫的文字”)來調(diào)用這段代碼。文字被存儲在字符串text[]中。 
              

            GLvoid glPrint(const char *fmt, ...)                    // 自定義GL輸出字體函數(shù)
            {

              
             下面的第一行定義了一個叫做length的變量。我們使用這個變量來查詢字符串的長度。第二行創(chuàng)建了一個大小為256個字符的字符數(shù)組,里面保存我們想要的文字串。第三行創(chuàng)建了一個指向一個變量列表的指針,我們在傳遞字符串的同時也傳遞了這個變量列表。如果我們傳遞文字時也傳遞了變量,這個指針將指向它們。 
              

                float        length=0;                    // 查詢字符串的長度
                char        text[256];                // 保存我們想要的文字串
                va_list        ap;                    // 指向一個變量列表的指針

              
             下面兩行代碼檢查是否有需要顯示的內(nèi)容,如果什么也沒有,屏幕上也就什么都沒有。
             
              

                if (fmt == NULL)                        // 如果無輸入則返回
                    return;                   
              
             接下來三行代碼將文字中的所有符號轉(zhuǎn)換為它們的字符編號。最后,文字和轉(zhuǎn)換的符號被存儲在一個叫做“text”的字符串中。以后我會多解釋一些有關(guān)字符的細(xì)節(jié)。 
              

                va_start(ap, fmt);                        // 分析可變參數(shù)
                    vsprintf(text, fmt, ap);                // 把參數(shù)值寫入字符串
                va_end(ap);                        // 結(jié)束分析

              
             感謝Jim Williams對下面一段代碼的建議。以前我是用手工將文字置于中心的,而他的辦法要好的多。
            我們從一個循環(huán)開始,它將逐個檢查文本中的字符。我們通過strlen(text)得到文本的長度。設(shè)置好了循環(huán)以后,我們將通過加上每個字符的長度來增加length的值。當(dāng)循環(huán)結(jié)束以后,被保存在length中的值就是整個字符串的長度。所以,如果我們要寫的是“hello”,假設(shè)每個字符的長度都為10個單位,我們先給length的值加上第一個字母的長度10。然后,我們檢查第二個字母的長度,它的長度也是10,所以length就變成10 + 10(20)。當(dāng)我們檢查完所有5個字母以后,length的值就會等于50(5 *10)。

            給出我們每個字符的長度的代碼是gmf[text[loop]].gmfCellIncX。記住,gmf存儲了我們每個顯示列表的信息。如果loop等于0,text[loop]就是我們的字符串中的第一個字符。如果loop等于1,text[loop]就是我們的字符串中的第二個字符。gmfCellIncX告訴我們被選擇的字符的長度。GmfCellIncX表示顯示位置從已繪制上的上一個字符向右移動的真正距離,這樣,字符之間就不會重疊在一起。同時,這個距離就是我們想得到的字符的寬度。你還可以通過gmfCelllncY命令來得到字符的高度。如果你是在垂直方向繪制文本而不是在水平方向時,這會很方便。

             
              

                for (unsigned int loop=0;loop<(strlen(text));loop++)    // 查找整個字符串的長度
                {
                    length+=gmf[text[loop]].gmfCellIncX;       
                }

              
             最后我們?nèi)〕鲇嬎愫蟮玫降膌ength,并把它變成負(fù)數(shù)(因?yàn)槲覀円獙⑽谋緩钠聊恢行淖笠茝亩颜麄€文本置于屏幕中間)。然后我們把length除以2。我們并不想移動整個文本的長度,只需要一半! 
              

                glTranslatef(-length/2,0.0f,0.0f);            // 把字符串置于最左邊

              
             然后我們將GL_LIST_BIT壓入屬性堆棧,它會防止glListBase影響到我們的程序中的其它顯示列表 
              

                glPushAttrib(GL_LIST_BIT);                // 把顯示列表屬性壓入屬性堆棧
                glListBase(base);                    // 設(shè)置顯示列表的基礎(chǔ)值為0

              
             現(xiàn)在OpenGL知道字符的存放位置了,我們就可以讓它在屏幕上顯示文字了。GlCallLists會調(diào)用多個顯示列表從而把整個文字的內(nèi)容同時顯示在屏幕上。
            下面的代碼做后續(xù)工作。首先,它告訴OpenGL我們將要在屏幕上顯示出顯示列表中的內(nèi)容。Strlen(text)函數(shù)用來計算我們將要顯示在屏幕上的文字的長度。然后,OpenGL需要知道我們允許發(fā)送給它的列表的最大值。我們依然不能發(fā)送長度大于255的字符串。所以我們使用UNSIGNED_BYTE。(用0 - 255來表示我們需要的字符)。最后,我們通過傳遞字符串文字告訴OpenGL顯示什么內(nèi)容。

            也許你想知道為什么字符不會彼此重疊堆積在一起。那時因?yàn)槊總€字符的顯示列表都知道字符的右邊緣在那里,在寫完一個字符后,OpenGL自動移動到剛寫過的字符的右邊,在寫下一個字或畫下一個物體時就會從GL移動到的最后的位置開始,也就是最后一個字符的右邊。

            最后,我們將GL_LIST_BIT屬性彈出堆棧,將GL恢復(fù)到我們使用glListBase(base)設(shè)置base之前的狀態(tài)。

             
              

                glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);    // 調(diào)用顯示列表繪制字符串
                glPopAttrib();                    // 彈出屬性堆棧
            }
              
             下面就是畫圖的代碼了。我們從清除屏幕和深度緩存開始。我們調(diào)用glLoadIdentity()來重置所有東西。然后我們將坐標(biāo)系向屏幕里移動十個單位。輪廓字體在透視圖模式下表現(xiàn)非常好。你將文字移入屏幕越深,文字開起來就更小。文字離你越近,它看起來就更大。
            也可以使用glScalef(x,y,z)命令來操作輪廓字體。如果你想把字體放大兩倍,可以使用glScalef(1.0f,2.0f,1.0f). 2.0f 作用在y軸, 它告訴OpenGL將顯示列表的高度繪制為原來的兩倍。如果2.0f作用在x軸,那么文本的寬度將變成原來的兩倍。

             
              

            int DrawGLScene(GLvoid)                    // 此過程中包括所有的繪制代碼
            {
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 清除屏幕及深度緩存
                glLoadIdentity();                    // 重置當(dāng)前的模型觀察矩陣
                glTranslatef(0.0f,0.0f,-10.0f);            // 移入屏幕一個單位

              
             在向屏幕里移動以后,我們希望文本能旋轉(zhuǎn)起來。下面3行代碼用來在3個軸上旋轉(zhuǎn)屏幕。我將rot乘以不同的數(shù),以便每個方向上的旋轉(zhuǎn)速度不同。 
              

                glRotatef(rot,1.0f,0.0f,0.0f);            // 沿X軸旋轉(zhuǎn)
                glRotatef(rot*1.5f,0.0f,1.0f,0.0f);            // 沿Y軸旋轉(zhuǎn)
                glRotatef(rot*1.4f,0.0f,0.0f,1.0f);            // 沿Z軸旋轉(zhuǎn)

              
             下面是令人興奮的顏色循環(huán)了。照常,我們使用唯一遞增的變量(rot)。顏色通過使用COS和SIN來循環(huán)變化。我將rot除以不同的數(shù),這樣每種顏色會以不同的速度遞增。最終的效果非常好。
             
              

                // 根據(jù)字體位置設(shè)置顏色
                glColor3f(1.0f*float(cos(rot/20.0f)),1.0f*float(sin(rot/25.0f)),1.0f-0.5f*float(cos(rot/17.0f)));

              
             我最喜歡的部分,將文字寫到屏幕上。我使用同將位圖字體寫到屏幕上相同的函數(shù)。將文字寫在屏幕上,所有你要做的就是glPrint(“你想寫的文字”)。很簡單。
            在下面的代碼中,我們要寫的是NeHe,空格,破折號,空格,然后是rot的值除以50后的結(jié)果(為了減慢計數(shù)器)。如果這個數(shù)大于999.99,左邊第四個數(shù)將被去掉(我們要求只顯示小數(shù)點(diǎn)左邊3位數(shù)字)。只顯示小數(shù)點(diǎn)右邊的兩位數(shù)字。
             
              

                 glPrint("NeHe - %3.2f",rot/50);                // 輸出文字到屏幕

              
             然后增大旋轉(zhuǎn)變量從而改變顏色并旋轉(zhuǎn)文字。 
              
            posted on 2007-12-14 14:27 sdfasdf 閱讀(284) 評論(0)  編輯 收藏 引用
            久久婷婷五月综合色奶水99啪| 久久国产亚洲精品无码| 国产精品美女久久久网AV| 国产精品欧美久久久久无广告| 国产2021久久精品| 亚洲国产精品无码成人片久久| 国产婷婷成人久久Av免费高清| 免费精品久久久久久中文字幕| 亚洲香蕉网久久综合影视| 国产激情久久久久影院| 香蕉久久久久久狠狠色| 色成年激情久久综合| 久久天天躁夜夜躁狠狠| 国内精品久久久久| 亚洲av伊人久久综合密臀性色| 久久亚洲欧洲国产综合| 9久久9久久精品| 无码人妻精品一区二区三区久久久| 国产精品日韩深夜福利久久| 一本久久a久久精品亚洲| 国内精品久久久久久久久| 国产精品无码久久久久久| 久久久久久久精品妇女99| 久久九九久精品国产| 四虎国产永久免费久久| 国产亚洲欧美精品久久久| 狠狠色婷婷久久一区二区| 国产69精品久久久久观看软件 | 久久久久久综合网天天| 大蕉久久伊人中文字幕| 久久婷婷综合中文字幕| 精品久久久久久久久中文字幕| 99久久精品午夜一区二区| 亚洲精品美女久久777777| 亚洲AV无码久久精品蜜桃| 伊人久久大香线焦AV综合影院| 一本色道久久HEZYO无码| 久久精品无码午夜福利理论片| 亚洲国产另类久久久精品| 精品无码久久久久久尤物| 狠狠色丁香久久婷婷综|