home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Virtual Reality Zone
/
VRZONE.ISO
/
mac
/
PC
/
REND386
/
FPOLY16
/
VGALINE.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-01-13
|
11KB
|
713 lines
TITLE VGALINE - Fast line drawing routine.
NAME VGALINE
COMMENT $
Name: VGALINE
Written and (c) by Dave Stampe 9/11/91
Not for commercial use, so get permission
before marketing code using this stuff!
For private PD use only.
$
COMMENT $
Name: VGALINE
Function: Draw a line in VGA 200 line 16 colour mode
Caller: C:
void vgaline(x1, y1, x2, y2, n);
int x1, y1, x2, y2; /* pixel co-ords */
int n; /* color */
no checking on endpoints!
Adapted from Richard Wilton's code (PC and PS/2 Video Systems).
Modified to use VGA write mode 3 (much faster)
Call setup_hdwe() before drawing groups of lines
$
.MODEL large
.CODE
BytesPerLine EQU 40
extrn _dpaddr
egapaddr PROC far
mov cl,bl
push dx
mov dx,BytesPerLine
mul dx
pop dx
shr bx,1
shr bx,1
shr bx,1
add bx,ax
add bx,word ptr ds:_dpaddr
mov ax,0a000h
mov es,ax
and cl,7
xor cl,7
mov ah,1
ret
egapaddr endp
; Stack frame addressing - LARGE CODE MODEL
ARGx1 EQU word ptr [bp+6]
ARGy1 EQU word ptr [bp+8]
ARGx2 EQU word ptr [bp+10]
ARGy2 EQU word ptr [bp+12]
ARGn EQU byte ptr [bp+14]
VARvertincr EQU word ptr [bp-6]
VARincr1 EQU word ptr [bp-8]
VARincr2 EQU word ptr [bp-10]
VARroutine EQU word ptr [bp-12]
ByteOffsetShift EQU 3
RMWbits EQU 0
PUBLIC _vgaline
_vgaline PROC far
push bp ; Set up stack frame
mov bp,sp
sub sp,14
push si
push di
; set color
mov dx,03CEH
xor al,al
mov ah,ARGn
out dx,ax
; check for vertical line
mov si,BytesPerLine
mov cx,ARGx2
sub cx,ARGx1
jz VertLine
; force x1 < x2
jns L01
neg cx
mov bx,ARGx2
xchg bx,ARGx1
mov ARGx2,bx
mov bx,ARGy2
xchg bx,ARGy1
mov ARGy2,bx
; calc dy = abs(y2 - y1)
L01:
mov bx,ARGy2
sub bx,ARGy1
jz HorizLine
jns L03
neg bx
neg si
; select appropriate routine for slope of line
L03:
mov VARvertincr,si
mov VARroutine,offset LoSlopeLine
cmp bx,cx
jle L04
mov VARroutine,offset HiSlopeLine
xchg bx,cx
; calc initial decision variable and increments
L04:
shl bx,1
mov VARincr1,bx
sub bx,cx
mov si,bx
sub bx,cx
mov VARincr2,bx
; calc first pixel address
push cx
mov ax,ARGy1
mov bx,ARGx1
call egapaddr
mov di,bx
shl ah,cl
mov bl,ah
pop cx
inc cx
jmp VARroutine
; routine for verticle lines
VertLine:
mov ax,ARGy1
mov bx,ARGy2
mov cx,bx
sub cx,ax
jge L31
neg cx
mov ax,bx
L31:
inc cx
mov bx,ARGx1
push cx
call egapaddr
shl ah,cl
pop cx
; draw the line
L32:
and es:[bx],ah
add bx,si
loop L32
jmp Lexit
; routine for horizontal line
HorizLine:
push ds
mov ax,ARGy1
mov bx,ARGx1
call egapaddr
mov di,bx
mov dh,ah
not dh
shl dh,cl
not dh
mov cx,ARGx2
and cl,7
xor cl,7
mov dl,0FFH
shl dl,cl
; determine byte offset of first and last pixel in line
mov ax,ARGx2
mov bx,ARGx1
mov cl,ByteOffsetShift
shr ax,cl
shr bx,cl
mov cx,ax
sub cx,bx
mov bx,dx
; set pixels in leftmost byte of line
or bh,bh
js L43
or cx,cx
jnz L42
and bl,bh
jmp short L44
L42:
and es:[di],bh
inc di
dec cx
; draw remainder of the line
L43:
mov al,0FFH
rep stosb
; set pixels in rightmost byte of line
L44:
and es:[di],bl
pop ds
jmp short Lexit
; routine for dy >= dx (slope <= 1)
LoSlopeLine:
L10:
mov ah,bl
L11:
or ah,bl
ror bl,1
jc L14
; bit mask not shifted out
or si,si
jns L12
add si,VARincr1
loop L11
and es:[di],ah
jmp short Lexit
L12:
add si,VARincr2
and es:[di],ah
add di,VARvertincr
loop L10
jmp short Lexit
; bit mask shifted out
L14:
and es:[di],ah
inc di
or si,si
jns L15
add si,VARincr1
loop L10
jmp short Lexit
L15:
add si,VARincr2
add di,VARvertincr
loop L10
jmp short Lexit
; routine for dy > dx (slope > 1)
HiSlopeLine:
mov bx,VARvertincr
L21:
and es:[di],ah
add di,bx
L22:
or si,si
jns L23
add si,VARincr1
loop L21
jmp short Lexit
L23:
add si,VARincr2
ror ah,1
adc di,0
loop L21
; return to caller
Lexit:
pop di
pop si
mov sp,bp
pop bp
ret
_vgaline endp
;
; int clipper (lpoints far *lp)
;
; /* returns 0 if unclipped, 1 if clipped, and -1 if invisible */
;
; Improved assembly version of Sutherland-Cohen line clipper
; Much more optimized than C version, and knows when to
; stop clipping!
;
PUBLIC _clipper
x1 EQU word ptr es:[bx] ; elements in point array
y1 EQU word ptr es:[bx+2]
x2 EQU word ptr es:[bx+4]
y2 EQU word ptr es:[bx+6]
left equ 8 ; clipping flag bits
above equ 4
right equ 2
below equ 1
EXTRN _l_clip ; clipping recangle (assumed in ds)
EXTRN _r_clip
EXTRN _t_clip
EXTRN _b_clip
_clipper proc far
.386 ; required for jump length only
push bp
mov bp,sp
dec sp
dec sp
push si
push di
les bx,dword ptr [bp+6] ; setup access to points
xor di,di ; flag1 = 0
mov ax,x1
cmp ax,word ptr ds:_l_clip ; set flag bits based on pos'n
jge short nleft1 ; for point 1
or di,8
nleft1:
cmp ax,word ptr ds:_r_clip
jle short nright1
or di,2
nright1:
mov ax,y1
cmp ax,word ptr ds:_t_clip
jge short ntop1
or di,4
ntop1:
cmp ax,word ptr ds:_b_clip
jle short nbot1
or di,1
nbot1:
xor si,si ; flag2 = 0
mov ax,x2
cmp ax,word ptr ds:_l_clip ; set flag bits based on pos'n
jge short nleft2 ; for point 2
or si,8
nleft2:
cmp ax,word ptr ds:_r_clip
jle short nright2
or si,2
nright2:
mov ax,y2
cmp ax,word ptr ds:_t_clip
jge short ntop2
or si,4
ntop2:
cmp ax,word ptr ds:_b_clip
jle short nbot2
or si,1
nbot2:
mov ax,di ; check if all inside rect
or ax,si
jne short not_in_box
xor ax,ax ; return 0: not clipped
rexit:
pop di
pop si ; early return
mov sp,bp
pop bp
ret
not_in_box:
test di,si ; check if all out of rect
je short needs_clipping
diagerr: ; too many clipping (diagonal)
mov ax,65535
jmp rexit ; return -1 (out of window)
needs_clipping: ; gotta do some serious work...
or di,di ; quick test if pt.1 OK
jne clip1
jmp do2
clip1: ; clipping point 1:
test di,8 ; left flag?
je short notleft1
doleft1:
;
; lp->y1 += (long)(lp->y2-lp->y1)*(l_clip-lp->x1)/(lp->x2-lp->x1);
;
mov cx,x2 ; denominator: 0?
sub cx,x1
je dontleft1
mov ax,y2
sub ax,y1
mov dx,ds:_l_clip
sub dx,x1
imul dx
idiv cx
add y1,ax
dontleft1:
mov dx,ds:_l_clip ; clip left
mov x1,dx
mov ax,y1 ; check if vert. clipping needed
cmp ax,word ptr ds:_t_clip
jl doabove1
cmp ax,word ptr ds:_b_clip
jg dobelow1
jmp do2 ; else check point 2
notleft1:
test di,2 ; test if right needs clipping
je notright1
doright1:
;
; lp->y1 += (long)(lp->y2-lp->y1)*(r_clip-lp->x1)/(lp->x2-lp->x1);
;
mov cx,x2 ; denominator: 0?
sub cx,x1
je dontright1
mov ax,y2
sub ax,y1
mov dx,ds:_r_clip
sub dx,x1
imul dx
idiv cx
add y1,ax
dontright1:
mov dx,ds:_r_clip ; clip right
mov x1,dx
mov ax,y1
cmp ax,word ptr ds:_t_clip ; check if vert. clipping needed
jl doabove1
cmp ax,word ptr ds:_b_clip
jg dobelow1
jmp do2
notright1:
test di,4 ; test if top clip needed
je short notabove1
doabove1:
;
; lp->x1 += (long)(lp->x2-lp->x1)*(t_clip-lp->y1)/(lp->y2-lp->y1);
;
mov cx,y2 ; denominator: 0?
sub cx,y1
je dontabove1
mov ax,x2
sub ax,x1
mov dx,ds:_t_clip
sub dx,y1
imul dx
idiv cx
add x1,ax
dontabove1:
mov dx,ds:_t_clip ; clip top
mov y1,dx
mov ax,x1
cmp ax,word ptr ds:_l_clip ; if hor. clip req, diagonal outside
jl diagerr ; doleft1
cmp ax,word ptr ds:_r_clip
jg diagerr ;doright1
jmp short do2
notabove1:
test di,1 ; test if bottom needs clipping
je short do2
dobelow1:
;
; lp->x1 += (long)(lp->x2-lp->x1)*(b_clip-lp->y1)/(lp->y2-lp->y1);
;
mov cx,y2 ; denominator: 0?
sub cx,y1
je dontbelow1
mov ax,x2
sub ax,x1
mov dx,ds:_b_clip
sub dx,y1
imul dx
idiv cx
add x1,ax
dontbelow1:
mov dx,ds:_b_clip
mov y1,dx
mov ax,x1
cmp ax,ds:_l_clip
jl diagerr ;oleft1
cmp ax,word ptr ds:_r_clip
jg diagerr ;doright1
do2:
or si,si ; same deal for point 2
je done2
test si,8
je short notleft2
doleft2:
;
; lp->y2 += (long)(lp->y1-lp->y2)*(l_clip-lp->x2)/(lp->x1-lp->x2);
;
mov cx,x1 ; denominator: 0?
sub cx,x2
je dontleft2
mov ax,y1
sub ax,y2
mov dx,ds:_l_clip
sub dx,x2
imul dx
idiv cx
add y2,ax
dontleft2:
mov dx,ds:_l_clip
mov x2,dx
mov ax,y2
cmp ax,word ptr ds:_t_clip
jl doabove2
cmp ax,word ptr ds:_b_clip
jg dobelow2
jmp done2
notleft2:
test si,2 ; test if right needs clipping
je notright2
doright2:
;
; lp->y2 += (long)(lp->y1-lp->y2)*(r_clip-lp->x2)/(lp->x1-lp->x2);
;
mov cx,x1 ; denominator: 0?
sub cx,x2
je dontright2
mov ax,y1
sub ax,y2
mov dx,ds:_r_clip
sub dx,x2
imul dx
idiv cx
add y2,ax
dontright2:
mov dx,ds:_r_clip
mov x2,dx
mov ax,y2
cmp ax,word ptr ds:_t_clip
jl doabove2
cmp ax,word ptr ds:_b_clip
jg dobelow2
jmp done2
notright2:
test si,4 ; test if top clip needed
je short notabove2
doabove2:
;
; lp->x2 += (long)(lp->x1-lp->x2)*(t_clip-lp->y2)/(lp->y1-lp->y2);
;
mov cx,y1 ; denominator: 0?
sub cx,y2
je dontabove2
mov ax,x1
sub ax,x2
mov dx,ds:_t_clip
sub dx,y2
imul dx
idiv cx
add x2,ax
dontabove2:
mov dx,ds:_t_clip
mov y2,dx
mov ax,x2
cmp ax,word ptr ds:_l_clip
jl diagerr ;doleft2
cmp ax,word ptr ds:_r_clip
jg diagerr ;doright2
jmp short done2
notabove2:
test si,1 ; test if bottom needs clipping
je short done2
dobelow2:
;
; lp->x2 += (long)(lp->x1-lp->x2)*(b_clip-lp->y2)/(lp->y1-lp->y2);
;
mov cx,y1 ; denominator: 0?
sub cx,y2
je dontbelow2
mov ax,x1
sub ax,x2
mov dx,ds:_b_clip
sub dx,y2
imul dx
idiv cx
add x2,ax
dontbelow2:
mov dx,ds:_b_clip
mov y2,dx
mov ax,x2
cmp ax,ds:_l_clip
jl diagerr ;doleft2
cmp ax,word ptr ds:_r_clip
jg diagerr ;doright2
done2: ; finished point 2
mov ax,1 ; return 1 for successful clipping
pop di
pop si
mov sp,bp
pop bp
ret
_clipper endp
end