现在的游戏大部分是用矢量字体了,但以前的游戏一般都是用点阵字体。下面先介绍一下点阵字体显示原理。 / {0 |4 s- D8 K
. A1 g ~ m4 ?+ o$ b3 a
汉字内码 ; E. r2 v1 P, D( D! C& \$ m
点头表示什么?是“对”、“YES”,偏偏有的地方表示的意义却恰恰相反。一个动作,有不同的诠释;一个问题,有不同的答案;而一个符号,却有不同的意义,关键在于:你是如何地理解。在电脑中亦如此,所有的数据都是以0和1保存的,按不同的数据操作,可以得到不同的结果。对于显示英文操作,由于英文字母种类很少,只需要8位(一字节)即可。而对于中文,常用却有5000以上,于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码。
( C7 S D$ |$ h6 X. _* t
( P( o# m# }' I0 A* f1 R% v7 K( E2 j汉字字模
6 `: M! N8 T* q2 ~' k- X1 R 得到了汉字的内码后,还仅是一组数字,那又如何在屏幕上去显示呢?这就涉及到文字的字模,字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状,如英文的'A'在字模中是这样记载的:
* w( {$ a( T, r! W m8 @, Z& Y( F; q7 x& \
6 \9 k C. i7 E: e
k& G# d' h5 [2 m8 E0 N# _
" f6 T7 `, W! h$ {4 J; E而中文的“你”在字模中却是这样记载的:
5 u& s( c7 D9 f, i6 q8 V
; {6 N& f6 f y3 A9 ~
# V1 g; T2 h8 k; ?
0 Y" h; W. T; w- V, W) D) Y) j) t# e5 ]' N' t0 `* K
所有的汉字字模组成点阵字库,像以前Dos下常用的Ucdos汉字系统就是用的点阵字库,点阵字库根据不同需要有好多种尺寸,如16*16 24*24,点越多显示的字越细致,特别是显示那些笔划比较多的字,效果越好。
7 |2 T, \& { {. L9 B" j- m3 v
, ]! {! M9 d' `7 d0 A下面进入GF字体的世界,GF的字体扩展名是.LAF,都打包存储于Data000.LAB文件中。先分析一下LAF的文件格式,然后再讨论如何在字库中加入中文。LAF格式由文件头、字体索引表、字体偏移量表、字体点阵四部分组成。 0 Y5 W+ n0 ^' r1 t! C
2 i& N- f) D# |: E E1. 文件头(32字节) & _5 Q- t8 ?2 L+ Y0 z) k* [% H) M
6 \4 j9 |/ q C3 T6 D+ T4 C. v
字段
3 y3 v( B+ s2 g. O, } a$ i 数据长度
( C( y3 t! n, h) Z2 ^ 描述 : I3 P$ n1 Y! M/ e8 ]* ^4 R+ W
0 u% l @- e2 h+ O5 u9 b5 MCharnum
7 k- J! l# D' w) l, v* H: x Long(4字节) 3 U$ B! @) D! _& k3 L% s
字库中字体个数 8 h. H- H8 m9 }# l; a; k: r( \
: X" R" y7 g' w6 E6 K0 b V7 g( o6 T
fontsize : a% G! a; F1 m- Y5 q
Long(4字节)
0 _( m! j8 n% R/ z e- l9 L 字体点阵部分的数据长度 6 t) @7 ]& p5 x' A; d0 z
' H/ y) h/ T5 M0 M$ x( OMaxWidth
- b2 b2 q: _* Q! f" m: s6 w' o Long(4字节)
- B" `5 q8 Q2 S- N8 N# c 字体最大宽度 ; ~ _+ o3 n' E3 _ ?# I" |
# T6 w5 v |' [" O. Z
MaxHeight 9 O9 p, q1 H1 t9 ~! b3 {+ o
Long(4字节)
/ ?' b& M% }, l$ v 字体最大高度 + J' A$ s! e" f2 s9 K
2 d$ `0 G' G% a( N. I; B0 S
Unknown - ?; `7 {* X0 e; g
Long(8字节) 3 @/ V: ^: U+ T/ T$ g/ E
未知 2 K* K; Q3 U s
& M4 r7 r$ D2 f! K: ?FirstChar
" a1 I, M; Q* d! M& D$ \% n Long(4字节)
9 l E. H0 f+ H 第一个字符编码
2 M7 }- }8 s! i* V4 l5 \4 ?
7 L8 @2 ^6 U# Y9 k: f/ _% SLastChar 8 k m' W5 y8 z
Long(4字节)
/ D, i; `% O& [0 z" X 最后一个字符编码
8 P8 O) I$ q+ b- v4 p: B
/ ~$ A( R$ z2 _3 h9 q0 A! U5 T% Z+ R I& U0 E) } p! ]8 i
/ @# g& o0 \* X& o( Y# h
" V+ a% O& K9 d9 D
2. 字体索引表
1 @, c* g" p5 E; `: @3 |0 r" x
I: [( J% V/ @ j与字体编码范围相对应,每个双字节保存一个字模在偏移量表中的偏移量。如GF的英文字库是显示ASCII码表中0-FF的字符,所以有256个字模,字体索引表有256*2 =512字节。保存内容为这256个字模在字体偏移量表中的偏移量
]4 q" n: n8 m& x1 ?6 e- ]# Z' W8 b3 |4 r
3. 字体偏移量表(与字体个数一一对应) % |* }/ | E, o8 }- [
3 e1 C' R3 \, e2 o; b2 q+ y' @
字段
0 {( b3 K/ r. Q: |6 a: I 数据长度 , f) M' O! k1 {4 t
描述
8 q y$ p0 Y v5 B
- \ i8 I; k/ ~; J9 r- _7 tOffset
+ v5 D6 I6 x- u7 s$ C4 B Long(4字节)
7 v: h9 {; G; A. |; j" Q- G. R 此字模相对字体点阵的偏移量
. Q! \0 j1 j" C g 9 y- e: j8 h1 T, l% Q7 [7 d
Unknown
2 B0 u" d8 _6 E# n5 n J. _' ~& t Long(4字节)
4 v& i$ H7 ~$ M 未知
; V6 P6 n; V+ H1 @% L* L 5 m* O# I) {% O, ~( Z
Width 1 t3 F/ T1 j5 z; H. o/ [. s
Long(4字节)
9 y* j3 l7 J* w 字模宽度
7 E; W }( P% W' s' b8 w. N3 f " w9 u4 {# b' e B V& ~
Height
' @* W5 h4 w( y# r" c' p6 K Long(4字节) ' [2 u! J& v8 z/ Z
字模高度 1 k$ q6 `' Z W9 `% g
+ s" G" z8 L: q+ b) T
2 k3 O4 a" r! r! z$ p3 E$ \
0 R! D' T- s" ?8 v
8 x: N; V4 ]$ w% k# e( i4. 字体点阵 % s' X3 \( D3 z( { R
& k+ X% y9 |; k" ]- V! {保存字体点阵。字体点阵的保存顺序是,从左到右,从上到下。0代表无点,ff代表有点。(这是GF点阵与一般字体点阵的区别,一般字体点阵一个二进制位的1代表一个点,但是GF的字库0xFF才代表一个点)。 % t I5 n0 h( s0 G1 n' M
3 e: k) F3 o* l7 E# G u现在举一个GF中的点阵的例子,下图是GF中汉字“选”的点阵,可以基本看出字形吧,每个汉字都要做成这样的点阵加入到字库中去。 - R- O: M+ h7 }- Y
6 F1 I) @9 M; X6 i2 {$ |
( f- ?' G; m/ t% M5 @0 j 2 @5 P0 H% Y" G( ?8 }+ B8 G
( A0 I7 ^& Q" Z' W7 B1 k1 M- t% f
现在举一个例子,说明GF程序如何显示一个英文字母N。(N的ASCII码是0x4E)
' K. h6 v( f+ z$ j" c9 p7 c! ^% a# E7 [ V2 y
1. 在字体索引表中找到字模在偏移量表中的偏移量。读文件32+4E*2 = 0xBC处的双字,得到偏移量4E。
: F* P) X; v: U# |* z5 Q
& Q8 ?2 d6 i; d- ?" N- B2 b0 o2. 在字体偏移量表中得到字体点阵的偏移量。读文件32+512+4E*16 = 0x700处得到字体点阵的偏移量0x17c0,再读0x708h得到字体N的宽0x0A,再读0x70ch处得到字体N的高0x0C。 / s5 C/ Z- \/ ]0 i& Y* ]5 t
( y% F2 L' K! t) Y5 M) m3 r
3. 读字体点阵显示字符N。字体点阵的首地址为16*256+512+32 = 0x1220H。字体N的点阵部分是在文件0x1220H+0x17c0H到0x1220H+0x17c0H+0D*0A之间。 6 p `8 z$ P( f7 }! E N' g
9 J/ \! I2 L7 }) K( P# P, K) {+ X
8 N9 j2 H* j3 T- X6 Z5 N9 I8 P' `" v1 L! Q" W9 c* l! d1 `
汉字编码GB2312-80简介 $ p5 @0 b9 v6 _' E! s
( V5 L$ {& _" d' H- M8 `
GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。
6 ?) |# {+ Q3 F5 F' {' ^1 ^7 I, @, c& m0 J6 t0 Q/ I. u$ d# @
GB2312收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。
3 @8 n( M4 U( s& x8 {3 [4 h: d' E; P! |/ O
GB2312将代码表分为94个区,对应第一字节;每个区94个位,对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区,10-15区、88-94区是有待进一步标准化的空白区。GB2312将收录的汉字分成两级:第一级是常用汉字计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排列。故而GB2312最多能表示6763个汉字。
+ Z6 }* V/ | P, Q1 j4 L2 e4 Q; z* `
GB2312的编码范围为2121H-777EH,与ASCII有重叠,通行方法是将GB码两个字节的最高位置1以示区别。 8 }, d" K5 Q* v" S6 p
5 f( i9 r9 L9 o7 ]改造字库 , O0 w- `% m3 n& k- Y& I/ d4 n
; r# z$ |" F/ y N8 W% t) |' M4 A( I我们现在要做的就是将GB2312中的6763个汉字加入到GF的字库中去。汉字点阵定为16*16。因为游戏中仍要部分内容要以英文方式显示,所以我们加入汉字并不应该破坏原有的英文点阵字库,而是应该在英文字库尾部追加这6763个汉字。 8 @5 v2 F! `, O# c, U4 H' C
9 O* ~ Y3 f' [2 J2 X
1. 首先要修改文件头部分,每个字段都要做相应调整。
7 ^0 g. z$ O- B8 H/ F
, J6 |4 c5 c9 j0 ~, m6 k! r- O9 Y* j2. 由于汉字编码范围是2121H-777EH,所以字体索引表至少要扩大为777E*2个字节。索引表的内容前512字节为原始的英文字体索引表,应该保留。在此之后,凡遇到字体索引表中GB2312汉字编码处是汉字的位置,添加汉字在字体偏移量表中的偏移量。汉字偏移量应该从0x100开始(前256是英文字库) # G B+ @$ \( M( G
- V8 C; W: q6 g( }2 }& c; ~3. 重建字体偏移量表,将6763个汉字在字体点阵的偏移量、汉字宽0x10,汉字高0x10写入。 8 I2 O; a( ?* a- O8 q
! @- O4 X- X+ ?/ Z/ \
4. 将6763个汉字的点阵追加到原来英文点阵的尾部。 ( D( Y3 O6 f' P. M
- j. U- P6 }' K3 Q( o3 |
经过以上4部,字库改造完毕。虽然修改只有4部分,但是每部分都涉及到各种偏移量的计算,多字节高低位的读取等、文件头的再修改等步骤,代码实现起来非常麻烦,稍有不甚就会失败,甚至导致GF运行时直接崩溃,调试时需要特别的耐心才行。
2 ]! x9 `9 I; e5 Y7 U( x& M) E
; Z1 I+ K4 w& G* ^3 t- e1 t9 S 在生成新的字库后,把新字库覆盖掉原来Data000.LAB中的同名字库文件,字库的修改就大功告成了。 |