上次整理以前DOS下的代码,找了个线性回归分析函数,觉得可能还有用,于是放在了《C语言版的线性回归分析函数》中,今天在CSDN的C/C++版,发现居然还有人求DOS下VGA 12H模式下的直接写屏代码,临时找了2个以前的文件,发了出去供参考。后来仔细找了一会,把以前DOS下写的供Trubo C使用的VGA 12H直接写屏图形函数找齐了,还有鼠标和XMS内存管理函数,决定放在这里,供C语言初学者参考。因为这些函数全部都是外部汇编代码文件,比较长,只得分几篇文章存放,由于时间太长,有些代码我自己现在也说不清楚,除个别情况外,本人不对代码作解释,纯粹代码粘贴。这篇文章中存放VGA 12H图形的基本函数和C调用头文件以及全部汇编函数的MAKEFILE。
有人可能说,Turbo C不是有图形库吗,为啥还要自己写图形库?因为Trubo C自带的图形库通用性太强,导致当时DOS下使用它时,速度很慢,所以我写了供自己用的专用VGA图形库,没有考虑通用性,故而速度相当快,现在的机器速度快,使用Trubo C的图形库当然没有慢的感觉了,不过,我认为这些代码对C初学者来说,还是有价值的:首先可以了解VGA12H模式下的直接写屏技术;其次可以掌握C语言与外部汇编函数的相互调用方式;再次,本图形库中很多函数中包含了一些现在的计算机书中很少有的基础图形算法,如任意直线、圆、弧、图形填充等整数算法。
首先给出全部汇编文件的MAKEFILE,该文件名graph.mak:
TASM = Tasm / ml
#
! if ! $d(MDL)
MDL = s
! endif
#
! if $(MDL) == t
TasmComm = / D__TINY__
! elif $(MDL) == s
TasmComm = / D__SMALL__
! elif $(MDL) == m
TasmComm = / D__MEDIUM__
! elif $(MDL) == c
TasmComm = / D__COMPACT__
! elif $(MDL) == l
TasmComm = / D__LARGE__
! endif
#
#
Dep_graph = graph$(MDL).lib
#
Dep_graphdlib =
xms.asm
mouse.asm
grroll.asm
grputch.asm
grimage.asm
grfill.asm
grellip.asm
grbase.asm
grarc.asm
graph.inc
tasm_c.inc
$(Dep_graph) : $(Dep_graphdlib)
del $(Dep_graph)
$(TASM) $(TasmComm) xms.asm
$(TASM) $(TasmComm) mouse.asm
$(TASM) $(TasmComm) grroll.asm
$(TASM) $(TasmComm) grputch.asm
$(TASM) $(TasmComm) grimage.asm
$(TASM) $(TasmComm) grfill.asm
$(TASM) $(TasmComm) grellip.asm
$(TASM) $(TasmComm) grbase.asm
$(TASM) $(TasmComm) grarc.asm
$(TLIB) $(Dep_graph) + xms.obj + mouse.obj + grroll.obj + grputch.obj
+ grimage.obj + grfill.obj + grellip.obj + grbase.obj + grarc.obj
del * .obj
在命令行使用Turbo C的make.exe,可以制造一个TC库文件GraphX.lib,其中X为存储模式,由make命令行的MDL宏指定(缺省为small模式),如制造一个中模式库,命令行为(注:由于10多年没用过这种东西,我的记忆不知道是否正确,如果错误,请原谅):
make -DMDL=m -fgraph.mak
然后给出TC调用的图形汇编函数的头文件,从这个头文件可以看出,在DOS下,不仅TC调用它们,也可供Turbo C++或者Borland C++调用本文的这些函数。需要说明的是,从InitUCDOS开始的函数已经不完全是纯图形函数了,而是与UCDOS有关的字符串显示函数,如果不使用UCDOS,可以将它们以及后面的代码删掉;另外,PutBmp函数只是用来显示16色未压缩过的位图文件的图形数据,没有打开文件功能,本文最后贴出以前的一个测试程序代码:
#ifndef __GRAPH_H
#define __GRAPH_H
#ifdef __cplusplus
extern " C " {
#endif
/* 打开图形屏幕 */
void OpenGraph( void );
/* 以正文方式关闭图形屏幕 */
void CloseGraph( void );
/* 设置图形操作边界, 参数: 左上角 X, Y 坐标, 右下角 X, Y 坐标;
除图像保存, 移动函数外, 所有图形均进行裁剪 */
void SetBorder( int , int , int , int );
/* 使用缺省的屏幕尺寸为图形边界 */
void DefBorder( void );
/* 设置当前作图颜色值为 Value, 返回当前的值 */
int SetColor( int Value );
/* 返回当前颜色值 */
int GetColor();
/* 置写图型屏幕方式(0 - 3), 返回当前的方式 */
int SetDrMode( int Mode );
/* 在(X, Y)用当前色写点 */
void PutPixel( int X, int Y);
/* 返回(X, Y)的颜色值 */
int GetPixel( int X, int Y);
/* 从(X1, Y1)至(X2, Y2)画直线 */
void Line( int X1, int Y1, int X2, int Y2);
/* 从(X1, Y1)至(X2, Y2)画填充矩形(无边界线) */
void Bar( int X1, int Y1, int X2, int Y2);
/* 用颜色从(X1, Y1)至(X2, Y2)画矩形 */
void Rectangle( int X1, int Y1, int X2, int Y2);
/* 保存(Left, Top)至(Right, Bottom)内的图象到 Buf 中 */
unsigned GetImage( int Left, int Top, int Right, int Bottom, void far * Buf);
/* 将 Buf 内保存的图象在(Row, Col)处显示, Mode 显示方式(0 - 3) */
void PutImage( int Row, int Col, void far * Buf, int Mode);
/* 计算并返回保存(Left, Top)至(Right, Bottom)内的图象缓冲区的字节数 */
long ImageSize( int Left, int Top, int Right, int Bottom);
/* 将屏幕区(Left, Top)至(Right, Bottom)垂直移动 N 线, N 上移, -N 下移 */
void Roll( int n, int Left, int Top, int Right, int Bottom);
/* 安装用户掩膜 LnStyle 返回当前的线型 */
int SetLnStyle( int Lnstyle);
/* 安装用户图案 Pattern 及颜色 Color */
void SetPattern( void far * Pattern, int Color);
/* 以(X, Y)为园心, Radius 为半径画园 */
void Circle( int X, int Y, int Radius);
/* 以(X, Y)为园心, RadiusX 为 X 半径, RadiusY 为 Y 半径画椭园 */
void Ellipse( int X, int Y, int Radiusx, int Radiusy);
/* 以(X, Y)为园心, Radius 为半径, Start 为起始角, End为结束角画园弧 */
void Arc( int X, int Y, int Start, int End, int Radius);
/* 以(X, Y)为园心, Radius 为半径, Start 为起始角, End为结束角画扇形(不填充) */
void Slice( int X, int Y, int Start, int End, int Radius);
/* 以(X, Y)为园心, Radius 为半径, Start 为起始角, End为结束角画馅饼形(不填充) */
void Pie( int X, int Y, int Start, int End, int Radius);
/* 以(X, Y)为内点, Color 为填充色, 以当前图案进行区域填充 */
void Fill( int X, int Y, int Color);
/* 改变系统的颜色, Index 调色板号(0-15), Red 红色值, Green 绿色值, Blus 蓝色值
颜色值范围为 0-63 */
void SetPalette( int Index, int Red, int Green, int Blus);
/* 从(X, Y)开始显示位图数据 Bmp */
void PutBmp( int X, int Y, void far * Bmp);
/* 定义字符显示和光标函数 */
/* 判断UCDOS是否启动, 已启动, 关闭UCDOS光标, 重新安装闪烁光标并返回 -1,
否则返回 0, 参数为光标颜色值, 用此值与屏幕异或成实际光标颜色 */
int InitUCDOS( int );
/* 撤消自安装的闪烁光标, 如果flag = 0恢复UCDOS光标 */
void RestUCDOS( int flag);
/* 显示光标 */
void ShowCursor( void );
/* 隐蔽光标, 如多次隐蔽后, 需多次调用 ShowCursor() */
void HideCursor( void );
/* 设置字符坐标点的左上角坐标, 参数: X 坐标, Y 坐标 */
void SetPos( int , int );
/* 返回当前光标处字符的左上角坐标, 参数: X 坐标指针, Y 坐标指针 */
void GetPos( int * , int * );
/* 设置光标状态为插入方式(8*8光标, 缺省)或改写方式(8*4光标), 分别返回 1 或 0 */
int InsertMode( void );
/* 在当前坐标写字符, 参数: 字符, 字符个数, 字符属性(高4位背景色,低4位前景色);
字符为 16*16 点阵, 显示字符后, 不改变坐标 */
void Putch( int , int , int );
/* 在给定的坐标处显示字符串, 坐标超长或遇结束符 0 中止, 返回实际写的字符数,
参数: X 起始坐标, Y 坐标, 字符串, X 结束坐标, 字符属性; 显示后坐标在字符串尾 */
int Putss( int , int , char * , int , int );
#ifdef __cplusplus
}
#endif
#endif
下面是TC外部汇编(TASM)函数通用的插入文件,该文件定义了一些与存储模式有关的宏,包含它的汇编文件可以用TASM.EXE编译成TC的任意模式obj文件:
IFNDEF __TINY__
IFNDEF __SMALL__
IFNDEF __MEDIUM__
IFNDEF __COMPACT__
IFNDEF __LARGE__
DISPLAY " **Warning** You must supply a model symbol. "
__SMALL__ equ 1
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
IDEAL
IFDEF __TINY__
LPROG equ 0
LDATA equ 0
MODEL TINY, PROLOG
ENDIF
IFDEF __SMALL__
LPROG equ 0
LDATA equ 0
MODEL SMALL, PROLOG
ENDIF
IFDEF __MEDIUM__
LPROG equ 1
LDATA equ 0
MODEL MEDIUM, PROLOG
ENDIF
IFDEF __COMPACT__
LPROG equ 0
LDATA equ 1
MODEL COMPACT, PROLOG
ENDIF
IFDEF __LARGE__
LPROG equ 1
LDATA equ 1
MODEL LARGE, PROLOG
ENDIF
IF LDATA
DPTR_ EQU dword
DS_ EQU ds:
ES_ EQU es:
MACRO LDS_ Register, Memory
lds Register, Memory
ENDM LDS_
MACRO LES_ Register, Memory
les Register, Memory
ENDM LES_
MACRO PUSHDS_
push ds
ENDM PUSHDS_
MACRO POPDS_
pop ds
ENDM POPDS_
MACRO PUSHES_
push es
ENDM PUSHES_
MACRO POPES_
pop es
ENDM POPES_
ELSE
DPTR_ EQU word
DS_ EQU
ES_ EQU
MACRO LDS_ Register, Memory
mov Register, Memory
ENDM LDS_
MACRO LES_ Register, Memory
mov Register, Memory
ENDM LES_
MACRO PUSHDS_
ENDM PUSHDS_
MACRO POPDS_
ENDM POPDS_
MACRO PUSHES_
ENDM PUSHES_
MACRO POPES_
ENDM POPES_
ENDIF
; TASM_C.INC END
基本图形文件,该文件提供了几个基本的图形函数(带下划线的函数)和其它图形汇编文件使用的内部函数(没有下划线的函数,C不能直接调用):
P386N
include tasm_c.inc
MAXCOLOR equ 15 ; 最大颜色值
MAXX equ 639 ; 最大 X 象素
MAXY equ 479 ; 最大 Y 象素
DSPMEMSEG equ 0A000h ; 屏显起始地址
DMWIDTH equ 80 ; 屏幕每线字节数
GRMODE equ 12h ; 屏显方式
DATASEG
PUBLIC Color
PUBLIC DrMode
PUBLIC MinX
PUBLIC MinY
PUBLIC MaxX
PUBLIC MaxY
PUBLIC WidthX
PUBLIC WidthY
Color dw 7
DrMode dw 3
LnStyle dw 0ffffh
Pattern db 8 dup (0ffh)
MinX dw 0
MinY dw 0
MaxX dw MAXX
MaxY dw MAXY
WidthX dw MAXX
WidthY dw MAXY
CODESEG
PUBLIC _OpenGraph
PUBLIC _CloseGraph
PUBLIC _Line
PUBLIC _PutPixel
PUBLIC _GetPixel
PUBLIC _SetColor
PUBLIC _GetColor
PUBLIC _SetDrMode
PUBLIC _SetLnStyle
PUBLIC _SetPattern
PUBLIC _Rectangle
PUBLIC _Bar
PUBLIC _SetPalette
PUBLIC _SetBorder
PUBLIC _DefBorder
PUBLIC GetDspMem
PUBLIC GetDspMemOff
PUBLIC SetWrMode
PUBLIC SetWrMode0
PUBLIC RestReg
PUBLIC RestReg0
PUBLIC TestPoint
PUBLIC Bar
PUBLIC GetPixel
PUBLIC PutPixel
;
; GetDspMem; ax = X, bx = Y, return es:bx = DspMem
;
PROC GetDspMem
push DSPMEMSEG
pop es
ENDP
;
PROC GetDspMemOff
push ax
shl bx, 4
mov ax, bx ; bx = Y * 16
shl ax, 2
add bx, ax ; ( bx += ( Y * 64 )) or ( bx = Y * 80 )
pop ax
shr ax, 3 ; ax = X / 8
add bx, ax ; return BX = ( Y * 80 + X / 8 )
ret
ENDP
;
PROC SetWrMode0
xor al, al
mov ah, [ byte Color]
mov dx, 3ceh
out dx, ax
mov ax, 0f01h
out dx, ax
xor ah, ah
ENDP
;
; SetWrMode, ah = Mode( 0 - 3 ); return dx = 3cfh
;
PROC SetWrMode
mov al, 5
mov dx, 3ceh
out dx, ax
mov ax, [DrMode]
out dx, ax
mov al, 8
out dx, al
inc dx
ret
ENDP
;
PROC RestReg0
mov dx, 3ceh
xor ax, ax
out dx, ax
inc ax
out dx, ax
ENDP
;
PROC RestReg
mov dx, 3ceh
mov ax, 0ff08h
out dx, ax
mov ax, 5
out dx, ax
mov ax, 3
out dx, ax
ret
ENDP
;
; TestPoint; ax = x1, bx = y1, si = x2, di = y2, cx = WintdX, dx = WidthY
;
PROC TestPoint
cmp ax, si
jle @@ 1
xchg ax, si
@@ 1 :
cmp bx, di
jle @@ 2
xchg bx, di
@@ 2 :
or di, di
js @@ 7
cmp di, dx
jle @@ 3
mov di, dx
@@ 3 :
or si, si
js @@ 7
cmp si, cx
jle @@ 4
mov si, cx
@@ 4 :
cmp bx, dx
jg @@ 7
or bx, bx
jns @@ 5
xor bx, bx
@@ 5 :
cmp ax, cx
jg @@ 7
or ax, ax
jns @@ 6
xor ax, ax
@@ 6 :
clc
ret
@@ 7 :
stc
ret
ENDP
;
; void _SetBorder( int X1, int Y1, int X2, int Y2 )
;
PROC _SetBorder
ARG X1 : word, Y1 : word, X2 : word, Y2 : word
mov ax, [X1]
mov bx, [X2]
cmp ax, bx
jle @@ 1
xchg ax, bx
@@ 1 :
or ax, ax
jns @@ 2
xor ax, ax
or bx, bx
jns @@ 2
xor ax, ax
@@ 2 :
cmp bx, MAXX
jle @@ 3
mov bx, MAXX
cmp ax, MAXX
jle @@ 3
mov ax, MAXX
@@ 3 :
mov [MinX], ax
mov [MaxX], bx
sub bx, ax
mov [WidthX], bx
;
mov ax, [Y1]
mov bx, [Y2]
cmp ax, bx
jle @@ 4
xchg ax, bx
@@ 4 :
or ax, ax
jns @@ 5
xor ax, ax
or bx, bx
jns @@ 5
xor ax, ax
@@ 5 :
cmp bx, MAXY
jle @@ 6
mov bx, MAXY
cmp ax, MAXY
jle @@ 6
mov ax, MAXY
@@ 6 :
mov [MinY], ax
mov [MaxY], bx
sub bx, ax
mov [WidthY], bx
ret
ENDP
;
PROC _DefBorder
mov [word MinX], 0
mov [word MinY], 0
mov [word MaxX], MAXX
mov [word MaxY], MAXY
mov [word WidthX], MAXX
mov [word WidthY], MAXY
ret
ENDP
;
; void OpenGraph()
;
PROC _OpenGraph
mov ax, GRMODE
int 10h
mov dx, 3c4h
mov ax, 0f02h
out dx, ax
call RestReg0
call _DefBorder
ret
ENDP
;
; void CloseGraph()
;
PROC _CloseGraph
mov ax, 3
int 10h
ret
ENDP
;
; int SetColor( int Color )
;
PROC _SetColor
ARG color : word
mov ax, [color]
and ax, MAXCOLOR
xchg ax, [Color]
ret
ENDP
;
; int SetDrMode( int Mode )
;
PROC _SetDrMode
ARG mode : word
mov ax, [mode]
and ax, 3
shl ax, 11
or ax, 3
xchg ax, [DrMode]
shr ax, 11
ret
ENDP
;
; int SetLnStyle( int linestyle )
;
PROC _SetLnStyle
ARG linestyle : word
mov ax, [linestyle]
xchg ax, [LnStyle]
ret
ENDP
;
; void SetPattern( void far * Pat, int color )
;
PROC _SetPattern
ARG pat : far ptr, color : word
USES di, si, ds
push [word color]
call _SetColor
pop ax
push ds
pop es
lea di, [Pattern]
lds si, [dword pat]
mov cx, 8
cld
rep movsb
ret
ENDP
;
; int GetColor( void )
;
PROC _GetColor
mov ax, [Color]
ret
ENDP
;
; ax = x, bx = y, dx = 03cfh
;
PROC PutPixel
cmp ax, [WidthX]
ja @@ 1
cmp bx, [WidthY]
ja @@ 1
add ax, [MinX]
add bx, [MinY]
push ax
call GetDspMem
pop cx
and cx, 7
mov al, 80h
shr al, cl
out dx, al
mov ax, [Color]
xchg al, [ byte es:bx]
@@ 1 :
ret
ENDP
;
; void PutPixel( int x, int y )
;
PROC _PutPixel
ARG x : word, y : word
mov ah, 2
call SetWrMode
mov ax, [x]
mov bx, [y]
call PutPixel
call RestReg
ret
ENDP
;
; ax = x, bx = y
;
PROC GetPixel
push ax
call GetDspMem
pop cx
not cl
and cl, 7
xor ch, ch
mov dx, 3ceh
mov al, 4
out dx, al
inc dx
mov al, 3
@@ 1 :
out dx, al
mov ah, [ byte es:bx]
shr ah, cl
and ah, 1
shl ch, 1
or ch, ah
dec al
jns @@ 1
mov al, ch
cbw
ret
ENDP
;
; int GetPixel( int x, int y )
;
PROC _GetPixel
ARG x : word, y : word
mov ax, [x]
mov bx, [y]
add ax, [MinX]
add bx, [MinY]
call GetPixel
ret
ENDP
;
; (b2 - b1) * (w - a1) / (a2 - a1));
; ax = w, cx = a1, bx = b1, si = a2, di = b2
;
PROC SumXY
push bx
push dx
push ax
mov ax, di
sub ax, bx
pop bx
sub bx, cx
imul bx
mov bx, si
sub bx, cx
idiv bx
pop dx
pop bx
ret
ENDP
; cx = x, bx = y; ret ax = Code
;
PROC OutCode
xor ax, ax
or cx, cx
jns @@ 1
or ax, 0001b
@@ 1 :
or bx, bx
jns @@ 2
or ax, 0010b
@@ 2 :
cmp cx, [WidthX]
jle @@ 3
or ax, 0100b
@@ 3 :
cmp bx, [WidthY]
jle @@ 4
or ax, 1000b
@@ 4 :
ret
ENDP
;
PROC _Line
ARG x1 : word, y1 : word, x2 : word, y2 : word
USES si, di
mov cx, [x2]
mov bx, [y2]
call OutCode
mov dh, al ; dh = p2
mov si, cx
mov di, bx
mov cx, [x1]
mov bx, [y1]
@@ 1 :
call OutCode
mov dl, al ; dl = al = p1
test al, dh ; if ((p1 & p2)) return
jz @@ 2
jmp @@ 17
@@ 2 :
or al, dh ; if ( ! (p1 | p2) line
jz @@ 7
cmp dl, 0 ; if ( ! p1) x1 swap x2; y1 swap y2; p1 swap p2
jne @@ 3
xchg cx, si
xchg bx, di
xchg dh, dl
@@ 3 :
test dl, 0001b
jz @@ 4
xor ax, ax ; if (x1 < 0 )
call SumXY
add bx, ax ; y1 += (y2 - y1) * ( - x1) / (x2 - x1)
xor cx, cx ; x1 = 0
jmp short @@ 1
@@ 4 :
test dl, 0010b
jz @@ 5
xor ax, ax ; if (y1 < 0 )
xchg cx, bx
xchg si, di
call SumXY
xchg cx, bx
xchg si, di
add cx, ax ; x1 += (x2 - x1) * ( - y1) / (y2 - y1)
xor bx, bx ; y1 = 0
jmp short @@ 1
@@ 5 :
test dl, 0100b
jz @@ 6
mov ax, [WidthX] ; if (x1 > WidthX)
call SumXY
add bx, ax ; y1 += (y2 - y1) * (WidthX - x1) / (x2 - x1)
mov cx, [WidthX] ; x1 = WidthX
jmp @@ 1
@@ 6 :
test dl, 1000b
jz @@ 1
mov ax, [WidthY] ; if (y1 > WidthY)
xchg cx, bx
xchg si, di
call SumXY
xchg cx, bx
xchg si, di
add cx, ax ; x1 += (x2 - x1) * (WidthY - y1) / (y2 - y1)
mov bx, [WidthY] ; y1 = WidthY
jmp @@ 1
@@ 7 :
mov ax, cx ; line(x1, y1, x2, y2)
add ax, [MinX]
add bx, [MinY]
add si, [MinX]
add di, [MinY]
mov [word y1], 80
mov [word x1], 0
cmp ax, si
jle @@ 8
xchg ax, si
xchg bx, di
@@ 8 :
sub si, ax
sub di, bx
jge @@ 9
neg [word y1]
neg di
@@ 9 :
cmp di, si
jle @@ 10
mov [word x1], 1
xchg di, si
@@ 10 :
push si
mov [y2], di
mov [x2], si
mov di, si
shr di, 1
push ax
call GetDspMem
mov ah, 2
call SetWrMode
mov si, [LnStyle]
pop cx
and cl, 7
mov al, 80h
shr al, cl
out dx, al
mov ah, [ byte Color]
pop cx
inc cx
@@ 11 :
test si, 8000h
jz @@ 12
push ax
xchg [ byte es:bx], ah
pop ax
@@ 12 :
rol si, 1
add di, [y2]
cmp di, [word x2]
jle @@ 13
add bx, [y1]
sub di, [x2]
jmp short @@ 14
@@ 13 :
cmp [word x1], 0
je @@ 14
add bx, [y1]
loop @@ 11
jmp short @@ 16
@@ 14 :
ror al, 1
test al, 80h
jz @@ 15
inc bx
@@ 15 :
out dx, al
loop @@ 11
@@ 16 :
call RestReg
@@ 17 :
ret
ENDP
;
; void Rectangle( int x1, int y1, int x2, int y2 )
;
PROC _Rectangle
ARG x1 : word, y1 : word, x2 : word, y2 : word
USES si, di
mov si, [x1]
mov di, [y1]
push di
push [word x2]
push di
push si
call _Line
add sp, 8
inc di
push [word y2]
push [word x2]
push di
push [word x2]
call _Line
add sp, 8
push [word y2]
push [word x2]
push [word y2]
push si
call _Line
add sp, 8
dec [word y2]
push [word y2]
push si
push di
push si
call _Line
add sp, 8
ret
ENDP
;
; ax = x1, bx = y1, si = x2, di = y2
;
PROC Bar
push bp
sub di, bx
inc di
push di
push bx
push ax
call GetDspMem
mov di, bx
pop ax
mov cx, ax
mov bx, 0ffffh
and cl, 7
shr bh, cl
mov cx, si
not cl
and cl, 7
shl bl, cl
shr ax, 3
shr si, 3
sub si, ax
mov bp, si
pop si
pop cx
cld
@@ 1 :
push cx
push di
push si
push ds
and si, 7
mov al, [ byte Pattern + si]
mov ah, al
and al, bh
mov cx, bp
mov si, di
push es
pop ds
dec cx
js @@ 2
out dx, al
movsb
mov al, ah
out dx, al
rep movsb
@@ 2 :
and al, bl
out dx, al
movsb
pop ds
pop si
pop di
pop cx
inc si
add di, DMWIDTH
loop @@ 1
pop bp
ret
ENDP
;
; void Bar( int x1, int y1, int x2, int y2 )
;
PROC _Bar
ARG x1 : word, y1 : word, x2 : word, y2 : word
USES si, di
mov ax, [x1]
mov bx, [y1]
mov si, [x2]
mov di, [y2]
mov cx, [WidthX]
mov dx, [WidthY]
call TestPoint
jc @@ 1
add ax, [MinX]
add bx, [MinY]
add si, [MinX]
add di, [MinY]
push ax
call SetWrMode0
pop ax
call Bar
call RestReg0
@@ 1 :
ret
ENDP
;
; void SetPalette( int index, int Red, int Green, int Blus)
;
PROC _SetPalette
ARG index : word, red : word, green : word, blus : word
mov al, [ byte index]
and al, 0fh
cmp al, 6
jl @@ 2
jg @@ 1
mov al, 14h
jmp short @@ 2
@@ 1 :
cmp al, 7
je @@ 2
add al, 30h
@@ 2 :
mov dx, 3c8h
out dx, al
inc dx
mov al, [ byte red]
out dx, al
mov al, [ byte green]
out dx, al
mov al, [ byte blus]
out dx, al
ret
ENDP
;
END
供其它汇编图形文件引用的插入文件:
P386N
include tasm_c.inc
MAXCOLOR equ 15 ; 最大颜色值
MAXX equ 639 ; 最大 X 象素
MAXY equ 479 ; 最大 Y 象素
DSPMEMSEG equ 0A000h ; 屏显起始地址
DMWIDTH equ 80 ; 屏幕每线字节数
GRMODE equ 12h ; 屏显方式
EXTRN Color:word
EXTRN DrMode:word
EXTRN MinX:word
EXTRN MinY:word
EXTRN MaxX:word
EXTRN MaxY:word
EXTRN WidthX:word
EXTRN WidthY:word
;
EXTRN _OpenGraph:proc
EXTRN _CloseGraph:proc
EXTRN _Line:proc
EXTRN _PutPixel:proc
EXTRN _GetPixel:proc
EXTRN _SetColor:proc
EXTRN _GetColor:proc
EXTRN _SetDrMode:proc
EXTRN _SetLnStyle:proc
EXTRN _SetPattern:proc
EXTRN _Rectangle:proc
EXTRN _Bar:proc
EXTRN _SetPalette:proc
EXTRN _SetBorder:proc
EXTRN _DefBorder:proc
EXTRN GetDspMem:proc
EXTRN GetDspMemOff:proc
EXTRN SetWrMode:proc
EXTRN SetWrMode0:proc
EXTRN RestReg:proc
EXTRN RestReg0:proc
EXTRN TestPoint:proc
EXTRN Bar:proc
EXTRN GetPixel:proc
EXTRN PutPixel:proc
EXTRN _farmalloc:proc
EXTRN _farfree:proc
显示位图数据函数文件:
include graph.inc
CODESEG
PUBLIC _PutBmp
;
; void PutBmp( int x, int y, void far * bmp)
;
PROC _PutBmp
ARG x : word, y :word, bmp : far ptr
USES si, di, ds
mov ah, 2
call SetWrMode
mov ax, [x]
mov bx, [y]
lds si, [dword bmp]
push bp
mov bp, [si]
add bx, [si + 2 ]
dec bx
push ax
call GetDspMem
pop cx
and cx, 7
mov ah, 80h
shr ah, cl
mov cx, [si + 2 ]
add si, 4
@@ 1 :
push bx
push ax
xor di, di
@@ 2 :
mov al, ah
out dx, al
test di, 1
jnz @@ 3
lodsb
shr al, 4
jmp short @@ 4
@@ 3 :
mov al, [si - 1 ]
and al, 0fh
@@ 4 :
xchg al, [ byte es:bx]
ror ah, 1
test ah, 80h
jz @@ 5
inc bx
@@ 5 :
inc di
cmp di, bp
jl @@ 2
pop ax
pop bx
sub bx, DMWIDTH
loop @@ 1
pop bp
call RestReg
ret
ENDP
;
END
PutBmp函数的测试程序:
#include " graph.h "
#include < stdlib.h >
#include < stdio.h >
#include < string .h >
#include < alloc.h >
char * buf = NULL;
void PutBmp( int , int , void far * );
typedef struct
{
unsigned char blue;
unsigned char green;
unsigned char red;
unsigned char reserved;
}BMPRGB;
typedef struct
{
char type[ 2 ];
long filesize;
char nul1[ 4 ];
long offbins;
long bisize;
long width;
long high;
int planes;
int bitcount;
long packtype;
long sizeimage;
long xwidth;
long ywidth;
long clrused;
long clrimportant;
BMPRGB bmpcolor[ 16 ];
}BMPTOP;
void main( int argc, char ** argv)
{
int x, y, * t;
char s[ 10 ];
unsigned size;
BMPTOP p;
BMPRGB * r;
FILE * f;
if (argc < 2 )
{
printf( " Windows BMP 文件显示程序(VGA 16 色和非压缩格式) " );
printf( " 调用格式: SHOWBMP <BMP 文件名> " );
return ;
}
if ((f = fopen(argv[ 1 ], " rb " )) == NULL)
{
printf( " %s File not find! " , argv[ 1 ]);
return ;
}
fread( & p, 1 , sizeof (BMPTOP), f);
if (memcmp(p.type, " BM " , 2 ) || p.bitcount != 4 || p.packtype != 0 )
{
fclose(f);
printf( " %s 文件不是16色模式非压缩形式的BMP文件, 不能显示! " );
return ;
}
size = p.filesize - p.offbins;
if ((buf = ( char * )malloc(size + 4 )) == NULL)
{
printf( " 文件太大, 内存不够使用! " );
fclose(f);
return ;
}
size = fread( & buf[ 4 ], 1 , size, f);
fclose(f);
if (size != p.filesize - p.offbins)
{
printf( " %s 文件已坏 " );
return ;
}
t = ( int * )buf;
* t ++ = p.width;
* t = p.high;
OpenGraph();
r = (BMPRGB * )p.bmpcolor;
for (x = 0 ; x < 16 ; x ++ )
SetPalette( x, r[x].red >> 2 , r[x].green >> 2 , r[x].blue >> 2 );
x = ( 640 - p.width) >> 1 ;
y = ( 480 - p.high) >> 1 ;
SetColor( 8 );
Bar(x - 10 , y - 10 , x + p.width + 10 , y + p.high + 10 );
PutBmp(x, y, buf);
gets(s);
CloseGraph();
}
未完待续。
===================================================================================
更新:有个现成的UCDOS字符串显示测试程序,其中还包括了GetImage和PutImage函数的测试,这些函数代码在《Turbo C使用的汇编函数 -- VGA 12H模式图形函数(二)》中,因那篇文章代码太多,太长,所以补充更新在此,供参考:
#include < alloc.h >
#include < stdio.h >
void main()
{
int i, j, k;
unsigned s1, s2;
char ss[ 9 ];
void far * s;
OpenGraph();
if ( ! InitUCDOS( 2 ))
return ;
for (i = 0 , k = 1 ; i < 128 ; i += 16 , k ++ )
{
SetPos( 0 , i);
Putch(k + 33 , 80 , k);
}
Putss( 10 , 128 , " 公安县统计局 " , 640 , 15 );
s1 = ImageSize( 0 , 0 , 639 , 127 );
s = farmalloc(s1);
if (s)
{
s2 = GetImage( 0 , 0 , 639 , 127 , s);
PutImage( 0 , 150 , s, 0 );
gets(ss);
}
RestUCDOS( 0 );
CloseGraph();
if ( ! s)
printf( " Error! " );
else
printf( " s1 = %u, s2 = %u " , s1, s2);
}