现在的游戏大部分是用矢量字体了,但以前的游戏一般都是用点阵字体。下面先介绍一下点阵字体显示原理。 3 }% F/ k2 _7 o& R& z
/ v3 S! ]- t* R- y# I
汉字内码
! m, a. o* C; Z8 h ^! K 点头表示什么?是“对”、“YES”,偏偏有的地方表示的意义却恰恰相反。一个动作,有不同的诠释;一个问题,有不同的答案;而一个符号,却有不同的意义,关键在于:你是如何地理解。在电脑中亦如此,所有的数据都是以0和1保存的,按不同的数据操作,可以得到不同的结果。对于显示英文操作,由于英文字母种类很少,只需要8位(一字节)即可。而对于中文,常用却有5000以上,于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码。 2 k$ b# I' h S
2 |& H. F) v/ E" C9 V+ e! J
汉字字模
- }$ V: c& [$ p- p 得到了汉字的内码后,还仅是一组数字,那又如何在屏幕上去显示呢?这就涉及到文字的字模,字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状,如英文的'A'在字模中是这样记载的: . I3 x6 h$ v/ F! }% n5 A, }0 b
: ?# G8 O6 G- M8 ~' U4 b- x
" q% G5 x6 M0 l6 r% f( W5 `
3 W1 i ~8 ^! U+ ?) |
6 J, n/ ?& h" S$ l i而中文的“你”在字模中却是这样记载的:
+ Z- e0 {8 K8 W* d+ c$ s$ a
& h' \( z! P) s2 P* o. h" m2 Q: W
8 U7 j8 u7 v* B( q/ R% T( J. p; X0 v! m' _4 J: J
( t- r& I- `+ H% m, ~
所有的汉字字模组成点阵字库,像以前Dos下常用的Ucdos汉字系统就是用的点阵字库,点阵字库根据不同需要有好多种尺寸,如16*16 24*24,点越多显示的字越细致,特别是显示那些笔划比较多的字,效果越好。 4 l- d+ `, G3 ^2 t% s( r l
2 R$ L- u( _7 P# e$ s; J下面进入GF字体的世界,GF的字体扩展名是.LAF,都打包存储于Data000.LAB文件中。先分析一下LAF的文件格式,然后再讨论如何在字库中加入中文。LAF格式由文件头、字体索引表、字体偏移量表、字体点阵四部分组成。 " n0 f2 p5 O8 y! P) j8 ~
$ K) v q4 @9 H: m
1. 文件头(32字节) ( O- P! [3 S! B6 }3 ^. R7 {) n
. \. A4 [" v7 u# u2 n* x- j9 U: @
字段
3 ~- L3 C; \' s7 f 数据长度 R- `/ O1 D/ L
描述 8 M1 ^ P4 q9 l# c3 K y
1 F$ k3 C8 a$ NCharnum
7 S( v( q( z1 ` k7 B Long(4字节)
# \% ] |% I- d( D ]0 D: B" l8 ] 字库中字体个数
3 p8 j$ i2 B/ Y+ E/ [3 i3 p: V $ Q1 U# S5 ?: w5 H! S* @. L
fontsize 5 c2 c9 W6 M! Q5 E/ a
Long(4字节) , @# @- @- m2 w$ P
字体点阵部分的数据长度 4 k( a/ w# m9 G' E/ {; V
5 W; b: e0 v' C* @5 j& q' i
MaxWidth q/ Q( v7 v% s/ ?, r y) p
Long(4字节) " \; F+ w Q( m2 l
字体最大宽度 6 o- x' x' C3 n2 b' _9 a
; E2 S- `3 l! r) l5 \) \ H
MaxHeight 2 r5 O1 \& O6 J2 u
Long(4字节)
5 e" O6 h8 @+ M9 p' U1 K& V3 t 字体最大高度 : N8 _! x* O: E9 g
# i& o& C. X# r, D
Unknown
7 d( i, U& F, D$ b: ], J: X Long(8字节) % ~4 i3 ^# f" `, K x# X4 N
未知 0 w: {# ]6 d0 f! Y% ^4 s
# v! d$ D6 |% ?$ S, t, m* A
FirstChar 1 {0 W _8 D0 c6 ]/ L
Long(4字节)
/ @ C0 P, i) \ 第一个字符编码
! p3 m8 b# y& i/ i 3 h. O8 n& O- s3 \4 O8 V. |
LastChar 7 s( U' o, @7 f8 s9 C9 A2 t3 d
Long(4字节)
: P; O7 s$ S. e3 H 最后一个字符编码
! |- y- T7 r, N& b5 }7 R$ f 9 `" F. V3 Z3 M7 a3 F
* o4 i1 O9 Y' g9 E7 J" q7 ~! y - }+ I: K" W8 u# M
$ Q, D, O# `: V+ k5 y; l
2. 字体索引表
1 w2 T; W# ^+ c: {' V V' B* L$ |- h* F4 W- B3 C
与字体编码范围相对应,每个双字节保存一个字模在偏移量表中的偏移量。如GF的英文字库是显示ASCII码表中0-FF的字符,所以有256个字模,字体索引表有256*2 =512字节。保存内容为这256个字模在字体偏移量表中的偏移量
0 c& L; ^! p0 G; a) p z0 K4 K: w6 y1 D* g1 b$ I
3. 字体偏移量表(与字体个数一一对应)
+ O; E; Z3 Y9 ?9 T$ ~
- y8 ^! \- M' i4 D" F8 P字段
1 c. ]; T; y+ U: R9 Z* g' M8 W 数据长度 9 M( _3 P0 M* Q6 D# w5 A6 O, ^
描述
( F2 d) }2 i9 t8 x4 Y
7 v* j; Z% S; g3 i7 c) f0 Y+ D! uOffset
* }9 T! a' l( k) A3 s5 b5 l0 ] Long(4字节) " j( l- v# [7 }4 D, u
此字模相对字体点阵的偏移量 H8 s% F5 F0 L2 X9 \
) m5 T: b& W: j2 u/ o9 vUnknown
* j7 p; Z' M. v) j. y+ o! b* k Long(4字节) 3 s2 ^) }5 a) |. `8 z3 X' \( [
未知 ; t+ ?6 k: l3 ~' ]' Z
2 C: K, e1 c t3 `
Width
. R+ }3 E1 y) T( l Long(4字节) , P4 x2 E L. Y0 ?
字模宽度 % u7 Q l* d+ T) t! ^
2 \& Z) J7 z( z; \& h4 o
Height ) Y: W& G) R2 {, M( o* S* p- N1 g- ]4 T
Long(4字节) 3 U$ S; s6 X! |& u4 ^+ v& n* p
字模高度 , i/ i4 b% v) ]3 d
9 ~- a; [% ~# B( O0 q9 B& R3 C% }. _
( G) s$ c! g4 J
j: {4 N: E7 q6 {* `8 w# |( R
$ R4 x4 e/ W/ ~4. 字体点阵 1 O+ J* @1 x+ t) j- g( \2 V- }
( t8 S* C a* q* ]3 Q3 W保存字体点阵。字体点阵的保存顺序是,从左到右,从上到下。0代表无点,ff代表有点。(这是GF点阵与一般字体点阵的区别,一般字体点阵一个二进制位的1代表一个点,但是GF的字库0xFF才代表一个点)。
+ j- G$ v* c7 v' a
& P+ r( E$ w9 ]8 G现在举一个GF中的点阵的例子,下图是GF中汉字“选”的点阵,可以基本看出字形吧,每个汉字都要做成这样的点阵加入到字库中去。
7 U5 J% s8 Z1 J
. Y) G2 j9 \) ]& X+ F4 b3 e$ u! X+ V9 k3 o% o" g
, ], G/ h1 T9 |( P. @. H
! Y$ d* a, ]+ i5 _; Z
现在举一个例子,说明GF程序如何显示一个英文字母N。(N的ASCII码是0x4E)
) k5 q' K* c+ g( W4 t
: i# x+ f; g6 _2 z1. 在字体索引表中找到字模在偏移量表中的偏移量。读文件32+4E*2 = 0xBC处的双字,得到偏移量4E。 % ]8 g' p( @; H) D5 ~6 ^% g) Q( N
. d7 I6 d' b# y: n$ z
2. 在字体偏移量表中得到字体点阵的偏移量。读文件32+512+4E*16 = 0x700处得到字体点阵的偏移量0x17c0,再读0x708h得到字体N的宽0x0A,再读0x70ch处得到字体N的高0x0C。 - S/ l8 b# f( m% q& t$ W3 L1 x
U4 e6 O, j% q. p: A5 E: D3. 读字体点阵显示字符N。字体点阵的首地址为16*256+512+32 = 0x1220H。字体N的点阵部分是在文件0x1220H+0x17c0H到0x1220H+0x17c0H+0D*0A之间。 0 C# k# h' ^( o- E* b
! e& [. a) D/ W# y' i9 s
" O' e9 ]2 u5 z; ~7 ^' c
0 m$ w V3 d( g! v+ T4 b8 o汉字编码GB2312-80简介
* Y; y8 p% S6 `. S- A( i' P# `
6 K, K0 u' y% S; _GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。 * V4 j: F+ Y. ^ S; K! A1 X
" o4 b5 A7 ]1 h6 p) v
GB2312收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。
; {8 X; K; ~& _" P7 ^& w. H4 y2 j! K( [$ S- E( K$ ^; H
GB2312将代码表分为94个区,对应第一字节;每个区94个位,对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区,10-15区、88-94区是有待进一步标准化的空白区。GB2312将收录的汉字分成两级:第一级是常用汉字计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排列。故而GB2312最多能表示6763个汉字。 5 {% X( D" R* m5 a% m7 y8 l7 b
0 t. \ n5 v" f5 x" C, E
GB2312的编码范围为2121H-777EH,与ASCII有重叠,通行方法是将GB码两个字节的最高位置1以示区别。
2 P8 R3 x3 o. [3 [! U5 c
0 z+ `( u9 |2 w% J4 p5 P. D改造字库
Y6 X+ I9 a: e9 W- @! s7 s8 E' Y0 A3 a" n
我们现在要做的就是将GB2312中的6763个汉字加入到GF的字库中去。汉字点阵定为16*16。因为游戏中仍要部分内容要以英文方式显示,所以我们加入汉字并不应该破坏原有的英文点阵字库,而是应该在英文字库尾部追加这6763个汉字。 ! q% w. D/ m D& {: y! j
J( l- \# t( ^) W
1. 首先要修改文件头部分,每个字段都要做相应调整。
* o, c. V5 F7 J9 R. K* x" l) y( k! C/ `
2. 由于汉字编码范围是2121H-777EH,所以字体索引表至少要扩大为777E*2个字节。索引表的内容前512字节为原始的英文字体索引表,应该保留。在此之后,凡遇到字体索引表中GB2312汉字编码处是汉字的位置,添加汉字在字体偏移量表中的偏移量。汉字偏移量应该从0x100开始(前256是英文字库)
_0 a& d, U* o% m/ ^2 m7 ^2 K% B' D" {( x& G
3. 重建字体偏移量表,将6763个汉字在字体点阵的偏移量、汉字宽0x10,汉字高0x10写入。
! [4 k t9 K& X
) j" h0 z1 r! T4. 将6763个汉字的点阵追加到原来英文点阵的尾部。
2 `9 Y2 c9 y" T5 D& Q$ @1 N" a$ [
4 z! I; V: F5 p% _2 `( \0 I m经过以上4部,字库改造完毕。虽然修改只有4部分,但是每部分都涉及到各种偏移量的计算,多字节高低位的读取等、文件头的再修改等步骤,代码实现起来非常麻烦,稍有不甚就会失败,甚至导致GF运行时直接崩溃,调试时需要特别的耐心才行。
: `( ?- `9 X8 s" S) ]* e) k- N7 {) ^+ ~0 \- a% U# S5 [* k) a
在生成新的字库后,把新字库覆盖掉原来Data000.LAB中的同名字库文件,字库的修改就大功告成了。 |