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

            Code Knight

            Programming is so cool
            隨筆 - 52, 文章 - 0, 評論 - 14, 引用 - 0
            數據加載中……

            [轉]CEGUI中的漢字顯示實現

            幾日前,用 CEGUI做界面,發現無法應用CEGUI的window中setText()函數直接顯示中文。上網google一下,原來經過簡單的字符轉化可以顯示中文(偷著樂,CEGUI太方便了)。

             

            方法如下(引用):http://blog.csdn.net/kun1234567/archive/2008/04/11/2282761.aspx

            CEGUI使用utf8編碼格式。這就意味著我們可以很簡單的就顯示中文。

             

            1、弄個包含中文的字體,在這里我借用大多數例子里的 “C:/windows/Font/simhei.ttf”文件。把這個文件拷貝到Datafiles文件夾的Font文件夾里。

             

            2、隨便照著一個 .Font文件,自己寫一個simhei.font文件。可以用TXT寫,然后保存,有的朋友說需要保存為utf8編碼格式,實際上是不需要的。

             

            3、同時注意修改你加載到程序里的scheme文件,將里面的字體文件設置成simhei.ttf。你也可以繼續使用FirstWindow這個例子,這樣的話直接修改源代碼里的字體為simhei.tff。

             

            4、現在在程序里進行字符編碼轉換,我拿代碼說明問題:

             

            std::wstring aa = L"123中文abcあいうえお";

            char buff[128] = "";

            WideCharToMultiByte( CP_UTF8, 0, aa.c_str(), aa.size(), buff, sizeof(buff), 0, 0);

            button1->setText ( CEGUI::String ( CEGUI::utf8* )buff );

             

            原理是這樣的,對于utf8來說,英文字符和ansi編碼在內存布局上沒什么區別,都是一個UCHAR。但是對于非英文字符,則是UCHAR+UCHAR+UCHAR。如果我們手工進行編碼格式轉換,會比較煩瑣。

             

            比較偷懶的方法就是,我們先用WCHAR(unicode內存布局,UCHAR+UCHAR+UCHAR+UCHAR)來儲存需要顯示的字符串,然后調用Win32API來幫我們把寬字符轉換成char(多字節字符集內存布局)。

             

            這就是基本方法了,然后我們可以根據這個轉換方針,利用Win32API隨意的轉換字符編碼格式,從而滿足程序中的各種需求。

             

             

                   通過此方法可以顯示中文,還沒來得急高興就發現了第二個問題:這種方法顯示中文速度太慢(顯示幾十個字需要等上7、8秒左右)。難道沒有高效的方法嗎?

            于是繼續Google(我很懶,別人能做的事情從來不麻煩自己,懶得跟蹤代碼),結果還真讓我找到了兩篇相關的文章:一份是千里馬肝的《游戲中漢字顯示的實現與技巧》,另一份是免費打工仔的《讓OGRE支持中文》。從中找到了原因:

                   原來在游戲中,是將點陣字庫或tif字體里的文字寫進紋理,根據需求貼到指定的位置。英文的顯示非常簡單,只有26個字母,就算再加一些標點、符號什么的,用一張位圖,就可以足以顯示所有的單詞了。而中文要像處理英文那樣,把所有的漢字都保存在一張位圖里,那么每一種字體都要生成一個巨型位圖。在 GB2312中,一共有6000多個漢字,就算是用16*16,據說會有2.5M!(馬肝兄說的,我沒算過)

                繼續Google,也沒有找到解決問題的直接辦法,唉,再懶也得自己上陣了。

            通過跟蹤調試,發現了問題所在,原來罪魁禍首就是他:

             

            const FontGlyph *Font::getGlyphData (utf32 codepoint)

            {

                 if (codepoint > d_maxCodepoint)

                     return 0;

             

                     if (d_glyphPageLoaded)

                     {

                          uint page = codepoint / GLYPHS_PER_PAGE;

                          uint mask = 1 << (page & (BITS_PER_UINT - 1));

                          if (!(d_glyphPageLoaded [page / BITS_PER_UINT] & mask))

                          {

                               d_glyphPageLoaded [page / BITS_PER_UINT] |= mask;

                               rasterize (codepoint & ~(GLYPHS_PER_PAGE - 1),

                                   codepoint | (GLYPHS_PER_PAGE - 1));

                          }

                     }

             

                     CodepointMap::const_iterator pos = d_cp_map.find (codepoint);

                     return (pos != d_cp_map.end()) ? &pos->second : 0;

            }

             

            原來CEGUI根據Unicode字符的編碼順序,為每256個字符分配一張紋理(例如編碼0-255存放在紋理一,編碼768-1023 存放在紋理四)。英文很容易搞定了,那么幾個字符一張紋理就夠了,可中文就得靠運氣了,有時顯示幾個字就要生成幾張紋理,還要將每張紋理用不需要的相鄰字填滿,勞民傷財!

            發現了問題,我便按照千里馬肝的思想對函數進行了改造,將使用的文字放入一張紋理中,因為紋理最大承載256個字,所以,當漢字超過256個時,則將不常用的去掉,將新的字符寫入。

            后來我發現漢字的引用沒有太多的規律,常用的一千多漢字出現的概率沒有那么懸殊(廢話,要不怎么是常用呢!),沒有辦法很好地按照使用的頻率將漢字限制在256個字以內,寫進紋理,就索性一旦滿了就將字全部釋放掉,重新寫入。(也需有我沒找到,還請高手指教)

            代碼如下:

            const FontGlyph *Font::getGlyphData (utf32 codepoint)

            {

                 if (codepoint > d_maxCodepoint)

                     return 0;

             

                 if(codepoint < 256)  //決定保留一張紋理放英文和字符

                 {

                     if (d_glyphPageLoaded)

                     {

                          uint page = codepoint / GLYPHS_PER_PAGE;

                          uint mask = 1 << (page & (BITS_PER_UINT - 1));

                          if (!(d_glyphPageLoaded [page / BITS_PER_UINT] & mask))

                          {

                               d_glyphPageLoaded [page / BITS_PER_UINT] |= mask;

                               rasterize (codepoint & ~(GLYPHS_PER_PAGE - 1),

                                   codepoint | (GLYPHS_PER_PAGE - 1));

                          }

                     }

             

                     CodepointMap::const_iterator pos = d_cp_map.find (codepoint);

                     return (pos != d_cp_map.end()) ? &pos->second : 0;

                 }

                 else //顯示漢字啦

                 {

                     CodepointMap::const_iterator pos;

             

                     pos = d_hz_map.find (codepoint);

             

                     if(pos != d_hz_map.end())

                     {

                          return (pos != d_hz_map.end()) ? &pos->second : 0;

                     }

                     else

                     {

                          rasterizeHZ(codepoint);

             

                          pos = d_hz_map.find (codepoint);

                          return (pos != d_hz_map.end()) ? &pos->second : 0;

                     }

                 }

            }

             

            void FreeTypeFont::rasterizeHZ (utf32 codepoint)

            {

                 int num;

                 uint texsize = 512;

             

                 if(d_hz_map.size() < 256)

                 {

                     float adv = d_fontFace->glyph->metrics.horiAdvance * float(FT_POS_COEF);

             

                     d_hz_map[codepoint] = FontGlyph (adv);

                 }

                 else

                 {

                     d_hz_map.clear();

             

                      ImagesetManager::getSingleton ().destroyImageset (hzImageset->getName ());

             

                     hzImageset = ImagesetManager::getSingleton ().createImageset (

                          d_name + "_auto_glyph_images_" ,

                          System::getSingleton ().getRenderer ()->createTexture ());

             

                     d_glyphImages.push_back (hzImageset);

             

                     float adv = d_fontFace->glyph->metrics.horiAdvance * float(FT_POS_COEF);

             

                     d_hz_map[codepoint] = FontGlyph (adv);

                 }

             

                 CodepointMap::const_iterator hzInter  = d_hz_map.find(codepoint);

             

                 if (!hzInter->second.getImage())

                 {

                     // Render the glyph

                     if (FT_Load_Char (d_fontFace, hzInter->first, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT |

                          (d_antiAliased ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO)))

                     {

                          std::stringstream err;

                          err << "Font::loadFreetypeGlyph - Failed to load glyph for codepoint: ";

                          err << static_cast<unsigned int> (hzInter->first);

                          err << ".  Will use an empty image for this glyph!";

                          Logger::getSingleton ().logEvent (err.str (), Errors);

             

                          // Create a 'null' image for this glyph so we do not seg later

                          Rect area(0, 0, 0, 0);

                          Point offset(0, 0);

                          String name;

                          name += hzInter->first;

                          hzImageset->defineImage(name, area, offset);

                          ((FontGlyph &)hzInter->second).setImage(&hzImageset->getImage(name));

                     }

                     else

                     {

                          uint glyph_w = d_fontFace->glyph->bitmap.width + INTER_GLYPH_PAD_SPACE;

                          uint glyph_h = d_fontFace->glyph->bitmap.rows + INTER_GLYPH_PAD_SPACE;

             

                          // Check if glyph right margin does not exceed texture size

                          uint x_next = m_nHZX + glyph_w;

                          if (x_next > texsize)

                          {

                              m_nHZX = INTER_GLYPH_PAD_SPACE;

                               x_next = m_nHZX + glyph_w;

                               m_nHZY = m_nHZYB;

                          }

             

                          // Check if glyph bottom margine does not exceed texture size

                          uint y_bot = m_nHZY + glyph_h;

                         

             

                          // Copy rendered glyph to memory buffer in RGBA format

                          drawGlyphToBuffer (hzmem_buffer + (m_nHZY * texsize) + m_nHZX, texsize);

             

                          // Create a new image in the imageset

                          Rect area(static_cast<float>(m_nHZX),

                               static_cast<float>(m_nHZY),

                               static_cast<float>(m_nHZX + glyph_w - INTER_GLYPH_PAD_SPACE),

                               static_cast<float>(m_nHZY + glyph_h - INTER_GLYPH_PAD_SPACE));

             

                          Point offset(d_fontFace->glyph->metrics.horiBearingX * static_cast<float>(FT_POS_COEF),

                               -d_fontFace->glyph->metrics.horiBearingY * static_cast<float>(FT_POS_COEF));

             

                          String name;

                          name += hzInter->first;

                          hzImageset->defineImage (name, area, offset);

                          ((FontGlyph &)hzInter->second).setImage (&hzImageset->getImage (name));

             

                          // Advance to next position

                          m_nHZX = x_next;

                          if (y_bot > m_nHZYB)

                          {

                               m_nHZYB = y_bot;

                          }

                     }

                 }

             

                 // Copy our memory buffer into the texture and free it

                 hzImageset->getTexture ()->loadFromMemory (hzmem_buffer, texsize, texsize, Texture::PF_RGBA);

             

            }

             

                 OK,問題搞定,打完收工。試試,效果還不錯,可以洗洗睡了。特將自己的一點體會寫出來,給新手提供個捷徑,也希望高手批評指教。

            posted on 2010-02-27 21:38 Code Knight 閱讀(773) 評論(0)  編輯 收藏 引用 所屬分類: GUI

            久久久精品国产sm调教网站 | 亚洲午夜久久久久久久久久| 久久av免费天堂小草播放| 一级做a爰片久久毛片人呢| 亚洲国产成人精品女人久久久| 久久午夜无码鲁丝片秋霞| 久久精品麻豆日日躁夜夜躁| 国产 亚洲 欧美 另类 久久| 久久久高清免费视频| 精品久久777| 久久人妻少妇嫩草AV蜜桃| 久久国产乱子精品免费女| 久久综合亚洲色一区二区三区| 大伊人青草狠狠久久| 久久成人小视频| 国产激情久久久久影院老熟女免费| 综合久久一区二区三区| 91精品国产综合久久四虎久久无码一级| 一级女性全黄久久生活片免费| 久久精品成人免费看| 青青草原精品99久久精品66| 欧美久久综合九色综合| 国产精品成人久久久久久久| 国产亚洲精品自在久久| 精品久久久无码人妻中文字幕| 久久久久人妻一区精品| 国产精品欧美亚洲韩国日本久久 | 99久久香蕉国产线看观香| 热99re久久国超精品首页| 久久99精品久久久久久动态图 | 国内精品久久久久影院免费| 久久伊人五月丁香狠狠色| 人妻无码久久精品| 久久久久这里只有精品| 久久精品无码一区二区日韩AV | 99蜜桃臀久久久欧美精品网站 | 精品久久久久久无码不卡| 精品综合久久久久久88小说 | 超级碰久久免费公开视频| 国产成人久久精品一区二区三区| 久久综合噜噜激激的五月天|