如何修改字幕输出函数,也许这篇文章可以参考。! {! a/ @7 N, Q$ Z) h2 {
/ D+ t$ |: ?- n( _
: W6 O8 M/ ~6 V' P- K让OGRE支持中文 (转贴)
$ \0 Y. e+ r" x* t
; x z: A! g4 U; G& S1 N4 r4 E# F. z6 c
0.前言:/ l* |+ n" o! b' J( k; v' z6 _4 N0 J
本人非计算机专业,凭着爱好和一腔热血混入游戏开发大军候补小队,平面尚未钻透。为赶时髦,企图叛变到3D阵营,慌乱之中捡起“OGRE”。学到如今,亦可让正方体飞机等不明物体在三次元空间胡乱打转。但觉得本引擎不支持中文显示而感到不爽,便四处寻求高人指教,但大部分高人指点说:“自己写引擎算了。”衡量了一下自己份量,觉得“自己写”这件事十年内恐尚难做到。再后来找到3DCastle论坛,经过“bug王”以及“浪客☆龙猫” 两位前辈的指点,也通过高手“renwind”遗留下来的教程,误打误撞竟然自己改出了中文支持,兴奋之余便想写点东西留点纪念。0 @/ f4 j- ^( S2 r9 V+ v
1.准备工作
/ v! c+ k" R, G+ l/ o) X“bug王”已经通过WINAPI实现了OGRE在Direct7.0下的中文支持,也有高手说这样效率不高,更因为本人基本上是不怎么熟悉WINAPI的,所以就放弃了这种方法。企图直接通过贴图来实现中文显示,毕竟OGRE本身文字输出也是用的这种办法,更好的是OGRE引擎除了普通的“ttf”字体外还支持位图字体(其实“ttf”在引擎中也被Ogre::Font::createTextureFromFont()转换成位图了),基本上就是做一个很大很大的图片,然后上面画满汉字,直接读进去就可以了,问题也就变成了——如何找这个大图片。
0 X/ R! T* o; v9 Y- }1 ~* k0 E幸好GBA游戏的开发者们已经找到了很好的文字来源和取得方法,通过金山的16*16点阵字库得到接近9000个字模,然后通过程序读出并写到2048*2048的单色位图上,转换成“png”格式图片才221k。
% T; ]0 d& I( \) |* E0 q( H0 @2.基本知识% l: l9 M2 j. T: S; `% V* M7 w7 }
修改引擎之前,我们先要知道OGRE是如何显示字体的。OGRE本身面向对象的设计和自带文档都做得非常规范漂亮,很容易就能找到关于显示文字的类以及相关函数。在这里主要看一下关于位图字体是如何显示在画面上。(1)字体的读取。! I3 S; B# P. m9 j" W3 X" H2 `
和这项功能相关的有两个类,一个是Ogre::FontManager类,负责分析字体信息(*.fontdef)文件。然后用builder模式构建一个Ogre::Font类。在Font类中最重要的数据莫过于mTexCoords_u1、mTexCoords_u2、mTexCoords_v1、mTexCoords_v2这四个数组,他们分别用来储存不同文字对应在图片上的纹理坐标。 不过数组大小明显不够储存9000个汉字的,一会儿要改的。9 x% N# D* d' K: [0 P! d
(2)字体的显示。3 p- j/ S S0 [( V; P0 G% R9 U
好像字体显示中用得较多的是Ogre::TextAreaGuiElement类,不过好像还有其他的,我们在这里只看这个吧,估计其他的也大同小异。看了看好像唯一和显示字体有关的函数就是void TextAreaGuiElement::updateGeometry()了,基本上就是根据要写到屏幕上的字串,在Ogre::Font类中得到相应的贴图坐标和贴图,然后画上去,道理也不是很难。- J7 F6 D8 g1 L
3.动手术9 }* S" f K% @1 Q4 G
目标锁定到Ogre::Font,Ogre::FontManager,Ogre::TextAreaGuiElement三个类中,把所有文件备份一遍手术开始!
" g" H: @% y! ^(1) Ogre::Font类。
$ l1 V! w! {( H, W: |/ I首先是储存文字贴图坐标的数组的大小不够,原来定义的是——宽字符集 (1024 - 32)、ASCII(256 - 32)。这点点大小怎么够我近9000字大军进入,索性都改成(9030 - 32)。还有就是set和get文字贴图的id都是char类型数据,256个id也不够分配给汉字,看来要都改成unsigned long形(其实大部分机器上int也是32位,不过long是固定32位的类型,感觉统用点)。. Q* L7 I+ e* h% b
(2) Ogre::FontManager类。
8 t9 H+ ]1 x6 ~5 Y里面从脚本文件中解析贴图坐标的方法是根据单字符的方式,为支持汉字,改成同时可以分析int的。一个汉字对应数字是他的区位码+161(前160个留给了半角字)。% o2 S& d$ x/ r/ c: ?7 R, @+ Z2 t
(3) Ogre::TextAreaGuiElement类。5 Z) |! z2 P$ r+ f$ i1 s
这个是相对比较麻烦的,他要从字串中分辨出到半角字和中文。在这里增加一个std::vector<unsigned long> caption,用来储存分辨的结果。增加以下几行。" Q3 P! a1 }7 S2 O( N
std::vector<unsigned long> caption;
$ b3 L3 x6 P; f+ Y5 k3 Z9 Uunsigned char nTemp; ?* u5 a1 B7 e! P- R3 _
String::iterator it=mCaption.begin();4 c) C* X0 H3 O. C0 ]. j( N/ ?2 ~
for(;it!=mCaption.end();++it)& d& H+ ^6 w$ B% T
{2 e3 o+ z2 p! n. _$ W
if(unsigned char(*it)<=160)//如果是半角
' h& O+ y; I2 j{
0 O2 M) u& I! i- ecaption.push_back((unsigned char)*it);
4 T- g! k# f2 b& G}" g: p8 l* Y2 _. i+ e& D
else//处理全角字符
/ `& x" p' @ Z. A& G+ x. r. o R0 o{
) [, X: y5 H8 w4 i1 V: }. enTemp=(unsigned char)(*it);
& R y. j; M: X$ R, Y* H++it;( W! u0 E/ ]5 g% y$ n, V$ N4 a( E
if(it==mCaption.end())
; ?: \& O7 r* R) k! _# v! j9 u% hbreak;
# E( I% d0 U! f/ r9 r( `+ }//下面是得到区位码+161的公式。0 P, x6 R4 } A4 p& S+ R
caption.push_back((94*(nTemp-0xa0-1)+((unsigned char)(*it)-0xa0-1))+161);7 s' i6 C, W( A9 R: ~
}$ |( m8 @: O' ~3 a" M5 {" ^" f2 x
}, d" m1 L# E; V0 p! X
然后后面所有关于mCaption的地方都用caption代替就ok了。* S, A3 E) D' n! F0 o
4.结果。) M/ \5 `3 Y* m6 I& o5 J
在OpenGL和DX9.0中成功的支持了中文,但是DX7.0中竟然出现了运行错误,具体问题还不清楚,还望各位高手指教。
& M( W5 y( H0 Z0 i. Q6 [: x' |因为字体本身原因,文字很扁平的不好看,索性又改了改Ogre::Font,Ogre::FontManager两个类,实现脚本中支持修改文字纵横比例的系数的proportion,当这个值设置为0.8的时候比较好看了。/ ]1 e5 T6 C7 P9 w
& O, j' U" ~6 O- H8 o. U
9 H; v1 I3 X7 p' ~相关文件
6 n! h# \/ n2 Q% d Tchinese.fontdef//字体信息文件 放在资源文件加中' }' g$ h- l; }, w) e
font.png//字体图片 放在资源文件加中
) R7 v6 h: |; ]3 ^* H* G J
( u7 ^6 L) L ^3 `) |/ ^3 Y9 [OgreFont.cpp, y! e. d" u& s$ D$ n* ^& b5 Q- l
OgreFont.h
+ o N' a8 ` _0 [OgreFontManager.cpp) c' E, I) S- L; ]- M8 s6 _/ y' M8 O V
OgreTextAreaGuiElement.cpp+ c! ?+ m) |4 z: x
//上面文件覆盖同名文件 就可以 先备份. z0 b) z O7 W4 b% Z
2 b* p/ I3 s9 A+ q: G. {( g这个是在ogre-win32-v0-13-1基础上改的,请到
+ k) \( s z m zogre-win32-v0-13-1.zip下载 e- c! f. v8 M8 R8 D8 H) O; ? L6 X
/ q( U& Q: d5 i4 v, I中文字体名字就叫 Chinese,以后能做中文游戏了! |