屏幕图象界面的艺术处理 王 涛 1995-01-06 软件用户界面技术已经成为计算机技术中的一个重要分支,它除了计算机专业知识外,还包含了图形学、美术学、心理学等多种学科知识,是一门综合技术。良好界面的重要性也越来越引起人们的重视。对于一个用户来说,他所使用的软件首先呈现在他面前的是软件的界面,界面的好坏将会直接影响到用户的使用兴趣。正如现代社会的商品非常讲究包装、装璜一样,一个优秀的软件其界面也必然是很优秀的,这个软件也一定更易于推广、使用。良好的用户界面往往会给用户带来很美的艺术感受,使用户兴趣大增。对于软件开发者来说,若对软件的用户界面、软件封面等进行一些艺术化处理,构筑一个优美良好的界面环境,无疑会对整个软件起到画龙点睛的作用,收到极好的效果。下面就谈一谈这方面的一些问题。 二、VGA 13H模式的硬件特性 要设计出一个好的用户界面,需要有硬件和软件两方面的支持。对于硬件来说,PC机的图形显示系统经历了MDA、CGA、EGA、VGA等几代产品的发展。早期的显示系统分辩率低、 颜色数少、功能单一,不能满足用户日益增长的需求,随着EGA的出现使PC显示系统进入了一个新的领域。 特别是后来推出的VGA显示系统,以其丰富的色彩、较高的分辩率、良好的兼容性和优越的性能,现在已经成为了PC机的显示标准。 标准VGA可以支持19种显示模式,最高分辩率达到640×480,最多可显示256K种颜色。其中模式13H分辨率为320×200, 可同时显示256种颜色,此模式下的图象丰富、自然、逼真,与普通彩色照片显示质量相差无几,所以受到越来越多的人的喜爱。众多软件开发者也在此模式下开发了大量的软件。本文就以此模式为基础,介绍在此模式下对屏幕图象界面进行艺术化处理的一些设计方法。 首先,介绍VGA 13H模式下的屏幕缓冲区。 VGA 13H模式采用线性内存结构,屏幕缓冲区起始地址为A0000H, 共占用64K字节。屏幕上所有象素按屏幕从左到右、从上到下与屏幕缓冲区地址形成一一对应。每个象素对应1个字节(8位),其ASCII值即为该象素所取的颜色号(0~255),因此,同一屏可显示最多256种不同的颜色。 VGA的另一个重要特性是数模转换器DAC。DAC是VGA所特有的寄存器, 它能将色彩数字信号转换成模拟信号以驱动VGA的模拟显示器。因此VGA的色彩变化可以非常平滑, 很适合人的主观视觉感受。通过对DAC编程能够获得较为逼真的色彩效果。 DAC包括三个转换寄存器(红、绿、兰各一个)。分别控制红、绿、兰三种基色的亮度值 (RGB值) 。每个寄存器占6位, 其亮度范围为0~63,3个寄存器组合总共可以配制643(266144)种颜色。同时,DAC必须从查色表中取得颜色编号以决定屏幕当前颜色,而查色表占8位,DAC一次只能从查色表中转换28(256)种颜色。所以DAC虽然能够配制643种颜色,但只能同时选取其中的256种颜色在屏幕上显示。 对DAC的编程方法通常为I/O端口操作和BIOS功能调用,由于端口操作速度快,所以本文采用这种方法。DAC所使用的几个端口是: I/O地址 寄存器 3C7 查色表读索引寄存器 3C8 查色表写索引寄存器 3C9 查色表数据寄存器 当向端口3C7写入一个8位索引值(代表颜色号),再从端口3C9读出3个6位值取得该颜色号的RGB值。当向端口3C8写入一个8位索引值(代表颜色号) ,再向端口3C8写入3个6位值就相当于设置了该颜色号的RGB值。色彩变化就会立即显示在屏幕上。 综上所述,要显示一幅VGA图象, 必须先定义各个彩色寄存器之值并写入DAC,然后再将图象数据送入屏幕缓冲区即可。 三、艺术化处理屏幕图象界面的方法、技巧 了解了以上知识,我们就可以设计出一些具有艺术化效果的屏幕图象界面了。下面分几个部分介绍其设计方法和编程技巧。(所用语言为TURBO PASCAL 6.0, 读者也可用其它语言如C语言、汇编语言编写) (一)汉字的显示: 关于西文图形模式下的汉字显示,不少报刊都有过介绍,但大都是针对12H模式,即16色640×480分辩率模式。13H模式下的汉字显示比较容易实现,根据其屏幕缓冲区特性,可以知道,屏幕上坐标为(X,Y)的某个象素其对应的屏幕缓冲区偏移地址为:VADDR=320×Y+X。要在屏幕上显示汉字,只需将汉字的字模数据读出,依次取出各位,根据上面的公式,若值为1,则将汉字颜色值写入对应缓冲区地址;若为0,则将背景色值写入对应地址,重复若干次,即完成一个汉字在屏幕上的显示。由于直接对存储器操作,所以显示速度非常快。 下面给出实现汉字显示的源程序: const get-point:array[1..8]of byte =(1,2,4,8,16,32,64,128); type hf=record re:array [1..32] of byte; end; PROCEDURE SHOWHZ(X,Y:INTEGER;HZSTR:STRING;color,bcolor:byte); BEGIN cc:=1;addr:=(y-1)*320+x+16; while cc0 then addr:=addr+320-16; for j:=8 downto 1 do begin pp:=getpoint[j] and cn.re[i]; if pp=getpoint[j] then mem[$a000:addr]:=color else mem[$a000:addr]:=bcolor; addr:=addr+1; end; end; cc:=cc+2;addr:=addr-16*319; end; END; VGA 13H模式下的汉字显示, 虽然分辨率不太高,但颜色丰富、编写简单,所以非常适用于进行软件封面、图象界面的设计。利用上述方法,还很容易实现汉字放大、立体空心、旋转、倾斜等修饰功能,将会使用户界面变得更加非常美观、醒目。 (二)图象的存储、显示: 了解了VGA 13H模式的一些特性后, 我们可以自己编程设计一些图形、图象,但是手工编程往往比较复杂,效率不高,而且并不是人人都有较高的美术基础。另一方面,我们发现, 现在不少的软件如一些游戏软件中大都采用了VGA 13H显示模式,且不少图象都是利用扫描仪输入生成的,画面相当优美。如果我们充分利用现有资源,将这些图象画面以文件形式保存下来,加在我们自己设计的软件中,作为软件封面、菜单背景等,这样呈现在用户面前的屏幕将是充满了情趣、亲切感的。 下面谈谈对图象进行存储、显示的设计方法。 1.图象的存储: VGA 13H模式下的图象存储较容易实现。可以事先编制一个TSR内存驻留程序,程序运行后,遇到需保存的画面时,按下热键,击活程序,首先将当前DAC的256种颜色值保存到文件中,然后将屏幕缓冲区中的数据共64K保存到文件中。 由于内存驻留技术已很成熟,所以下面只给出实现图象存储过程的程序: var pav:array[1..768] of byte; procedure savepic; var f1:file; result:integer; begin assign(f1,name); rewrite(f1,1); port[$3c7]:=0; for i:=1 to 768 do pav[i]:=port[$3c9]; blockwrite(f1,pav,768); blockwrite(f1,mem[$a000:0000],64000,result); close(f1); end; 2.图象的显示: 图象显示实际上是图象存储的逆过程,实现起来并不复杂。但是如果将图象数据直接送屏幕缓冲区显示图象会显得很单调、呆板。如果我们将其显示过程作一些艺术化处理,采用动态过程显示,将会大大增强屏幕画面的美学艺术效果。笔者在工作中,摸索出这方面的一些技巧,现总结出以下几种方式: ①淡入、淡出式 淡入、淡出显示技术是一种极具艺术效果的特技显示技术,现被很多游戏软件所采用。淡入是指图象由最暗逐渐增强亮度和饱和度,产生出图象由远至近,由暗到明缓缓升起的效果,非常生动、鲜明;而淡出则是淡入的逆过程,图象由明至暗逐渐消隐,直至消失。 实现淡出的基本思想是,将当前DAC数据读取到缓冲区中, 然后将缓冲区中DAC数据的RGB值分别减1,再重新设置到DAC寄存器中,循环上述过程,直到RGB值全部减为0为止。淡入的实现过程则相反,首先将DAC数据置为全0,然后将RGB值分别加1,重新设置到DAC寄存器,循环上述过程,直到RGB值等于原DAC中的RGB值。 按照上述方法在具体实现过程中发现,淡出过程完全正确,而淡入过程不十分理想。经过和淡出过程对比分析后发现, 淡入不理想的原因在于初始DAC值全为0,递增加1时是RGB值同时加1,结果成了每一种颜色的RGB值都相同,达不到原来DAC色彩的正常变化。所以正确的方法应该是, 先比较每种颜色RGB值的大小,只有最大值的那种基色才加1,重新设置到DAC寄存器,然后再将最大值减1,重复上述过程,直到RGB值等于原DAC中的RGB值。可见,在编程时,淡入过程并不完全是淡出过程的逆过程,还需要加一些修正语句。下面给出实现上述方法的源程序: type bt=array[1..64000]of byte; var dac,plate: array[1..768]of byte; i,j,k,m:word; f1:file; result:integer; picdat:^bt; procedure vgaload; {图象数据送缓冲区} begin port[$3c8]:=0; for i:=1 to 768 do port[$3c9]:=0; move(picdat^,mem[$a000:0],64000); end; procedure appear(ytime:word); {淡入过程} var r,g,b:word; rok,gok,bok:boolean; begin for i:=1 to 768 do plate[i]:=0; for j:=0 to 63 do begin for i:=0 to 255 do begin r:=i*3+1;g:=i*3+2;b:=i*3+3; port[$3c8]:=i; port[$3c9]:=plate[r]; port[$3c9]:=plate[g]; port[$3c9]:=plate[b]; if (plate[r]=dac[b]-plate[b])  and (dac[r]>=dac[g]-plate[g]) then rok:=true else rok:=false; if (plate[g]=dac[r]-plate[r]) and (dac[g]>=dac[b]-plate[b]) then gok:=true else gok:=false; if (plate[b]=dac[r]-plate[r]) and (dac[b]>=dac[g]-plate[g]) then bok:=true else bok:=false; if rok then plate[r]:=plate[r]+1; if gok then plate[g]:=plate[g]+1; if bok then plate[b]:=plate[b]+1; end; delay(ytime); {延时} end; end; procedure disappear(ytime:word); {淡出过程} begin for j:=63 downto 0 do begin for i:=0 to 255 do begin port[$3c8]:=i; port[$3c9]:=plate[i*3+1]; port[$3c9]:=plate[i*3+2]; port[$3c9]:=plate[i*3+3]; if plate[i*3+1]>0 then plate[i*3+1]:=plate[i*3+1]-1; if plate[i*3+2]>0 then plate[i*3+2]:=plate[i*3+2]-1; if plate[i*3+3]>0 then plate[i*3+3]:=plate[i*3+3]-1; end; delay(ytime); end; end; ②百页窗式 此方式是模拟百页窗,将图象画面划分成若干个平行横栏,然后象拉百页窗一样,一栏一栏地将画面展开,直到画面占满屏幕。画面清除过程相反,尤如关闭百页窗一样,一栏一栏地消失。 此方式非常美观,富有情趣。源程序如下: procedure bwin; begin {展开} for i:=0 to 9 do begin for j:=0 to 19 do for k:=0 to 319 do mem[$a000:(i+j*10)*320+k]:=picdat^[(i+j*10)*320+k+1]; delay(180); end; ch:=readkey; for i:=0 to 9 do {关闭} begin for j:=0 to 19 do for k:=0 to 319 do mem[$a000:(i+j*10)*320+k]:=0; delay(280); end; end; ③帷幕落下式 此方式是模拟舞台帷幕落下,画面从屏幕顶端冒出,自顶向下,逐渐平滑下落,直至屏幕底端。此方式生动、形象。源程序如下: procedure screendecline; begin for i:=0 to 199 do begin for j:=0 to i do move(picdat^[(199-j)*320+1],mem[$a000:(i-j)*320],320); delay(40); end; ch:=readkey; end; ④雨点下坠式 此方式模拟雨点落下,画面自顶向下下落过程中,尤如流星雨样,每一个象素均有一长长的尾巴拖动痕迹,直到下坠至屏幕底端。 此方式极具动感效果,非常醒目。源程序如下: procedure raindrop; begin for i:=199 downto 0 do begin for j:=0 to i do move(picdat^[i*320+1],mem[$a000:j*320],320); delay(20); end; ch:=readkey; end; ⑤中心展开式 此方式下,画面自屏幕中心逐层向四周展开,直至充满屏幕。有一种由远至近、由小变大的视觉感受。源程序如下: procedure spread; var x,y:word; begin x:=160;y:=100; for i:=0 to 100 do begin for j:=x-i to x+i do mem[$a000:(y-i)*320+j]:=picdat^[(y-i)*320+j+1]; for j:=x-i to x+i do mem[$a000:(y+i)*320+j]:=picdat^[(y+i)*320+j+1]; for j:=y-i to y+i do mem[$a000:j*320+x+i]:=picdat^[j*320+x+i+1]; for j:=y-i to y+i do mem[$a000:j*320+x-i]:=picdat^[j*320+x-i+1]; delay(50); end; for i:=101 to 160 do begin for j:=0 to 199 do mem[$a000:j*320+x+i]:=picdat^[j*320+x+i+1]; for j:=0 to 199 do mem[$a000:j*320+x-i]:=picdat^[j*320+x-i+1]; delay(50); end; ch:=readkey; end; 四、结束语 高性能的VGA显示系统为我们提供了良好的硬件基础, 在此系统下,将软件中的屏幕图象界面作一些艺术化处理,将会使界面更加美观、生动、形象、友善,增加了用户的使用兴趣,使软件更具魅力。 本文对此在方法和技巧上作了一些探索,由于水平有限,不妥之处在所难免,目的旨在抛砖引玉,相信读者只要充分发挥自己的想象力和创造力,一定会设计出更多、更美的图象界面,促进软件技术的普及、发展。