如何修改字幕输出函数,也许这篇文章可以参考。
j" V; K' a1 [4 i! H& \/ P: m
+ K( Q& c$ N1 _- x4 G. |* h4 j. q4 e! v9 J! t- K- [- Z; N" y
让OGRE支持中文 (转贴)
F7 S+ I3 A2 u, C5 X0 y& g$ b! T$ f
$ V( F6 h) K, _+ k7 s, r/ g
0.前言:
- }- \6 e* \$ O: x/ H P" O本人非计算机专业,凭着爱好和一腔热血混入游戏开发大军候补小队,平面尚未钻透。为赶时髦,企图叛变到3D阵营,慌乱之中捡起“OGRE”。学到如今,亦可让正方体飞机等不明物体在三次元空间胡乱打转。但觉得本引擎不支持中文显示而感到不爽,便四处寻求高人指教,但大部分高人指点说:“自己写引擎算了。”衡量了一下自己份量,觉得“自己写”这件事十年内恐尚难做到。再后来找到3DCastle论坛,经过“bug王”以及“浪客☆龙猫” 两位前辈的指点,也通过高手“renwind”遗留下来的教程,误打误撞竟然自己改出了中文支持,兴奋之余便想写点东西留点纪念。
1 _9 { j) l( m# t% E7 r" @1 L* ]1.准备工作. a7 d O4 E% P5 R. Y) Z3 j
“bug王”已经通过WINAPI实现了OGRE在Direct7.0下的中文支持,也有高手说这样效率不高,更因为本人基本上是不怎么熟悉WINAPI的,所以就放弃了这种方法。企图直接通过贴图来实现中文显示,毕竟OGRE本身文字输出也是用的这种办法,更好的是OGRE引擎除了普通的“ttf”字体外还支持位图字体(其实“ttf”在引擎中也被Ogre::Font::createTextureFromFont()转换成位图了),基本上就是做一个很大很大的图片,然后上面画满汉字,直接读进去就可以了,问题也就变成了——如何找这个大图片。) b! b7 Z4 k+ Y& Z. E
幸好GBA游戏的开发者们已经找到了很好的文字来源和取得方法,通过金山的16*16点阵字库得到接近9000个字模,然后通过程序读出并写到2048*2048的单色位图上,转换成“png”格式图片才221k。2 ?9 W5 u# A1 ^, x
2.基本知识9 ]9 r& d8 n3 }4 \; a
修改引擎之前,我们先要知道OGRE是如何显示字体的。OGRE本身面向对象的设计和自带文档都做得非常规范漂亮,很容易就能找到关于显示文字的类以及相关函数。在这里主要看一下关于位图字体是如何显示在画面上。(1)字体的读取。' F3 Y- g& F! Y8 m5 Q; C
和这项功能相关的有两个类,一个是Ogre::FontManager类,负责分析字体信息(*.fontdef)文件。然后用builder模式构建一个Ogre::Font类。在Font类中最重要的数据莫过于mTexCoords_u1、mTexCoords_u2、mTexCoords_v1、mTexCoords_v2这四个数组,他们分别用来储存不同文字对应在图片上的纹理坐标。 不过数组大小明显不够储存9000个汉字的,一会儿要改的。/ N/ ^' T7 q, w! Q/ o) ^7 f: z+ f
(2)字体的显示。
2 |, ?. q) x, J# u1 R8 E( H2 m3 B好像字体显示中用得较多的是Ogre::TextAreaGuiElement类,不过好像还有其他的,我们在这里只看这个吧,估计其他的也大同小异。看了看好像唯一和显示字体有关的函数就是void TextAreaGuiElement::updateGeometry()了,基本上就是根据要写到屏幕上的字串,在Ogre::Font类中得到相应的贴图坐标和贴图,然后画上去,道理也不是很难。 J1 Q+ F& w, z& D5 I) H
3.动手术" _! s: x1 }( I% t9 S1 B( w
目标锁定到Ogre::Font,Ogre::FontManager,Ogre::TextAreaGuiElement三个类中,把所有文件备份一遍手术开始!2 ^8 Y* Q$ q& x4 \
(1) Ogre::Font类。
$ j2 p t& q' c/ ]1 o4 W- w9 w: I首先是储存文字贴图坐标的数组的大小不够,原来定义的是——宽字符集 (1024 - 32)、ASCII(256 - 32)。这点点大小怎么够我近9000字大军进入,索性都改成(9030 - 32)。还有就是set和get文字贴图的id都是char类型数据,256个id也不够分配给汉字,看来要都改成unsigned long形(其实大部分机器上int也是32位,不过long是固定32位的类型,感觉统用点)。
a' P7 a# B( e5 ^7 u$ D(2) Ogre::FontManager类。) I" j, C1 B9 |
里面从脚本文件中解析贴图坐标的方法是根据单字符的方式,为支持汉字,改成同时可以分析int的。一个汉字对应数字是他的区位码+161(前160个留给了半角字)。1 j6 ]8 H- N. x1 F: b; L$ r! M
(3) Ogre::TextAreaGuiElement类。& f, c( j7 y) L3 c1 s
这个是相对比较麻烦的,他要从字串中分辨出到半角字和中文。在这里增加一个std::vector<unsigned long> caption,用来储存分辨的结果。增加以下几行。0 ?$ _/ M/ A: t. M% t/ J9 \
std::vector<unsigned long> caption;' y% E+ l) C+ t, t( W2 B8 D
unsigned char nTemp;! J" J" O5 |, @! S" b6 I$ @! U
String::iterator it=mCaption.begin();1 Y! Z* H" E/ w/ e7 g& Y, l& l
for(;it!=mCaption.end();++it)
2 f6 A' m$ s, n! c5 Z{
6 Z, x% A4 a* K) Z9 {2 [if(unsigned char(*it)<=160)//如果是半角, N) Z5 O( }& U/ B0 q
{
9 ^: p; ^+ }2 ?+ K7 a7 I' a# icaption.push_back((unsigned char)*it);5 E+ d% U! q. x" G" \
}
' L, V. z0 l8 |else//处理全角字符
7 w9 P' s5 s. E' K' n; v. b{
% _: Z5 M7 w: u0 enTemp=(unsigned char)(*it);2 @2 K/ Z& ^) i4 [9 X3 O
++it;0 Q$ y5 D s( b$ ~5 @; z5 Q" t
if(it==mCaption.end())
) d! [9 q# o5 X3 z" h* F8 A1 ybreak;
6 U# [5 @7 r2 e* a- g6 Q2 w0 V: T//下面是得到区位码+161的公式。
6 t! \+ g4 t6 Dcaption.push_back((94*(nTemp-0xa0-1)+((unsigned char)(*it)-0xa0-1))+161);/ y: A1 g" P2 `
}/ [/ p: Y6 h. b/ F7 m0 [
}
; f4 N; s$ E6 T& [然后后面所有关于mCaption的地方都用caption代替就ok了。
$ t2 k T" u2 C* f% y) [4.结果。3 z: a* i+ Q# }2 N
在OpenGL和DX9.0中成功的支持了中文,但是DX7.0中竟然出现了运行错误,具体问题还不清楚,还望各位高手指教。# M7 F' v0 Z7 a8 e; a% Y
因为字体本身原因,文字很扁平的不好看,索性又改了改Ogre::Font,Ogre::FontManager两个类,实现脚本中支持修改文字纵横比例的系数的proportion,当这个值设置为0.8的时候比较好看了。
7 Y! f$ n1 i) s g2 S: v; [; N* b8 E: S2 g/ M9 I
3 E# m. X1 ]8 I' U6 H" z2 t$ T相关文件$ c( O& b6 O$ c2 ~' Y' V1 O! E
chinese.fontdef//字体信息文件 放在资源文件加中- i5 G0 b# l4 S' A- i& a
font.png//字体图片 放在资源文件加中
1 z% s) h: C; k
8 [( W# E2 W- }0 Q* E [ lOgreFont.cpp% ?' g+ p6 L8 }. R4 d4 k: e5 \
OgreFont.h
4 b/ H7 j5 O7 m# dOgreFontManager.cpp: t, w* W# L) [0 \" K
OgreTextAreaGuiElement.cpp7 n3 Y M! x: c _
//上面文件覆盖同名文件 就可以 先备份( z# O# X3 `3 X! G* g7 x- r1 o2 [2 d
3 i+ B: Y. i1 ^# r
这个是在ogre-win32-v0-13-1基础上改的,请到5 J; Y7 ]5 o, o9 C
ogre-win32-v0-13-1.zip下载
( w5 ^3 D5 M: F6 K \$ @2 M: B
6 y* y7 ~/ @( h+ E/ c! X中文字体名字就叫 Chinese,以后能做中文游戏了! |