开源的图形渲染引擎OGRE(3) --让OGRE支持中文TTF字体 n$ f9 Q# @! S% k
( x d- x' S7 H
0.还是前言
' g; n0 c9 e N1 K5 w8 r$ U
7 d% T4 W* C/ x- Z: l" } 如果你希望能看懂这篇文章,请先确定你已经看到了《让OGRE支持中文》(http://www.gameres.com/Articles/Program/Visual/3D/OgreSupChn.htm),因为本文是在上一篇文章的基础上写的,并且假设文件都已经按照上一篇文章进行了手术。但是如果你只想简单的使用TTF字体,只要下载本文附带的文件,重新编译就可以了。
+ I$ M/ J9 T* L! x1 L4 }* T. u% Y& h! v1 P3 @
1.检讨 : i& U; j2 w) \0 I
! |4 x/ `6 f5 _/ u& D
正如上回说的,我们已经实现了一个位图的字体。但是当冷静下来思考时,就能发现这种方法的诸多缺陷。读入一个2048*2048的位图,等于在显存中保存一个2048*2048的贴图,不说是否所有显卡都支持这么大的贴图,单是每个Font字体类吃显存的胃口,就足以令人心惊肉跳。如果定义足够多的字体类,我想你的游戏的配置要求,在某些方面足以超过《DOOM3》了。
, M2 p! G3 n, l! E% B @( l0 P P i$ x
而且这并不是唯一的缺陷,文字大小相对于位图大小比例相差太大,导致浮点数的文字位置误差很大,你可以在一个文字旁边看到其他文字的影子。(虽然可以通过增加文字间距来解决。)还有点阵字体本身的缺陷,就是字形单一,不适合放大缩小,一些文字边缘的马赛克,足以熄灭任何玩家的投入感。
: t1 d _% w! m0 r% ^5 t9 s* K% I- ?3 M& S+ ~6 `) e
似乎TTF是唯一的解决之道。 : i- U9 Z) N% [/ T
" H& _* t& h3 h
2.基本知识
: v9 `9 |4 w$ p z& C0 H( h. y" g, Z+ o6 y$ _
(1)TTF字体。
) Q+ G% m5 l5 r& Z9 m
8 q" j* V; F I. j# f7 c TTF是一种矢量字库。我们经常可以听到矢量这个词,像是FLASH中的矢量图形,在100*100分辨率下制作的flash,就算它放大为全屏,显示出的画面也不会出现马赛克。所谓矢量,其实说白了就是用点和线来描述图形,这样,在图形需要放大的时候,只要把所有这个图形的点和线放大相应的倍数就可以了。而且,在网站上有很多的TTF字库可以下载,或者你可以去买一些专门的字库光盘。然后在你发行你精心制作的游戏时,可以顺便捎上这些后缀为.ttf的文件就行了。包括Quake这样的惊世之作,也都是用的TTF字库。
8 D9 v3 N/ }, d# e1 i
( B- {1 [+ o/ D(2)FreeType2库 5 ]- C- l& E9 O {5 z4 c) R
6 I/ a" W$ L: R% k" x0 t 在http://www.freetype.org,有一个FreeType的免费库,而且是OpenSource的。它目前有2个版本:1.0和2.0。其区别在于,1.0只能读取TTF格式的,而2.0支持更多的文件格式,在使用它之前请详细阅读所要遵循的Licence,以下是摘自FreeType2.0对字库的支持列表: 9 a+ Y$ X0 G% q
1 ^* D, a* P% s+ Q% t y
TrueType fonts (and collections)
P4 w4 g, g9 E$ n
w3 |' z8 o3 o9 U4 V9 B. ^ Type 1 fonts
: E7 w9 b$ d- m1 |7 |# e
7 ?* `/ l8 X C$ {$ t! D& L" `5 V/ U1 X CID-keyed Type 1 fonts
0 M4 z6 j2 {" e% j4 d
2 j$ S2 G' M# i, n# k CFF fonts
0 ~) n/ b% Z: S4 T9 G: P( o; l6 n9 {6 h3 I( ]* k
OpenType fonts (both TrueType and CFF variants) 4 W* i! V4 v# h L
! \8 A& Y- |: H
SFNT-based bitmap fonts
$ Q9 c9 M$ {& m8 R/ x* T4 Z
! v, d. t3 S2 G+ _ X11 PCF fonts $ `( L) j# N, d* r" ?6 X
8 T$ q4 f% j9 ?( D, a4 g5 f1 _ Windows FNT fonts 4 D+ e# J5 D# w& w$ X; H, C3 v
# k% c* E* M+ \
(3)“主体思想” " ?/ i6 E, _. t g1 |% R* y
7 P- X1 c! X& F( I+ c" y& F( L 请参照炎龙工作室的《游戏中汉字显示的实现与技巧》这篇文章,可惜使用的是Windows API,作者千里马肝,上网上搜一下吧。
/ z* K* |$ e( t A7 T7 Z* B2 i0 |9 B4 M( T; X4 j
附带说一句,上面两条都是直接从这文章中剪切下来的,>_< 不要骂我啊,不知道算不算侵权呢。
4 }8 f- |! `* s, r' v* i* V X+ u, U& k
3.动手术---比你想象的要麻烦 " O8 n/ O( f |% |5 Z
(1)
% y# y2 H& \+ L" O% S" U+ z 首先要告诉字体类,我们下一次渲染需要哪些字。以便字体类可以在需要的时候释放不使用的字体。
5 l: R% y" Z3 f) \3 j8 k( k) w9 X' L7 w4 c& E
在Font类中~ ! w! X4 G. k. L: V* U
' \) G0 T8 t! w( L6 p0 Y a.增加数据 bool mUsing[OGRE_NUM_GLYPHS]; 用来标记文字是否使用。 2 v' t, z/ G# d4 z* h
% v$ z9 D$ U! E" ^
b.增加函数
1 H H7 P# w1 o, N& c. c) d. g
inline void setUsing(std::vector<unsigned long>& caption)
& F! r; c5 I5 n: f' b$ d4 @+ ]: r' R/ |: s8 z8 z0 P
{
% H5 e N' _0 a# d! s) q- o: v. n/ T, J5 i6 b ^) z; e$ f m
memset(this->mUsing,0,sizeof(this->mUsing));
2 }8 Q6 q0 S" v5 h. A
5 y$ L1 _7 R9 T- p: T. S4 U5 B% b std::vector<unsigned long>::iterator it;4 k1 ~( q/ C6 U' ^& \
R0 k, n: r1 H) | for(it=caption.begin();it!=caption.end();++it)
- Y7 E, J$ z+ j- ?; h
. I2 d/ {# H4 g5 c% _! B {
( N! g/ W3 N9 J7 c7 M3 d- n3 a9 V& {6 w1 H) \
if(OGRE_GLYPH_INDEX(*it)<OGRE_NUM_GLYPHS)9 y; t6 y4 Y% s6 ]' k7 g5 }8 H
( ?; u2 P( I6 x2 B$ [9 ^" ^% ?! W
this->mUsing[OGRE_GLYPH_INDEX(*it)]=1;//标记文字为使用
, k& U( J4 X; q
8 J7 G( C5 {6 s1 x! R }
7 c: f. q8 J5 k% W" |; Z$ [) b5 ?" t9 U# C
}
9 w. d# D" k9 B
, V5 N4 \9 t: r1 w* ~ 并在 void TextAreaGuiElement::updateGeometry() 中调用这个函数。 & p- | _/ \ L. D+ d: x. L
(2)
5 U1 ~$ V2 n; k* M1 T/ k
Y) P7 [! N. k8 e4 K3 Y/ M 然后是修改void Font::createTextureFromFont(void);, n- ~( Z+ K9 b4 V/ t0 A
; X) [& P- ^! n Font类是通过void Font::createTextureFromFont(void)来把通过FreeType2分析好的英文字画在一个2^n*2^n的贴图上,然后再保存英文字的位置。 1 g. }8 D L' P s3 m5 P+ U
" n( z6 S* j5 ]- s0 f! F3 r/ _5 G5 n
我们需要修改的是:
6 U$ Y4 y6 y1 r5 @/ F/ ]$ v! s
' @0 [5 `2 D3 u% x a.从函数中分离并保存画字的FreeType2和辅助变量。我们通过一个类来保存和处理这些变量。
, B* u5 U8 n- K" X, o0 d; X9 T/ l! K: \# g0 J( {# v
class TTFMsg/ b3 j# R$ j9 I2 n& b
" I0 K* W: n: [ E1 k! j) G4 I2 O {
9 T$ v, D5 g8 R9 p' h/ v7 \) k
class Max//类中类,用来保存几个"最大",7 M) l, |! I8 v8 ?4 H- U
/ q$ X; {6 q. K2 _3 Z" i
{: ?: X- ^5 V( }
2 Z! j2 b* `& s! P; M
int nothing;//这个是用来占位的,没意义,反正没他就运行出错,可能和数据对齐有关吧。
' Y4 \! G& o2 J( n& r% I
, h' {, G5 d0 Q: l5 @3 ^' z public:5 ?4 B. F! f$ N& ^8 C
int height;//文字最大高度 & }7 @% A! x8 b: n+ [; G
int width;//最大宽度
0 g7 S% l r* M$ Q' o' ]& r3 j$ H int bear;//最大空隙? . N( H- G) v' _ x+ {. J
};
$ q. \$ L$ z: M }. Y+ r: D public:# n; U5 }4 h0 Q! k
FT_Library ftLibrary;//FreeType2用
# T$ @2 w+ u' o6 }$ ]. h FT_Face face;//FreeType2接口?
2 p9 Z6 v" j1 W3 |4 M0 D% q uint char_spacer;//文字空隙 ; p4 X& A: a4 c0 X- w+ I" j
SDDataChunk ttfchunk;//数据块,用来保存ttf信息 9 x H* `* O/ O
FT_F26Dot6 ftSize;//FreeType2字体大小 * b- S4 d% f, q. L* ~3 q) _+ ~
std::pair<uint,uint> point;//在位图上画字的点 . w5 i a- Z- }& t1 n' f
SDDataChunk imgchunk;//数据块,用来保存位图信息 * M- N; r {4 x& ?( D
bool dirty;//标记,看是否需要更新贴图 7 i1 ]7 S5 e' X _: i! ~( d. R
Max max;//几个最大 9 |1 L0 B; s; ~( M) s
: q; A; D2 }2 V% v) Q inline bool init(Font* font) //这个是初始化函数在void Font::createTextureFromFont(void);中调用.* y/ r8 p! {; P* d
; T+ h( i2 N: m& ]/ c) _2 G& ~
{
5 v+ E* L6 S2 G# e
9 E& L, L7 t! Q1 V& W //以下都是初始化,大部分都是从void Font::createTextureFromFont(void);移植过来的
" W+ \$ i4 s5 g* {
5 q5 c7 x' _. U5 j: J; a: T dirty=false;$ S) Y- z# C2 V6 v4 Y! j
( \0 Q/ H& M8 ~* D( E+ W
if( FT_Init_FreeType( &ftLibrary ) )3 g% o7 j% A& c6 X+ Q! l5 m
, g& |1 z3 D4 @9 _
Except( Exception::ERR_INTERNAL_ERROR, "Could not init FreeType library!",$ y( T" d* F/ s
& y! o! O( t" ^1 k% t$ v
"Font::Font");
2 `4 |' m! m4 ~' S2 ^
1 H9 b2 z5 D2 w+ Z& m- D$ C * @( ]9 }/ i1 H3 T1 Z+ w
" B, g# z; e I& X char_spacer= 5;
/ p* a# I: ~$ A+ W( s2 w
: h& ^/ z1 t8 G; K9 p9 ^ FontManager::getSingleton()._findResourceData(font->mSource,ttfchunk);
1 `2 k- p w) V5 n3 T& p! c2 B# v# u: A d( d4 k6 F" S5 p
if( FT_New_Memory_Face( ftLibrary, ttfchunk.getPtr(), (FT_Long)ttfchunk.getSize() , 0, &face ) )
5 C# i0 y* f J7 L; `
& G* [& T4 z" `+ v Except( Exception::ERR_INTERNAL_ERROR,
5 U' C0 `; q2 ] g6 `* O4 V" Z l6 N: ?0 u! ?% `5 J X
"Could not open font face!", "Font::createTextureFromFont" );( t( v+ ^5 ?- p
4 R o! z+ J) F ftSize = (FT_F26Dot6)(font->mTtfSize * (1 << 6));
) P' N3 u; ?# h% |$ N( M
: {6 @5 l$ R& Y7 X* p8 Q F if( FT_Set_Char_Size( face, ftSize, 0, font->mTtfResolution, 0 ) )* X5 t4 C! n( v, G
; X r9 ?) N( B4 d1 C6 H5 X Except( Exception::ERR_INTERNAL_ERROR,
( p( s* l0 W& G2 V
8 s( \; p: ?: [7 D" V0 o7 L "Could not set char size!", "Font::createTextureFromFont" );3 |* j1 ?# D/ I8 |; E }
5 A; Y! h% |# M% s& b7 [' M
$ ?' P5 s5 ~3 k
( t6 D. ~4 n- V# E4 F" u I5 V return true;
7 m: Z5 m- U* S% M9 `1 x& G+ v
4 V6 Q2 `( R9 b: c8 T }
) N& n0 s/ l0 _! N" A% b3 i) W) ` p5 n }1 ]) d
inline bool done(), q1 B4 F& B" f, F/ \; |
& _# z7 E( k3 m7 ?3 p, H {
8 ^. V) L0 A1 J* i3 k7 I: R
9 A7 W! P0 p7 h, @, ^7 G- b //在Font的解构函数中调用的,本来应该调用下面两个函数,但是不知道为什么一调用就出错,不用倒没事。 7 S! s c( D5 ]- z9 Z7 A
1 O: X9 q: Q% h# W" b* O6 N //FT_Done_Face(face);
. J8 d, O& d' I$ v! u8 N! _5 {5 o5 W/ {% m8 c$ b
//FT_Done_FreeType(ftLibrary);( z K2 m, l; G( ~, _/ ?3 N9 f* L- C
+ y- X/ Q' Z, O- D) C
return true;" |% B2 P0 L) F$ W" ~
2 Q0 H' p* F; Z }
- n( S/ n* I0 E/ u+ y0 U! P5 p+ Y+ Z+ P: n: e- K7 A
inline bool getRect(Image::Rect & rect)//这个函数以后用的,是用来找到可以画字的贴图的空的位置
; A T& J( Y6 @: u' `8 U+ X
( g1 X8 v' U: n& f/ q {; ^2 c% }3 p T/ ^) M( t7 q
& G5 ]& Y$ M# u if(511<point.second+max.height+char_spacer)
9 {+ G8 q. I/ c6 k3 P$ Z& U% i6 x/ J) r! j* S9 T9 _& T
{9 \! T \% z4 W# o" T
$ {2 A2 V) D7 A9 b/ }& w M rect.right=rect.top=rect.left=rect.bottom=-1;
! u" l9 t: B3 z3 s) x1 L) g* n* E3 z2 N$ @0 B6 C" N# l u7 ^, X
return false;4 z+ B/ c2 k- T: ]$ `$ d
& i. g' n/ ~$ x- L3 C/ Z }; A s, {1 Q6 R$ G' A( a
3 ?4 j/ d7 m! _. D( f if(511<point.first+max.width+char_spacer)
' @: p+ j/ ?6 b% c$ ^# h, ]; s4 A4 ?4 b: Y" ]$ {# h4 f
{. j8 Z" r) C+ O% Q8 G0 I
! {" t3 O2 e" T" H, R( } % o4 {2 m8 K; m+ j4 k
' A* G! K) ]0 K9 A point.second+=max.width+char_spacer;
2 o2 F* y# W& E: L6 i: C
% n' G2 I8 f# Z, Z point.first=0;7 S1 ~+ d3 ?! H) G0 y% V/ Q% q
7 ^: \6 J6 i' `" C1 d
if(511<point.second+max.height+char_spacer)# r6 c; M" T2 S* f. G
/ T- n! F/ A& O {
0 g$ T5 ]' l' W; n5 ?5 k8 x- z6 f* m5 c
) N Q4 y, r# l+ f! g1 A$ w' g2 d4 a8 l# I! C( b7 U
rect.right=rect.top=rect.left=rect.bottom=-1;
t+ T! W- I, R4 s5 K3 a/ }+ h5 C! k7 d! M, a; y
return false;0 Y. l$ Z) V7 U, T
% k9 `2 l7 |5 f3 R9 H
}
$ Q1 d7 ~+ ~1 h6 F) Q6 Y3 ]; V6 {
}' F7 J' N3 {+ E! Z9 c- O
/ n7 ?0 m6 q$ U rect.left=point.first;
- I U7 P1 r1 w* C/ |
9 k/ F! t: F5 _" ?5 p. r rect.top=point.second;
) G2 F4 Q7 v# P- C7 M. z/ `: d# t* ?2 Z
rect.bottom=max.height;; f6 u5 Q( @# Y+ a$ f$ R
1 g5 ` e! X+ o) Q% r6 A) F2 {, S
rect.right=max.width;
% X- j5 Z7 f+ F! y7 u1 e! g9 r$ _* T! ?2 m
point.first+=max.width+char_spacer;
" Q" S" W% b3 r* U" Q6 L) j: c/ C- c
5 j0 A; g! C1 `4 E return true;
9 G$ |- q: K* B& L9 E" i% u' O W$ T9 E+ D( g
}8 f0 q. M. Q( h9 v
$ G; P. P+ F" n3 ?& S) p- q };# Z! ^4 a. X: n; N# w( d" U: ]0 U
n9 i! z& E3 a( G! A4 Z% G
上面的类定义在Font类中,在Font中增加 TTFMsg * mTTFMsg 数据,并在构造函数中 mTTFMsg=new TTFMsg;
8 T: J F- \9 s! z, P
7 i9 g( P* { t, C b 0 Z# k- C$ S3 f' P# G
; D% X9 K# T+ p% M8 l( R7 L
正是修改void Font::createTextureFromFont(void);函数,主要几点,首先是分离出很多变量和构造到TTFMsg类中了,然后是贴图从2^n*2^n变成固定的512*512,为什么要这个数字呢,因为256太小(废话了)。能保证512*512大小的文本区不会出现不够画字的情况(所有英文+符号+没有重复的汉字),这个安全区域基本上是够用的。(什么,你要画满屏幕的汉字?哪你自己看着改吧。)还有一个重要功能是,要找100个汉字,找出最高和最宽和最大空隙作参考。修改完成这个样子了~ i3 Q1 W1 i! \; q
7 J: _* u# N! T/ b void Font::createTextureFromFont(void)8 h, |+ m! l3 `2 E( d
; Z; t8 Q9 {, M* R& h
{
6 G, W& ^0 q. h& s* k6 K& O( u1 F7 \3 k5 E
mTTFMsg->init(this);//初始化FreeType2
8 f1 F$ E& g* r4 b8 P' w+ N
5 ?( A6 I' A- B3 D6 }9 y7 E. [% P& W uint i, l, m, n;
5 J. C" M* U# j. Q9 c H8 Z% K: |
+ Z5 y. |9 Q, D, O; F int j, k;
( ]2 v6 p- y. G4 x- s7 | e |& s) u( t7 I6 H6 P/ W
R$ S$ Z5 k3 U0 u& A
# k0 j/ U6 o8 Y& [" a# E6 z( r0 h9 L
9 g, z7 o1 I( r) u* _# I% p7 v1 Y# D4 p. y7 W" b8 b
FILE *fo_def = stdout;//啥意思?我看不明白 8 O f( g2 ~5 [, o8 G
- W, R0 F( s: N0 N/ h
$ |# x( ~; L' Y' P# R! x! P* W& |+ ^+ J/ Y7 T* F
int max_height = 0, max_width = 0, max_bear = 0;
7 m: {6 P2 R' }5 n7 k' a0 w- Q/ q, M
# Y3 ]( a6 A/ o; i1 s$ A
5 ?; ]. x9 r8 a$ b6 c7 ^ uint startGlyph = 33;% m/ M6 c. ~7 H( X
0 h4 ]4 M8 \$ {$ O9 d
uint endGlyph = 167;9 A! e* ?6 v& l2 h; @! n
# l: u Y9 F- w0 Z; ~8 A" U
7 v+ m8 _( O, z$ h! B8 p+ c
! x/ ^3 w: l2 n1 m9 v1 \! Y // 找英文的找出最高和最宽和最大空隙 # w1 e& D1 ?) S2 {9 J3 Y6 d# ]
1 c% n6 \$ u) d4 c" y# D6 v
// Calculate maximum width, height and bearing
5 Y4 g' F+ J! ~3 B; i5 t' z! c8 Y3 }; l" u3 Y+ ]
for( i = startGlyph, l = 0, m = 0, n = 0; i < endGlyph; i++ )
, }2 @9 S/ G% c3 S! f B* D( o* j. m& n+ y; }6 P5 ^
{
' B y+ W, a4 x( n% ^( S6 @
9 c" V+ N, g, Q: a8 e FT_Load_Char( mTTFMsg->face, i, FT_LOAD_RENDER );9 _5 G5 X7 H4 a, h
1 L k1 X1 z% A: W$ t9 E2 B; h" | ` //以后的 <<6和>>6都是FreeType2中的数据和我们使用的数据的转换 ; j: ^$ [4 C9 O2 l. G/ z/ K. _% i; }
& s6 K" m( M% H1 L/ {& T
if( ( 2 * ( mTTFMsg->face->glyph->bitmap.rows << 6 ) - mTTFMsg->face->glyph->metrics.horiBearingY ) > max_height )
% `6 h' [0 x, O: j' y" p0 V! i
& s/ N1 w& P% v* l9 b max_height = ( 2 * ( mTTFMsg->face->glyph->bitmap.rows << 6 ) - mTTFMsg->face->glyph->metrics.horiBearingY );
8 Y" w' L' M7 Q
& d( N0 W7 o J- t" L4 ` if( mTTFMsg->face->glyph->metrics.horiBearingY > max_bear )2 A6 m. \' v- |0 O$ @1 K$ U, o
" s4 N9 Q9 r, [ max_bear = mTTFMsg->face->glyph->metrics.horiBearingY;7 a: t) l- d9 l$ L
8 @+ r4 C6 t8 `5 @ n! N ) }9 E/ B1 x. M& m' |) `
! K; l! o. U* ]' X; k: u" Z
if( (mTTFMsg->face->glyph->advance.x >> 6 ) + ( mTTFMsg->face->glyph->metrics.horiBearingX >> 6 ) > max_width)
4 G% s. X6 I# e- g8 ]7 F0 h9 v9 D. q7 a
max_width = (mTTFMsg->face->glyph->advance.x >> 6 ) + ( mTTFMsg->face->glyph->metrics.horiBearingX >> 6 );
" B) H2 s5 w* C1 Z9 P0 }
9 n$ L5 N! U, T }5 U% {/ M H8 f& F9 j4 v( i
- n, r1 ~8 P* O0 Q- x) G% a
4 d- E' a$ _ q: u7 @, H# K1 \ [5 u# `/ U3 Z) [: m% J7 T
) Q; Y6 X+ [+ W, J+ u# ^% d
& _) r% Q ]9 \; z" t, C //下面的for是找100个汉字,找出最高和最宽和最大空隙作参考。姑且认为最的汉字就在这一百个里了。 8 T. ~6 g( N+ b' [6 n1 n3 t
0 P$ P# A5 P; J7 N
for( i = 20643, l = 0, m = 0, n = 0; i < 20743; i++ )
3 h8 L/ W" v+ F4 {. b- m" f
% u- P' Z& j, e, Z { o4 S5 f; x- y" J) u6 N9 }5 I
5 F; u9 V3 V D5 H6 z: Y1 ? FT_Load_Char( mTTFMsg->face, i, FT_LOAD_RENDER );
5 l+ {, K8 e" M/ z, J
' J1 Q3 R1 p4 I. E
: k" h+ D8 w+ V; P, @# c0 S E P5 k2 K! ]" m/ `( ?: y& f+ y
if( ( 2 * ( mTTFMsg->face->glyph->bitmap.rows << 6 ) - mTTFMsg->face->glyph->metrics.horiBearingY ) > max_height )
7 Y- t( h1 {# `" M+ y$ ~5 J0 v) W+ O2 r
max_height = ( 2 * ( mTTFMsg->face->glyph->bitmap.rows << 6 ) - mTTFMsg->face->glyph->metrics.horiBearingY );7 P4 y8 b4 X! l$ b; b
+ |& I, ?$ t+ R4 T5 H+ o
if( mTTFMsg->face->glyph->metrics.horiBearingY > max_bear )
3 Z; `6 `# J. a$ R: [
0 S& G/ a D- `0 r5 C max_bear = mTTFMsg->face->glyph->metrics.horiBearingY;6 q$ f5 n6 @9 z: m
$ d/ P. M/ A3 g
& g T2 d1 ]) Y% L
7 d H' S: F, h: p6 j+ j if( (mTTFMsg->face->glyph->advance.x >> 6 ) + ( mTTFMsg->face->glyph->metrics.horiBearingX >> 6 ) > max_width)
1 ~ a+ f8 e! A' e
( L0 |" j+ m, i( ?1 Y/ j k max_width = (mTTFMsg->face->glyph->advance.x >> 6 ) + ( mTTFMsg->face->glyph->metrics.horiBearingX >> 6 );
3 V3 o5 y* @7 v7 g! w2 f* \8 S, g0 D: w* ]0 f$ ^5 F# N
4 q' V" Z; T3 R C% `4 M+ e& [
G* X+ V8 h Y4 Q, n, W
: j. Z' l9 ^% i0 D8 a1 r) j& \ K+ t' z- P2 C6 ]* ^! C3 D& [0 Y
if( (mTTFMsg->face->glyph->advance.x ) + ( mTTFMsg->face->glyph->metrics.horiBearingX ) > mTTFMsg->max.width)3 G, A u! t- t9 V1 J& m# {7 U7 {
d; H `1 S: Q8 f( n mTTFMsg->max.width = (mTTFMsg->face->glyph->advance.x ) + ( mTTFMsg->face->glyph->metrics.horiBearingX );
8 f7 E# e$ s2 U1 y$ r* }
1 g1 U8 C8 O+ d0 J! l0 r$ g }8 E7 H5 l! g! ?! {# x+ e! L" M" p3 v
! x1 b: ^' |& z
3 m9 f; c# z7 O" ?# c4 q* g |0 H4 s$ O, z& u& O
//下面几行行不需要了 我们要512*512' |! v: u0 N' N4 X* x- W* n' m
8 K5 T+ @% H5 _ H+ ~+ ` size_t tex_side=512;//就是这个了 512, \8 f) @7 N5 e- Q1 T+ G9 k
# g5 Z1 P, k8 c% k2 ]6 b; b$ a
//定义数据宽度 因为是32位的位图 四个char为一个像素,为什么要位这么大呢,难道不能用8位的么,我尝试着改来着,不过改了之后就不透明了。望高手看看能不能改。 & s. o! y. b! h/ b* J
; q3 k8 v2 ~4 h$ }
size_t data_width = tex_side * 4;7 L( w4 M! E* V/ F1 j& h4 T, }( h; h: G
V$ ~9 R: b+ H" D4 ?' F" i1 T/ l
: o- G1 I. g+ A7 P: @: h
0 `& r F2 h+ n5 A4 V, i# l- o" K LogManager::getSingleton().logMessage("Font " + mName + "using texture size " +5 N* L1 V7 L6 f1 T
- m$ p/ ]. m- f8 H: N4 R StringConverter::toString(tex_side) + "x" + StringConverter::toString(tex_side)); / Y+ ]% U( V0 t
" Y" D# q$ @0 o9 s9 g2 b S3 z
$ m" U9 m9 t; K/ |
6 a7 m: X& e( G* c9 M
uchar* imageData = new uchar[tex_side * tex_side * 4];//设置一个空间用来保存位图 " o, Y2 H/ S; x- f
6 B7 H: Q+ x E7 {" g // Reset content
# C5 k. [0 r/ x% y8 V+ P; Z5 U4 ]' c' Y1 u* P6 \9 _
memset(imageData, 0, tex_side * tex_side * 4);//清零
4 e3 j9 s, I1 B" l( K# y- L; U
t9 B1 U3 ?3 b! G0 @
' M3 b* \6 h, _3 l6 o. j- o
5 ?: ?9 A% g @8 l5 d. Y for( i = startGlyph, l = 0, m = 0, n = 0; i < endGlyph; i++ )//遍历每个字,
8 F& S. w4 M) {7 A' m' O0 Y) F" L* E: B% @* l7 `( W
{# t. f$ b. H+ U' t
& S4 R/ h" E3 m# ~
1 f; n$ S% \; E/ L4 g% b) P- T3 g
" q: Z- P/ z- q, V9 K5 O
FT_Error ftResult;
" x$ e7 W9 x, f4 A' u3 @5 b; C r
+ ]% Q0 D: R4 |% C( z: y1 f 2 ~: \% f$ N2 m: I+ [7 e3 F
5 [% W4 r p& W. |. C% d5 j // Load & render glyph
7 g! }# m c1 W9 {/ v
7 R# a# k5 }5 q; t6 f7 u6 |8 j ftResult = FT_Load_Char( mTTFMsg->face, i, FT_LOAD_RENDER );//读取字体
+ R, Z1 F+ [$ l
2 S! h5 v. P5 f9 }' b if (ftResult)
. s& \7 V7 c+ L3 t! h
) j5 u4 K8 [4 C+ i {8 t6 W& x1 W/ y C# F! l- S
) H' z' f8 O1 G( s1 |; P4 R
// problem loading this glyph, continue % Q3 \4 @4 j! a* n( ^! z) n* x
' ]0 H' @! `4 Y LogManager::getSingleton().logMessage("Info: cannot load character " +7 [/ r4 T+ d( I
6 F t! a6 x# X3 N% @7 T/ |7 u StringConverter::toString(i) + " in font " + mName);
1 c8 k* A8 x3 o, Y9 H. _. |
' M9 j# ? |+ [, n! m continue;//如果错误跳过 q4 u/ Y% N3 j# e
! u/ ^0 T9 T7 F/ K
}
% q* ~' P3 a& t) x7 h4 _9 E$ r" D8 x" L q( _( J( U% t0 W! a
6 U( M& R7 J4 B5 L: K8 f; e- |1 o8 Z! g
// 应该是字宽
. @; v) i- O0 o" Q' |
9 j% g0 c; D) K$ X! a FT_Int advance = (mTTFMsg->face->glyph->advance.x >> 6 ) + ( mTTFMsg->face->glyph->metrics.horiBearingX >> 6 );
/ ~9 t# B1 _$ Q- q" M7 Z3 p$ M: S( z% Z9 Y- b
$ _3 a1 h8 D% F4 d- N9 {, Y! N
$ k6 E' k2 ? ~" E( i
// 得到FreeType2的位图
8 y4 M t9 H# ^1 E
, e W# m- ~7 B% U unsigned char* buffer = mTTFMsg->face->glyph->bitmap.buffer;2 u8 h7 R: T, k* l4 K- U
* f7 M% f) ^! S: o
/ X/ h" S1 J* z+ {) D. F1 e) I5 I& ~! h# B& V
if (!buffer)( c) Q9 d4 r$ ~, u- u4 l
1 y$ }% K! }: ^5 J& C% _
{
$ O6 ]2 @! S" t% ?) @3 K1 y n
" x, ]5 w& H. V9 @9 \- z4 X6 o // Yuck, FT didn't detect this but generated a null pointer!
7 N9 E; i; |$ v: C9 `
3 a! M6 Y; P& I7 E) V- ?# L LogManager::getSingleton().logMessage("Info: Freetype returned null for character " +
9 X% b; A \& [- W
( U3 `, G' S( @" Z StringConverter::toString(i) + " in font " + mName);( M2 a' r- e( i& g9 y
8 M2 A- y. W I9 O: L# V. W. o; { continue;//如果得不到跳过 E% j: \6 p' h! k$ a
( B/ y6 W) M/ Z: l }
* E! ^' T/ J2 D1 l& I
3 S; H, w+ g. F0 R( p+ Z ( d1 X3 X$ m( I9 w& @1 U
, u; g* P d+ {5 n8 \: E
// 得到y的空隙 (最大空-空-本字空)就是说空出这些字底部就平了
1 ?, q! I( R( e5 N: W0 `5 {$ j6 p8 Z
int y_bearnig = ( max_bear >> 6 ) - ( mTTFMsg->face->glyph->metrics.horiBearingY >> 6 );
$ ^1 Q6 i9 S7 Y |' S# U& a5 U6 G; h/ f; k
3 A+ X# c3 Z# w3 ^: z3 y
8 i4 _$ r- N D5 M for( j = 0; j < mTTFMsg->face->glyph->bitmap.rows; j++ )
* c1 H! b- P5 n" ~; C& O* P& c8 b% `
{5 f) W9 D( c/ B+ m. b' x$ V4 {
3 k2 N" a2 k$ e# b2 C int row = j + m + y_bearnig;//相对行+本字在位图的总行+空隙
1 S% _1 E; U- s* e2 t3 y
- g5 K5 u9 U X& s int col = l;//列 * s; O* J4 j$ Q7 s' p) w- [* \2 i
: A. J! @- m- ^ uchar* pDest = &imageData[(row * data_width) + l * 4];//找起点
6 `! N& G$ ?# r( j& Q, h1 h' ^0 |; P m6 v$ I
for( k = 0; k < mTTFMsg->face->glyph->bitmap.width; k++ )//画图 ! q2 k% Y. w2 w6 u/ Y5 a3 u
2 H" w7 ?- W( _5 S
{
+ r; N* y; V* Q% _, n, F+ w1 _3 }0 Z
if (mAntialiasColour)//看不大懂,难道是灰色字体? G+ T- H: q; ]& |
* E' ?" @& \1 F: I+ J* Q X' P' R
{
" n$ e% w% n9 X4 R: z4 q; d/ }* E
2 L8 f, q7 q. v2 U // Use the same greyscale pixel for all components RGBA
% s. A/ p& n/ n; F8 f+ `; a
; @5 I) Q, ~" g/ B O0 U' w/ O *pDest++= *buffer;
( G" T+ k2 [/ v4 s* Q/ O' f H. E) D7 }2 L% C& H0 X! p
*pDest++= *buffer;2 U4 Q; p ?. n2 \4 H n% r
+ d9 M- ? k$ Q$ w& O( T' s9 l2 R *pDest++= *buffer;2 V6 K! x& z' m1 Z( K U
8 M% j7 S6 W O. C9 M
}0 g# d6 @) v# T$ v+ l$ M5 _7 u( {
* t- z6 L6 J! E" P6 b
else 7 p! r, ?$ C2 T3 S1 p
, f' i; O0 B8 v' t2 j
{
) u( U2 G, r% b$ G& o' e* |8 w3 O5 E8 l
// Clamp colour to full white or off
E4 ~6 B+ I9 W. I
/ }# h/ b" \8 S if (*buffer > 0)" d/ y: ]5 K; O' v9 X7 g3 ^
* R+ A p ~1 { {
l& F. _+ d! p' U A( ~, ~$ ?% b8 I# q# o8 m6 ?6 i
*pDest++= 0xFF;
6 [# G# n. Z. ~8 i4 z. _0 k
7 I0 E) P- p- `" g u, L5 y1 d' [% T *pDest++= 0xFF;' M$ h" ]2 n. ~
2 z( w$ F' ?/ X3 L' Y- a7 a. R" w2 F
*pDest++= 0xFF;& a, A4 o& k& b4 ~7 E" L. t' \
* [- U6 K$ d4 L. g8 R V
}
" H8 s6 a3 ]8 w9 X7 N- S' n9 d2 D3 S; ?- ~, k" w
else 1 o7 c! f- b. c0 Y% X( h
- h% f1 O8 @5 k5 ]; H7 H+ l/ U. y7 b
{% b( Z: \0 |) I: H6 R
' `+ u+ E. |( y- ]% h4 y4 r
*pDest++= 0;
) L3 w- R1 K0 R# h
8 Q* F4 `% F8 H/ N0 }3 p" \. Y *pDest++= 0;0 t0 X' A+ u) I3 o" \; G4 L' A" n
6 M% M6 P' [; S8 i
*pDest++= 0;
/ D) T, h% z+ N0 m$ e: H" y- p- M" J7 L( D5 i" p* g6 e) J, ]8 x
}
4 b( H/ N0 L: A# c5 l
0 c9 [- W# B& |' g/ M }' c4 m: P; @% U# |. L. Y
# X$ P6 T6 g+ Y3 X
// Always use the greyscale value for alpha 8 c! v0 F+ N4 @
3 V8 b& `, I `. u$ n: R b" [
. k) \ h9 w" p" S# X& n8 C
- ^* o. x v x$ s# j3 z
*pDest++= *buffer++;//alpha! 我是一点不了解了为什么是这个? 8 ]* b. s! L- ]% H9 x
. ~' I- ~ f* @
}7 }- \ V7 b) O9 @' d, g9 P* j1 f
% U; _4 N3 @- \5 ?6 W0 C8 F }: {- V7 q [! D& s
# Z6 h; g4 l7 f* w0 g
/ Q6 I1 p! Y- l' i& k3 J, X+ d) C7 S
- _ l. W- s$ \( j
this->setGlyphTexCoords( i, - g! }+ ]7 q( u0 w2 m
4 e- ?6 p2 d; }) v2 R (Real)l / (Real)tex_side, // u1
5 P6 L: N! {4 `6 u) ^6 M! V0 \" ~$ W& I8 W# V& d8 y
(Real)m / (Real)tex_side, // v1
+ b& Z# j* e/ M' Z" v% h) Z4 B# [+ U' |5 N7 Q# { Z! |' U- n
(Real)( l + ( mTTFMsg->face->glyph->advance.x >> 6 ) ) / (Real)tex_side, // u29 H: L+ V$ ~- Q* b
* @! V/ g1 \1 w/ D5 K# s (Real)( m + ( max_height >> 6 ) ) / (Real)tex_side // v2
4 d# _" U2 P, q+ `) k- P/ o7 _! i' {# s, q0 e( N2 a1 Q
);//设置坐标 9 U7 ?- T" r, ~7 C" r
, d$ Y+ ]/ ?! ]4 n2 |( g
, B- L: Q8 x. Q
1 g7 [' g' ~& n$ }0 K // Advance a column , z' ?# w5 N9 g2 U
! M8 h8 X3 `5 A( |7 ]' \
l += (advance + mTTFMsg->char_spacer);
4 F' j) }' v- W: h' u
; l& B; F9 X; X3 D6 V2 h //l+= 本字宽+字空
s/ z+ u! X; z. C) U& r) Z7 |; y3 }( N3 a: U* m
: h; h9 ]& t" q$ E: A' @' |7 m4 a3 z9 e
// If at end of row
0 w8 P/ B F C1 o" [0 z8 p, ?
7 a& j% L8 ~, @; ~ //如果到头容不下一个字
$ G) K% N. |8 }
1 C: {$ s- p% y9 m5 ?' s if( tex_side - 1 < l + ( advance ) )
6 X" ~: {8 X9 w0 I% K3 U) t& r' `) \
; F- ^) f3 j' I" H8 I% r {
2 N8 w4 a& i: }4 z/ c; q9 o2 M! c: Y8 q, N8 \' \5 A8 k b
m += ( max_height >> 6 ) + mTTFMsg->char_spacer;
! G! p; o5 `$ O8 S. h/ I- t+ s+ Q+ x; e: s O
l = n = 0;
' x% n* G" u5 J7 Q8 `' \
9 k2 w- p" I. p8 e }
# v1 Z3 }$ V1 c: v* P, R! u* k1 e0 ^5 \4 l( v; m, H2 u
% S; \3 Q. ]7 A F7 E- F
/ D% X# p z$ r7 O) v+ C$ z8 [
}! t3 |+ b9 o* i/ h
9 \5 P+ n# n- o( P' k6 ?
// 把信息存到我们的mTTFMsg中 >_<
' C" W3 ?8 ]4 Y" | T' y8 Q
1 f- ^7 L6 K) }% F& o$ P if(l)3 R& P9 q3 Q+ J" e' z' c' @1 S3 L
7 y! Z1 L h! R A mTTFMsg->point.second = m + ( max_height >> 6 ) + mTTFMsg->char_spacer;$ q, \9 J' [' J) e
" D2 r. U% c- z* w else # m+ n; J( b5 h' A" B
2 E9 p k1 {; w+ V- ?6 g mTTFMsg->point.second = m;
R7 `, C( Z% Q2 B0 B4 {
- ?: [. O q- ~0 s
6 Y) D' f" f! m' j" Y3 }
- v4 _. \" H! ~! N- [ mTTFMsg->point.first = 0;//另起一行
$ ~7 |. P' B3 ~+ h% J0 l
2 u0 O( l( f, `5 _# Y, l" }# o2 h % _4 b& x* w% b6 }7 `( Q
7 P' y$ u' `- G ?9 L
//下面是保存几个最大。
. B) U9 @* H5 N2 R
5 K/ g# z- M3 B3 [* a7 {0 ?4 Y mTTFMsg->max.height = max_height >> 6;
5 t! f% u$ }. `# c: |" ^! h! }8 z$ s4 p" K3 M: z6 l' x |4 f
mTTFMsg->max.bear=max_bear >> 6;
$ \1 `) m# n# D! z+ g
4 d9 y# [$ x' S# c( K mTTFMsg->max.width=max_width;" L8 e) P9 B9 X) [( K w
9 |% k2 K9 o- F6 S+ x, L
) {4 L" M# U+ f0 Y% l) d4 q" l0 h8 i' H1 K
mTTFMsg->imgchunk.allocate( tex_side * tex_side * 4,imageData);$ y6 |9 H& s' x; I0 L1 `: }
% z6 P0 b7 I6 f, ?6 a- V7 S
& K( R6 x1 y! B: l& e* `
+ k8 E+ c. z- K$ @( Q //不知道为什么要设置img这个中间变量,似乎可以直接从chunk创建贴图 ( _# L! x5 W) [3 ^) i; f. L
$ k2 ]) S/ c( N8 \# c
//--Image img; 7 s! Y7 X2 g3 v6 ^2 ~9 i
V* W, M$ x/ G2 Q7 S; [5 K0 R
//img.loadRawData( imgchunk, tex_side, tex_side, PF_A8R8G8B8 );8 s, u% G, ?6 |! R
- v8 J$ A. j# |4 N1 q
3 P3 [9 |# k4 T4 Q( q0 {
1 {: m% U( p; I: I6 I, W0 r ~4 Z! F //贴图名
1 F! x& S: D# ~. u7 k* n) a! l* j. c: ?3 F4 Y4 u& |
String texName = mName + "Texture";
/ r) W* \) `) ?+ S
! c( _) O" c- X. I0 q( G" v // Load texture with no mipmaps
9 n; M P5 W/ u/ L: Q5 R& I6 K, K2 @0 K7 P% D' K* K D
// 把从img创建位图改成直接从chunk创建贴图
2 I$ k1 X+ j, l7 V* E0 n1 V, u6 o! m) f6 Z
//TextureManager::getSingleton().loadImage( texName , img, TEX_TYPE_2D, 0 );& s! q* F/ j3 e+ X
3 u/ g3 Y" T% G+ ]
TextureManager::getSingleton().loadRawData ( texName , mTTFMsg->imgchunk,tex_side, tex_side,PF_A8R8G8B8, TEX_TYPE_2D, 0 );
% f7 o4 ~" B$ I7 f! Q! o% }" ^' ?8 X" w4 P% k% V" ~
TextureUnitState* t = mpMaterial->getTechnique(0)->getPass(0)->createTextureUnitState( texName );
5 x3 |5 i6 V, a* P4 M
7 R: ?5 w4 C' W; K1 N+ c& ^& x, I // Allow min/mag filter, but no mip " f5 u. j- V# T4 T$ R
& r4 f" m t$ D! p9 g7 c t->setTextureFiltering(FO_LINEAR, FO_LINEAR, FO_NONE);
0 q* v1 g& L) O( T3 |6 Q* D1 N& V$ N. e( j
// SDDatachunk will delete imageData . h/ q& V8 R1 l4 N( U
) P# `: |: C' l c. _- R 9 h5 L0 c! e: X4 N& x6 v. q# e
8 [& m/ m5 i* T- k) p+ x, Z }
" h5 R" |7 I( o, m' e$ z/ }
2 G! }- q- |, o9 g8 J2 S5 @% R 你应该对照一下以前的函数,改了很多的。
& @' D* F* {7 f8 V! ^ h8 x$ K3 w' S3 ]+ I
/ g0 u; z) t$ g1 H) D8 }3 |
, R4 s# Y1 M+ Y" \$ K8 F/ r
( X2 F" Q& H- c2 y$ ? I9 A! c% I0 c0 x
(3) & [8 i- x' T/ }
" w2 `4 K. k+ z5 N: p$ q
然后最重要的是动态的申请和画字。
' S3 H5 u3 k" W
% V* \ B: ~0 t1 S" C, m 首先最重要的是我们要一个方法得到汉字的unicode码,我们用到了unicodeMap数组,提供了区位码到unicode码的转换工作,等一下提供这个表给你,好不容易从网上找到的阿,可惜这个表没有中文标点的对应,如果希望支持中文标点,就要努力找到unicode码并加进这个表了。这个表是这样的 char c[3]="邸";unicodeMap[94*(c[0]-0xa0-1)+c[1]-0xa0-1];就得到邸的unicode码,不知道为什么没有5165~5169的unicode码,是轮空么?
* B% }7 k4 A' S, Z' Y% [% U# A9 W9 m/ n( D, u& g. C( V
V* w8 l; L% K. R$ o5 a6 X6 d Q. @, X& c6 p5 Q" Y
申请渲染(字) 3 S2 I! m0 H" \" g- L
4 N8 f A c6 \6 S) ?0 B4 y7 f {
3 T1 d2 B. _' ~0 F+ N" z
! y1 |9 H2 Y Q/ g if(有这个字)
7 I7 E j2 E9 @' ], m# k8 X' a) }- d# l/ e8 B
返回位置 , H- z3 @) g X% w! T
0 s, H* R7 a7 y$ K' t else. s: n+ V4 c# t
! |! s! g3 j/ X3 \* |4 O- W2 } P {. a7 B" G) u1 A g8 _
( m8 y$ J( O" j0 m if(有空间)
3 P+ h" N$ D8 e8 w/ r/ C5 @: l& ^$ z6 v c6 `$ m
画字 $ c0 R8 D8 r ~+ a! A u
( Q4 X3 q8 k( p4 f0 v else* N$ q, s+ x0 y) ^/ K
( ? Z. e' t7 s# H6 Z3 [3 o+ H: j 找不用的字//找不到就出错,没地方画了
; x* j+ E8 T3 H1 F0 |" m/ d( z! s% N
删除 在这个位置上画字
" L/ L/ ]. A* s i
* ]* r. [$ X; s9 o% v 返回位置 % J- d" i* n3 t& W/ E) P6 x
" F: c. E% O m
}
7 {' i! C8 [- Y# w' a7 Z6 P, X3 e. m* J6 J9 b
}
2 h/ H! {2 B( N9 g# @3 b6 g: a0 S" \3 \! b
上面很直观把,大体就这个意思了,申请渲染的函数是inline void getGlyphTexCoords(unsigned long id, Real& u1, Real& v1, Real& u2, Real& v2 ) const。去掉const改一改。得到
1 H2 a5 x" ?: A) |3 m' v* C$ I9 I% s1 f4 C+ ]9 F' c
a.申请渲染 ^ w; H, C3 ]9 T' r7 A# N
1 ?8 h3 {1 v# u& N; J$ B( k1 m! v8 J inline void getGlyphTexCoords(unsigned long id, Real& u1, Real& v1, Real& u2, Real& v2 )
; _$ w! S8 C7 `" F, O0 D+ W, E( \
4 R' F) i+ L5 ?( u6 o {5 f4 j/ C! b2 S
" F8 K- P! ]# ?0 ?: x" z unsigned long idx = OGRE_GLYPH_INDEX(id);9 F& k+ o X4 U$ ?4 e( Y& U
* b, ?5 ~& L" C6 k; r4 x if(this->mType==FT_TRUETYPE)//ttf?) a5 y. @9 f0 Q% Z
+ A- o J7 k* m" R9 y. F
if(id>=161&&idx<OGRE_NUM_GLYPHS)//汉字?
0 { U4 v7 `& B% e/ T ^: U! [+ h$ k: z/ {' N: z5 e( G
if(!mTexCoords_v2[ idx ])//没有?* d2 d# r" j3 B+ A9 H
& ^! C% n9 ]9 L4 Z* x. Y
setChar(id);//画字去 ! |* _. q8 v( l
" f% x @8 H$ K. X. n
; M b, R- T8 u" x- o, U6 a. b6 c3 L X* Q$ W) L
u1 = mTexCoords_u1[ idx ];
% E, @/ s7 n! {& i
- P7 p, B5 X; h v1 = mTexCoords_v1[ idx ];
2 d( P" o4 V( E( a9 F
1 V: e) D( c7 M u2 = mTexCoords_u2[ idx ];
! [ n- I# ~: A/ |# w& f7 `% C6 \$ i* ?6 r- L7 G' u! b
v2 = mTexCoords_v2[ idx ];
1 u/ j0 R# H7 F: \5 E1 P, m2 ~
' Q( Q3 [8 W! P* p7 u+ q }7 ^* E- Z) ]: F
9 U1 N1 u$ K: L8 ?' S' ?
b.画字等 ; n P. z- O9 A( D: {
0 g2 O) a( \+ C" E0 q
bool Font::setChar(unsigned long dwChar)
8 N" T) H9 f5 O4 o n% O/ m6 e; m/ ? w, Q$ ?- t
{
' [) C4 y( Q! ]/ i) R) o" E8 m; q0 X1 E5 U$ y; R$ C6 _" \
int j,k;
8 ]3 q' t/ }+ z, `" Z. R3 a7 h7 `+ q9 \3 E% p1 |9 K) p
uchar* pDest;//操作数据的指针
. Q" s4 P# a5 y( N/ ]0 ^, F' [$ y, b! C: l5 h6 @$ p
mProportion=0.8;//不知为什么,总觉得中文都太扁平了,所以设置这个参数,在《让OGRE支持中文》中创造的参数 , m: i; S+ E0 E. G5 w
N$ i* g0 s3 F) M& w# z
Image::Rect rect;//画字的位置
9 s, }( [: l; B. W& ^7 L( S" A* k$ u9 ^
if(!mTTFMsg->getRect(rect)/*回头看看这个函数吧*/)//如果得不到空位置
# t6 S U8 X+ u$ Y
2 @& g* D. T8 A4 Y; d {
& Q/ A$ B# p% [5 s. o1 P* q& @' s9 D5 g9 Q
for(int i=161;i<OGRE_NUM_GLYPHS;++i)//寻找不用的字
" i+ E# t6 Q1 b7 d5 \
* d6 p1 g% l$ K7 c. G {
6 \7 k" d( f0 s4 k& {0 m h/ J% C* e e6 B- _
if(!mUsing&&mTexCoords_v2)$ Z. j- Y! S7 t0 a1 c$ K
$ \' ], K- f- ~! @8 l# ?
{ ?* o1 C, B# o* f
( v4 C( i( ]% W8 C* a
// 得到坐标
! |3 j7 E! |, |' y" i9 x3 f* n5 L3 U5 d
rect.left=mTexCoords_u1*512;
2 {* u: Y5 X7 l& j" ]# ?6 F# W
v+ B5 ]0 a% f4 ~$ A rect.top=mTexCoords_v1*512;9 }! y- t3 b; R( S/ V
$ I8 A1 p. a7 t$ t( O: i4 G
rect.bottom=mTTFMsg->max.height;
4 z9 R' S1 y; S4 n) h; a* R; T% h0 Q
rect.right=mTTFMsg->max.width;
' }8 \# D4 x) `2 D& _4 q
: p8 d0 k# ~# Q' ? ` 4 v: b" @9 C/ X6 I3 ~
7 s% w0 U% f+ Z6 X
5 L! o+ k; L# X: J
. m$ z" Q. k' E9 b' z 3 c3 b+ h# z& W. v% y( }
7 L% e( `0 t x+ I
2 S* N4 J u" l6 V* Z+ Q& }
( n- m5 A' u8 r5 n- L. d+ i //擦除(这段代码没有试验过,等做完输入的类在检查吧)
% i& f o4 y9 R% B4 R7 @7 w
% {& V2 d) r$ a$ W) W, j* u: ^ for( j = 0; j < mTTFMsg->max.height; j++ )" g9 p4 @7 l/ k8 i
! S5 D2 N* p. X! f' } {
6 f" Y9 x! J" y" o& I$ S' J9 J* U C+ M0 ~1 M7 o, b
pDest=mTTFMsg->imgchunk.getPtr();
, K0 _, p) U6 e
- h/ ]2 c6 c" L! z7 {( R pDest+=((j + rect.top)* (512*4)) + rect.left * 4;
% a/ ^7 M# l1 W2 C X9 y( ?9 I% G+ T( d
memset(pDest,0,mTTFMsg->max.width*4);* A' K5 x+ J+ M# N
) l( @ S' l, v }
( R- V4 ~" i9 d. W; I. ]- `$ F
* K/ D3 Q* C) W0 [0 r! I7 z2 d# N mTexCoords_u1=mTexCoords_v1=mTexCoords_u2=mTexCoords_v2=0;
: C4 s7 {, Q, R! g$ b" m9 q2 D/ F
* n7 k3 j; Q) c. L * R( T2 X8 l7 [+ `2 H2 w' e$ J
0 N$ F y$ e+ e- F4 S& o( o5 Z break;5 x- K( W2 s0 l5 f& S
) U: x2 t! g0 W4 Q7 k
}$ ~6 ]- `7 J5 y" i
3 y- `8 w$ I# s
}
5 \2 a: m' a* d% W t9 p. E
5 }% h) I0 C) e3 t* F0 \, K& N
, ?1 B, `2 Z4 F# _) U, p7 N8 Q1 E5 }0 T# t7 @ O* f o
if(rect.top==-1)//啊啊啊啊啊啊啊啊啊,贴图竟然都用完了,没办法了,出错了
# I1 J, M& P! c& A8 O' R2 q. R6 E% G' x9 [ P8 y: _5 G$ o7 |
{; f6 q, Y1 [% c7 U( s
' H$ B6 Q. ^* j8 j" ]# Y
LogManager::getSingleton().logMessage("你太贪婪了,用的汉字太多了,这是对你的惩罚."); " }! z0 P8 X7 ]& }
$ d' Y$ [3 `* c5 i! h. K$ r
return false;4 v- l+ X- l' }+ b
; f' X( H$ D( Z( x6 Z& H" m
}$ u6 Q8 S# v& r5 S. C
0 _+ c% L3 l5 X1 y& ]1 a 8 s, Z: N" [7 M: ]
0 S e, d' b8 p3 s% I }" M; ?" b2 q! c
- O3 a! @* [+ d1 K
a l+ L/ y4 t
0 m$ o/ a/ r/ }' e/ _
- b, ~* e4 A8 p& X& I$ y4 a _( V D w& l1 @: @
//以下画字的都是招葫芦画瓢的,
7 ?, I, R! Z% y: Z( y, O6 h* s7 V( }; Z$ Z, [3 }! j) k+ j
FILE *fo_def = stdout;
. }1 I- J" {! l* }3 _* S! z5 |2 J$ a& T( z+ g2 H
FT_Error ftResult; H3 U- C, S4 u
6 f. v! d5 j7 N/ H6 Y2 z
" Z) N' L+ i; O. f8 G* b( y
+ X( r- ~0 L) x8 \5 H
// Load & render glyph : ]% }7 f, m7 u! _# C
& t/ ~! C; G9 F5 e# d
# v3 S$ d! @- R6 p
- S% O. f/ V* v7 h* n9 P% I1 j
ftResult = FT_Load_Char( mTTFMsg->face, unicodeMap[dwChar-161], FT_LOAD_RENDER );//读取字体
- A w8 e9 k& z, f
1 Q. p7 m0 r, l( ?/ V, U if (ftResult)6 Z% x5 G4 q% Q3 u) S' a4 s
1 L7 ^1 V! v8 ^7 q+ y
{( Y/ i; ]! p: D* o+ p
: t# S0 r. X% h8 f5 l+ q5 I // problem loading this glyph, continue , z, C" P' ^. Z0 j" }0 ~
# z0 O3 n2 Z% O. | LogManager::getSingleton().logMessage("Info: cannot load character " +) X, @! B W7 _2 `5 g
/ m/ V1 @! K9 E% |$ _
StringConverter::toString(unicodeMap[dwChar-161]) + " in font " + mName);0 ^! m( {) f1 W
3 k+ C" n' I Y, P2 ?* z; X
return false;//如果错误跳过 , j! V" V! H6 J, F8 M1 w
: u& i: e' A1 O8 ~3 A9 y. l* @0 n }+ B# O% I* u( R. H1 U* _# ^* |
$ k: R( k" c1 C
' \! f" M& Z6 Z. r2 k/ G: v `, F- h% Q C
unsigned char* buffer = mTTFMsg->face->glyph->bitmap.buffer;
. ~/ \$ c& i% \/ ], x
8 L- ^3 B- z/ W$ o k+ a# |% |) p0 z // 位图指针
- ^7 f6 F. v, A
/ d, R- m+ W) l% Y2 |1 l1 w8 N4 j0 j if (!buffer)
, N0 K, G8 d1 P
% h# ~/ ~: D( ]& b# W; D/ U {4 C3 S! l" M& x1 Q
8 s: Z$ Z8 n5 W2 `0 P7 ], b
// Yuck, FT didn't detect this but generated a null pointer!
& U( [" r3 V, a: x; ]4 W* _2 _4 ?' L) X. Q4 d0 |! `& d4 a$ s
LogManager::getSingleton().logMessage("Info: 1111Freetype returned null for character " +
6 W7 o; p8 ^; G3 j/ }" A9 ?# [3 h9 z8 a ]& B0 x7 }
StringConverter::toString(unicodeMap[dwChar-161]) + " in font " + mName);6 Q/ z0 l j2 W4 o
% }! F$ v4 o1 g8 H' F- Q2 ?( o3 ? return false;//如果得不到跳过
" h! r: D" l" @* i% [" i
5 _ J! a7 Z* B! |2 c+ D# m" z9 _ }
5 m- i6 {7 m8 X' A# t$ {/ c0 g2 Z( s
* {1 ~$ J$ `' p9 } H l; Q B' ^1 F" C
int y_bearnig = ( mTTFMsg->max.bear) - ( mTTFMsg->face->glyph->metrics.horiBearingY >> 6 );
8 j+ i8 Q1 P0 A# L# k/ j& ]0 ]6 p
$ w5 q5 h# J6 l5 j9 r! J/ @
- j; c5 B- j+ K ~; X& Z+ z/ {
( q- G0 N' Y5 t; T& A- X
8 k( U3 K% g/ ~( R* c for( j = 0; j < mTTFMsg->face->glyph->bitmap.rows; j++ )
5 e7 o9 \0 r' v- ^( H& [5 O: ?$ l; @) j2 j7 I
{
) D7 Q% A, R5 k0 t1 \3 ?) l+ i
& e& b: W6 C4 E! @7 Y int row = j + rect.top+y_bearnig;
) |5 F/ y( b1 x; `4 y. t5 J' y# Z
4 C* x. z3 s* g. [/ B& ? int col = rect.left;//列
6 C3 O: D5 D# Z! Y" e
4 K, k, p) V' i( _& h! ^4 I2 E pDest=mTTFMsg->imgchunk.getPtr();
* s' k* [4 R' o& U7 T" l ]0 z t4 d$ T9 z0 a
9 Z- J, w( g0 H# E
0 A @' L- P6 ] y& Z " I3 Q) o8 o; |2 q7 i
H, \5 G# C% \6 G5 u7 @- ?! c
pDest+=(row * (512*4)) + col * 4;% @) |. {( t6 M
7 c4 g: l. I" C for( k = 0; k < mTTFMsg->face->glyph->bitmap.width; k++ )//每行的点
# o0 F: |$ S n( L
! K8 g- ?+ e6 C. Z- a: M n {
: G% `/ R( w$ _0 G6 }9 }6 l5 k% f E, }
if (mAntialiasColour)3 \' H4 Y K0 ?3 K( W! }
9 C( U# U- i3 T2 W4 J' z! k {
7 s# S8 V S0 P9 Q; E0 K$ Z
A% v+ L; c) R L+ X) w, d // Use the same greyscale pixel for all components RGBA 5 c8 y: H- h: k4 C4 D, H
3 n/ r8 t5 E1 x" B" c. e, G# c \ *pDest++= *buffer;
6 s. t' ]; f+ p+ y0 s; C% O* m+ q! T& E
*pDest++= *buffer;( a/ e. s! s' t
1 R5 P# f& v) ^) |7 e *pDest++= *buffer;7 A8 i0 q/ |0 d( A4 Y9 B3 P) ]
- [. K/ E8 f4 K6 c& A& S' L M }
\2 B5 u9 t4 Z# g
9 {5 e2 y1 o) T else * s# U# n+ R& ?- p+ G4 d
/ E; W' s: N& o3 b
{
7 m4 { V* p3 Z! H! e6 L7 i2 p7 T0 q5 Z
// Clamp colour to full white or off
6 I. V2 |6 a' ^$ o+ E5 M" J, _" m; q5 D
if (*buffer > 0)$ g/ \5 {% |. E/ o
7 h! b& ]2 j; }
{5 t# T" ]! G, h; d( E+ g
& ^; U& _% `" H# k% U H- p+ Z *pDest++= 0xFF;) D2 Y ~, O* `* C' N) o [
- w! A% ?( P( P. V' s- W *pDest++= 0xFF;# O- d8 {8 J, M$ w) X
]# S$ z4 }' A- x' q$ u
*pDest++= 0xFF;
% w( y* o# N3 V$ g6 R0 l
6 _9 j! }$ Q9 z) _ }
i$ P$ N5 d" C$ T( i; x% F& `" ~0 C0 b4 D
else & D m+ u( [8 g6 [4 ^
0 F6 C8 H+ V3 }3 _' ]$ j7 ? {
" a+ {) f' [) M; k6 U. \% i( b0 p G7 q, S' |) N9 ^
*pDest++= 0;
6 j+ B9 H0 |, _6 R& [% |! f
( z V- z# D% Z; w+ {" e" G, I *pDest++= 0;
* @( ?5 A/ g& D( J% a7 d* Y
0 ?9 ?/ u: y: f- S *pDest++= 0;
" Y8 `0 `; r7 ^3 q
+ Z- G0 {6 A( i2 {& A7 X4 i }
) V* A8 U" @6 @, Q+ l/ N! _; O7 g! E3 v# o; E
}
4 R. z7 f8 j/ c$ y" T" s1 l: Z4 n% d8 ], q6 ]; a
// Always use the greyscale value for alpha
8 s' H) j+ F2 Y# t K0 F& ^0 K
: F4 {8 y h1 R ; N) ]; t l9 k& k! h& M+ @
+ ~# X6 y4 a7 c! ~ // LogManager::getSingleton().logMessage(StringConverter::toString(*buffer)+"is cool");# N. S& Y, I% t3 S
2 p% C8 Q) d- r# F3 b f* }
*pDest++= *buffer++;
- O4 {' u* J7 a# i: A' J+ \8 P1 j# i$ c1 ^9 S
}) x2 i5 ^( E6 r x9 s: Z, O
: k1 ?; W) W1 {+ |. N. @! @0 x
4 n% C# v; j! ~4 g6 t: H' b) G0 l' V1 O% u+ M6 ]8 t2 F% d2 B
}0 h/ O" p8 U x& K! l
1 o0 D$ C e4 w, Q! O4 h6 b // 设置位置 ' ~4 ?9 G2 c- @+ o
9 Q: o* W4 u1 L% Q! k this->setGlyphTexCoords( dwChar,
/ e0 G u! g0 A/ t8 w* N! x; ? E j" Q7 n; n
(Real)rect.left / 512.0f, // u1$ M' O% D' t0 i B$ e V3 Y
/ m- y# v& N* k) k3 R (Real)rect.top / 512.0f, // v1 d; ?8 ~7 N ^: m' M( m
& m4 A# D |1 r# b) O; P" |! [
(Real)( rect.left + (mTTFMsg->face->glyph->advance.x >> 6) ) / 512.0f, // u2: _2 z) H6 n6 E* b, y; s
; n7 ?# s# A" G: |; j" Y (Real)( rect.top + rect.bottom ) / 512.0f // v2
. G3 H8 D! Y& r: E# t! G) u* r
. f& z+ d, P4 s0 k6 E );
0 F' W- A+ S5 b$ r
; {, B/ }' D) U0 ^$ j8 h, ~6 T, {! i+ w mTTFMsg->dirty=true;//贴图需要更新
% B7 n4 Z) L; l; h- m+ ~2 }/ m# d1 y; { `2 Z$ h+ }$ ~% C: b, @- r
return true;! F: D, e, m; N7 q6 t
" F/ j4 H# E. {; i7 a }7 l I0 i. y/ J7 s* I
& [ h6 b4 z2 N: O
- B' E$ Q# ~ |: i
0 J9 O, p6 d6 o8 c, r, B* {
(4)
% H4 v9 w0 I8 p/ ~8 X' l! o' c- g+ c" |/ {3 w
松口气吧,繁重的工作都做完了,就是更新贴图了。
) |. x; \( I. ?% ~& M, ^, ^5 @% e6 \/ B/ N/ [2 w
Font类中~8 ]* r5 E6 K$ | K# _# j
& C7 a( q; h. o: V$ Z inline void write(). p/ j( x/ E' V' p0 e
: y7 ^& s8 U9 z B! [# J/ n9 u2 d {1 b9 c0 Q; G/ b0 U, y* S, n3 |
4 q- E: G* L7 y" Z W0 l7 N if(mTTFMsg->dirty)( ]2 @5 p% X" [; y- a
0 H1 N7 V) y) U$ d* A. z {
2 f9 j; s, k7 M
$ x( O9 V x4 j // 重新载入贴图,顺便说一句,类似功能的函数还有
" z9 ^5 K; E# g- N( ~! Z2 a9 B3 g6 H1 u/ i
//virtual void blitToTexture (const Image &src, unsigned uStartX, unsigned uStartY)=0
2 t% s: |) U( o1 P& A
& k+ z. @( [" l D' Q! G. A7 Y2 }3 V ~* z //和virtual void blitImage (const Image &src, const Image::Rect imgRect, const Image::Rect texRect)! O% F9 ]* ?1 d* s% e$ a8 {1 B6 r
4 Y1 g4 } E6 x //不过blitToTexture()在ogre-win32-v0-14-0之前没有实现,没有尝试使用。 blitImage()就算到现在也没有实现。
. J) D0 w$ l: \8 F: w7 d, \
/ ]. X5 `8 W' e6 S# D" i4 j. r5 g 5 X- q, L" f& K/ }+ j7 B: x; }
% m% W# `7 l6 G# G; d0 Z& A$ H
TextureManager::getSingleton().unload ( mName + "Texture");
/ K( s, L( ^4 y9 V: P$ F% V
" N* }- e m7 o; K$ \ TextureManager::getSingleton().loadRawData ( mName + "Texture" , mTTFMsg->imgchunk,512, 512,PF_A8R8G8B8, TEX_TYPE_2D, 0 );, z- q" P9 y3 y; D; S
$ R7 p( r/ N8 v- l/ j- n
mTTFMsg->dirty=false;
& j4 n: c3 ?6 m0 H3 r# W" O7 p/ f2 a! t; J3 ?4 l' V
}
; V/ L7 H* U" J5 y4 l \# X
$ Y+ [/ E; m8 T }
" M1 I2 O- b* X: k/ `! C4 Q
" w) w! j$ i( @/ \3 t! A* k# @- R
( f0 D; D- f, x2 i* P; r# l" w, n+ Q, r; z R( Q6 T2 F
在 void TextAreaGuiElement::updateGeometry() 中调用这个函数。
. T- Z: S2 I0 C$ g, J* y% |! F
9 A' q# E) w" k5 J+ i+ U4 } . J' ^% U8 [5 }7 I& K* X% r
4 K5 H# y+ r- O( R* ` 8 e) f: _ o' ^) N
1 N+ T: M- F. H: ?" \
4.结果。 # x# [0 D6 ~& o: L1 R9 O
/ m% z/ N: F- X& H% ~3 G; \0 @ 好长阿,写了好长。虽然多是代码,但写注释也很累啊。重温了这些天的工作结果。就像上一篇一样“在OpenGL和DX9.0中成功的支持了中文,但是DX7.0中竟然出现了运行错误,具体问题还不清楚,还望各位高手指教。”。不过本来OGRE就不怎么支持DX7的,不管了吧。OpenGL中渲染的比DX9.0清晰,是我的显卡的原因么?以上的winXp+vs2003.net+艾尔沙980se通过~。。 . G; n9 ~( X# G9 `8 }
1 n8 n9 H) D9 C4 j: i 顺便说两句,上次发表了拙作,没想到好多朋友和高人们找到了我。甚至联系到了一个南方的公司,说要做一个引擎支持中文的方面。但是卖完400多的火车票之后竟然因为住房问题作废了,5555,退票少了80元啊。还是自己差阿,如果再多学点可能就能要我了把~。努力吧,争取写《让OGRE支持中文》三部曲。
! y" l- @ e: n
* o6 R" S7 z' a/ b0 b* K: x 下一篇应该是《可以输入中文了》。
6 q# w( e& t6 o q" w0 `& w
4 H: J( [3 a+ @- W 也可能写不出来的~~~~~~~~~~~~~~~~~~~~ 6 A7 ~0 u. O. B& \; p
1 t/ Y. k0 x: Y, M 相关文件
, U( t5 w1 v7 `" F8 H* z
+ t2 R; Z E, ^( ?2 J* C( U1 o. W chinese.fontdef//字体信息文件 放在资源文件加中 4 s0 {2 n# o' S1 L J
$ D3 T2 f2 n: O
font.png//字体图片 放在资源文件加中
6 S! C2 t, Z/ T1 V! @5 Z1 t/ i
+ `5 g; G$ ^# W, B 6 B- d4 e+ P9 G1 j! M
/ F2 @. y; C) s" ]6 |% q' D
OgreFont.cpp# c) { l- w H6 f s
! Q1 a$ O) v; @! O) Z OgreFont.h9 {& v: t& O5 A% u6 D+ D7 B# ^
7 I1 `! m" R& ]( q# y, n1 n3 I
OgreFontManager.cpp( s+ |- a4 ^ y$ b
' _: a" y2 G" K. K
OgreTextAreaGuiElement.cpp
+ E/ K! D' K8 g- [+ @- C+ z+ o9 P8 c9 C4 C: J) R8 k! t+ B
//上面文件覆盖同名文件 就可以 先备份 2 O, ^" y0 I+ k4 [) ?( ^; e
( A& C# O3 R4 U+ Q2 R
; @: N }/ q+ |0 v2 A6 n) F% k+ s* N+ A' v( I
solo5.ttf//这个是一个中文ttf 我直接替换了原来的ttf/ L! N0 K) J' t2 [+ @: T" q* ^
+ K0 ?8 [) i V& S$ O unicodemap.h//这个重要,是换算unicode码的数组(文中提到)
. \+ D4 a3 K$ z/ W& W- l2 k8 Y% ^: u% \2 S: v' m g
$ v' K5 W1 U. i- b
( _0 s R, z+ D/ _. N
这个是在ogre-win32-v0-14-0基础上改的(上次是ogre-win32-v0-13-1),
) N5 U6 ~7 O3 z, q
3 H3 j9 G) c6 j请到http://sourceforge.net/projects/ogre/下载 / c. z) Q. W* C# T, O# V
% A6 ~: c- T( }7 T
配套档案下载:http://www.gameres.com/Articles/ ... /ttf.files/file.rar : k j- `8 ~( ~* i3 E9 ^
$ y: T+ Q% N- D9 |5 ?4 l" E6 k 免费打工仔QQ:1850070
( ?- p! F3 F& k }- y; L" T: g( X3 P# l8 t& }
From: GameRes 9 K3 g- Z( K! W! |- p. G# c
! V+ E9 R1 n/ b4 D( r2 P5 [
http://www.gameres.com
5 m: r F# ?" `
8 F9 z; Z4 I8 h: a- S, ^上面图中“免费打工仔TTF:213.786”是TTF 其他是位图的,中文的位图字体也小修改了一下,支持半角字体了~ |