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