;**********************************************************;
;* ------< VGA GRAPHICS LIBRARY - BY TENIE REMMEL >------ *;
;* *;
;* L13H.ASM - This is a highly optimized graphics library *;
;* for the 320x200x256 VGA Mode 13h (19d). It is quite *;
;* complete, and is also small (2« K). This is intended *;
;* for Tiny and Small model ASM programs. *;
;* *;
;* This library is public domain. However, if you intend *;
;* to distribute this source code, you MUST retain this *;
;* header in its original form. *;
;**********************************************************;
Ideal
Jumps
Warn ICG
NoWarn ALN
Public InitGraph,SetPixel,GetPixel
Public ClearScreen,ClearViewport
Public Line,Rectangle
Public FillRectangle,OutChar
Public OutStr,GetImage,PutImage
Public MinX,MinY,MaxX,MaxY
Public FontPtr,FontWidth
Public FontHeight,Color
Model Tiny
P186
CodeSeg
MinX dw 0
MinY dw 0
MaxX dw 319
MaxY dw 199
FontPtr dd 0
FontWidth db 8
FontHeight db 8
Color db 15
;**************************** InitGraph -- Sets up 320x200x256x1 mode
ALIGN 16
Proc InitGraph
pusha ;Save registers
push es
mov ax,13h ;Video mode 13h
int 10h ;Set video mode
mov ax,1130h ;Get pointer to
mov bh,3 ;ROM 8x8 font
int 10h
mov [word cs:FontPtr],bp ;Save this pointer
mov [word cs:FontPtr+2],es
pop es ;Restore registers
popa
Dummy: ret ;Return
EndP InitGraph
;**************************** SetPixel -- plots a pixel
ALIGN 16
Proc SetPixel
;Supply CX=x, DX=y, AL=color
cmp cx,[cs:MinX] ;X < MinX?
jl sp_done
cmp dx,[cs:MinY] ;Y < MinY?
jl sp_done
cmp cx,[cs:MaxX] ;X > MaxX?
jg sp_done
cmp dx,[cs:MaxY] ;Y > MaxY?
jg sp_done
push cx di ds ;Save registers
push 0A000h ;DS = video memory
pop ds
mov di,dx ;DI = DX * 320...
shl di,2
add di,dx
shl di,6
add di,cx ;Add in column
mov [di],al ;Store byte
pop ds di cx ;Restore registers
sp_done: ret ;Return
EndP SetPixel
;**************************** GetPixel -- reads a pixel
ALIGN 16
Proc GetPixel
;Supply CX=x, DX=y, returns AL=color
cmp cx,[cs:MinX] ;X < MinX?
jl gp_bad
cmp dx,[cs:MinY] ;Y < MinY?
jl gp_bad
cmp cx,[cs:MaxX] ;X > MaxX?
jg gp_bad
cmp dx,[cs:MaxY] ;Y > MaxY?
jg gp_bad
push si es ;Save registers
push 0A000h ;ES = video memory
pop es
mov si,dx ;SI = DX * 320...
shl si,2
add si,dx
shl si,6
add si,cx ;Add in column
seges lodsb ;Read byte
pop es si ;Restore registers
ret ;Return
gp_bad: mov al,0 ;Bad value, return 0
ret
EndP GetPixel
;**************************** ClearScreen -- clears the screen
ALIGN 16
Proc ClearScreen
pusha ;Save registers
push ds
push 0A000h ;DS = video memory
pop ds
xor ax,ax ;Clear AX
xor di,di ;Clear DI
mov si,10 ;SI = 10
mov cx,3200 ;3200 iterations
ALIGN 16 ;Force paragraph alignment
clear_loop: mov [di],ax ;Clear 10 bytes with DI
mov [di+2],ax
mov [di+4],ax
mov [di+6],ax
mov [di+8],ax
add di,20
mov [si],ax ;Clear 10 bytes with SI
mov [si+2],ax
mov [si+4],ax
mov [si+6],ax
mov [si+8],ax
add si,20
dec cx ;Loop back
jnz clear_loop
pop ds ;Restore registers
popa
ret ;Return
EndP ClearScreen
;**************************** ClearViewport -- clears the viewport
ALIGN 16
Proc ClearViewport
pusha ;Push registers
push es
push 0A000h ;ES = video memory
pop es
mov ax,[cs:MinX] ;Get corners of viewport
mov bx,[cs:MinY] ;in AX, BX, CX, DX
mov di,[cs:MaxX]
mov si,[cs:MaxY]
sub di,ax ;Get distances in SI, DI
sub si,bx
inc di ;Add one for ends
mov dx,di ;X distance in DX
add ah,bl ;Calculate offset
shl bx,6
add ax,bx
mov di,ax ;DI = offset
xor ax,ax ;AX = 0 (black)
mov bp,320 ;Auxiliary increment in BP
sub bp,dx
xor bx,bx ;Clear BX
shr dx,1 ;DX = X distance in words
adc bx,0 ;BX = odd byte
ALIGN 16 ;Force paragraph alignment
cv_loop: mov cx,dx ;CX = words
rep stosw ;Store by words
mov cx,bx ;CX = odd byte
rep stosb ;Store odd byte
add di,bp ;Next line
dec si ;Dec line counter
jns cv_loop ;Loop back
pop es ;Restore registers
popa
ret ;Exit
EndP ClearViewport
;**************************** Line -- draws a line
ALIGN 16
Proc Line
;Supply AX=x1, BX=y1, CX=x2, DX=y2
pusha ;Push registers
push ds es
push 0A000h ;ES = video memory
pop es
push cs ;DS = CS
pop ds
cmp bx,dx ;Is it horizontal?
je HorizLine
cmp ax,cx ;Vertical?
je VertLine
cmp ax,[MaxX] ;X1 > MaxX?
jg l_x1g
cmp ax,[MinX] ;X1 < MinX?
jl l_x1l
l_cx2g: cmp cx,[MaxX] ;X2 > MaxX?
jg l_x2g
l_cx2l: cmp cx,[MinX] ;X2 < MinX?
jl l_x2l
l_checky: cmp bx,[MaxY] ;Y1 > MaxY?
jg l_y1g
cmp bx,[MinY] ;Y1 < MinY?
jl l_y1l
l_cy2g: cmp dx,[MaxY] ;Y2 > MaxY?
jg l_y2g
l_cy2l: cmp dx,[MinY] ;Y2 < MinY?
jl l_y2l
jmp l_cont1
l_x1g: cmp cx,[MaxX] ;X1 > MaxX.
jg l_done ;Both > MaxX?
push cx dx ;Save x2, y2
sub cx,ax
sub dx,bx ;Calculate the intersection:
sub ax,[MaxX]
neg ax ; (MaxX - x1) * (y2 - y1)
imul dx ;y1 + -----------------------
idiv cx ; (x2 - x1)
add bx,ax
pop dx cx ;Restore x2, y2
mov ax,[MaxX] ;x1 = MaxX
jmp l_cx2l
l_x1l: cmp cx,[MinX] ;X1 < MinX.
jl l_done ;Both < MinX?
push cx dx ;Save x2, y2
sub cx,ax
sub dx,bx ;Calculate the intersection:
sub ax,[MinX]
neg ax ; (MinX - x1) * (y2 - y1)
imul dx ;y1 + -----------------------
idiv cx ; (x2 - x1)
add bx,ax
pop dx cx ;Restore x2, y2
mov ax,[MinX] ;x1 = MinX
jmp l_cx2g
l_x2g: push ax bx ;Save x1, y1
sub cx,ax
sub dx,bx ;Calculate the intersection:
sub ax,[MaxX]
neg ax ; (MaxX - x1) * (y2 - y1)
imul dx ;y1 + -----------------------
idiv cx ; (x2 - x1)
add bx,ax
mov dx,bx
pop bx ax ;Restore x1, y1
mov cx,[MaxX] ;x2 = MaxX
jmp l_checky
l_x2l: push ax bx ;Save x1, y1
sub cx,ax
sub dx,bx ;Calculate the intersection:
sub ax,[MinX]
neg ax ; (MinX - x1) * (y2 - y1)
imul dx ;y1 + -----------------------
idiv cx ; (x2 - x1)
add bx,ax
mov dx,bx
pop bx ax ;Restore x1, y1
mov cx,[MinX] ;x2 = MinX
jmp l_checky
l_y1g: cmp dx,[MaxY] ;Y1 > MaxY.
jg l_done ;Both > MaxY?
push cx dx ;Save x2, y2
xchg ax,bx
xchg cx,dx
sub cx,ax ;Calculate the intersection:
sub dx,bx
sub ax,[MaxY] ; (MaxY - y1) * (x2 - x1)
neg ax ;x1 + -----------------------
imul dx ; (y2 - y1)
idiv cx
add ax,bx
pop dx cx ;Restore x2, y2
mov bx,[MaxY] ;y1 = MaxX
jmp l_cy2l
l_y1l: cmp dx,[MinY] ;Y1 < MinY.
jl l_done ;Both < MinY?
push cx dx ;Save x2, y2
xchg ax,bx
xchg cx,dx
sub cx,ax ;Calculate the intersection:
sub dx,bx
sub ax,[MinY] ; (MinY - y1) * (x2 - x1)
neg ax ;x1 + -----------------------
imul dx ; (y2 - y1)
idiv cx
add ax,bx
pop dx cx ;Restore x2, y2
mov bx,[MinY] ;y1 = MinY
jmp l_cy2g
l_y2g: push ax bx ;Save x1, y1
xchg ax,bx
xchg cx,dx
sub cx,ax ;Calculate the intersection:
sub dx,bx
sub ax,[MaxY] ; (MaxY - y1) * (x2 - x1)
neg ax ;x1 + -----------------------
imul dx ; (y2 - y1)
idiv cx
add ax,bx
mov cx,ax
pop bx ax ;Restore x1, y1
mov dx,[MaxY] ;y2 = MaxY
jmp l_cont1
l_y2l: push ax bx ;Save x1, y1
xchg ax,bx
xchg cx,dx
sub cx,ax ;Calculate the intersection:
sub dx,bx
sub ax,[MinY] ; (MinY - y1) * (x2 - x1)
neg ax ;x1 + -----------------------
imul dx ; (y2 - y1)
idiv cx
add ax,bx
mov cx,ax
pop bx ax ;Restore x1, y1
mov dx,[MinY] ;y2 = MinY
l_cont1: push ax bx ;Save starting position
sub cx,ax ;get X and Y distance
mov [xinc_str],1 ;Increments are 1
mov [yinc_str],1
jge l_xplus ;X positive?
neg [xinc_str] ;If not, negate
neg cx
l_xplus: sub dx,bx ;get Y distance
jge l_yplus ;Y positive?
neg [yinc_str] ;If not, negate
neg dx
l_yplus: mov ax,[xinc_str] ;Copy into the
mov [xinc_diag],ax ;diagonal values
mov ax,[yinc_str]
mov [yinc_diag],ax
cmp cx,dx ;X < Y ?
jle l_ystr ;If so, go vertical
mov [yinc_str],0 ;Otherwise go horizontal
jmp l_cont2 ;At l_cont2: xinc, yinc_str are
l_ystr: mov [xinc_str],0 ;the straight increments and xinc,
xchg cx,dx ;yinc_diag are the diag. increments
l_cont2: mov di,dx ;cx, dx are straight, perpendicular
mov [deltav_str],di ;Get dev. increments and start value
sub di,cx ;Str. incr = perp_dist
mov [deltav_diag],di ;Perp. incr = perp_dist - str_dist
add di,dx ;Starting value =
sar di,1 ;(2 * perp_dist - str_dist) / 2
mov si,di ;Put starting dev. in SI
mov di,cx ;Put length in DI
inc di ;One more point (ends)
pop dx cx ;Get starting point in (cx,dx)
ALIGN 16 ;Force paragraph alignment
l_loop: mov bx,cx ;BX = x
add bh,dl ;BX = x + y * 256
shl dx,6 ;BX = x + y * 256 + y * 64
add bx,dx ;so BX = x + y * 320
shr dx,6 ;Restore DX
mov al,[Color] ;Get color
mov [es:bx],al ;Write pixel
test si,si ;Decide whether to go straight
jg l_godiag ;or diagonal
l_gostr: add cx,[xinc_str] ;Go straight
add dx,[yinc_str]
add si,[deltav_str]
jmp l_loopback
l_godiag: add cx,[xinc_diag] ;Go diagonal
add dx,[yinc_diag]
add si,[deltav_diag]
l_loopback: dec di ;Decrement counter
jnz l_loop ;Loop back
l_done: pop es ds ;Restore registers
popa
ret ;Return
ALIGN 16 ;Force paragraph alignment
HorizLine: cmp bx,[cs:MaxY] ;Y > MaxY?
jg l_done
cmp bx,[cs:MinY] ;Y < MinY?
jl l_done
cmp ax,[cs:MaxX] ;X1 > MaxX?
jg lh_x1g
cmp ax,[cs:MinX] ;X1 < MinX?
jl lh_x1l
lh_cx2g: cmp cx,[cs:MaxX] ;X2 > MaxX?
jg lh_x2g
lh_cx2l: cmp cx,[cs:MinX] ;X2 < MinX?
jl lh_x2l
jmp lh_cont ;Continue
lh_x1g: cmp cx,[cs:MaxX] ;X1 > MaxX.
jg l_done ;Both > MaxX?
mov ax,[cs:MaxX] ;No, fix X1
jmp lh_cx2l
lh_x1l: cmp cx,[cs:MinX] ;X1 < MinX.
jl l_done ;Both < MinX?
mov ax,[cs:MinX] ;No, fix X1
jmp lh_cx2g
lh_x2g: mov cx,[cs:MaxX] ;X2 > MaxX, fix X2
jmp lh_cont
lh_x2l: mov cx,[cs:MinX] ;X2 < MinX, fix X2
lh_cont: sub cx,ax ;Get X distance
jge lh_xplus ;Negative?
add ax,cx ;AX = previous CX
neg cx ;Make it positive
lh_xplus: inc cx ;Adjust
add ah,bl ;AX = x + 256 * y
shl bx,6 ;multiply BX by 64
add ax,bx ;AX = x + 320 * y
mov di,ax ;Offset in DI
mov al,[cs:Color] ;Get color in AL, AH
mov ah,al
xor bx,bx ;Clear BX
shr cx,1 ;CX = width / 2
adc bx,0 ;Odd byte in BX
EVEN ;Force word alignment
rep stosw ;Store by words
mov cx,bx ;Odd byte?
rep stosb ;Store odd byte
jmp l_done ;Return
ALIGN 16 ;Force paragraph alignment
VertLine: cmp ax,[cs:MaxX] ;X > MaxX?
jg l_done
cmp ax,[cs:MinX] ;X < MinX?
jl l_done
cmp bx,[cs:MaxY] ;Y1 > MaxY?
jg lv_y1g
cmp bx,[cs:MinY] ;Y1 < MinY?
jl lv_y1l
lv_cy2g: cmp dx,[cs:MaxY] ;Y2 > MaxY?
jg lv_y2g
lv_cy2l: cmp dx,[cs:MinY] ;Y2 < MinY?
jl lv_y2l
jmp lv_cont ;Continue
lv_y1g: cmp dx,[cs:MaxY] ;Y1 > MaxY.
jg l_done ;Both > MaxY?
mov bx,[cs:MaxY] ;No, fix Y1
jmp lv_cy2l
lv_y1l: cmp dx,[cs:MinY] ;Y1 < MinY.
jl l_done ;Both < MinY?
mov bx,[cs:MinY] ;No, fix Y1
jmp lv_cy2g
lv_y2g: mov dx,[cs:MaxY] ;Y2 > MaxY, fix Y2
jmp lv_cont
lv_y2l: mov dx,[cs:MinY] ;Y2 < MinY, fix Y2
lv_cont: sub dx,bx ;Get Y distance
jge lv_yplus ;Negative?
add bx,dx ;BX = previous DX
neg dx ;Make it positive
lv_yplus: add ah,bl ;AX = x + 256 * y
shl bx,6 ;multiply BX by 64
add ax,bx ;AX = x + 320 * y
mov di,ax ;Offset in DI
mov al,[cs:Color] ;AL = color
ALIGN 16 ;Force paragraph alignment
lv_loop: stosb ;Write pixel
add di,319 ;Next line
dec dx ;Done?
jns lv_loop ;Loop back
jmp l_done ;Return
EVEN ;Force word alignment
deltav_str dw 0 ;Deviation change straight
deltav_diag dw 0 ;Deviation change diagonal
xinc_str dw 0 ;X increment straight
xinc_diag dw 0 ;X increment diagonal
yinc_str dw 0 ;Y increment straight
yinc_diag dw 0 ;Y increment diagonal
EndP Line
;**************************** Rectangle -- draws a rectangle
ALIGN 16
Proc Rectangle
;Supply AX=x1, BX=y1, CX=x2, DX=y2
push si ;Save SI
mov si,cx ;Save X2
mov cx,ax ;X2 = X1
call Line ;Draw top side
mov cx,si ;Restore X2
mov si,ax ;Save X1
mov ax,cx ;X1 = X2
call Line ;Draw bottom side
mov ax,si ;Restore X1
mov si,dx ;Save Y2
mov dx,bx ;Y2 = Y1
call Line ;Draw left side
mov dx,si ;Restore Y2
mov si,bx ;Save Y1
mov bx,dx ;Y1 = Y2
call Line ;Draw right side
mov bx,si ;Restore Y2
pop si ;Restore SI
ret ;Return
EndP Rectangle
;**************************** FillRectangle -- draws a filled rectangle
ALIGN 16
Proc FillRectangle
;Supply AX=x1, BX=y1, CX=x2, DX=y2
pusha ;Push registers
push es
push 0A000h ;ES = video memory
pop es
cmp ax,[cs:MaxX] ;X1 > MaxX?
jg fr_x1g
cmp ax,[cs:MinX] ;X1 < MinX?
jl fr_x1l
fr_cx2g: cmp cx,[cs:MaxX] ;X2 > MaxX?
jg fr_x2g
fr_cx2l: cmp cx,[cs:MinX] ;X2 < MinX?
jl fr_x2l
fr_checky: cmp bx,[cs:MaxY] ;Y1 > MaxY?
jg fr_y1g
cmp bx,[cs:MinY] ;Y1 < MinY?
jl fr_y1l
fr_cy2g: cmp dx,[cs:MaxY] ;Y2 > MaxY?
jg fr_y2g
fr_cy2l: cmp dx,[cs:MinY] ;Y2 < MinY?
jl fr_y2l
jmp fr_cont ;Continue
fr_x1g: cmp cx,[cs:MaxX] ;X1 > MaxX.
jg fr_done ;Both > MaxX?
mov ax,[cs:MaxX] ;No, fix X1
jmp fr_cx2l
fr_x1l: cmp cx,[cs:MinX] ;X1 < MinX.
jl fr_done ;Both < MinX?
mov ax,[cs:MinX] ;No, fix X1
jmp fr_cx2g
fr_x2g: mov cx,[cs:MaxX] ;X2 > MaxX, fix X2
jmp fr_checky
fr_x2l: mov cx,[cs:MinX] ;X2 < MinX, fix X2
jmp fr_checky
fr_y1g: cmp dx,[cs:MaxY] ;Y1 > MaxY.
jg fr_done ;Both > MaxY?
mov bx,[cs:MaxY] ;No, fix Y1
jmp fr_cy2l
fr_y1l: cmp dx,[cs:MinY] ;Y1 < MinY.
jl fr_done ;Both < MinY?
mov bx,[cs:MinY] ;No, fix Y1
jmp fr_cy2g
fr_y2g: mov dx,[cs:MaxY] ;Y2 > MaxY, fix Y2
jmp fr_cont
fr_y2l: mov dx,[cs:MinY] ;Y2 < MinY, fix Y2
fr_cont: mov si,dx ;Get distances in SI, DI
mov di,cx
sub di,ax ;Is the X distance negative?
jge fr_xplus ;Switch points and negate
neg di
xchg cx,ax
fr_xplus: sub si,bx ;Same thing for Y
jge fr_yplus
neg si
xchg dx,bx
fr_yplus: inc di ;Add one for ends
mov dx,di ;X distance in DX
add ah,bl ;Calculate offset
shl bx,6
add ax,bx
mov di,ax ;DI = offset
mov al,[cs:Color] ;Color in AL, AH
mov ah,al
mov bp,320 ;Auxiliary increment in BP
sub bp,dx
xor bx,bx ;Clear BX
shr dx,1 ;DX = X distance in words
adc bx,0 ;BX = odd byte
ALIGN 16 ;Force paragraph alignment
fr_loop: mov cx,dx ;CX = words
rep stosw ;Store by words
mov cx,bx ;CX = odd byte
rep stosb ;Store odd byte
add di,bp ;Next line
dec si ;Dec line counter
jns fr_loop ;Loop back
fr_done: pop es ;Restore registers
popa
ret ;Exit
EndP FillRectangle
;**************************** OutChar -- outputs a character
ALIGN 16
Proc OutChar
;Supply AL=char, CX=x, DX=y, returns CX=x+width
pusha ;Save registers
push ds es
push 0A000h ;ES = video memory
pop es
lds si,[cs:FontPtr] ;DS:SI = font
cmp cx,[cs:MinX] ;X < MinX?
jl oc_bad
cmp dx,[cs:MinY] ;Y < MinY?
jl oc_bad
add cl,[cs:FontWidth] ;Lower right corner
adc ch,0
add dl,[cs:FontHeight]
adc dh,0
cmp cx,[cs:MaxX] ;X > MaxX?
jg oc_bad
cmp dx,[cs:MaxY] ;Y > MaxY?
jg oc_bad
sub cl,[cs:FontWidth] ;Back to upper left
sbb ch,0
sub dl,[cs:FontHeight]
sbb dh,0
add ch,dl ;Get offset, which is
shl dx,6 ;x + 320 * y
add cx,dx
mov di,cx
cmp [cs:FontWidth],6 ;6 wide?
je oc_6wide
cmp [cs:FontWidth],8 ;8 wide?
jne oc_bad ;Invalid width
oc_8wide: mov cl,[cs:FontHeight] ;CX = font height
xor ch,ch
mul cl ;Point to specific char
add si,ax
mov ah,[cs:Color] ;AH = color
ALIGN 16 ;Force paragraph alignment
oc_8loop: lodsb ;Load byte
test al,80h ;Pixel in column 0?
jz oc_8_1 ;No, jump
mov [es:di],ah ;Yes, store byte
oc_8_1: test al,40h ;Pixel in column 1?
jz oc_8_2 ;No, jump
mov [es:di+1],ah ;Yes, store byte
oc_8_2: test al,20h ;Pixel in column 2?
jz oc_8_3 ;No, jump
mov [es:di+2],ah ;Yes, store byte
oc_8_3: test al,10h ;Pixel in column 3?
jz oc_8_4 ;No, jump
mov [es:di+3],ah ;Yes, store byte
oc_8_4: test al,08h ;Pixel in column 4?
jz oc_8_5 ;No, jump
mov [es:di+4],ah ;Yes, store byte
oc_8_5: test al,04h ;Pixel in column 5?
jz oc_8_6 ;No, jump
mov [es:di+5],ah ;Yes, store byte
oc_8_6: test al,02h ;Pixel in column 6?
jz oc_8_7 ;No, jump
mov [es:di+6],ah ;Yes, store byte
oc_8_7: test al,01h ;Pixel in column 7?
jz oc_8_8 ;No, jump
mov [es:di+7],ah ;Yes, store byte
oc_8_8: add di,320 ;Next line
dec cx ;Loop back
jnz oc_8loop
jmp oc_done
oc_6wide: mov cl,[cs:FontHeight] ;CX = font height
xor ch,ch
mul cl ;Point to specific char
add si,ax
mov ah,[cs:Color] ;AH = color
ALIGN 16 ;Force paragraph alignment
oc_6loop: lodsb ;Load byte
test al,80h ;Pixel in column 0?
jz oc_6_1 ;No, jump
mov [es:di],ah ;Yes, store byte
oc_6_1: test al,40h ;Pixel in column 1?
jz oc_6_2 ;No, jump
mov [es:di+1],ah ;Yes, store byte
oc_6_2: test al,20h ;Pixel in column 2?
jz oc_6_3 ;No, jump
mov [es:di+2],ah ;Yes, store byte
oc_6_3: test al,10h ;Pixel in column 3?
jz oc_6_4 ;No, jump
mov [es:di+3],ah ;Yes, store byte
oc_6_4: test al,08h ;Pixel in column 4?
jz oc_6_5 ;No, jump
mov [es:di+4],ah ;Yes, store byte
oc_6_5: test al,04h ;Pixel in column 5?
jz oc_6_6 ;No, jump
mov [es:di+5],ah ;Yes, store byte
oc_6_6: add di,320 ;Next line
dec cx ;Loop back
jnz oc_6loop
oc_done: pop es ds ;Restore registers
popa
add cl,[cs:FontWidth] ;Advance X
adc ch,0
ret ;Return
oc_bad: pop es ds ;Restore registers
popa
ret ;Return
EndP OutChar
;**************************** OutStr -- outputs a string
ALIGN 16
Proc OutStr
;Supply DS:SI=string, CX=x, DX=y
pusha ;Save registers
os_loop: lodsb ;Load byte
test al,al ;Zero = done
jz os_done
mov bx,cx ;Save old X
call OutChar ;Output character
cmp cx,bx ;Did it work?
jne os_loop ;If yes, loop back
os_done: popa ;Restore registers
ret ;Return
EndP OutStr
;**************************** GetImage -- gets a rectangular image
ALIGN 16
Proc GetImage
;Supply DS:SI=buffer, AX=x1, BX=y1, CX=x2, DX=y2
pusha ;Save registers
push ds es
push ds ;ES:DI = DS:SI
pop es
mov di,si
push 0A000h ;DS = video memory
pop ds
xchg ax,cx ;CX = x, DX = y,
xchg bx,dx ;AX = width,
sub ax,cx ;BX = height
sub bx,dx
inc ax ;Adjust AX, BX
inc bx
add ch,dl ;SI = offset
shl dx,6 ;(x + y * 320)
add cx,dx
mov si,cx
stosw ;Store width
xchg ax,bx ;Switch AX, BX
stosw ;Store height
xor dx,dx ;Clear DX
shr bx,1 ;BX = width in words
adc dx,0 ;DX = odd byte
mov bp,si ;BP = SI
GetLoop: mov cx,bx ;CX = width in words
rep movsw ;Move by words
mov cx,dx ;CX = odd byte
rep movsb ;Move odd byte
add bp,320 ;Next line
mov si,bp ;offset in SI
dec ax ;Dec line counter
jnz GetLoop ;Loop back
pop es ds ;Restore registers
popa
ret ;Return
EndP GetImage
;**************************** PutImage -- puts a rectangular image
ALIGN 16
Proc PutImage
;Supply DS:SI=buffer, CX=x, DX=y
pusha ;Save registers
push ds es
push 0A000h ;ES = video memory
pop es
lodsw ;Load width
mov bx,ax ;Put it in BX
lodsw ;Load height
cmp cx,[cs:MinX] ;X < MinX?
jl pi_done
cmp dx,[cs:MinY] ;Y < MinY?
jl pi_done
add cx,bx ;Lower right corner
add dx,ax
cmp cx,[cs:MaxX] ;X > MaxX?
jg pi_done
cmp dx,[cs:MaxY] ;Y > MaxY?
jg pi_done
sub cx,bx ;Back to upper left
sub dx,ax
add ch,dl ;DI = offset
shl dx,6 ;(x + y * 320)
add cx,dx
mov di,cx
xor dx,dx ;Clear DX
shr bx,1 ;BX = width in words
adc dx,0 ;DX = odd byte
mov bp,di ;BP = DI
PutLoop: mov cx,bx ;CX = width in words
rep movsw ;Move by words
mov cx,dx ;CX = odd byte
rep movsb ;Move odd byte
add bp,320 ;Next line
mov di,bp ;offset in DI
dec ax ;Dec line counter
jnz PutLoop ;Loop back
pi_done: pop es ds ;Restore registers
popa
ret ;Return
EndP PutImage
End