如何修改字幕输出函数,也许这篇文章可以参考。9 G. A( L# r v% M! D; A8 x
* I0 j$ r, N0 S( w
5 ~ U+ _4 _5 `* r; U8 M5 h+ M0 R
让OGRE支持中文 (转贴)
( w/ F+ u6 @+ E* `9 z3 c4 D9 O, c8 J1 r+ C* j
, s! ]7 G0 a- E9 |0.前言:8 W6 @6 }4 P D! E8 j
本人非计算机专业,凭着爱好和一腔热血混入游戏开发大军候补小队,平面尚未钻透。为赶时髦,企图叛变到3D阵营,慌乱之中捡起“OGRE”。学到如今,亦可让正方体飞机等不明物体在三次元空间胡乱打转。但觉得本引擎不支持中文显示而感到不爽,便四处寻求高人指教,但大部分高人指点说:“自己写引擎算了。”衡量了一下自己份量,觉得“自己写”这件事十年内恐尚难做到。再后来找到3DCastle论坛,经过“bug王”以及“浪客☆龙猫” 两位前辈的指点,也通过高手“renwind”遗留下来的教程,误打误撞竟然自己改出了中文支持,兴奋之余便想写点东西留点纪念。
/ w. ~3 E6 m% |# z5 R: Z1.准备工作/ r4 Y8 {( T. {: B4 p0 O6 D
“bug王”已经通过WINAPI实现了OGRE在Direct7.0下的中文支持,也有高手说这样效率不高,更因为本人基本上是不怎么熟悉WINAPI的,所以就放弃了这种方法。企图直接通过贴图来实现中文显示,毕竟OGRE本身文字输出也是用的这种办法,更好的是OGRE引擎除了普通的“ttf”字体外还支持位图字体(其实“ttf”在引擎中也被Ogre::Font::createTextureFromFont()转换成位图了),基本上就是做一个很大很大的图片,然后上面画满汉字,直接读进去就可以了,问题也就变成了——如何找这个大图片。
. [0 C% z5 @# G) K: O幸好GBA游戏的开发者们已经找到了很好的文字来源和取得方法,通过金山的16*16点阵字库得到接近9000个字模,然后通过程序读出并写到2048*2048的单色位图上,转换成“png”格式图片才221k。+ M+ b p* L$ T. s/ l5 O6 ~: K
2.基本知识
* X/ E+ x+ p; Z1 ]修改引擎之前,我们先要知道OGRE是如何显示字体的。OGRE本身面向对象的设计和自带文档都做得非常规范漂亮,很容易就能找到关于显示文字的类以及相关函数。在这里主要看一下关于位图字体是如何显示在画面上。(1)字体的读取。9 |, B8 o. l: a, Y: q) ^& Y* E' l
和这项功能相关的有两个类,一个是Ogre::FontManager类,负责分析字体信息(*.fontdef)文件。然后用builder模式构建一个Ogre::Font类。在Font类中最重要的数据莫过于mTexCoords_u1、mTexCoords_u2、mTexCoords_v1、mTexCoords_v2这四个数组,他们分别用来储存不同文字对应在图片上的纹理坐标。 不过数组大小明显不够储存9000个汉字的,一会儿要改的。
! s( Z3 e' u9 E, F( }, |(2)字体的显示。
7 `! ]) E; B6 U: ~# ]( \( X2 i好像字体显示中用得较多的是Ogre::TextAreaGuiElement类,不过好像还有其他的,我们在这里只看这个吧,估计其他的也大同小异。看了看好像唯一和显示字体有关的函数就是void TextAreaGuiElement::updateGeometry()了,基本上就是根据要写到屏幕上的字串,在Ogre::Font类中得到相应的贴图坐标和贴图,然后画上去,道理也不是很难。
! X0 {! H' _( w/ r+ G7 s5 i" g5 f3.动手术
8 C% c: }5 k$ e6 P3 {目标锁定到Ogre::Font,Ogre::FontManager,Ogre::TextAreaGuiElement三个类中,把所有文件备份一遍手术开始!
) B7 q0 h3 M6 P- B) I(1) Ogre::Font类。7 r7 X) L/ n1 M9 F4 d
首先是储存文字贴图坐标的数组的大小不够,原来定义的是——宽字符集 (1024 - 32)、ASCII(256 - 32)。这点点大小怎么够我近9000字大军进入,索性都改成(9030 - 32)。还有就是set和get文字贴图的id都是char类型数据,256个id也不够分配给汉字,看来要都改成unsigned long形(其实大部分机器上int也是32位,不过long是固定32位的类型,感觉统用点)。+ U0 Q/ N s" ]4 J7 P( \8 K
(2) Ogre::FontManager类。
" @: d/ Y* b9 C里面从脚本文件中解析贴图坐标的方法是根据单字符的方式,为支持汉字,改成同时可以分析int的。一个汉字对应数字是他的区位码+161(前160个留给了半角字)。
( W& F* m- n5 J( d- }) Q(3) Ogre::TextAreaGuiElement类。
: }4 u6 {0 P* h6 h, M8 [' _- D# \$ X这个是相对比较麻烦的,他要从字串中分辨出到半角字和中文。在这里增加一个std::vector<unsigned long> caption,用来储存分辨的结果。增加以下几行。* O& f2 t9 l. y! Y7 S3 K
std::vector<unsigned long> caption;
Z2 O: E6 B1 Q; Lunsigned char nTemp;
7 o* s5 }$ v* W$ HString::iterator it=mCaption.begin();
8 c. t& S. r9 P* `# k( }for(;it!=mCaption.end();++it)
) j# [. l: V6 z5 a: M: E{+ k6 K* f2 S' B2 ` N. M
if(unsigned char(*it)<=160)//如果是半角) u6 r- o* m# \9 Z' _ Q" u8 g0 e
{
: ~$ @ D0 ^' A( Xcaption.push_back((unsigned char)*it);$ M t% z3 ^- [7 }1 D! g/ Q; }
}9 R K; h% z* n5 b5 v! d2 v
else//处理全角字符
' {- ~& P0 G# F2 \% ^{ ; S# Q, r" t% O+ @' P( p* u
nTemp=(unsigned char)(*it);
7 p5 z+ ^; V' |3 v' ?4 b++it;& B v$ S0 e b! J0 u
if(it==mCaption.end())& M& M- t2 q* e) Q1 G3 O4 `
break;$ F" }( K. T: ]. ]3 C3 O7 w6 f
//下面是得到区位码+161的公式。+ X w$ n( L5 h5 P! U+ q' q5 A
caption.push_back((94*(nTemp-0xa0-1)+((unsigned char)(*it)-0xa0-1))+161);9 g: x4 N; e) j8 k! l
}
: p6 K" _) `* k8 ^7 B}3 x# O! q6 D( h9 E# Z
然后后面所有关于mCaption的地方都用caption代替就ok了。3 F- |5 I7 A8 ]# y7 V( N; \. j
4.结果。
- ]2 J. \. E* p0 {' P1 g在OpenGL和DX9.0中成功的支持了中文,但是DX7.0中竟然出现了运行错误,具体问题还不清楚,还望各位高手指教。
/ M* \) C& k8 P8 L# z6 c$ i因为字体本身原因,文字很扁平的不好看,索性又改了改Ogre::Font,Ogre::FontManager两个类,实现脚本中支持修改文字纵横比例的系数的proportion,当这个值设置为0.8的时候比较好看了。" y& {2 _& p9 Q e5 q5 J
- P- k: B$ m# x' G* x
3 n8 U0 f! W- h( ]4 \- P( T) M
相关文件) P1 v4 d1 U# v% B4 j
chinese.fontdef//字体信息文件 放在资源文件加中
* X+ l L+ j3 P4 ~- G3 kfont.png//字体图片 放在资源文件加中8 o& C& r3 ]( O) q% M c
+ z z8 [8 p) F; M6 U; s
OgreFont.cpp6 N E/ z0 q- B8 ]4 ]0 d
OgreFont.h
# y( l& w- Y5 EOgreFontManager.cpp/ U% O4 D0 r0 A6 ~ Q7 L
OgreTextAreaGuiElement.cpp
2 N( P( m; E+ a$ [7 A8 R3 |- p8 Q- t//上面文件覆盖同名文件 就可以 先备份
2 G; H6 d* E! w! c" Z, Y
2 L* F9 P: L% O" P: W- y这个是在ogre-win32-v0-13-1基础上改的,请到& [* f# j4 \8 F1 e& F" k% L8 ^
ogre-win32-v0-13-1.zip下载
) H: T! C1 l8 F5 g! U r
) U1 D3 R4 i$ R/ x, g+ N中文字体名字就叫 Chinese,以后能做中文游戏了! |