home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Virtual Reality Homebrewer's Handbook
/
vr.iso
/
vr386
/
xyclip.asm
< prev
Wrap
Assembly Source File
|
1996-03-19
|
15KB
|
756 lines
TITLE XYCLIP - SUTHERLAND-HODGEMAN CLIPPER IN ASSEMBLER
COMMENT $
// 26/12/93 by Dave Stampe
// All algorithms and code (c) 1993 by Dave Stampe
/*
This code is part of the REND386 project, created by Dave Stampe and
Bernie Roehl.
Copyright 1992, 1993, 1994 by Dave Stampe and Bernie Roehl.
May be freely used to write software for release into the public domain;
all commercial endeavours MUST contact BOTH Bernie Roehl and Dave Stampe
for permission to incorporate any part of this software into their
products! Usually there is no charge for under 50-100 items for
low-cost or shareware, and terms are reasonable. Any royalties are used
for development, so equipment is often acceptable payment.
ATTRIBUTION: If you use any part of this source code or the libraries
in your projects, you must give attribution to REND386, Dave Stampe,
and Bernie Roehl in your documentation, source code, and at startup
of your program. Let's keep the freeware ball rolling! No more
code ripoffs please.
CONTACTS: dstampe@psych.toronto.edu, broehl@sunee.uwaterloo.ca
See the COPYRITE.H file for more information.
*/
This is a reasonably efficient semi-recursive XY screen clipper
for polygons. XY_clip_array() is the C call, which takes an array of
(NVERTEX *) and processes to an output array. New clipped vertices
may be produced: old vertices are not discarded.
/* Contact: dstampe@sunee.waterloo.edu */
$
.MODEL large
.386
.DATA
include 3dstruct.inc
include viewdata.inc
; clipper record variables
first_top_vtx dd 0 ; for each level: record first, and latest vertex
last_top_vtx dd 0
first_bottom_vtx dd 0
last_bottom_vtx dd 0
first_left_vtx dd 0
last_left_vtx dd 0
first_right_vtx dd 0
last_right_vtx dd 0
destptr dd 0 ; where to put output
vtxcount dw 0 ; vertex passed count
include rendmem.inc
.CODE RENDERER
; defined in RENDMEM.INC
; alloc new vertex
; returns new vertex in ES:BX
; BX only affected
;ALLOCVTX MACRO
; les bx,_nvalloc
; sub bx, SIZE NVERTEX
; mov _nvalloc,bx
; mov WORD PTR es:[bx].NV_persp,0
; ENDM
;/********** CREATE NEW INTERCEPT VERTEX **************/
; static NVERTEX *y_intercept(NVERTEX *v1, NVERTEX *v2, long edge)
; static NVERTEX *x_intercept(NVERTEX *v1, NVERTEX *v2, long edge)
; ARGUMENTS:
; v1: ES:SI
; v2: ES:DI
; edge: ecx
; new, return: ES:BX
; MAKES ASSUMPTION THAT ALL
x1 equ DWORD PTR es:[di].NV_xs ; NVERTEX ARE IN SAME SEGMENT
y1 equ DWORD PTR es:[di].NV_ys
z1 equ DWORD PTR es:[di].NV_z ; vtx 1
x2 equ DWORD PTR es:[si].NV_xs ; vtx 2
y2 equ DWORD PTR es:[si].NV_ys
z2 equ DWORD PTR es:[si].NV_z
xn equ DWORD PTR es:[bx].NV_xs ; intercept
yn equ DWORD PTR es:[bx].NV_ys
zn equ DWORD PTR es:[bx].NV_z
y_intercept proc near
ALLOCVTX ; es:bx is new vertex, assume es is renderer temp
mov yn,ecx
mov ecx,y1
sub ecx,y2
jl fwd_clip_y ; clip from high end to prevent roundoff
jg rev_clip_y
mov eax,x1 ; no slope: copy vtx 1
mov xn,eax
mov eax,z1
mov zn,eax
ret
rev_clip_y:
mov eax,yn ; compute new z
sub eax,y2
mov edx,z1
sub edx,z2
imul edx
idiv ecx
add eax,z2
mov zn,eax
mov eax,yn ; compute new x
sub eax,y2
mov edx,x1
sub edx,x2
imul edx
idiv ecx
add eax,x2
mov xn,eax
ret
fwd_clip_y:
neg ecx
mov eax,yn ; compute new z
sub eax,y1
mov edx,z2
sub edx,z1
imul edx
idiv ecx
add eax,z1
mov zn,eax
mov eax,yn ; compute new x
sub eax,y1
mov edx,x2
sub edx,x1
imul edx
idiv ecx
add eax,x1
mov xn,eax
ret
y_intercept endp
x_intercept proc near
ALLOCVTX ; es:bx is new vertex, assume es is renderer temp
mov xn,ecx
mov ecx,x1
sub ecx,x2
jl fwd_clip_x ; clip from high end to prevent roundoff
jg rev_clip_x
mov eax,y1 ; no slope: copy vtx 1
mov yn,eax
mov eax,z1
mov zn,eax
ret
rev_clip_x:
mov eax,xn ; compute new z
sub eax,x2
mov edx,z1
sub edx,z2
imul edx
idiv ecx
add eax,z2
mov zn,eax
mov eax,xn ; compute new y
sub eax,x2
mov edx,y1
sub edx,y2
imul edx
idiv ecx
add eax,y2
mov yn,eax
ret
fwd_clip_x:
neg ecx
mov eax,xn ; compute new z
sub eax,x1
mov edx,z2
sub edx,z1
imul edx
idiv ecx
add eax,z1
mov zn,eax
mov eax,xn ; compute new y
sub eax,x1
mov edx,y2
sub edx,y1
imul edx
idiv ecx
add eax,y1
mov yn,eax
ret
x_intercept endp
;/************* CLIPPER C INTERFACE **********/
; XY clip an array of vertices, store in array
; returns number of vertices produced
;
; int XY_clip_array(NVERTEX **src, NVERTEX **dest, int count);
src equ DWORD PTR [bp+8] ; arguments
dest equ DWORD PTR [bp+12]
count equ WORD PTR [bp+16]
srcptr equ DWORD PTR [bp-4] ; locals
n equ WORD PTR [bp-8] ; vertex counter
;CHECKMEM MACRO num_vertex ;; DEFINED IN RENDMEM.INC
; mov ax,num_vertex
; imul ax,SIZE NVERTEX
; add ax,200
; add ax,WORD PTR _npalloc
; neg ax
; add ax,WORD PTR _nvalloc ; carry clear if out of memory
; ENDM
PUBLIC _XY_clip_array
_XY_clip_array proc far
push ebp
mov ebp,esp
sub esp,16
push esi
push edi
push ecx
push edx
mov last_top_vtx,0 ; reset clipper variables
mov last_bottom_vtx,0
mov last_left_vtx,0
mov last_right_vtx,0
mov vtxcount,0
mov eax,src
mov srcptr,eax
mov eax,dest
mov destptr,eax
mov ax,count
mov n,ax
; enough mem for all vtxs?
CHECKMEM 10
jc have_memory
mov vtxcount,-1
jmp exit_clip
have_memory:
next_clip:
mov ax,OTOP ; call top level of clipper
push ax
les bx,srcptr
mov eax,es:[bx]
push eax
call near ptr XY_clip
add esp,6
add srcptr,4
dec n
jne next_clip
cmp count,2
jle exit_clip
mov ax,OTOP ; flush clipper
push ax
xor eax,eax
push eax
call near ptr XY_clip
add esp,6
exit_clip:
mov ax,vtxcount
pop edx
pop ecx
pop edi
pop esi
mov esp,ebp
pop ebp
ret
_XY_clip_array endp
;/************ RECURSIVE CLIPPER KERNAL *************/
;static void XY_clip(NVERTEX *vtx, int stage)
; /* XY semirecursive clipper */
; /* set last = NULL before first call */
; /* call with all (copied) vertices */
; /* call with NULL to flush */
; /* also copies output to poly table */
vtx equ DWORD PTR [bp+6] ; arguments
stage equ WORD PTR [bp+10] ; FOR NEAR CALL OFFSETS
XY_clip proc near
push ebp ; generic entry
mov ebp,esp
mov ax,stage ; find stage
cmp ax,OTOP
je top_clip
cmp ax,ORIGHT
je right_clip
cmp ax,OBOTTOM
je bottom_clip
jmp left_clip
XY_clip_bottom: ; fast local entries
push ebp
mov ebp,esp
jmp bottom_clip
XY_clip_left:
push ebp
mov ebp,esp
jmp left_clip
XY_clip_right:
push ebp
mov ebp,esp
jmp right_clip
XY_clip_top:
push ebp
mov ebp,esp
;;;;;;;; START OF TOP CLIP;;;;;;;;;;;
top_clip:
mov eax,DWORD PTR last_top_vtx ; is this the first?
or eax,eax
jnz not_first_top
or eax,vtx ; traps NULL if first=last
je right_clip
mov last_top_vtx,eax ; record
mov first_top_vtx,eax
les bx,vtx
mov al,BYTE PTR es:[bx].NV_ocode ; pass if in window
test al,OTOP ; we can use outcode on first only
jnz end_XY_clip
jmp right_clip
not_first_top: ; OK, we've got an edge
mov eax,DWORD PTR vtx
or eax,eax
jnz not_flush_top ; NULL to flush clipper
les si,first_top_vtx ; look for window top crossing
mov al,BYTE PTR es:[si].NV_ocode
les di,last_top_vtx
xor al,BYTE PTR es:[di].NV_ocode
test al,OTOP
jz right_clip
; nv = y_intercept(first_top_vtx, last_top_vtx, VS_top4);
; XY_clip(nv,RIGHT); /* process this new point */
mov ecx,_VS_top4 ; si,di,es already loaded
call y_intercept ; create intercept vertex
push es
push bx
call near ptr XY_clip_right ; and clip it
add esp,4
jmp right_clip ; continue to flush
not_flush_top:
les si,vtx
mov al,BYTE PTR es:[si].NV_ocode
push ax
les di,last_top_vtx
xor al,BYTE PTR es:[di].NV_ocode
test al,OTOP
jz do_top_clip
mov ecx,_VS_top4 ; si,di,es already loaded
call y_intercept ; create intercept vertex
push es
push bx ; and clip it
call near ptr XY_clip_right
add esp,4 ; continue with original vertex
do_top_clip:
mov eax,vtx ; ave as last vertex
mov last_top_vtx,eax
pop ax
test al,OTOP ; was vertex in window?
jnz end_XY_clip ; no: discard it
;;;;;;;; START OF RIGHT CLIP;;;;;;;;;;;
right_clip:
mov eax, last_right_vtx
or eax,eax
jnz not_first_right
or eax, vtx
je bottom_clip
mov last_right_vtx,eax ; first vertex
mov first_right_vtx,eax
les bx, vtx
mov eax, es:[bx].NV_xs
cmp eax, _VS_right4
jg end_XY_clip
jmp bottom_clip
not_first_right:
mov eax, vtx
or eax,eax
jnz not_flush_right
les si, first_right_vtx ; flush: test for in-out pair
mov eax, es:[si].NV_xs
cmp eax, _VS_right4
jle pas1b
les di, last_right_vtx
mov eax, es:[di].NV_xs
cmp eax, _VS_right4
jle pas2b
jmp bottom_clip
pas1b:
les di, last_right_vtx
mov eax, es:[di].NV_xs
cmp eax, _VS_right4
jg pas2b
jmp bottom_clip
pas2b:
; nv = x_intercept(first_right_vtx, last_right_vtx, VS_right4);
; XY_clip(nv,BOTTOM); /* process this new point */
mov ecx,_VS_right4 ; si,di,es already loaded
call x_intercept ; create intercept vertex
push es
push bx
call near ptr XY_clip_bottom ; and clip it
add esp,4
jmp bottom_clip ; continue to flush
not_flush_right: ; full in-out test
les si, vtx
mov eax, es:[si].NV_xs
cmp eax, _VS_right4
jle pat1b
les di, last_right_vtx
mov eax, es:[di].NV_xs
cmp eax, _VS_right4
jg no_right_clip
; nv = x_intercept(vtx, last_right_vtx, VS_right4);
; XY_clip(nv,BOTTOM); /* process this new point */
mov ecx,_VS_right4 ; si,di,es already loaded
call x_intercept ; create intercept vertex
push es
push bx
call near ptr XY_clip_bottom ; and clip it
add esp,4
no_right_clip:
mov eax, vtx ; save
mov last_right_vtx,eax ; was outside, so junk vtx
jmp end_XY_clip
pat1b: ; in-window test cont'd
les di, last_right_vtx
mov eax, es:[di].NV_xs
cmp eax, _VS_right4
jle do_right_clip
; nv = x_intercept(vtx, last_right_vtx, VS_right4);
; XY_clip(nv,BOTTOM); /* process this new point */
mov ecx,_VS_right4 ; si,di,es already loaded
call x_intercept ; create intercept vertex
push es
push bx
call near ptr XY_clip_bottom ; and clip it
add esp,4
do_right_clip:
mov eax, vtx ; was in window: continue
mov last_right_vtx,eax
;;;;;;;; START OF BOTTOM CLIP;;;;;;;;;;;
bottom_clip:
mov eax, last_bottom_vtx
or eax,eax
jnz not_first_bottom
or eax, vtx
je left_clip
mov last_bottom_vtx,eax
mov first_bottom_vtx,eax
les bx, vtx
mov eax, es:[bx].NV_ys
cmp eax, _VS_bottom4
jg end_XY_clip
jmp left_clip
not_first_bottom:
mov eax, vtx
or eax,eax
jnz not_flush_bottom
les si, first_bottom_vtx
mov eax, es:[si].NV_ys
cmp eax, _VS_bottom4
jle pas1bb
les di, last_bottom_vtx
mov eax, es:[di].NV_ys
cmp eax, _VS_bottom4
jle pas2bb
jmp left_clip
pas1bb:
les di, last_bottom_vtx
mov eax, es:[di].NV_ys
cmp eax, _VS_bottom4
jg pas2bb
jmp left_clip
pas2bb:
; nv = y_intercept(first_bottom_vtx, last_bottom_vtx, VS_bottom4);
; XY_clip(nv,LEFT); /* process this new point */
mov ecx,_VS_bottom4 ; si,di,es already loaded
call y_intercept ; create intercept vertex
push es
push bx
call near ptr XY_clip_left ; and clip it
add esp,4
jmp left_clip ; continue flush
not_flush_bottom:
les si, vtx
mov eax, es:[si].NV_ys
cmp eax, _VS_bottom4
jle pat1t
les di, last_bottom_vtx
mov eax, es:[di].NV_ys
cmp eax, _VS_bottom4
jg no_bottom_clip
; nv = y_intercept(vtx, last_bottom_vtx, VS_bottom4);
; XY_clip(nv,LEFT); /* process this new point */
mov ecx,_VS_bottom4 ; si,di,es already loaded
call y_intercept ; create intercept vertex
push es
push bx
call near ptr XY_clip_left ; and clip it
add esp,4
no_bottom_clip:
mov eax, vtx
mov last_bottom_vtx,eax
jmp end_XY_clip ; out, so discard it
pat1t:
les di, last_bottom_vtx
mov eax, es:[di].NV_ys
cmp eax, _VS_bottom4
jle do_bottom_clip
; nv = y_intercept(vtx, last_bottom_vtx, VS_bottom4);
; XY_clip(nv,LEFT); /* process this new point */
mov ecx,_VS_bottom4 ; si,di,es already loaded
call y_intercept ; create intercept vertex
push es
push bx
call near ptr XY_clip_left ; and clip it
add esp,4 ; in, so continue
do_bottom_clip:
mov eax, vtx
mov last_bottom_vtx,eax
;;;;;;;; START OF LEFT CLIP;;;;;;;;;;;
left_clip:
mov eax, last_left_vtx
or eax,eax
jnz not_first_left
or eax, vtx
je end_XY_clip
mov last_left_vtx,eax
mov first_left_vtx,eax
les bx, vtx
mov eax, es:[bx].NV_xs
cmp eax, _VS_left4
jl end_XY_clip
jmp do_left_clip
not_first_left:
mov eax, vtx
or eax,eax
jnz not_flush_left
les si, first_left_vtx
mov eax, es:[si].NV_xs
cmp eax, _VS_left4
jge pas1x
les di, last_left_vtx
mov eax, es:[di].NV_xs
cmp eax, _VS_left4
jge pas2x
jmp end_XY_clip
pas1x:
les di, last_left_vtx
mov eax, es:[di].NV_xs
cmp eax, _VS_left4
jge end_XY_clip
pas2x:
; nv = x_intercept(first_left_vtx, last_left_vtx, VS_left4);
mov ecx,_VS_left4 ; si,di,es already loaded
call x_intercept ; create intercept vertex
mov ax,es ; build far ptr
shl eax,16
mov ax,bx
les di,destptr
add destptr,4
mov es:[di],eax ; store new vertex ptr
inc vtxcount
jmp end_XY_clip
not_flush_left:
les si, vtx
mov eax, es:[si].NV_xs
cmp eax, _VS_left4
jge pat1x
les di, last_left_vtx
mov eax, es:[di].NV_xs
cmp eax, _VS_left4
jl no_left_clip
; nv = x_intercept(vtx, last_left_vtx, VS_left4);
mov ecx,_VS_left4 ; si,di,es already loaded
call x_intercept ; create intercept vertex
mov ax,es ; build far ptr
shl eax,16
mov ax,bx
les di,destptr
add destptr,4
mov es:[di],eax ; store new vertex ptr
inc vtxcount
no_left_clip:
mov eax, vtx
mov last_left_vtx,eax
jmp end_XY_clip
pat1x:
les di, last_left_vtx
mov eax, es:[di].NV_xs
cmp eax, _VS_left4
jge do_left_clip
; nv = x_intercept(vtx, last_left_vtx, VS_left4);
mov ecx,_VS_left4 ; si,di,es already loaded
call x_intercept ; create intercept vertex
mov ax,es ; build far ptr
shl eax,16
mov ax,bx
les di,destptr
add destptr,4
mov es:[di],eax ; store new vertex ptr
inc vtxcount
do_left_clip:
mov eax, vtx
mov last_left_vtx,eax
les di,destptr
add destptr,4
mov es:[di],eax ; store new vertex ptr
inc vtxcount
end_XY_clip:
mov esp,ebp
pop ebp
ret
XY_clip endp
end