现在的游戏大部分是用矢量字体了,但以前的游戏一般都是用点阵字体。下面先介绍一下点阵字体显示原理。 2 [3 Y2 w7 B4 a
5 G. V f: G+ o+ h t) S- @ ]
汉字内码
. o. `6 X" J: v, W 点头表示什么?是“对”、“YES”,偏偏有的地方表示的意义却恰恰相反。一个动作,有不同的诠释;一个问题,有不同的答案;而一个符号,却有不同的意义,关键在于:你是如何地理解。在电脑中亦如此,所有的数据都是以0和1保存的,按不同的数据操作,可以得到不同的结果。对于显示英文操作,由于英文字母种类很少,只需要8位(一字节)即可。而对于中文,常用却有5000以上,于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码。
$ Q, T5 O8 v1 k, |% t/ q; e$ v9 a& Q$ L4 P: [. V
汉字字模
3 C& J) A8 @$ g9 h0 t B% d$ | 得到了汉字的内码后,还仅是一组数字,那又如何在屏幕上去显示呢?这就涉及到文字的字模,字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状,如英文的'A'在字模中是这样记载的:
" w' l0 L/ Q7 H! K! g3 l4 O1 l; C2 h
1 g, l6 j+ l1 B& o. l2 L
& D- @: s Y7 y8 z$ f- _# ~0 `- o& L6 R' [% [+ F& m
9 x9 }1 b1 ]8 z8 Y; u9 y3 t+ [
而中文的“你”在字模中却是这样记载的:
9 G) _: \, M4 B/ C: q. A" S & f! P. x7 A' ^& Z- }, W2 D: o# j$ d
! l& x& Q6 A) d, |5 `
7 K9 z- U" j; z; |4 s6 T' H- J8 \1 V! ~' k4 ^6 V1 ?# J
所有的汉字字模组成点阵字库,像以前Dos下常用的Ucdos汉字系统就是用的点阵字库,点阵字库根据不同需要有好多种尺寸,如16*16 24*24,点越多显示的字越细致,特别是显示那些笔划比较多的字,效果越好。
# c1 l; M, r! I, g5 O! ~
$ f$ X% j; E. B; j Z s/ q: `) F下面进入GF字体的世界,GF的字体扩展名是.LAF,都打包存储于Data000.LAB文件中。先分析一下LAF的文件格式,然后再讨论如何在字库中加入中文。LAF格式由文件头、字体索引表、字体偏移量表、字体点阵四部分组成。 . u9 t/ l/ _. b: b% X4 O: X( l
2 Q ~5 u) j* R' q" O$ `" }1. 文件头(32字节) ! U. I( a: X$ B( g
/ f: F* f' U5 @8 N字段
% Y9 k1 c, _9 s 数据长度
& g# ]- x6 {/ U; Q1 Y; j 描述
' o& i/ o v9 E
$ I. a8 L1 R% |: ACharnum x8 j; Q. |4 Y' F
Long(4字节) . H' @- X1 T5 _+ ` |/ V8 j
字库中字体个数 q$ h, A5 ]9 l7 R: V( b+ {
0 k7 e" X8 k" @ z' m3 J' d
fontsize " E9 s) ]6 h. q, e$ G
Long(4字节)
# A, p) U4 l. y( c p2 N' W5 { 字体点阵部分的数据长度
4 T" i" T$ _& [6 t 7 R- c4 L3 q; Z1 t0 p0 s
MaxWidth
3 q7 d m' i$ ^! M P; ` Long(4字节)
& Y7 @, F3 s' p) l" m1 L$ U 字体最大宽度 4 o& @3 X! c# M* P1 T
9 V. E, Y- {4 y% e+ M( s+ KMaxHeight
7 h3 D/ d0 ]+ J% z. [% Q Long(4字节) 3 T" ]& @+ V7 |3 z: J8 X
字体最大高度 " G: A/ V4 f5 K- @: F+ e( R
2 [1 ^: o- g! j: x% z4 I
Unknown
! G5 g6 Q" S! g Long(8字节) ( o& U% y8 B- o' c6 A
未知
\& g: u& Y0 m1 O& N: J- a6 B# ?
0 R6 O$ l5 K. ], E' t5 T' i- @. bFirstChar ; E- x' Z& Z4 k8 _ @
Long(4字节)
% i- w# k$ l/ p3 K6 R+ x 第一个字符编码 $ b7 z4 m; V- K
+ n+ i V7 l9 |/ YLastChar
4 o9 ]$ G* u; p8 Q* R" t* L( j Long(4字节)
0 M2 {0 h7 R# [6 F; z 最后一个字符编码
; m: o: h, D" R9 z/ F+ {! B* _9 D) O
2 A, f- q& R: g1 Y7 L) A* {6 M7 e: I0 ^# S5 i9 }/ y+ ~
- g" L* c' i& r ~! U
) }) V5 F* D5 E. t1 A0 \8 D2. 字体索引表 3 z8 ~2 O+ |% _4 Q9 z
! i6 H) o7 Q- X与字体编码范围相对应,每个双字节保存一个字模在偏移量表中的偏移量。如GF的英文字库是显示ASCII码表中0-FF的字符,所以有256个字模,字体索引表有256*2 =512字节。保存内容为这256个字模在字体偏移量表中的偏移量
' W4 d/ l/ c7 x' i% g3 T4 w. ]8 N, x9 S4 [0 I& G) p: g6 J# p
3. 字体偏移量表(与字体个数一一对应) : p2 b( _+ P) N8 `! Z& j
: u; ^# U! V# u) o5 P字段
' H: r+ Q& n& w4 x5 G$ t0 M 数据长度
4 C' Z9 |/ y; _: T6 l+ N 描述 - |/ Y* _ s1 r. k6 o
; B3 p( i+ c2 MOffset
7 X% }( m2 j3 q% @! u! {7 o1 Q2 t Long(4字节) 7 M7 g$ G; a- U* v! l4 T
此字模相对字体点阵的偏移量 4 z0 O0 ~# g& q% Y4 E+ f1 v
4 C$ C. E7 B0 \5 D; s% ^
Unknown & _# A7 y4 G8 z1 w- X2 N% o- Q1 l
Long(4字节)
5 Y; m& X k1 R 未知
: X* c; B) L9 n; p$ m ; s, g- I q, A* {
Width , j4 w3 p0 j5 R( l- x
Long(4字节) ' _ r- m# A) e$ t$ @; R8 @6 W1 i$ y4 h
字模宽度 & G0 ^& h1 o" s7 u
0 t6 x( r& u6 b/ N
Height
7 g o2 s: ^6 {8 } Long(4字节)
3 M* `" \1 A6 U, Z o8 H0 C1 u* p 字模高度 1 M$ F* S- |. @
: |) V2 ~- |/ O
& b% p' I+ ?2 c) y2 G
. C% ]) ^6 x' v; J& E( Y: X' B, ~4 Q# t3 y5 i: n* N% Y
4. 字体点阵
( [: x, I$ B0 Y+ B
: W: q3 m! s+ \3 ?0 g& |2 Y保存字体点阵。字体点阵的保存顺序是,从左到右,从上到下。0代表无点,ff代表有点。(这是GF点阵与一般字体点阵的区别,一般字体点阵一个二进制位的1代表一个点,但是GF的字库0xFF才代表一个点)。
2 H. o h' N2 F; E3 i9 [1 W; O
+ r2 f2 |! {+ F6 {现在举一个GF中的点阵的例子,下图是GF中汉字“选”的点阵,可以基本看出字形吧,每个汉字都要做成这样的点阵加入到字库中去。 2 p9 t0 B4 k$ @! I
3 c6 u/ M8 M% W. c+ H3 H0 s* [2 b) H) ~- E. t
; l+ ` `0 D# b w
* ]+ l0 T. A$ }2 U& `( f3 G现在举一个例子,说明GF程序如何显示一个英文字母N。(N的ASCII码是0x4E) 0 G6 m$ ]: \) ?$ q. Y: _7 o
5 m A( l, x2 ]7 I* h3 a1 a
1. 在字体索引表中找到字模在偏移量表中的偏移量。读文件32+4E*2 = 0xBC处的双字,得到偏移量4E。
' a, M" ~# R+ s$ b5 M$ |4 ?, i0 k$ x4 f+ U9 f
2. 在字体偏移量表中得到字体点阵的偏移量。读文件32+512+4E*16 = 0x700处得到字体点阵的偏移量0x17c0,再读0x708h得到字体N的宽0x0A,再读0x70ch处得到字体N的高0x0C。
+ e( \) [' }' o9 n5 h
( {/ C' [. x) C _" L3. 读字体点阵显示字符N。字体点阵的首地址为16*256+512+32 = 0x1220H。字体N的点阵部分是在文件0x1220H+0x17c0H到0x1220H+0x17c0H+0D*0A之间。 3 z7 t8 j$ N7 d
T/ ^3 g' [" W* F8 Y, B2 `, M+ B
8 H/ Z# F# V+ Y. S; v1 _% ]. @2 z# e& `: G- l# _
汉字编码GB2312-80简介
% h+ H1 i l `0 a
+ w7 G( l( c' i; X' [2 m- iGB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。
5 p9 `3 l7 f$ ^" s$ e
6 T3 R/ L7 T @# q GB2312收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。
/ |- d. b( z9 A, K! m8 h( a
3 l) F8 R* R. M; u GB2312将代码表分为94个区,对应第一字节;每个区94个位,对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区,10-15区、88-94区是有待进一步标准化的空白区。GB2312将收录的汉字分成两级:第一级是常用汉字计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排列。故而GB2312最多能表示6763个汉字。
. f" t" P/ r! z* e- _# @
1 ^+ _& G3 k. T) F+ EGB2312的编码范围为2121H-777EH,与ASCII有重叠,通行方法是将GB码两个字节的最高位置1以示区别。 1 S r& u5 l3 u( T( p
8 |0 K$ g2 A0 J+ j0 A5 |/ f/ a& A改造字库
# N+ ~* z d( S% i S: _+ Y7 o5 w. T& I+ N
我们现在要做的就是将GB2312中的6763个汉字加入到GF的字库中去。汉字点阵定为16*16。因为游戏中仍要部分内容要以英文方式显示,所以我们加入汉字并不应该破坏原有的英文点阵字库,而是应该在英文字库尾部追加这6763个汉字。
! p" H7 w% K, p, ~3 M
: ~+ M) o% B' y: j/ a( C }# E1. 首先要修改文件头部分,每个字段都要做相应调整。 + M4 R: ^$ V2 w: g
, w( t% \/ ^' I5 G, l2 D2. 由于汉字编码范围是2121H-777EH,所以字体索引表至少要扩大为777E*2个字节。索引表的内容前512字节为原始的英文字体索引表,应该保留。在此之后,凡遇到字体索引表中GB2312汉字编码处是汉字的位置,添加汉字在字体偏移量表中的偏移量。汉字偏移量应该从0x100开始(前256是英文字库)
8 E8 X/ o* w; }( |
0 y4 d5 L- n. L+ Z$ _0 C: |3. 重建字体偏移量表,将6763个汉字在字体点阵的偏移量、汉字宽0x10,汉字高0x10写入。 / O( |5 o% T* @& \$ X& e. Y/ L
; Y4 u$ h/ c0 f- z2 \! ?+ O2 X
4. 将6763个汉字的点阵追加到原来英文点阵的尾部。 / \: _1 r/ s/ \5 Q+ _: J
. S$ H# B9 a2 D+ C8 N, K" o经过以上4部,字库改造完毕。虽然修改只有4部分,但是每部分都涉及到各种偏移量的计算,多字节高低位的读取等、文件头的再修改等步骤,代码实现起来非常麻烦,稍有不甚就会失败,甚至导致GF运行时直接崩溃,调试时需要特别的耐心才行。 ; a0 e7 i6 u# A; t
1 g9 k1 j# X1 I" _
在生成新的字库后,把新字库覆盖掉原来Data000.LAB中的同名字库文件,字库的修改就大功告成了。 |