天天看點

讓OGRE支援中文(二)

讓OGRE支援中文(二)

        ----支援TTF字型了

0.還是前言

        如果你希望能看懂這篇文章,請先确定你已經看到了《讓OGRE支援中文》,因為本文是在上一篇文章的基礎上寫的,并且假設檔案都已經按照上一篇文章進行了手術。但是如果你隻想簡單的使用TTF字型,隻要下載下傳本文附帶的檔案,重新編譯就可以了。

1.檢讨

        正如上回說的,我們已經實作了一個位圖的字型。但是當冷靜下來思考時,就能發現這種方法的諸多缺陷。讀入一個2048*2048的位圖,等于在顯存中儲存一個2048*2048的貼圖,不說是否所有顯示卡都支援這麼大的貼圖,單是每個Font字型類吃顯存的胃口,就足以令人心驚肉跳。如果定義足夠多的字型類,我想你的遊戲的配置要求,在某些方面足以超過《DOOM3》了。

        而且這并不是唯一的缺陷,文字大小相對于位圖大小比例相差太大,導緻浮點數的文字位置誤差很大,你可以在一個文字旁邊看到其他文字的影子。(雖然可以通過增加文字間距來解決。)還有點陣字型本身的缺陷,就是字形單一,不适合放大縮小,一些文字邊緣的馬賽克,足以熄滅任何玩家的投入感。

        似乎TTF是唯一的解決之道。

2.基本知識

(1)TTF字型。

        TTF是一種矢量字庫。我們經常可以聽到矢量這個詞,像是FLASH中的矢量圖形,在100*100分辨率下制作的flash,就算它放大為全屏,顯示出的畫面也不會出現馬賽克。所謂矢量,其實說白了就是用點和線來描述圖形,這樣,在圖形需要放大的時候,隻要把所有這個圖形的點和線放大相應的倍數就可以了。而且,在網站上有很多的TTF字庫可以下載下傳,或者你可以去買一些專門的字庫CD光牒。然後在你發行你精心制作的遊戲時,可以順便捎上這些字尾為.ttf的檔案就行了。包括Quake這樣的驚世之作,也都是用的TTF字庫。

(2)FreeType2庫

        在http://www.freetype.org,有一個FreeType的免費庫,而且是OpenSource的。它目前有2個版本:1.0和2.0。其差別在于,1.0隻能讀取TTF格式的,而2.0支援更多的檔案格式,在使用它之前請詳細閱讀所要遵循的Licence,以下是摘自FreeType2.0對字庫的支援清單:

        TrueType fonts (and collections)

        Type 1 fonts

        CID-keyed Type 1 fonts

        CFF fonts

        OpenType fonts (both TrueType and CFF variants)

        SFNT-based bitmap fonts

        X11 PCF fonts

        Windows FNT fonts

(3)“主體思想”

        請參照炎龍工作室的《遊戲中漢字顯示的實作與技巧》這篇文章,可惜使用的是Windows API,作者千裡馬肝,上網上搜一下吧。

        附帶說一句,上面兩條都是直接從這文章中剪切下來的,>_<  不要罵我啊,不知道算不算侵權呢。

3.動手術---比你想象的要麻煩

(1)

        首先要告訴字型類,我們下一次渲染需要哪些字。以便字型類可以在需要的時候釋放不使用的字型。

        在Font類中~

        a.增加資料 bool mUsing[OGRE_NUM_GLYPHS]; 用來标記文字是否使用。

        b.增加函數

                inline void setUsing(std::vector<unsigned long>& caption)

                {

                        memset(this->mUsing,0,sizeof(this->mUsing));

                        std::vector<unsigned long>::iterator it;

                        for(it=caption.begin();it!=caption.end();++it)

                        {

                                if(OGRE_GLYPH_INDEX(*it)<OGRE_NUM_GLYPHS)

                                this->mUsing[OGRE_GLYPH_INDEX(*it)]=1;//标記文字為使用

                        }

                }

        并在 void TextAreaGuiElement::updateGeometry() 中調用這個函數。

(2)

        然後是修改void Font::createTextureFromFont(void);

        Font類是通過void Font::createTextureFromFont(void)來把通過FreeType2分析好的英文字畫在一個2^n*2^n的貼圖上,然後再儲存英文字的位置。

        我們需要修改的是:

        a.從函數中分離并儲存畫字的FreeType2和輔助變量。我們通過一個類來儲存和處理這些變量。

        class TTFMsg

                {

                        class Max//類中類,用來儲存幾個"最大",

                        {

                                int nothing;//這個是用來占位的,沒意義,反正沒他就運作出錯,可能和資料對齊有關吧。

                        public:

                                int height;//文字最大高度

                                int width;//最大寬度

                                int bear;//最大空隙?

                        };

                public:

                        FT_Library ftLibrary;//FreeType2用

                        FT_Face face;//FreeType2接口?

                        uint char_spacer;//文字空隙

                        SDDataChunk ttfchunk;//資料塊,用來儲存ttf資訊

                        FT_F26Dot6 ftSize;//FreeType2字型大小

                        std::pair<uint,uint> point;//在位圖上畫字的點

                        SDDataChunk imgchunk;//資料塊,用來儲存位圖資訊

                        bool dirty;//标記,看是否需要更新貼圖

                        Max max;//幾個最大

                        inline bool init(Font*  font) //這個是初始化函數在void Font::createTextureFromFont(void);中調用.

                        {      

                                //以下都是初始化,大部分都是從void Font::createTextureFromFont(void);移植過來的

                                dirty=false;

                                if( FT_Init_FreeType( &ftLibrary ) )

                                  Except( Exception::ERR_INTERNAL_ERROR, "Could not init FreeType library!",

                                "Font::Font");

                                char_spacer= 5;

                                FontManager::getSingleton()._findResourceData(font->mSource,ttfchunk);

                                if( FT_New_Memory_Face( ftLibrary, ttfchunk.getPtr(), (FT_Long)ttfchunk.getSize() , 0, &face ) )

                                         Except( Exception::ERR_INTERNAL_ERROR,

                                        "Could not open font face!", "Font::createTextureFromFont" );

                                ftSize = (FT_F26Dot6)(font->mTtfSize * (1 << 6));

                                if( FT_Set_Char_Size( face, ftSize, 0, font->mTtfResolution, 0 ) )

                                        Except( Exception::ERR_INTERNAL_ERROR,

                                        "Could not set char size!", "Font::createTextureFromFont" );

                                return true;

                        }

                        inline bool done()

                        {

                                //在Font的解構函數中調用的,本來應該調用下面兩個函數,但是不知道為什麼一調用就出錯,不用倒沒事。

                                //FT_Done_Face(face);

                                //FT_Done_FreeType(ftLibrary);

                                return true;

                        }

                        inline bool getRect(Image::Rect & rect)//這個函數以後用的,是用來找到可以畫字的貼圖的空的位置

                        {

                                if(511<point.second+max.height+char_spacer)

                                {

                                        rect.right=rect.top=rect.left=rect.bottom=-1;

                                        return false;

                                }

                                if(511<point.first+max.width+char_spacer)

                                {

                                        point.second+=max.width+char_spacer;

                                        point.first=0;

                                        if(511<point.second+max.height+char_spacer)

                                        {

                                                rect.right=rect.top=rect.left=rect.bottom=-1;

                                                return false;

                                        }

                                }

                                rect.left=point.first;

                                rect.top=point.second;

                                rect.bottom=max.height;

                                rect.right=max.width;

                                point.first+=max.width+char_spacer;

                                return true;

                        }

                };

        上面的類定義在Font類中,在Font中增加 TTFMsg * mTTFMsg 資料,并在構造函數中 mTTFMsg=new TTFMsg;

        正是修改void Font::createTextureFromFont(void);函數,主要幾點,首先是分離出很多變量和構造到TTFMsg類中了,然後是貼圖從2^n*2^n變成固定的512*512,為什麼要這個數字呢,因為256太小(廢話了)。能保證512*512大小的文本區不會出現不夠畫字的情況(所有英文+符号+沒有重複的漢字),這個安全區域基本上是夠用的。(什麼,你要畫滿螢幕的漢字?那你自己看着改吧。)還有一個重要功能是,要找100個漢字,找出最高和最寬和最大空隙作參考。修改完成這個樣子了~

    void Font::createTextureFromFont(void)

    {

        mTTFMsg->init(this);//初始化FreeType2

        uint i, l, m, n;

        int j, k;

        FILE *fo_def = stdout;//啥意思?我看不明白

        int max_height = 0, max_width = 0, max_bear = 0;

        uint startGlyph = 33;

        uint endGlyph = 167;

        // 找英文的找出最高和最寬和最大空隙

        // Calculate maximum width, height and bearing

        for( i = startGlyph, l = 0, m = 0, n = 0; i < endGlyph; i++ )

        {

            FT_Load_Char( mTTFMsg->face, i, FT_LOAD_RENDER );

            //以後的 <<6和>>6都是FreeType2中的資料和我們使用的資料的轉換

            if( ( 2 * ( mTTFMsg->face->glyph->bitmap.rows << 6 ) - mTTFMsg->face->glyph->metrics.horiBearingY ) > max_height )

                max_height = ( 2 * ( mTTFMsg->face->glyph->bitmap.rows << 6 ) - mTTFMsg->face->glyph->metrics.horiBearingY );

            if( mTTFMsg->face->glyph->metrics.horiBearingY > max_bear )

                max_bear = mTTFMsg->face->glyph->metrics.horiBearingY;

            if( (mTTFMsg->face->glyph->advance.x >> 6 ) + ( mTTFMsg->face->glyph->metrics.horiBearingX >> 6 ) > max_width)

                max_width = (mTTFMsg->face->glyph->advance.x >> 6 ) + ( mTTFMsg->face->glyph->metrics.horiBearingX >> 6 );

        }

        //下面的for是找100個漢字,找出最高和最寬和最大空隙作參考。姑且認為最的漢字就在這一百個裡了。

        for( i = 20643, l = 0, m = 0, n = 0; i < 20743; i++ )

        {

            FT_Load_Char( mTTFMsg->face, i, FT_LOAD_RENDER );

            if( ( 2 * ( mTTFMsg->face->glyph->bitmap.rows << 6 ) - mTTFMsg->face->glyph->metrics.horiBearingY ) > max_height )

                max_height = ( 2 * ( mTTFMsg->face->glyph->bitmap.rows << 6 ) - mTTFMsg->face->glyph->metrics.horiBearingY );

            if( mTTFMsg->face->glyph->metrics.horiBearingY > max_bear )

                max_bear = mTTFMsg->face->glyph->metrics.horiBearingY;

            if( (mTTFMsg->face->glyph->advance.x >> 6 ) + ( mTTFMsg->face->glyph->metrics.horiBearingX >> 6 ) > max_width)

                max_width = (mTTFMsg->face->glyph->advance.x >> 6 ) + ( mTTFMsg->face->glyph->metrics.horiBearingX >> 6 );

            if( (mTTFMsg->face->glyph->advance.x ) + ( mTTFMsg->face->glyph->metrics.horiBearingX ) > mTTFMsg->max.width)

                mTTFMsg->max.width = (mTTFMsg->face->glyph->advance.x  ) + ( mTTFMsg->face->glyph->metrics.horiBearingX );

        }

                //下面幾行行不需要了 我們要512*512

                size_t tex_side=512;//就是這個了 512

        //定義資料寬度 因為是32位的位圖 四個char為一個像素,為什麼要位這麼大呢,難道不能用8位的麼,我嘗試着改來着,不過改了之後就不透明了。望高手看看能不能改。

                size_t data_width = tex_side * 4;

                LogManager::getSingleton().logMessage("Font " + mName + "using texture size " +

                        StringConverter::toString(tex_side) + "x" + StringConverter::toString(tex_side));

        uchar* imageData = new uchar[tex_side * tex_side * 4];//設定一個空間用來儲存位圖

                // Reset content

                memset(imageData, 0, tex_side * tex_side * 4);//清零

        for( i = startGlyph, l = 0, m = 0, n = 0; i < endGlyph; i++ )//周遊每個字,

        {

            FT_Error ftResult;

            // Load & render glyph

            ftResult = FT_Load_Char( mTTFMsg->face, i, FT_LOAD_RENDER );//讀取字型

            if (ftResult)

            {

                // problem loading this glyph, continue

                LogManager::getSingleton().logMessage("Info: cannot load character " +

                    StringConverter::toString(i) + " in font " + mName);

                continue;//如果錯誤跳過

            }

                        // 應該是字寬

                        FT_Int advance = (mTTFMsg->face->glyph->advance.x >> 6 ) + ( mTTFMsg->face->glyph->metrics.horiBearingX >> 6 );

                        // 得到FreeType2的位圖

            unsigned char* buffer = mTTFMsg->face->glyph->bitmap.buffer;

            if (!buffer)

            {

                // Yuck, FT didn't detect this but generated a null pointer!

                LogManager::getSingleton().logMessage("Info: Freetype returned null for character " +

                    StringConverter::toString(i) + " in font " + mName);

                continue;//如果得不到跳過

            }

                        // 得到y的空隙 (最大空-空-本字空)就是說空出這些字底部就平了

            int y_bearnig = ( max_bear >> 6 ) - ( mTTFMsg->face->glyph->metrics.horiBearingY >> 6 );

            for( j = 0; j < mTTFMsg->face->glyph->bitmap.rows; j++ )

            {

                                int row = j + m + y_bearnig;//相對行+本字在位圖的總行+空隙

                int col = l;//列

                uchar* pDest = &imageData[(row * data_width) + l * 4];//找起點  

                for( k = 0; k < mTTFMsg->face->glyph->bitmap.width; k++ )//畫圖

                {

                    if (mAntialiasColour)//看不大懂,難道是灰色字型?

                    {

                        // Use the same greyscale pixel for all components RGBA

                        *pDest++= *buffer;

                            *pDest++= *buffer;

                            *pDest++= *buffer;

                    }

                    else

                    {

                        // Clamp colour to full white or off

                        if (*buffer > 0)

                        {

                            *pDest++= 0xFF;

                            *pDest++= 0xFF;

                            *pDest++= 0xFF;

                        }

                        else

                        {

                            *pDest++= 0;

                            *pDest++= 0;

                            *pDest++= 0;

                        }

                    }

                    // Always use the greyscale value for alpha

                    *pDest++= *buffer++;//alpha! 我是一點不了解了為什麼是這個?

                }

            }

            this->setGlyphTexCoords( i,

                (Real)l / (Real)tex_side,  // u1

                (Real)m / (Real)tex_side,  // v1

                (Real)( l + ( mTTFMsg->face->glyph->advance.x >> 6 ) ) / (Real)tex_side, // u2

                (Real)( m + ( max_height >> 6 ) ) / (Real)tex_side // v2

                );//設定坐标

            // Advance a column

            l += (advance + mTTFMsg->char_spacer);

                        //l+= 本字寬+字空

            // If at end of row

                        //如果到頭容不下一個字

            if( tex_side - 1 < l + ( advance ) )

            {

                m += ( max_height >> 6 ) + mTTFMsg->char_spacer;

                l = n = 0;

            }

        }

                // 把資訊存到我們的mTTFMsg中 >_<

                if(l)

                        mTTFMsg->point.second = m + ( max_height >> 6 ) + mTTFMsg->char_spacer;

                else

                        mTTFMsg->point.second = m;

                mTTFMsg->point.first = 0;//另起一行

                //下面是儲存幾個最大。

                mTTFMsg->max.height = max_height >> 6;

                mTTFMsg->max.bear=max_bear >> 6;

                mTTFMsg->max.width=max_width;

                mTTFMsg->imgchunk.allocate( tex_side * tex_side * 4,imageData);

                //不知道為什麼要設定img這個中間變量,似乎可以直接從chunk建立貼圖

        //--Image img;

                //img.loadRawData( imgchunk, tex_side, tex_side, PF_A8R8G8B8 );

                //貼圖名

        String texName = mName + "Texture";

                // Load texture with no mipmaps

        // 把從img建立位圖改成直接從chunk建立貼圖

                //TextureManager::getSingleton().loadImage( texName , img, TEX_TYPE_2D, 0  );

                TextureManager::getSingleton().loadRawData ( texName , mTTFMsg->imgchunk,tex_side, tex_side,PF_A8R8G8B8, TEX_TYPE_2D, 0  );

        TextureUnitState* t = mpMaterial->getTechnique(0)->getPass(0)->createTextureUnitState( texName );

                // Allow min/mag filter, but no mip

                t->setTextureFiltering(FO_LINEAR, FO_LINEAR, FO_NONE);

        // SDDatachunk will delete imageData

    }

        你應該對照一下以前的函數,改了很多的。

(3)

        然後最重要的是動态的申請和畫字。

        首先最重要的是我們要一個方法得到漢字的unicode碼,我們用到了unicodeMap數組,提供了區位碼到unicode碼的轉換工作,等一下提供這個表給你,好不容易從網上找到的阿,可惜這個表沒有中文标點的對應,如果希望支援中文标點,就要努力找到unicode碼并加進這個表了。這個表是這樣的 char c[3]="邸";unicodeMap[94*(c[0]-0xa0-1)+c[1]-0xa0-1];就得到邸的unicode碼,不知道為什麼沒有5165~5169的unicode碼,是輪空麼?

        申請渲染(字)

        {

                if(有這個字)

                        傳回位置

                else

                {

                        if(有空間)

                                畫字

                        else

                            找不用的字//找不到就出錯,沒地方畫了

                                删除 在這個位置上畫字

                傳回位置

                }

        }

        上面很直覺把,大體就這個意思了,申請渲染的函數是inline void getGlyphTexCoords(unsigned long id, Real& u1, Real& v1, Real& u2, Real& v2 )  const。去掉const改一改。得到

        a.申請渲染

        inline void getGlyphTexCoords(unsigned long id, Real& u1, Real& v1, Real& u2, Real& v2 )        

        {

                unsigned long idx = OGRE_GLYPH_INDEX(id);

                if(this->mType==FT_TRUETYPE)//ttf?

                if(id>=161&&idx<OGRE_NUM_GLYPHS)//漢字?

                        if(!mTexCoords_v2[ idx ])//沒有?

                                setChar(id);//畫字去

            u1 = mTexCoords_u1[ idx ];

            v1 = mTexCoords_v1[ idx ];

            u2 = mTexCoords_u2[ idx ];

            v2 = mTexCoords_v2[ idx ];

        }

        b.畫字等

        bool Font::setChar(unsigned long dwChar)

        {

                int j,k;

                uchar* pDest;//操作資料的指針

                mProportion=0.8;//不知為什麼,總覺得中文都太扁平了,是以設定這個參數,在《讓OGRE支援中文》中創造的參數

                Image::Rect  rect;//畫字的位置

                if(!mTTFMsg->getRect(rect))//如果得不到空位置

                {

                        for(int i=161;i<OGRE_NUM_GLYPHS;++i)//尋找不用的字

                        {

                                if(!mUsing[i]&&mTexCoords_v2[i])

                                {

                                        // 得到坐标

                                        rect.left=mTexCoords_u1[i]*512;

                                        rect.top=mTexCoords_v1[i]*512;

                                        rect.bottom=mTTFMsg->max.height;

                                        rect.right=mTTFMsg->max.width;

                                        //擦除(這段代碼沒有試驗過,等做完輸入的類在檢查吧)

                                        for( j = 0; j < mTTFMsg->max.height; j++ )

                                        {

                                                pDest=mTTFMsg->imgchunk.getPtr();

                                                pDest+=((j + rect.top)* (512*4)) + rect.left * 4;

                                                memset(pDest,0,mTTFMsg->max.width*4);

                                        }

                                        mTexCoords_u1[i]=mTexCoords_v1[i]=mTexCoords_u2[i]=mTexCoords_v2[i]=0;

                                        break;

                                }

                        }

                        if(rect.top==-1)//啊啊啊啊啊啊啊啊啊,貼圖竟然都用完了,沒辦法了,出錯了

                        {

                                LogManager::getSingleton().logMessage("你太貪婪了,用的漢字太多了,這是對你的懲罰.");

                                return false;

                        }

                }

                  //以下畫字的都是招葫蘆畫瓢的,

                  FILE *fo_def = stdout;

                 FT_Error ftResult;

            // Load & render glyph

            ftResult = FT_Load_Char( mTTFMsg->face, unicodeMap[dwChar-161], FT_LOAD_RENDER );//讀取字型

            if (ftResult)

            {

                // problem loading this glyph, continue

                LogManager::getSingleton().logMessage("Info: cannot load character " +

                    StringConverter::toString(unicodeMap[dwChar-161]) + " in font " + mName);

                return false;//如果錯誤跳過

            }

          unsigned char* buffer = mTTFMsg->face->glyph->bitmap.buffer;

                  // 位圖指針

            if (!buffer)

            {

                // Yuck, FT didn't detect this but generated a null pointer!

                LogManager::getSingleton().logMessage("Info: 1111Freetype returned null for character " +

                    StringConverter::toString(unicodeMap[dwChar-161]) + " in font " + mName);

                return false;//如果得不到跳過

            }

                         int y_bearnig = ( mTTFMsg->max.bear) - ( mTTFMsg->face->glyph->metrics.horiBearingY >> 6 );

            for( j = 0; j < mTTFMsg->face->glyph->bitmap.rows; j++ )

            {

                int row = j + rect.top+y_bearnig;

                int col = rect.left;//列

                                pDest=mTTFMsg->imgchunk.getPtr();

                                pDest+=(row * (512*4)) + col * 4;

               for( k = 0; k < mTTFMsg->face->glyph->bitmap.width; k++ )//每行的點

                {

                    if (mAntialiasColour)

                    {

                        // Use the same greyscale pixel for all components RGBA

                                                        *pDest++= *buffer;

                            *pDest++= *buffer;

                            *pDest++= *buffer;

                    }

                    else

                    {

                        // Clamp colour to full white or off

                        if (*buffer > 0)

                        {

                            *pDest++= 0xFF;

                            *pDest++= 0xFF;

                            *pDest++= 0xFF;

                        }

                        else

                        {

                            *pDest++= 0;

                            *pDest++= 0;

                            *pDest++= 0;

                        }

                    }

                    // Always use the greyscale value for alpha

                                //      LogManager::getSingleton().logMessage(StringConverter::toString(*buffer)+"is cool");

                    *pDest++= *buffer++;

                }

                        }

                        // 設定位置

                        this->setGlyphTexCoords( dwChar,

                                 (Real)rect.left / 512.0f,  // u1

                                (Real)rect.top / 512.0f,  // v1

                                (Real)( rect.left + (mTTFMsg->face->glyph->advance.x >> 6) ) / 512.0f, // u2

                                (Real)( rect.top + rect.bottom ) / 512.0f // v2

                                        );

                mTTFMsg->dirty=true;//貼圖需要更新

                return true;

        }

(4)

        松口氣吧,繁重的工作都做完了,就是更新貼圖了。

        Font類中~

        inline void write()

                {

                        if(mTTFMsg->dirty)

                        {      

                                // 重新載入貼圖,順便說一句,類似功能的函數還有

                                //virtual void  blitToTexture (const Image &src, unsigned uStartX, unsigned uStartY)=0

                                //和virtual void  blitImage (const Image &src, const Image::Rect imgRect, const Image::Rect texRect)

                                //不過blitToTexture()在ogre-win32-v0-14-0之前沒有實作,沒有嘗試使用。 blitImage()就算到現在也沒有實作。

                                TextureManager::getSingleton().unload ( mName + "Texture");

                                TextureManager::getSingleton().loadRawData ( mName + "Texture" , mTTFMsg->imgchunk,512, 512,PF_A8R8G8B8, TEX_TYPE_2D, 0  );

                                mTTFMsg->dirty=false;

                        }

                }

         在 void TextAreaGuiElement::updateGeometry() 中調用這個函數。

4.結果。

        好長阿,寫了好長。雖然多是代碼,但寫注釋也很累啊。重溫了這些天的工作結果。就像上一篇一樣“在OpenGL和DX9.0中成功的支援了中文,但是DX7.0中竟然出現了運作錯誤,具體問題還不清楚,還望各位高手指教。”。不過本來OGRE就不怎麼支援DX7的,不管了吧。OpenGL中渲染的比DX9.0清晰,是我的顯示卡的原因麼?以上的winXp+vs2003.net+艾爾沙980se通過~。。

        順便說兩句,上次發表了拙作,沒想到好多朋友和高人們找到了我。甚至聯系到了一個南方的公司,說要做一個引擎支援中文的方面。但是賣完400多的火車票之後竟然因為住房問題廢棄了,5555,退票少了80元啊。還是自己差阿,如果再多學點可能就能要我了把~。努力吧,争取寫《讓OGRE支援中文》三部曲。

        下一篇應該是《可以輸入中文了》。

        也可能寫不出來的~~~~~~~~~~~~~~~~~~~~   

    相關檔案

    chinese.fontdef//字型資訊檔案 放在資源檔案加中

    font.png//字型圖檔 放在資源檔案加中

    OgreFont.cpp

    OgreFont.h

    OgreFontManager.cpp

    OgreTextAreaGuiElement.cpp

    //上面檔案覆寫同名檔案 就可以 先備份

   solo5.ttf//這個是一個中文ttf 我直接替換了原來的ttf

   unicodemap.h//這個重要,是換算unicode碼的數組(文中提到)

   這個是在ogre-win32-v0-14-0基礎上改的(上次是ogre-win32-v0-13-1),

   請到http://sourceforge.net/projects/ogre/下載下傳

    配套檔案下載下傳:http://www.gameres.com/Articles/Program/Visual/3D/ogre/ttf.files/file.rar

    免費打工仔QQ:1850070

From: GameRes

http://www.gameres.com

         上面圖中“免費打工仔TTF:213.786”是TTF 其他是位圖的,中文的位圖字型也小修改了一下,支援半角字型了~

繼續閱讀