; Tenie Remmel's Graphics library
Ideal
Jumps
Model Tiny
P186
CodeSeg
Org 0100h
Start:
MinX dw 0
MinY dw 0
MaxX dw 359
MaxY dw 239
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
CurVidSeg dw 0A000h
;**************************** Setup -- Sets up 360x240x256 mode
ALIGN 16
Proc Setup
pusha ;Save registers
push es
mov ax,13h ;Set 320x200x256x1 mode
int 10h
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
cli ;Disable interrupts
mov dx,03C4h ;Sequencer port
mov ax,0100h ;Synchronous reset
out dx,ax
mov ax,0604h ;Disable Chain-4 Mode
out dx,ax
mov dx,03C2h ;Misc Output port
lea si,[CRTdata] ;Point to data
segcs outsb ;Output byte
mov dx,03C4h ;Sequencer port
mov ax,0300h ;Restart Sequencer
out dx,ax
mov ax,0F02h ;Enable all planes
out dx,ax ;(for clearscreen)
mov dx,03D4h ;CRTC port
segcs lodsw ;Load count
mov cx,ax ;Put in CX
segcs rep outsw ;Output data
mov es,[cs:CurVidSeg] ;ES = video memory
xor di,di ;Zero DI, AX
xor ax,ax
mov cx,8000h ;Clear the screen
rep stosw
sti ;Enable interrupts
pop es ;Restore registers
popa
Dummy: ret ;Return
CRTdata db 0E7h ;480 scanlines, 28 MHz
dw 18
dw 02C11h ;De-protect regs
dw 06B00h ;Horizontal Total
dw 05901h ;Horizontal Display End
dw 05A02h ;Horizontal Start Blanking
dw 08E03h ;Horizontal End Blanking
dw 05E04h ;Horizontal Start Retrace
dw 08A05h ;Horizontal End Retrace
dw 03E07h ;Vertical Overflow
dw 00D06h ;Vertical Total
dw 0DF12h ;Vertical Display End
dw 0EA10h ;Vertical Start Blanking
dw 0AC11h ;Vertical End Blanking
dw 0E715h ;Vertical Start Retrace
dw 00616h ;Vertical End Retrace
dw 04109h ;Pixel Height
dw 02D13h ;Memory Allocation
dw 00014h ;Disable Doubleword Mode
dw 0E317h ;Enable Byte Mode
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
pusha ;Save registers
push ds
mov ds,[cs:CurVidSeg] ;DS = video memory
mov si,dx ;SI = y, BX = CX = x
mov bx,cx
and cl,3 ;CL = bit plane
mov ch,al ;Save color in CH
mov ah,1 ;AH = plane mask
shl ah,cl
shr bx,2 ;BX = X offset
mov dx,03C4h ;Sequencer port
mov al,2 ;Set Map Mask
out dx,ax
mov ax,90 ;Multiply Y by 90
mul si
add bx,ax ;BX = offset
mov [bx],ch ;Put byte in memory
pop ds ;Restore registers
popa
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 bx cx dx si ;Save registers
push ds ax
mov ds,[cs:CurVidSeg] ;DS = video memory
mov si,dx ;SI = y, BX = CX = x
mov bx,cx
mov ah,bl
and ah,3 ;AH = bit plane
shr bx,2 ;BX = X offset
mov dx,03CEh ;Graphics port
mov al,4 ;Set Read Plane
out dx,ax
mov ax,90 ;Multiply Y by 90
mul si
add bx,ax ;BX = offset
pop ax ;Restore AX
mov al,[bx] ;Get byte
pop ds si dx cx bx ;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
mov ds,[cs:CurVidSeg] ;DS = video memory
mov dx,03C4h ;Sequencer port
mov ax,0F02h ;Set Map Mask
out dx,ax
xor ax,ax ;Clear AX
xor di,di ;Clear DI
mov si,10 ;SI = 10
mov cx,1080 ;1080 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
mov es,[cs:CurVidSeg] ;ES = video memory
mov ax,[cs:MinX] ;Get corners of viewport
mov bx,[cs:MinY] ;in AX, BX, CX, DX
mov cx,[cs:MaxX]
mov dx,[cs:MaxY]
sub dx,bx ;DX = height
mov di,ax ;Put X1, X2 in DI, SI
mov si,cx
shr di,2 ;Divide them by 4
shr si,2
push ax ;Save AX
mov al,90 ;Multiply Y by 90
mul bl
add di,ax ;Add to X1
add si,ax ;Add to X2
pop ax ;Restore AX
and ax,3 ;AX = X1 mod 4
and cx,3 ;CX = Y1 mod 4
mov bx,0101h ;BL = 1, BH = 1
inc cl ;Adjust shift count
shl bh,cl ;Calculate map mask
dec bh ;for the right side
xchg ax,cx ;Switch AX, CX
shl bl,cl ;for the left side
neg bl ;which is a little
add bl,16 ;more complicated
cmp si,di ;Thin rectangle?
je cv_thin ;Jump if yes
cv_loop: pusha ;Save all registers
mov dx,03C4h ;Sequencer port
mov al,2 ;Set Map Mask
mov ah,bl ;Left side
out dx,ax ;Send command
xor al,al ;AL = 0 (black)
stosb ;Store byte
mov al,2 ;Set Map Mask
mov ah,bh ;Right side
out dx,ax ;Send command
mov [byte es:si],0 ;Store byte
mov ax,0F02h ;Enable all planes
out dx,ax ;Send command
mov al,ch ;AL = color
mov ah,al ;AH = color
mov cx,si ;CX = distance
sub cx,di
xor dx,dx ;Clear DX
shr cx,1 ;CX = words
adc dx,0 ;DX = odd byte
rep stosw ;Store by words
mov cx,dx ;Get odd byte
rep stosb ;Store odd byte
popa ;Restore registers
add di,90 ;Next line
add si,90
dec dx ;Dec line counter
jns cv_loop ;Loop back
jmp cv_done ;Return
cv_thin: and bl,bh ;AND masks together
push dx ;Save DX
mov dx,03C4h ;Sequencer port
mov al,2 ;Set Map Mask
mov ah,bl ;Short line
out dx,ax ;Send command
pop dx ;Restore DX
xor al,al ;AL = 0 (black)
cvt_loop: stosb ;Store byte
add di,89 ;Next line
dec dx ;Dec line counter
jns cvt_loop ;Loop back
cv_done: 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
mov es,[cs:CurVidSeg] ;ES = video memory
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: push cx dx ;Save registers
mov bp,si
mov si,dx ;SI = y, BX = CX = x
mov bx,cx
and cl,3 ;CL = bit plane
mov ah,1 ;AH = plane mask
shl ah,cl
shr bx,2 ;BX = X offset
mov dx,03C4h ;Sequencer port
mov al,2 ;Set Map Mask
out dx,ax
mov ax,90 ;Multiply Y by 90
mul si
add bx,ax ;BX = offset
mov ch,[Color] ;CH = color
mov [es:bx],ch ;Store byte
pop dx cx ;Restore registers
mov si,bp
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: cmp cx,ax ;X1 > X2?
jge lh_xplus
xchg cx,ax ;Switch them
lh_xplus: mov di,ax ;Put X1, X2 in DI, SI
mov si,cx
shr di,2 ;Divide them by 4
shr si,2
push ax ;Save AX
mov al,90 ;Multiply Y by 90
mul bl
add di,ax ;Add to X1
add si,ax ;Add to X2
pop ax ;Restore AX
and ax,3 ;AX = X1 mod 4
and cx,3 ;CX = Y1 mod 4
mov bx,0101h ;BL = 1, BH = 1
inc cl ;Adjust shift count
shl bh,cl ;Calculate map mask
dec bh ;for the right side
xchg ax,cx ;Switch AX, CX
shl bl,cl ;for the left side
neg bl ;which is a little
add bl,16 ;more complicated
cmp si,di ;Short line?
je lh_short ;Jump if yes
mov dx,03C4h ;Sequencer port
mov al,2 ;Set Map Mask
mov ah,bl ;Left side
out dx,ax ;Send command
mov al,[Color] ;AL = color
mov ch,al ;CH = color
stosb ;Store byte
mov al,2 ;Set Map Mask
mov ah,bh ;Right side
out dx,ax ;Send command
mov [es:si],ch ;Store byte
mov ax,0F02h ;Enable all planes
out dx,ax ;Send command
mov al,ch ;AL = color
mov ah,al ;AH = color
mov cx,si ;CX = distance
sub cx,di
xor dx,dx ;Clear DX
shr cx,1 ;CX = words
adc dx,0 ;DX = odd byte
rep stosw ;Store by words
mov cx,dx ;Get odd byte
rep stosb ;Store odd byte
jmp l_done ;Return
lh_short: and bl,bh ;AND masks together
mov dx,03C4h ;Sequencer port
mov al,2 ;Set Map Mask
mov ah,bl ;Short line
out dx,ax ;Send command
mov al,[Color] ;AL = color
stosb ;Store 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: push ax ;Save X
mov al,90 ;AX = Y * 90
mul bl
pop bx ;BX = X
mov cl,bl ;CL = low 2 bits of X
and cl,3
shr bx,2 ;X = X / 4
add ax,bx ;AX = X + Y * 90
mov di,ax ;Offset in DI
mov ah,1 ;AH = 1
shl ah,cl ;AH = bit plane mask
mov al,2 ;AL = 2: Set Map Mask
push dx ;Save DX
mov dx,03C4h ;Sequencer Port
out dx,ax ;Send command
pop dx ;Restore DX
mov al,[Color] ;AL = color
ALIGN 16 ;Force paragraph alignment
lv_loop: stosb ;Write pixel
add di,89 ;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
mov es,[cs:CurVidSeg] ;ES = video memory
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: sub dx,bx ;DX = height
mov di,ax ;Put X1, X2 in DI, SI
mov si,cx
shr di,2 ;Divide them by 4
shr si,2
push ax ;Save AX
mov al,90 ;Multiply Y by 90
mul bl
add di,ax ;Add to X1
add si,ax ;Add to X2
pop ax ;Restore AX
and ax,3 ;AX = X1 mod 4
and cx,3 ;CX = Y1 mod 4
mov bx,0101h ;BL = 1, BH = 1
inc cl ;Adjust shift count
shl bh,cl ;Calculate map mask
dec bh ;for the right side
xchg ax,cx ;Switch AX, CX
shl bl,cl ;for the left side
neg bl ;which is a little
add bl,16 ;more complicated
cmp si,di ;Thin rectangle?
je fr_thin ;Jump if yes
fr_loop: pusha ;Save all registers
mov dx,03C4h ;Sequencer port
mov al,2 ;Set Map Mask
mov ah,bl ;Left side
out dx,ax ;Send command
mov al,[Color] ;AL = color
mov ch,al ;CH = color
stosb ;Store byte
mov al,2 ;Set Map Mask
mov ah,bh ;Right side
out dx,ax ;Send command
mov [es:si],ch ;Store byte
mov ax,0F02h ;Enable all planes
out dx,ax ;Send command
mov al,ch ;AL = color
mov ah,al ;AH = color
mov cx,si ;CX = distance
sub cx,di
xor dx,dx ;Clear DX
shr cx,1 ;CX = words
adc dx,0 ;DX = odd byte
rep stosw ;Store by words
mov cx,dx ;Get odd byte
rep stosb ;Store odd byte
popa ;Restore registers
add di,90 ;Next line
add si,90
dec dx ;Dec line counter
jns fr_loop ;Loop back
jmp fr_done ;Return
fr_thin: and bl,bh ;AND masks together
push dx ;Save DX
mov dx,03C4h ;Sequencer port
mov al,2 ;Set Map Mask
mov ah,bl ;Short line
out dx,ax ;Send command
pop dx ;Restore DX
mov al,[Color] ;AL = color
frt_loop: stosb ;Store byte
add di,89 ;Next line
dec dx ;Dec line counter
jns frt_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
mov es,[cs:CurVidSeg] ;ES = video memory
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
push ax cx ;Save AX, CX
and cl,3 ;Calculate map mask
mov ch,1
shl ch,cl
mov [cs:init_mask],ch ;Save mask
pop cx ;Restore CX
mov ax,90 ;Get offset, which is
mul dx ;x / 4 + 90 * y
shr cx,2
add cx,ax
mov di,cx ;Offset in DI
pop ax ;Restore AX
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
ALIGN 16 ;Force paragraph alignment
oc_8loop: mov bl,[si] ;Load byte
mov bh,80h
inc si
push cx di ;Save CX, DI
mov ah,[cs:init_mask] ;Get initial mask
mov al,2 ;Set Map Mask command
mov dx,03C4h ;Sequencer port
mov cx,8 ;8 wide
oc_8pxloop: test bl,bh ;Is bit set?
jz oc_8px1 ;Jump if not
out dx,ax ;Set sequencer
push ax ;Save AX
mov al,[cs:Color] ;Put color byte
mov [es:di],al ;on screen
pop ax
oc_8px1: shl ah,1 ;Next pixel
shr bh,1
test ah,16 ;Byte boundary?
jz oc_8pxlb ;Jump if not
mov ah,1 ;Next byte,
inc di ;mask = 0001
oc_8pxlb: dec cx ;Loop back
jnz oc_8pxloop
pop di cx ;Restore CX, DI
add di,90 ;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
ALIGN 16 ;Force paragraph alignment
oc_6loop: mov bl,[si] ;Load byte
mov bh,80h
inc si
push cx di ;Save CX, DI
mov ah,[cs:init_mask] ;Get initial mask
mov al,2 ;Set Map Mask command
mov dx,03C4h ;Sequencer port
mov cx,6 ;6 wide
oc_6pxloop: test bl,bh ;Is bit set?
jz oc_6px1 ;Jump if not
out dx,ax ;Set sequencer
push ax ;Save AX
mov al,[cs:Color] ;Put color byte
mov [es:di],al ;on screen
pop ax
oc_6px1: shl ah,1 ;Next pixel
shr bh,1
test ah,16 ;Byte boundary?
jz oc_6pxlb ;Jump if not
mov ah,1 ;Next byte,
inc di ;mask = 0001
oc_6pxlb: dec cx ;Loop back
jnz oc_6pxloop
pop di cx ;Restore CX, DI
add di,90 ;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
init_mask db 0
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
mov ds,[cs:CurVidSeg] ;DS = video memory
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
push ax ;SI = offset
mov ax,90 ;(x + y * 90)
mul dx
mov bp,cx ;BP = horiz. position
shr cx,2
add cx,ax
pop ax
mov si,cx
stosw ;Store width
mov cx,ax ;CX = width
mov ax,bx ;AX = height
stosw ;Store height
mov dx,03CEh ;Graphics Controller Port
mov ax,bp ;Horiz. position in AH
mov ah,al
mov al,4 ;Set Read Plane command
and ah,3
mov [cs:gi_plane],ah ;gi_plane = starting plane
mov [cs:gi_cplane],0 ;gi_cplane = 0
gi_ploop: out dx,ax ;Send command
push ax bx cx si ;Save AX, BX, CX, SI
mov bp,si ;BP = SI
add cx,3 ; (CX + 3 - Plane)
sub cx,[cs:gi_cplane] ;CX = ----------------
shr cx,2 ; 4
mov [cs:gi_width],cx ;Save CX
gi_loop: mov cx,[cs:gi_width] ;Get width
shr cx,1 ;Divide by 2
rep movsw ;Move by words
test [cs:gi_width],1 ;Odd byte?
jz $+3 ;Jump if not
movsb ;Move odd byte
add bp,90 ;Next line
mov si,bp ;Offset in SI
dec bx ;Decrement counter
jnz gi_loop ;Loop back
pop si cx bx ax ;Restore registers
inc ah ;Next plane
cmp ah,4 ;Next byte too?
jne $+5 ;Jump if not
inc si ;Increment offset
xor ah,ah ;Plane 0
inc [cs:gi_cplane] ;Next plane
cmp ah,[cs:gi_plane] ;Back to start?
jne gi_ploop ;Jump if not
pop es ds ;Restore registers
popa
ret ;Return
EVEN ;Force word alignment
gi_width dw 0 ;Total width
gi_cplane dw 0 ;Current plane
gi_plane db 0 ;Starting plane
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
mov es,[cs:CurVidSeg] ;ES = video memory
lodsw ;Load width
mov bx,ax ;Put it in CX
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
push ax ;DI = offset
mov ax,90 ;(x + y * 90)
mul dx
mov bp,cx ;BP = horiz. position
shr cx,2
add cx,ax
pop ax
mov di,cx
mov cx,bx ;CX = width
mov bx,ax ;BX = height
mov dx,03C4h ;Sequencer Port
mov al,2 ;Set Write Plane command
mov ah,11h ;AH = 11h
xchg cx,bp ;Switch with CX
and cl,3 ;CX = CX and 3
shl ah,cl ;AH = AH shl CX
mov cx,bp ;Restore CX
mov [cs:pi_plane],ah ;pi_plane = starting plane
mov [cs:pi_cplane],0 ;pi_cplane = 0
pi_ploop: out dx,ax ;Send command
push ax bx cx di ;Save AX, BX, CX, DI
mov bp,di ;BP = DI
add cx,3 ; (CX + 3 - Plane)
sub cx,[cs:pi_cplane] ;CX = ----------------
shr cx,2 ; 4
mov [cs:pi_width],cx ;Save CX
pi_loop: mov cx,[cs:pi_width] ;Get width
shr cx,1 ;Divide by 2
rep movsw ;Move by words
test [cs:pi_width],1 ;Odd byte?
jz $+3 ;Jump if not
movsb ;Move odd byte
add bp,90 ;Next line
mov di,bp ;Offset in SI
dec bx ;Decrement counter
jnz pi_loop ;Loop back
pop di cx bx ax ;Restore registers
shl ah,1 ;Next plane
jnc $+5 ;Next byte too?
inc di ;Increment offset
mov ah,11h ;Plane 0
inc [cs:pi_cplane] ;Next plane
cmp ah,[cs:pi_plane] ;Back to start?
jne pi_ploop ;Jump if not
pi_done: pop es ds ;Restore registers
popa
ret ;Return
EVEN ;Force word alignment
pi_width dw 0 ;Total width
pi_cplane dw 0 ;Current plane
pi_plane db 0 ;Starting plane
EndP PutImage
End Start