现在的游戏大部分是用矢量字体了,但以前的游戏一般都是用点阵字体。下面先介绍一下点阵字体显示原理。
3 @$ v! V7 D C# d8 f! L1 n; H4 r
3 N) v. a9 Y: p3 l" Y$ }7 W汉字内码 . I; v! o6 S2 t/ V, u2 p5 l' U
点头表示什么?是“对”、“YES”,偏偏有的地方表示的意义却恰恰相反。一个动作,有不同的诠释;一个问题,有不同的答案;而一个符号,却有不同的意义,关键在于:你是如何地理解。在电脑中亦如此,所有的数据都是以0和1保存的,按不同的数据操作,可以得到不同的结果。对于显示英文操作,由于英文字母种类很少,只需要8位(一字节)即可。而对于中文,常用却有5000以上,于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码。 ) x5 m( h' t7 I, A+ E. E, x3 p
& h* E% n A( |: @8 W# |
汉字字模 - A b8 R1 o' h- |% ]2 {
得到了汉字的内码后,还仅是一组数字,那又如何在屏幕上去显示呢?这就涉及到文字的字模,字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状,如英文的'A'在字模中是这样记载的:
8 p# q2 l" \2 ]$ j. R
, K1 \/ H# Y2 z7 A! |! t 5 j4 Q$ {/ O+ m1 V" b# J% Y' Q+ G
& u- \% K1 S2 \/ c- G7 I) \8 I
1 P: o# p. k( B# z1 u- B1 Z( B( h而中文的“你”在字模中却是这样记载的: ( A. k! m$ S1 A' T+ F
7 K7 z+ D1 U+ Q2 E9 f1 B" V: Y* l7 |% y. ]3 H5 [$ D
, K* y- P+ Q, F+ M5 F
`9 _6 a8 y; T& W# r d, r所有的汉字字模组成点阵字库,像以前Dos下常用的Ucdos汉字系统就是用的点阵字库,点阵字库根据不同需要有好多种尺寸,如16*16 24*24,点越多显示的字越细致,特别是显示那些笔划比较多的字,效果越好。 / [# M D( X6 S1 H8 A0 E0 l% P
8 W& Q* ?( }# q8 [
下面进入GF字体的世界,GF的字体扩展名是.LAF,都打包存储于Data000.LAB文件中。先分析一下LAF的文件格式,然后再讨论如何在字库中加入中文。LAF格式由文件头、字体索引表、字体偏移量表、字体点阵四部分组成。 7 S" u6 x( ~; j5 o Q
) s- }" g% m6 F0 ~
1. 文件头(32字节) / N. @: G$ ^ B
4 @$ H% c+ C& {& Q字段
$ w/ k i* e: W 数据长度
& {: L, G- w& b. F 描述 * c# B8 y+ `- \5 G' g$ D
$ U8 w/ T0 O. l5 m3 s) \0 J0 ^* aCharnum . R: |% T1 X$ T! M; n3 X8 \
Long(4字节)
" n, l: K7 _2 k3 ~$ c 字库中字体个数 0 x0 o$ a) T" b& |0 D; c
- F0 \% U! J& u2 q* p+ bfontsize
& [" L W1 B' \2 \$ R; y2 a Long(4字节) 2 n3 G. t: @* b K4 l' Z: F6 ^
字体点阵部分的数据长度
* r& E2 i3 z) G. Y5 ]5 t, I
' s7 H: E- P1 I" }' r. OMaxWidth 5 f2 J9 N6 x5 b+ R
Long(4字节) 3 h% H5 {- L$ d0 ]
字体最大宽度 0 h8 k+ F/ h) g: T
7 d4 M. c9 T/ X; x
MaxHeight 0 W+ v* `0 M; d$ k6 m& I+ B
Long(4字节)
+ L4 y( u* c( O0 w( k( \5 } 字体最大高度 ) Q" q" z d6 u! Y2 D- r
$ A/ L# n( _. I8 r
Unknown
6 j6 ~! r) s5 O# a1 ]0 ^ Long(8字节)
! Y# Y' F3 I# _5 @* @ 未知 ) [2 n; L* \3 ]) f0 J/ u. p8 e! T0 J
4 T4 `' e! o( ~FirstChar
; ^ }1 g; Q4 S% \/ y- d. M Long(4字节)
1 J' T+ e' v/ q6 M: u9 z+ h 第一个字符编码 - `) v0 g `8 y& M
& | V0 p5 N. J% j5 b) LLastChar
: R# \4 \& x' C; f; [7 X/ ]! b; A3 \ Long(4字节) 9 E; B3 v r" y" @5 ~- Z/ {
最后一个字符编码
5 }; B7 ^" I- T % g$ \& h1 [2 k' Y, g. P
* ?0 J: h! z5 l; A/ O1 l ~; m
: O" o. S/ @( M2 X. V
3 d8 ?3 U% ~+ T! w9 n* @& T2. 字体索引表
) b9 ], }0 k9 Q& Y0 Z# l3 N" d7 U% Q/ ?5 Y2 s
与字体编码范围相对应,每个双字节保存一个字模在偏移量表中的偏移量。如GF的英文字库是显示ASCII码表中0-FF的字符,所以有256个字模,字体索引表有256*2 =512字节。保存内容为这256个字模在字体偏移量表中的偏移量
, \6 V3 R4 |8 ~3 R) h) ]9 r$ Z! `, S
3. 字体偏移量表(与字体个数一一对应) ; T5 w% k6 t. r$ ^( Q7 r) `( J
: A2 S/ A3 {$ a. B1 j9 |2 h
字段 + p }/ \+ `/ U0 l* m
数据长度 3 ?2 H4 ]* k- k
描述
g# G5 C' g2 U3 e) d ( S% M! G8 q" r7 E
Offset 7 p; e. U' R; W6 a7 O
Long(4字节)
7 i& l& X( g8 x9 ?' N( |& h4 [6 q 此字模相对字体点阵的偏移量
* y8 R4 j/ N& B! d8 e
" {3 i$ V2 X, X+ y GUnknown
8 d. W4 a+ \% L9 p, n Long(4字节) + S) n V& H# k c. ~% `+ U4 w9 }: y! |
未知
+ I, m% C/ I9 z8 r' c( _ " q. A% V! L% C8 S+ ^& n
Width # ]' ~+ }8 E ~
Long(4字节) $ C+ a/ t4 z' o% s9 h
字模宽度
' s8 Q& g2 l, V; n/ C! ~2 ?/ p, B ' }7 H! S2 u/ j( ^2 S" M
Height
, H" e4 Z3 x0 N; I3 g Long(4字节) k) A9 O/ H" [7 A# t" j
字模高度 $ w5 [! a5 @8 _ U- i( Y* Y
9 y7 H0 u& F* X: H$ i
0 i. J$ p; G. t" K- h' t # a& M; C0 f! |5 y
. N1 L) A. u% U' k/ T
4. 字体点阵 # k- T! E' o5 s) m2 y/ K
7 I! W3 H& }) v4 d( f4 D
保存字体点阵。字体点阵的保存顺序是,从左到右,从上到下。0代表无点,ff代表有点。(这是GF点阵与一般字体点阵的区别,一般字体点阵一个二进制位的1代表一个点,但是GF的字库0xFF才代表一个点)。
+ g) V( i- o) Y8 X$ f% j+ C
- z7 n6 ]/ ^- o0 w现在举一个GF中的点阵的例子,下图是GF中汉字“选”的点阵,可以基本看出字形吧,每个汉字都要做成这样的点阵加入到字库中去。
* T) L9 L9 F/ \, Y' V' N$ a+ d- O t I* S1 q/ w- n
) Z% n. }' X' R- { - `; H: d x x
* x5 O4 o8 a) s2 [+ O
现在举一个例子,说明GF程序如何显示一个英文字母N。(N的ASCII码是0x4E)
& m9 B/ S, m. ^; [( A% l3 }8 r
4 o5 r& F* {0 z' E- M" Y7 \( o1. 在字体索引表中找到字模在偏移量表中的偏移量。读文件32+4E*2 = 0xBC处的双字,得到偏移量4E。 4 M) J- e5 _/ P' y$ \& B& I4 r# Y
! T- M4 o1 `# p" O
2. 在字体偏移量表中得到字体点阵的偏移量。读文件32+512+4E*16 = 0x700处得到字体点阵的偏移量0x17c0,再读0x708h得到字体N的宽0x0A,再读0x70ch处得到字体N的高0x0C。 5 w; i6 Y" v3 P# b
. p' t/ `1 o: X/ V) p% P7 ]1 y, K
3. 读字体点阵显示字符N。字体点阵的首地址为16*256+512+32 = 0x1220H。字体N的点阵部分是在文件0x1220H+0x17c0H到0x1220H+0x17c0H+0D*0A之间。 ) q! }0 w* P% @8 ~
$ y0 M; o, b3 K ?
9 h' G0 _! q2 ]5 L3 ~, O6 i7 \ b# h' u* u; q* w
汉字编码GB2312-80简介
" g g& h9 I: I/ k. Y, y& j4 ~6 _+ W: G5 J( k$ K' q" |
GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。
' R: Q g* I. _6 P* h s$ X! K$ _
3 S6 ], M; U" F- {/ m) i GB2312收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。
% T* U% X# X3 A$ w0 b+ ~& Y, |1 J' ?0 M/ L; O4 |9 D
GB2312将代码表分为94个区,对应第一字节;每个区94个位,对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区,10-15区、88-94区是有待进一步标准化的空白区。GB2312将收录的汉字分成两级:第一级是常用汉字计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排列。故而GB2312最多能表示6763个汉字。
: q+ j$ m) }+ `6 A9 Y) B
" c3 G3 S J& |7 TGB2312的编码范围为2121H-777EH,与ASCII有重叠,通行方法是将GB码两个字节的最高位置1以示区别。
; m) ~- g" Y! t$ g3 Y" V \ c! y8 Q) ~8 [9 B8 V) K5 Z0 x& o* o
改造字库
2 g+ e6 C0 ^7 N7 X+ J1 z) ^$ Y" B1 p- I" s5 n
我们现在要做的就是将GB2312中的6763个汉字加入到GF的字库中去。汉字点阵定为16*16。因为游戏中仍要部分内容要以英文方式显示,所以我们加入汉字并不应该破坏原有的英文点阵字库,而是应该在英文字库尾部追加这6763个汉字。
: q. p v" | S. L# R7 M
5 [" ] }+ P$ U6 B: v1. 首先要修改文件头部分,每个字段都要做相应调整。
4 g8 x, W B! T( P
7 T* E- B* W& A9 Z2. 由于汉字编码范围是2121H-777EH,所以字体索引表至少要扩大为777E*2个字节。索引表的内容前512字节为原始的英文字体索引表,应该保留。在此之后,凡遇到字体索引表中GB2312汉字编码处是汉字的位置,添加汉字在字体偏移量表中的偏移量。汉字偏移量应该从0x100开始(前256是英文字库)
+ a, K- l) \/ T. h6 m8 K4 }, t& A: F0 T: ]* b; i
3. 重建字体偏移量表,将6763个汉字在字体点阵的偏移量、汉字宽0x10,汉字高0x10写入。
8 i* v& I! O i7 k. ~7 {' k9 [: ^, V V* N9 L+ p$ N4 _
4. 将6763个汉字的点阵追加到原来英文点阵的尾部。
/ U6 D/ E0 S% d2 e% g/ @; t
. e8 s0 h! P7 ]% b3 |$ p经过以上4部,字库改造完毕。虽然修改只有4部分,但是每部分都涉及到各种偏移量的计算,多字节高低位的读取等、文件头的再修改等步骤,代码实现起来非常麻烦,稍有不甚就会失败,甚至导致GF运行时直接崩溃,调试时需要特别的耐心才行。 & x4 H; h, z3 N# D3 o0 ~
# L/ |* W& ~: F3 e$ q+ v7 J 在生成新的字库后,把新字库覆盖掉原来Data000.LAB中的同名字库文件,字库的修改就大功告成了。 |