现在的游戏大部分是用矢量字体了,但以前的游戏一般都是用点阵字体。下面先介绍一下点阵字体显示原理。
0 f$ B4 Z( G% m, l7 V9 U8 g8 i) L
+ F* W0 _. d V2 d. [* T, R* V# E汉字内码
" F' }) ~8 P" g& [9 q 点头表示什么?是“对”、“YES”,偏偏有的地方表示的意义却恰恰相反。一个动作,有不同的诠释;一个问题,有不同的答案;而一个符号,却有不同的意义,关键在于:你是如何地理解。在电脑中亦如此,所有的数据都是以0和1保存的,按不同的数据操作,可以得到不同的结果。对于显示英文操作,由于英文字母种类很少,只需要8位(一字节)即可。而对于中文,常用却有5000以上,于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码。
6 M& \1 P/ Y! C) C* N# ]) C8 j' H+ A1 Q x3 p; j. e8 e) [
汉字字模 * |/ F( u, p5 v' s r
得到了汉字的内码后,还仅是一组数字,那又如何在屏幕上去显示呢?这就涉及到文字的字模,字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状,如英文的'A'在字模中是这样记载的: & L; c6 f- I' w3 ?" g4 @
7 h7 \) o4 m2 o% m S! H' g- K% t
& [( R, k7 w. G( f# Q- X, B
5 g1 c. G" r0 c& w6 L) ?3 _" `( S' r
而中文的“你”在字模中却是这样记载的: $ _0 w# I. |2 A$ z6 t& Y, _
+ [; E# d/ N! R% o4 Q- a7 m W
2 i6 Q5 V! o4 `0 X0 _
! ^1 v( p. ^* p2 W8 W) k; L( P+ H: [- m( C
所有的汉字字模组成点阵字库,像以前Dos下常用的Ucdos汉字系统就是用的点阵字库,点阵字库根据不同需要有好多种尺寸,如16*16 24*24,点越多显示的字越细致,特别是显示那些笔划比较多的字,效果越好。
. p8 \1 z) W: h* J* j! f, m
0 n+ m" v) M- \" q& c$ e下面进入GF字体的世界,GF的字体扩展名是.LAF,都打包存储于Data000.LAB文件中。先分析一下LAF的文件格式,然后再讨论如何在字库中加入中文。LAF格式由文件头、字体索引表、字体偏移量表、字体点阵四部分组成。
. P! B! t/ V: w) f# T$ }% [3 T
& w# x1 M% s/ Y8 _1. 文件头(32字节)
' F; z7 m2 r S8 f7 e9 M8 s; [ p8 i9 x- J# k
字段
; I) ]) V& n) h+ Q- m) ] 数据长度
" t9 u! {) H1 X( B9 d: [ 描述
4 L( C, V. o: R; d$ I
. _& f+ W3 I5 H$ \- d! K7 L$ \) iCharnum ) u8 {) y) q$ v' q; u7 M/ v. G6 C9 w
Long(4字节) - \0 `. @# e; Z k2 E R
字库中字体个数
. r4 b$ `: V! w* H) e# ^
c% h( O8 A8 U# u/ |fontsize
7 f2 ? D! g' N1 Z3 G Long(4字节) * ~9 G, {) A6 K7 T; X4 H) q2 Z
字体点阵部分的数据长度 4 x$ |3 ]) W9 y' p. `$ V
# t" ]1 B. e9 U% O
MaxWidth $ p+ W! m4 x* ^
Long(4字节)
, S" t! F; T4 c m4 l 字体最大宽度 ; J4 o& m9 g1 L9 \
& A* Z6 a# d7 D' J ~MaxHeight 9 B. q% L4 ]0 E. F6 D4 M M. a
Long(4字节)
2 i- \5 b3 i, w0 j+ l 字体最大高度 & \- u0 D$ d0 j/ X6 t
: {7 u1 |: s) @5 h' s0 a7 M# w/ p) nUnknown # [7 E9 z" I- ~' Y4 a0 j* g
Long(8字节)
, ]7 J2 x' f3 t' j2 q 未知
/ m% t) H+ _3 q# w9 r% ~* F P9 T : o! L. ` E# Y7 k
FirstChar
9 m9 h4 w, u" `5 P b* p; N Long(4字节) & f$ L) h7 _; `' W; ^! H+ z$ V$ a
第一个字符编码
) N4 t" j( a; S- X: X2 N& w7 d, O
7 t. W5 y6 g& `$ z+ NLastChar
! d$ A& s0 P: W Long(4字节) * ]2 ]5 y- p7 u! q
最后一个字符编码
9 p% A; @! p" Y& r! w 9 ~. f8 @; z0 z, _
0 s; @; E6 A1 R$ K6 g, d
( K( e+ Q1 Z$ z6 q
4 {$ C; D3 {5 V1 O" U/ |9 e* V% l2. 字体索引表
/ X6 v3 T& V0 F5 z3 T M2 Q; o2 Z3 t6 T9 ~5 c
与字体编码范围相对应,每个双字节保存一个字模在偏移量表中的偏移量。如GF的英文字库是显示ASCII码表中0-FF的字符,所以有256个字模,字体索引表有256*2 =512字节。保存内容为这256个字模在字体偏移量表中的偏移量 0 J' j0 v1 t4 ^ } ]& ^; V
% }$ m4 ?" Q8 N" y. f3. 字体偏移量表(与字体个数一一对应)
3 L1 f, H0 [: {; E& ]: K8 Z9 `; k m1 V4 m1 z- q$ g' ?8 Y5 H
字段 h, }, C3 m1 w1 T z* f. W- V, h& j
数据长度
2 J' I0 T" Y" @4 N0 @0 a' R8 X4 P% N) u3 r 描述
7 V7 N4 J$ G" w" j6 n7 L' I
( B) w) N+ t, v! XOffset $ Q! [' r- s& `& Z
Long(4字节)
2 s$ c: ^- e" b; p% ` 此字模相对字体点阵的偏移量
& b# V, ~8 k# ^% N
7 Y( i' W! q0 Q+ B: J( I* @: m) b2 {Unknown : o9 d5 L0 O( Z( `& ~" D
Long(4字节) * b$ T4 m- T! Y2 J2 \* J4 L5 H
未知 3 m6 P6 ~8 `4 k8 P9 Z P5 Q- e
& u' l5 ?3 a* u% b# X8 I* K) d
Width
; g0 B3 r+ Z; `' ]2 I! T Long(4字节) # c y* q _* N! L- q9 H+ H0 r7 ?
字模宽度 B. c9 x4 C' Z: }% I
; @+ [* L8 b) JHeight ' k _+ P! z+ A: H" Y
Long(4字节) ) r6 B1 v' |. t# s; x' H* v
字模高度 ( Y# _, @$ _. S
9 ]$ m( P7 ?' U6 T) m
! R' h; _5 N3 b' e0 P7 } X% u' { 7 C y# F7 l( V9 d$ U
- T: l) R; t( M0 F: t% u4. 字体点阵 # c" s5 Y, f/ A- @+ |. x2 O, p% n
' f! b$ c; K0 K% F3 r! m. V0 Y0 {% U' v保存字体点阵。字体点阵的保存顺序是,从左到右,从上到下。0代表无点,ff代表有点。(这是GF点阵与一般字体点阵的区别,一般字体点阵一个二进制位的1代表一个点,但是GF的字库0xFF才代表一个点)。
! w* [) n( R# Y$ Q7 v' M7 O
* J ?! S! [/ y现在举一个GF中的点阵的例子,下图是GF中汉字“选”的点阵,可以基本看出字形吧,每个汉字都要做成这样的点阵加入到字库中去。 ! Y! j3 O$ f; i8 K( t$ ]5 |& ~4 z8 H
: G, H9 H0 C' Y
n( e* |+ d7 K
' w/ F2 b1 B0 N8 n
. y( M3 V j u2 b. S现在举一个例子,说明GF程序如何显示一个英文字母N。(N的ASCII码是0x4E)
m- y& [. J9 d2 f0 C7 T8 @* X( [, r. ^7 }, Q- y$ N2 Z. W3 p
1. 在字体索引表中找到字模在偏移量表中的偏移量。读文件32+4E*2 = 0xBC处的双字,得到偏移量4E。
% C) u& W: z( L" F' d5 s! e
- T9 e; W% o" N/ m; p5 h. G x" u2. 在字体偏移量表中得到字体点阵的偏移量。读文件32+512+4E*16 = 0x700处得到字体点阵的偏移量0x17c0,再读0x708h得到字体N的宽0x0A,再读0x70ch处得到字体N的高0x0C。 ; ^' y* }2 f7 h5 A
7 v# g( ?+ E6 p
3. 读字体点阵显示字符N。字体点阵的首地址为16*256+512+32 = 0x1220H。字体N的点阵部分是在文件0x1220H+0x17c0H到0x1220H+0x17c0H+0D*0A之间。 ; b& k" _# Q2 e, w: A5 H, v
* E& ~* v, G, j- @
. w! @6 N0 V5 E* |2 C3 w* m6 {2 I5 W
汉字编码GB2312-80简介 % n, h0 R, |- p
& W' C7 R ~) @+ Q% kGB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。
$ L# l0 N% t. o" q; v5 p0 g
4 _2 Q! J( Q& O" j8 P GB2312收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。 & l( t1 k* M) n# L9 r
2 C6 Z7 i1 O, ^7 N" V
GB2312将代码表分为94个区,对应第一字节;每个区94个位,对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区,10-15区、88-94区是有待进一步标准化的空白区。GB2312将收录的汉字分成两级:第一级是常用汉字计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排列。故而GB2312最多能表示6763个汉字。
0 Y7 `: X: L4 B+ Q3 w7 d+ d* l2 Y! j/ B
GB2312的编码范围为2121H-777EH,与ASCII有重叠,通行方法是将GB码两个字节的最高位置1以示区别。 4 ?' ]" P9 `. U/ y( ?* S; ] [
; v8 t7 k6 Y7 [0 D3 B8 Y改造字库
: a: ]' ^, [2 _& P- t9 j& V4 k1 z, Z5 }# n
我们现在要做的就是将GB2312中的6763个汉字加入到GF的字库中去。汉字点阵定为16*16。因为游戏中仍要部分内容要以英文方式显示,所以我们加入汉字并不应该破坏原有的英文点阵字库,而是应该在英文字库尾部追加这6763个汉字。 % t, [9 ~1 ` U+ H/ L
' z% c. A( b% i3 w1. 首先要修改文件头部分,每个字段都要做相应调整。 4 {7 W9 i. a7 Z- n4 Y) @
9 L+ `; B# F7 H( K: y
2. 由于汉字编码范围是2121H-777EH,所以字体索引表至少要扩大为777E*2个字节。索引表的内容前512字节为原始的英文字体索引表,应该保留。在此之后,凡遇到字体索引表中GB2312汉字编码处是汉字的位置,添加汉字在字体偏移量表中的偏移量。汉字偏移量应该从0x100开始(前256是英文字库) 2 p/ B* h, G/ k" i" x6 D
/ B! U9 w0 v, V( v/ C) v8 I$ `
3. 重建字体偏移量表,将6763个汉字在字体点阵的偏移量、汉字宽0x10,汉字高0x10写入。 + X& W2 M- K8 y4 V
% c( r5 d/ z* D) f) G4 o
4. 将6763个汉字的点阵追加到原来英文点阵的尾部。
5 X. b% F! A9 K3 N e5 q$ K n$ }
. }, D0 [ e/ z" E5 F经过以上4部,字库改造完毕。虽然修改只有4部分,但是每部分都涉及到各种偏移量的计算,多字节高低位的读取等、文件头的再修改等步骤,代码实现起来非常麻烦,稍有不甚就会失败,甚至导致GF运行时直接崩溃,调试时需要特别的耐心才行。
8 y {$ t! x% M) w& b1 y: K$ l$ R5 i1 q. @. q( S
在生成新的字库后,把新字库覆盖掉原来Data000.LAB中的同名字库文件,字库的修改就大功告成了。 |