• <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)

            我參與的團隊

            搜索

            •  

            積分與排名

            • 積分 - 398977
            • 排名 - 59

            最新評論

            閱讀排行榜

            評論排行榜

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

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

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

             
              

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

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

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

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

            base = glGenLists(256);                        // 創(chuàng)建256個顯示列表   
            wglUseFontOutlines(    hDC,                    // 設置當前窗口設備描述表的句柄
                            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,            // 使用多邊形來生成字符,每個頂點具有獨立的法線
                            gmf);                //一個接收字形度量數(shù)據(jù)的數(shù)組的地址,每個數(shù)組元素用它對應的顯示列表字符的數(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文字程序了。你可以通過調用glPrint(“需要寫的文字”)來調用這段代碼。文字被存儲在字符串text[]中。 
              

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

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

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

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

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

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

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

              
             最后我們取出計算后得到的length,并把它變成負數(shù)(因為我們要將文本從屏幕中心左移從而把整個文本置于屏幕中間)。然后我們把length除以2。我們并不想移動整個文本的長度,只需要一半! 
              

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

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

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

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

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

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

             
              

                glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);    // 調用顯示列表繪制字符串
                glPopAttrib();                    // 彈出屬性堆棧
            }
              
             下面就是畫圖的代碼了。我們從清除屏幕和深度緩存開始。我們調用glLoadIdentity()來重置所有東西。然后我們將坐標系向屏幕里移動十個單位。輪廓字體在透視圖模式下表現(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();                    // 重置當前的模型觀察矩陣
                glTranslatef(0.0f,0.0f,-10.0f);            // 移入屏幕一個單位

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

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

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

                // 根據(jù)字體位置設置顏色
                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后的結果(為了減慢計數(shù)器)。如果這個數(shù)大于999.99,左邊第四個數(shù)將被去掉(我們要求只顯示小數(shù)點左邊3位數(shù)字)。只顯示小數(shù)點右邊的兩位數(shù)字。
             
              

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

              
             然后增大旋轉變量從而改變顏色并旋轉文字。 
              
            posted on 2007-12-14 14:27 sdfasdf 閱讀(278) 評論(0)  編輯 收藏 引用
            国产精品久久久久久福利漫画 | 久久久久国产精品嫩草影院| 亚洲国产精品久久久久| 久久久久九国产精品| 亚洲综合熟女久久久30p| 久久精品国产亚洲AV大全| 久久93精品国产91久久综合| 2020国产成人久久精品| 99久久99这里只有免费的精品| 久久精品国产亚洲AV不卡| 久久久噜噜噜久久中文字幕色伊伊 | 久久99亚洲综合精品首页| 中文字幕日本人妻久久久免费| 久久久久综合网久久| 久久天天躁狠狠躁夜夜96流白浆| 久久免费99精品国产自在现线 | 国产成人精品久久一区二区三区| 日产久久强奸免费的看| 一本一道久久精品综合| 精品无码久久久久久午夜| 亚洲国产一成久久精品国产成人综合 | 亚洲精品乱码久久久久66| 精品久久久久国产免费| 99久久人妻无码精品系列蜜桃| 久久这里的只有是精品23| 久久精品中文字幕第23页| 99久久99久久精品国产| 久久久久人妻精品一区二区三区| 狠狠色丁香久久婷婷综合_中| 国产无套内射久久久国产| 国产亚洲色婷婷久久99精品| 2020国产成人久久精品| 伊人久久国产免费观看视频| 久久激情亚洲精品无码?V| 91精品国产91久久| 狠狠色伊人久久精品综合网 | 中文字幕精品久久| 久久无码精品一区二区三区| 日日狠狠久久偷偷色综合96蜜桃| 久久本道综合久久伊人| 精品久久久久一区二区三区 |