如何修改字幕输出函数,也许这篇文章可以参考。$ q, i. F, `- [6 O
" L1 V. j! G* n6 z6 n
/ [; p. y! P# E) o& p0 h8 e3 a7 ^让OGRE支持中文 (转贴)
+ q5 q3 m5 N, e( K8 [: N; @7 y# `
( T, r. d9 d) A1 M# ?% Y4 u: D4 l9 N2 G- Z5 o- ^
0.前言:; u2 J& Q* F: H! [ p. A
本人非计算机专业,凭着爱好和一腔热血混入游戏开发大军候补小队,平面尚未钻透。为赶时髦,企图叛变到3D阵营,慌乱之中捡起“OGRE”。学到如今,亦可让正方体飞机等不明物体在三次元空间胡乱打转。但觉得本引擎不支持中文显示而感到不爽,便四处寻求高人指教,但大部分高人指点说:“自己写引擎算了。”衡量了一下自己份量,觉得“自己写”这件事十年内恐尚难做到。再后来找到3DCastle论坛,经过“bug王”以及“浪客☆龙猫” 两位前辈的指点,也通过高手“renwind”遗留下来的教程,误打误撞竟然自己改出了中文支持,兴奋之余便想写点东西留点纪念。) {" M( T8 a0 Q& o9 M2 ] ?' P
1.准备工作
$ R- H9 o- R" u“bug王”已经通过WINAPI实现了OGRE在Direct7.0下的中文支持,也有高手说这样效率不高,更因为本人基本上是不怎么熟悉WINAPI的,所以就放弃了这种方法。企图直接通过贴图来实现中文显示,毕竟OGRE本身文字输出也是用的这种办法,更好的是OGRE引擎除了普通的“ttf”字体外还支持位图字体(其实“ttf”在引擎中也被Ogre::Font::createTextureFromFont()转换成位图了),基本上就是做一个很大很大的图片,然后上面画满汉字,直接读进去就可以了,问题也就变成了——如何找这个大图片。7 V" f ?" `; V
幸好GBA游戏的开发者们已经找到了很好的文字来源和取得方法,通过金山的16*16点阵字库得到接近9000个字模,然后通过程序读出并写到2048*2048的单色位图上,转换成“png”格式图片才221k。
+ x, b& `7 d @- D" F- u( |2.基本知识
?; c# i( L0 [/ y修改引擎之前,我们先要知道OGRE是如何显示字体的。OGRE本身面向对象的设计和自带文档都做得非常规范漂亮,很容易就能找到关于显示文字的类以及相关函数。在这里主要看一下关于位图字体是如何显示在画面上。(1)字体的读取。
' {( U: Y' l6 d/ T8 }# l0 u) b和这项功能相关的有两个类,一个是Ogre::FontManager类,负责分析字体信息(*.fontdef)文件。然后用builder模式构建一个Ogre::Font类。在Font类中最重要的数据莫过于mTexCoords_u1、mTexCoords_u2、mTexCoords_v1、mTexCoords_v2这四个数组,他们分别用来储存不同文字对应在图片上的纹理坐标。 不过数组大小明显不够储存9000个汉字的,一会儿要改的。- {5 Z! [# [2 {: ^, C1 C0 `" z# w
(2)字体的显示。7 g) i% s' w. o; r% q8 d( U# l
好像字体显示中用得较多的是Ogre::TextAreaGuiElement类,不过好像还有其他的,我们在这里只看这个吧,估计其他的也大同小异。看了看好像唯一和显示字体有关的函数就是void TextAreaGuiElement::updateGeometry()了,基本上就是根据要写到屏幕上的字串,在Ogre::Font类中得到相应的贴图坐标和贴图,然后画上去,道理也不是很难。) [- b4 i, Z, g3 [- k# `
3.动手术7 Y# M9 Q5 g$ X9 \1 n+ ~+ }
目标锁定到Ogre::Font,Ogre::FontManager,Ogre::TextAreaGuiElement三个类中,把所有文件备份一遍手术开始!. a( @1 r2 P- q$ v
(1) Ogre::Font类。8 ~: ?( I D- r. N6 A
首先是储存文字贴图坐标的数组的大小不够,原来定义的是——宽字符集 (1024 - 32)、ASCII(256 - 32)。这点点大小怎么够我近9000字大军进入,索性都改成(9030 - 32)。还有就是set和get文字贴图的id都是char类型数据,256个id也不够分配给汉字,看来要都改成unsigned long形(其实大部分机器上int也是32位,不过long是固定32位的类型,感觉统用点)。/ L' p. \" l$ u/ ?6 ^% R
(2) Ogre::FontManager类。
6 l1 _4 x: t0 Y6 [! m里面从脚本文件中解析贴图坐标的方法是根据单字符的方式,为支持汉字,改成同时可以分析int的。一个汉字对应数字是他的区位码+161(前160个留给了半角字)。
* \6 n- [# X, z( q1 {3 E* q# _(3) Ogre::TextAreaGuiElement类。
5 ] A7 O# L/ T! _这个是相对比较麻烦的,他要从字串中分辨出到半角字和中文。在这里增加一个std::vector<unsigned long> caption,用来储存分辨的结果。增加以下几行。
: W, f; y$ g+ n+ T+ p6 \$ ^std::vector<unsigned long> caption;
( |- u+ m& l: d! |4 L/ N/ Q( Eunsigned char nTemp;; ]* o* |) w( W+ U
String::iterator it=mCaption.begin();
4 W( Y+ v4 K8 Afor(;it!=mCaption.end();++it)1 R1 K5 @8 l% u/ |' D
{
6 f0 y2 x4 I9 Z" gif(unsigned char(*it)<=160)//如果是半角5 o7 q# S( q5 G
{
7 q5 H+ @/ V5 o; o* r5 p% c: Z kcaption.push_back((unsigned char)*it);& @; Q/ d$ [/ F9 x/ L- J
}$ k! D1 [5 s- m' J6 O* f8 [) A3 X X
else//处理全角字符
8 I# ?! `# ? _2 O{
4 e$ y* i5 N9 F0 p% X; y# _3 JnTemp=(unsigned char)(*it);8 E& o1 Y0 d7 m% o& F: w
++it;
% m6 e* A& @& A5 f2 c d: iif(it==mCaption.end())
, Z# b) J4 V; |9 p; jbreak;
; _- I, W5 s+ X; Z//下面是得到区位码+161的公式。, o9 U! z' L* E4 t0 g# O
caption.push_back((94*(nTemp-0xa0-1)+((unsigned char)(*it)-0xa0-1))+161);: R4 W! v/ t1 t7 t% m0 S
}
0 h4 G9 S6 K) h8 E0 u}$ Q; `, p$ o. Q/ {# n
然后后面所有关于mCaption的地方都用caption代替就ok了。9 A F. E/ l( R/ x/ u
4.结果。
% `9 h1 ~# M9 A" l6 j+ I4 H v在OpenGL和DX9.0中成功的支持了中文,但是DX7.0中竟然出现了运行错误,具体问题还不清楚,还望各位高手指教。7 u k. u' [5 ` `. t5 N8 x+ R
因为字体本身原因,文字很扁平的不好看,索性又改了改Ogre::Font,Ogre::FontManager两个类,实现脚本中支持修改文字纵横比例的系数的proportion,当这个值设置为0.8的时候比较好看了。# C3 C; o4 ~' T0 a& T: {8 p- ^- a
% B% E6 d2 R+ K) I
# i: f/ v0 [2 H& A8 h相关文件
3 z$ v1 t: K; {: V$ zchinese.fontdef//字体信息文件 放在资源文件加中" ?- y. X: O" r/ A
font.png//字体图片 放在资源文件加中
& [6 R: K" d2 o, n8 ~2 c: S S; o; K3 U" S' w) h4 I' L
OgreFont.cpp: Q$ `- ^- Q2 ?& o. ]: M) W
OgreFont.h
$ J# x" F1 e. \' J' @6 {$ wOgreFontManager.cpp" }9 l# r% ^- }( v2 F+ l8 y2 r
OgreTextAreaGuiElement.cpp
6 I* O# X9 r7 f# n- q$ V) c//上面文件覆盖同名文件 就可以 先备份# x* f" q7 o( V
; W; y; y5 o5 l' Z
这个是在ogre-win32-v0-13-1基础上改的,请到1 ?. X8 _+ T; ^1 D9 t
ogre-win32-v0-13-1.zip下载
+ C' z, E$ s( f( q1 p2 D( ~6 I9 s0 Z: c" p+ k
中文字体名字就叫 Chinese,以后能做中文游戏了! |