栏目搜索
 
 
 
 
 

可移植的256色图形用户界面的设计

作者:不详  来源:不详  发布人:admin  发布时间:2005-10-16 20:18:39

该文从软件可移植性角度指出设计256色图形用户界面时应当注意问题,在对SuperVGA产品进行分析基础上,提出了基于表格驱动程序设计思想,并给出了范例。
随着各种超级VGA出现,同时具有高分辨率和丰富色彩图形用户界面已经成为程序员和用户共同追求目标。然而由于各制造商提供VGA产品之间差异,使得高分辨率256色图形界面兼容性受到影响,常常会出现这样情况:在一个显示系统下运行良程序,在另一种显示系统下变得面目全非,甚至根本不显示。这表明程序员对程序可移植性重视不够,或对各种显示设备缺乏足够了解。
软件可移植性是指软件产品从一个硬件/软件环境转移到另一个硬件/软件环境难易与繁简程度。它从软件对新环境适应性这一方面,反映了软件质量。为了提高软件可移植性,应尽量使软件与具体设备无关,即提高软件设备独立性。对于256色图形界面而言,就是使程序不依赖于某种特定显示器。例,程序员没有任何理由假定用户使用是TVGA。为此,程序员必须提供显示卡常规检测例程,并能根据检测结果决定图形算法具体实现。
提高软件设备独立性方法有很多,表格驱动就是其中一种。所谓表格,就是根据需设计数据结构。表格中数据由检测例程填写。表格中包含哪些栏目,应在对各制造商提供SuperVGA产品足够了解基础上取舍,栏目应体现各产品之间差异。
一、SuperVGA编程综述
SuperVGA产品在体系结构上和标准IBM VGA有所不同。但编程思想基本上是一样,这些编程方法已有许多文章介绍,这不再重复。
影响256色图形界面可移植性障碍来自各制造商提供VGA产品下面几点差异。
1.显示模式定义不同。5DH对TVGA而言,代表640×480
×256色模式,对PVGA而言却代
表1024×768×16色模式。因此,直接用这种模式号初始化显示系统是不可取。和显示模式密切相关是水平分辨率和垂直分辨率。尽管各VGA256色显示模式定义迥异,但都支持下几种流行分辨率,现用统一模式号定义见附表。
@@10A06500.GIF;附表@@
不同分辨率之间区别,体现在编程上就是同一屏幕坐标映射到显存地址不同,但映射机理却是一样。具体地说,坐标(x,y)对应显存偏移地址(相对于A000)为Addr=-vga-width*y+x
2.分页机制不同。SuperVGA使用256K、512K或1M
显示存储器结构。为了使处理器可通过一个64K主窗口来存取这样显示存储器,SuperVGA有一个存储器分页机制,使得只将显示存储器一部分映射到处理器地址空间。值得注意是,不同VGA产品,其页小不同,页起始地址粒度也是可变。具体页选择算法请查阅制造商提供资料。
不同显示模式,显示一屏图像所需页数是不同
除了可移植性外,效率也是一个不可忽视因素。图形系统核心部分应使用汇编语言编程。这不仅是因为汇编语言效率高,而且还因为汇编语言子程序可再用性和可协用性也很。核心部分应十分重视下面几点:(1)减少不必页边界检查次数;(2)只有在必时才进行页选择;(3)选择高效机器指令。现举例说明。程序1是图像显示系统中常用函数,其功能是将解包后图像数据送到显存。为便于阅读同时给出了C语言调用原型。程序在传送每一行数据时,提前预测是否会遇到页边界,果没有,直接传送;果有,则将数据分成两部分,分别传送,中间插入页选择。所有传送均用操作代替节操作。页边界检查只有一次,分页操作只有在必时才发生,图像显示用最高效指令REP MOVSW。
程度1:
;原型:void LineDump(int x,int y, int num, char far*ptr)
;参数:
; x,y-屏幕坐标
; num-本行像素个数
; ptr-指向像素数据远指针
LineDump proc far
push bp
mov bp,sp
sub sp,2;WORD Reserved for local var.
push ds
push es
push si
push di
reserved equ [bp-2];Local var.save seg(DGROUP)
x equ [bp+6];Large Model
y equ [bp+8]
num equ [bp+10]
offs equ [bp+12]
pseg equ [bp+14]
mov reserved,ds
mov ds,pseg
mov si,offs ;DS:SI图像数据所在源地址
mov ax,0a000h;显存段址
mov es,ax ;ES:DI显存目地址
mov ax,y
push ds
mov ds,reserved
mul word ptr DGROUP:-vga-width
pop ds
add ax,x
adc dx,0
mov di,ax ;DI=-vga-width*y+x
mov ah,dl ;进位部分(DL)=页号
call dword ptr cs:-PageSelect
mov cx, num ;本行传送节数
mov bx, cx
add bx,di ;检测传送是否在一个页内
jnc Dump-In-One-Page
sub cx,bx ;CX=本页节数,BX=下页节数
shr cx,1 ;CX/2=
rep movsw ;本页内传送
adc cx,0
rep movsb ;处理可能奇数节数
inc ah ;调整页号
call dword ptr cs:-PageSelect
mov cx,bx ;新页内节数
jcxz Dump-Done
Dump-In-One-Page:
shr cx,1 ;CX/2=
rep movsw ;图像传送
adc cx,0
rep movsb ;处理可能奇数节数
Dump-Done:
pop di
pop si
pop es
pop ds
mov sp,bp
pop bp
ret
LineDump endp
二、表格驱动基本思想
根据上面分析,用以驱动显示系统表格,至少应当包含下列项目:
(1)实际显示模式:vga-mode
(2)水平分辨率:vga-width
(3)垂直分辨率:vga-depth
(4)页选择例程入口地址:PageSelect
(5)当前显示方式所使用页号:vga-pages
这个表格由图形初始化例程来填写。图形初始化例程接收显示模式是统一模式号,这样可以撇开具体设备,InitVGA(TVGA800×600)。该例程调用显示设备检测程序DetectVGA来判断显示器类型,从而填写表格中各栏目,并初始化图形系统为所需图形方式。所有图形算法都查此表。
除了用上述方法来实现兼容外,视频电子标准协会(VESA)为们提供了另一种方法。
VESA
提供了一组附加BIOS功能,这组功能以标准方式访问SuperVGA扩充模式。VESA附加功能都是通过BIOS中断10H4FH功能来实现。VESA子功能01能返回非常有用SuperVGA模式信息,包括分页例程地址。
因此,程序员可以按照VESA标准来编写图形系统,这样程序可以在所有支持VESA显示器上运行。由于VESA包括了世界上VGA供应商,写出来程序可移植性是很。但是,其效率却可能是最低。所以最采用一种折衷办法,对于熟悉产品,可以不用VESA功能,对于不熟悉(资料不全)或检测不出来显示器尝试用VESA提供手段来编程,当然检测显示设备是否支持VESA。
有时出于某种考虑,不希望支持所有显示设备代码集中在一个程序中,可以为每个显示设备分别提供驱动模块,主程序根据检测结果选择一个合适模块加载。BorlandC++就是这样,它有一套BGI驱动程序,各驱动程序提供统一图形函数接口。笔者在实际工作中,为每一种显示设备编写了一个256色BGI格式驱动程序,这样,在编写图形系统时,再也没有必考虑用户实际显示设备了。
三、范 例
本文附有两个图形显示例子。ShowGif能显示16/256色GIF格式图像,能以任何256色模式启动,支持多种显示器。图像可以漫游,并可随时通过按键切换显示方式。Main则是一个BGI驱动鼠标/键盘控制256色汉图形菜单。它自己会挑选一个合适BGI,也可以从命令行指定一个BGI(比指定VESA256给TVGA显示器)。
限于篇幅,这仅给出有关数据结构和部分函数说明(程序2)。然后给出一个初始化显
示系统C语言片断(程序3)。
程序2(TVGA256.H):
/* 统一模式集 */
enum TVGA-MODE
TVGA320x200=0,
TVGA640x400=1,
TVGA640x480=2,
TVGA800x600=3,
TVGA1024x768=4,
;
void TVGA256-driver(void);
void PVGA256-driver(void);
void AVGA256-driver(void);
...
void VESA256-driver(void);
extern int far-Cdecl TVGA256-driver-far[];
extern int far-Cdecl PVGA256-driver-far[];
extern int far-Cdecl AVGA256-driver-far[];
...
extern int far-Cdecl VESA256-driver-far[];
/* 支持VGA集合 */
enum VGAs{
UnKnownVGA,
TridentVGA,
ParadiseVGA,
AheadVGA,
...
VesaVGA
};
/* 对应BGI驱动程序名 */
unsigned char *Drivers[]={
"TVGA256",
"TVGA256",
"AVGA256",
...
"VESA256",
};
extern int DetectVGA(void);
/* 功 能:检测显示卡型号
返回值:0-Unknowm1-Trident VGA2-Paradise VGA
...
x-不能检测出VGA,但支持VESA
返回值同时写入全局变量vga-type */
extern int VesaFound(void);
/* 功 能:检测VESA BIOS存在性
返 回:0-不支持VESA;
其它-VESA版本号(0x0102即1.02版);
返回值同时写入全程变量vesa-found. */
extern void InitVesa(void);
/* 功 能:初始化VESA.根据-vga-mode模式号换算成VESA标准模式号填写页粒度(WinGranularity),页小(WinSize),
和分页例程入口地址(WinFuncPtr)
VESA标准模式解释下:
100h-640x400 256
101h-640x480 256
102h-800x600 16
103h-800x600 256
104h-1024x768 16
105h-1024x768 256 etc.
InitVesa供给InitVGA调用 */
extern void InitVGA(int mode);
/* 功 能:初始化显示系统(自动调用DetectVGA检测显示卡)
参 数:mode=TVGA320x200(0)
TVGA640x400(1)
TVGA640x480(2)
TVGA800x600(3)
TVGA1024x768(4)
返 回:InitVGA没有显式返回值,但它初始化下列全程变量:
vga-mode,vga-width,vga-depth,vga-pages,PageSelect
时自动调用InitVesa
*/
extern int vga-type;
extern int vga-mode;
extern int vga-width;
extern int vga-depth;
extern int vga-pages;
extern int vga-pages;
extern char page-number;
extern int vesa-found;
...
程序3(初始化显示系统程序片断):
...
int GraphDriver, GraphMode;
unsigned char *bgiDriver="PVGA256";
bgiDriver=Drivers[DetectVGA()];
GraphDriver=installuserdriver(bgiDriver,NULL);
GraphMode=TVGA800x600;
initgraph(&GraphDriver, &GraphMode," ");...

参考文献
1 来文占等编译.Super VGA高级编程指南.北京:北京科海培训中心,1991.5.
2 张一波编译.Super VGA与VESA编程指南.北京:海洋出版社,1992.

作者:杨茂林

 
 
  信息栏
 
 
 
 
  相关文章