现在的游戏大部分是用矢量字体了,但以前的游戏一般都是用点阵字体。下面先介绍一下点阵字体显示原理。 ) |( z% {0 A p4 a& V7 l q
4 F* p6 d' i: m汉字内码
* m% c7 H; i( {' g/ n: {; ] 点头表示什么?是“对”、“YES”,偏偏有的地方表示的意义却恰恰相反。一个动作,有不同的诠释;一个问题,有不同的答案;而一个符号,却有不同的意义,关键在于:你是如何地理解。在电脑中亦如此,所有的数据都是以0和1保存的,按不同的数据操作,可以得到不同的结果。对于显示英文操作,由于英文字母种类很少,只需要8位(一字节)即可。而对于中文,常用却有5000以上,于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码。 , t% r& K3 ]( U5 F# A1 H \! d
3 d e9 U2 `# F
汉字字模
0 r8 p) t' D3 x$ x* v) Z9 T x 得到了汉字的内码后,还仅是一组数字,那又如何在屏幕上去显示呢?这就涉及到文字的字模,字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状,如英文的'A'在字模中是这样记载的:
* x( y7 N; u. `* w+ O1 [% ~, ]
% |2 V1 z' c( C1 p9 H$ f * P! I$ H7 u. o- m4 e$ K: q: t+ [
1 ]5 K3 G$ V" c4 @* ]+ _- b+ K Z( \ _( s I% T
而中文的“你”在字模中却是这样记载的: & \1 r6 C7 A. \" I" g2 f( {
9 X4 m Y/ A! S$ S7 @0 y
8 z6 U9 x( Q2 Y; R+ W1 L b% w* \# k6 J6 X! y! n$ i0 N
3 a3 j) P+ h: m( C
所有的汉字字模组成点阵字库,像以前Dos下常用的Ucdos汉字系统就是用的点阵字库,点阵字库根据不同需要有好多种尺寸,如16*16 24*24,点越多显示的字越细致,特别是显示那些笔划比较多的字,效果越好。 : o- z4 w# U& G1 l; J0 g/ L% m
1 j# b0 d/ V0 ]' Q: \' W1 t下面进入GF字体的世界,GF的字体扩展名是.LAF,都打包存储于Data000.LAB文件中。先分析一下LAF的文件格式,然后再讨论如何在字库中加入中文。LAF格式由文件头、字体索引表、字体偏移量表、字体点阵四部分组成。 * n2 z$ J8 T. p" p, O; H
1 Z; i& A# D$ u& C2 L
1. 文件头(32字节) ( f8 S9 K; H9 O P# c
$ X; L0 ]$ R) R' D
字段
8 H, E* T- o% s W' X 数据长度 U* A1 k2 H" d" {! L
描述
4 t7 I: ~( k7 R* X: @6 l0 m1 E
, h$ R% J0 i T6 i" {. jCharnum
" B% ^3 U; t0 \ Long(4字节) 2 Q3 d+ {- ]5 ?( ]
字库中字体个数 * x) _! p+ d, l2 v4 J, f4 Z
; i3 B: p: U1 U. U- a `& f% @7 U, ^ d
fontsize
6 w) k- G* K" Z9 p' L9 }. D Long(4字节) ! T" \) ~. r" m* ^8 T
字体点阵部分的数据长度 ! g. G3 q0 n1 F& l6 @ I: D) h( a
0 v. G7 D/ k4 q: SMaxWidth ) C+ h& [+ _) R- ~% M+ p
Long(4字节)
7 t) p7 S0 ]% O: M0 Q+ @ 字体最大宽度 % Z, r' r3 r. {! i9 v" U+ O
5 x! f. D7 e* k) g- d. ZMaxHeight
5 s6 j5 z$ L5 p* e% a T8 Y Long(4字节)
- k% O, G# }) M. x( |; v, w 字体最大高度
9 f# s1 r9 S( N) g( [
- y0 O2 b4 Z- W* x5 @9 X1 ^. BUnknown ) F0 ~" Z: A, v& Z
Long(8字节)
' U6 m0 F1 L, z) {7 u( [ 未知
9 a$ x- L+ u4 z ' j9 Z3 e0 h+ X6 j
FirstChar
6 D& \1 I0 X/ w# T5 O, B# J Long(4字节)
$ d1 V0 K. k) R8 o# [: Q 第一个字符编码 ! M3 d) k$ n9 c; F, z9 _
( K) s+ h' d/ O. h$ o2 y) VLastChar ' J5 m8 M- @* o" {4 d9 t
Long(4字节) % t4 ^) ]& b1 A+ `1 E h+ Q
最后一个字符编码 3 v( Y2 d6 j; P' L z
7 J9 F4 f2 y1 t" h ^1 `
, c4 E; m' I3 p! Z3 D3 k7 H
H$ \% z# W0 l5 E( M: [
0 @6 c7 |& M) B. j) H# n! D! `2. 字体索引表 / ?9 Q" L: y! m6 V7 {% F
- [; z: x6 v. Y% G0 d9 Y F% M! X$ ^3 h与字体编码范围相对应,每个双字节保存一个字模在偏移量表中的偏移量。如GF的英文字库是显示ASCII码表中0-FF的字符,所以有256个字模,字体索引表有256*2 =512字节。保存内容为这256个字模在字体偏移量表中的偏移量 ' m" M- Q6 i' c9 J/ p
/ \: r! `+ M* D7 R2 x8 `: W: P* W4 u
3. 字体偏移量表(与字体个数一一对应)
/ L/ v& j% o0 z0 R/ f! m5 B4 r$ ]
字段
+ a6 ]4 b6 Y: m& r 数据长度 / O: B3 Z! H1 E/ o' C
描述
# M% g6 J; k. d8 `3 `6 {
: h: q e$ j5 o5 c- j9 _" M% ~Offset
# [$ v7 L3 e( F/ q2 v( B Long(4字节)
' q6 ~9 v3 P7 F8 M: h. V7 v) p, G$ {$ z 此字模相对字体点阵的偏移量
4 o! K. Y4 E8 z5 f# R 1 M/ @ ~, t* ~7 w# P) g$ [) M
Unknown % E% d1 v/ }3 {3 `4 j6 p
Long(4字节) 7 x& }* P1 V9 l R' P# _, p
未知
8 x, r# {) l2 s* C* p& a. d
6 M3 ?1 J3 ~# o$ b/ p, r% GWidth
2 n" K a; K$ O% c& K4 L Long(4字节)
. Q& m5 Q2 V+ A& q5 q' [+ w 字模宽度 & D7 v" P% y( ?, X/ @" g
$ D& q6 @1 \9 g4 P! |, c$ q' ~Height & L% \% w( w0 K; b
Long(4字节)
7 Q% }) A' k6 x 字模高度
* @* U% @( T/ U" ?/ r
H( F n# e ^/ h# w! L+ `: y0 s$ Q7 h7 s5 g( G
/ P' X$ ` l3 G* P
: o k0 D$ i$ h4. 字体点阵 4 X1 [& u' Y- R& _
% i3 }+ X8 W* s' x Q/ s" e) Z
保存字体点阵。字体点阵的保存顺序是,从左到右,从上到下。0代表无点,ff代表有点。(这是GF点阵与一般字体点阵的区别,一般字体点阵一个二进制位的1代表一个点,但是GF的字库0xFF才代表一个点)。
- L8 |7 g6 v' _; z4 Q# O# s
6 H! }# F' c( s2 z现在举一个GF中的点阵的例子,下图是GF中汉字“选”的点阵,可以基本看出字形吧,每个汉字都要做成这样的点阵加入到字库中去。
& q, h$ K# J5 s2 R, F
( ?3 A! k7 U- P/ f2 _+ S
! C4 |4 a. f$ n
, I7 R+ H, g4 g% X9 a9 U B
2 |% D& p) k; _9 d& F) a( n+ C现在举一个例子,说明GF程序如何显示一个英文字母N。(N的ASCII码是0x4E) . B( K0 f. c6 y
* }" s5 w3 ^/ _7 C
1. 在字体索引表中找到字模在偏移量表中的偏移量。读文件32+4E*2 = 0xBC处的双字,得到偏移量4E。
( @; }7 v0 O+ t) t( n5 \, L! ~$ o! F$ _" W& Y) S
2. 在字体偏移量表中得到字体点阵的偏移量。读文件32+512+4E*16 = 0x700处得到字体点阵的偏移量0x17c0,再读0x708h得到字体N的宽0x0A,再读0x70ch处得到字体N的高0x0C。
l5 b8 a& y$ Q* w S' m9 p3 Y
@* X8 [7 ~9 P' v3. 读字体点阵显示字符N。字体点阵的首地址为16*256+512+32 = 0x1220H。字体N的点阵部分是在文件0x1220H+0x17c0H到0x1220H+0x17c0H+0D*0A之间。
6 v& H @, |1 j8 w
t7 Q z! D+ |( s, n! J0 ?7 l
5 P' H+ p& D9 A+ n9 y2 f
- h* d" @9 a! C* w! H Y汉字编码GB2312-80简介
2 ^; \/ d0 m8 S
' a# p( {& r( o2 fGB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。
4 g6 f+ u1 g/ W7 O4 h" p# V* b5 ~- |+ X/ Z- g( t0 P
GB2312收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。
6 Q2 |% m2 C) U0 ]7 F
2 o# F K& ~& d5 E! ^ GB2312将代码表分为94个区,对应第一字节;每个区94个位,对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区,10-15区、88-94区是有待进一步标准化的空白区。GB2312将收录的汉字分成两级:第一级是常用汉字计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排列。故而GB2312最多能表示6763个汉字。 4 N; f: t' a5 T" s& y# `
4 ^, e0 w/ w( F2 A& t/ A: jGB2312的编码范围为2121H-777EH,与ASCII有重叠,通行方法是将GB码两个字节的最高位置1以示区别。 ) T; v$ v) O) b( t' z- d: @
. a7 ? H- H; C& G4 j ^- z改造字库
p: y- g# l9 X+ l( |; ~3 [0 H( Y
% `; {" j/ K- A% `我们现在要做的就是将GB2312中的6763个汉字加入到GF的字库中去。汉字点阵定为16*16。因为游戏中仍要部分内容要以英文方式显示,所以我们加入汉字并不应该破坏原有的英文点阵字库,而是应该在英文字库尾部追加这6763个汉字。 + n9 u0 i* X" E+ D# D4 }& b
1 d+ p; F+ N. Q+ U0 f
1. 首先要修改文件头部分,每个字段都要做相应调整。 / |6 M1 k; v& C3 v/ p
u' g* @! Z* @
2. 由于汉字编码范围是2121H-777EH,所以字体索引表至少要扩大为777E*2个字节。索引表的内容前512字节为原始的英文字体索引表,应该保留。在此之后,凡遇到字体索引表中GB2312汉字编码处是汉字的位置,添加汉字在字体偏移量表中的偏移量。汉字偏移量应该从0x100开始(前256是英文字库) , R" C2 `) T6 V( ?, d4 y7 Q
- R, U# _9 |4 `9 V/ M
3. 重建字体偏移量表,将6763个汉字在字体点阵的偏移量、汉字宽0x10,汉字高0x10写入。 ( V/ p& {" B: {7 v- o
2 w/ p3 m8 K% X5 m' l/ j8 D4. 将6763个汉字的点阵追加到原来英文点阵的尾部。 . `( a8 g; j; W. \
/ ^4 Z+ I3 a+ V* ?3 l; U经过以上4部,字库改造完毕。虽然修改只有4部分,但是每部分都涉及到各种偏移量的计算,多字节高低位的读取等、文件头的再修改等步骤,代码实现起来非常麻烦,稍有不甚就会失败,甚至导致GF运行时直接崩溃,调试时需要特别的耐心才行。 6 w+ r( ?! p; U G- O5 R
; a# u' M5 z) t X; ?* I0 |
在生成新的字库后,把新字库覆盖掉原来Data000.LAB中的同名字库文件,字库的修改就大功告成了。 |