; Tenie Remmel's Graphics library
Ideal
Jumps
Warn ICG
NoWarn ALN
Model Tiny
P186
CodeSeg
Org 0100h
Start:
MinX dw 0
MinY dw 0
MaxX dw 319
MaxY dw 199
FontPtr dd 0
FontWidth db 8
FontHeight db 8
Color db 15
Org 0110h
ProcTable dw offset Setup
dw offset SetPixel
dw offset GetPixel
dw offset ClearScreen
dw offset ClearViewport
dw offset Line
dw offset Rectangle
dw offset FillRectangle
dw offset OutChar
dw offset OutStr
dw offset GetImage
dw offset PutImage
;**************************** Setup -- Sets up 320x200x256x1 mode
ALIGN 16
Proc Setup
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 Setup
;**************************** 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 Start