;/**************************************************************************** ;** MODULE: adrawclp.asm ;** AUTHOR: Sami Tammilehto / Fennosoftec OY ;** DOCUMENT: ? ;** VERSION: 1.0 ;** REFERENCE: - ;** REVISED BY: - ;***************************************************************************** ;** ;** Polygon clipping (included to adraw.asm) ;** All routines take DS:SI as an entry list and write a clipped list to ;** ES:DI. The clipnear also returns in AX the orred visvf for the clipped ;** polygon since it might change during Z clipping. ;** ;****************************************************************************/ ALIGN 16 newclipflip db 0,0 newclipprog dw 0 clipcount dw 0 clipzero dw 0 clipvisfl dw 0 newclip_grd PROC NEAR ;DS:BX->DS:SI is clipped at CX (BX end=0..16384=SI end) ;resulted clip stored to ES:DI mov ax,ds:[bx+POLYGR] sub ax,ds:[si+POLYGR] imul cx shld dx,ax,2 add dx,ds:[si+POLYGR] mov ds:[di+POLYGR],dx ret ENDP NEWCLIPCALC MACRO clipped,other local l1,l2,l3,l4,l5,l6 ;DS:BX->DS:SI is clipped at (-,BP) with result stored to DS:DI push si push bx push bp mov dx,ds:[si+other] mov cx,ds:[si+clipped] mov ax,ds:[bx+other] mov bx,ds:[bx+clipped] mov cs:newclipflip,0 cmp cx,bx jl l3 mov cs:newclipflip,1 xchg cx,bx xchg ax,dx l3: push dx sub bp,cx sub ax,dx push ax mov dx,bp xor ax,ax shrd ax,dx,2 sar dx,2 ;dx:ax=short length*16384 sub bx,cx idiv bx mov bx,ax ;bx=0..16384 multiplier pop ax imul bx shld dx,ax,2 pop ax add dx,ax ;dx=clipped other pop bp mov cx,bp cmp ds:[di+other-4],dx jne l1 cmp ds:[di+clipped-4],cx jne l1 jmp l2 l1: mov ds:[di+other],dx mov ds:[di+clipped],cx mov cx,bx pop bx mov ax,cs:newclipprog or ax,ax jz l4 mov dl,cs:newclipflip or dl,dl jz l6 xchg si,bx l6: call ax ;also stores gouraud&texture clipped l4: add di,4 jmp l5 l2: pop bx l5: pop si ENDM NEWCLIPNEXT MACRO ;sets bx(last)=si(current) and loads si with next vertex local l1,l2 mov bx,si mov dx,cs:clipcount dec dx cmp dx,1 jl @@0 ;list ended, jmp to end of clip procedure mov cs:clipcount,dx jg l1 ;1 vertex left, means we rotated the list mov si,cs:clipzero jmp l2 l1: add si,4 l2: ENDM NEWCLIPCOPY MACRO ;should copy also texture local l1 mov eax,ds:[si+POLYX] ;&POLYY cmp ds:[di+POLYX-4],eax je l1 mov ds:[di+POLYX],eax mov ax,ds:[si+POLYGR] mov ds:[di+POLYGR],ax add di,4 l1: ENDM ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ZCLIPCLIP MACRO local l1,l41,l42,l43,l44 ;(fs:bp)-(fs:bx) is clipped at (-,-,ECX) with result stored to (DX,CX) & AX=visfl push bx push bp push esi push edi push ecx ; mov eax,fs:[bx+vlist_z] mov edx,fs:[bp+vlist_z] cmp eax,edx jg l1 xchg eax,edx xchg bx,bp l1: ;EAX=farther vertex (>EDX), BX=offset of farther vertex mov esi,eax mov edi,eax sub esi,edx ;>=0 divver sub edi,ecx ;>=0 muller, esi>edi ; mov eax,fs:[bp+vlist_x] sub eax,fs:[bx+vlist_x] imul edi idiv esi add eax,fs:[bx+vlist_x] push eax ; mov eax,fs:[bp+vlist_y] sub eax,fs:[bx+vlist_y] imul edi idiv esi add eax,fs:[bx+vlist_y] ; pop esi ;X pop ecx ;cliplimit xor di,di ; imul gs:_projmuly idiv ecx add eax,gs:_projaddy cmp eax,gs:_projclipy[CLIPMAX] jng l41 or di,VF_DOWN l41: cmp eax,gs:_projclipy[CLIPMIN] jnl l42 or di,VF_UP l42: push ax ; mov eax,esi imul gs:_projmulx idiv ecx add eax,gs:_projaddx cmp eax,gs:_projclipx[CLIPMAX] jng l43 or di,VF_RIGHT l43: cmp eax,gs:_projclipx[CLIPMIN] jnl l44 or di,VF_LEFT l44: ; mov dx,ax mov ax,di pop cx ;dx=x,cx=y,ax=visfl pop edi pop esi pop bp pop bx ;NOTE: ECX was destroyed while clipping. It is used to return data. ;It must be pushed by the 'calling' procedure after the macro and ;the usage of the data the macro returned! ENDM ZCLIPGETVX MACRO ;reads to bx the offset of next vertex from DS:SI (copies last vx to bp) local l1,l2 mov bp,bx mov dx,cs:clipcount dec dx cmp dx,1 jl @@0 ;list ended, jmp to end of clip procedure mov cs:clipcount,dx jg l1 ;1 vertex left, means we rotated the list mov si,cs:clipzero jmp l2 l1: add si,4 l2: mov bx,ds:[si+POLYVX] ENDM ZCLIPADDVISVX MACRO ;adds ds:si[bx+POLYX/Y] to list (the vx must be visible for this to work) at DS:DI local l1,l2 mov dx,ds:[si+POLYX] mov ax,ds:[si+POLYY] cmp ds:[di+POLYX-4],dx jne l1 cmp ds:[di+POLYY-4],ax jne l1 jmp l2 l1: mov ds:[di+POLYX],dx mov ds:[di+POLYY],ax mov ax,ds:[si+POLYGR] mov ds:[di+POLYGR],ax add di,4 l2: ;;; ENDM ZCLIPADDVX MACRO ;adds (DX,CX) to list at DS:DI local l1,l2 cmp ds:[di+POLYX-4],dx jne l1 cmp ds:[di+POLYY-4],cx jne l1 jmp l2 l1: mov ds:[di+POLYX],dx mov ds:[di+POLYY],cx mov ax,ds:[di-4+POLYGR] mov ds:[di+POLYGR],ax add di,4 l2: ;;; ENDM clipnear PROC NEAR ;clips list DS:SI -> DS:DI (source list must NOT be empty) push bp push si push di mov cs:clipzero,si mov ecx,gs:_projclipz[CLIPMIN] ;ECX=cliplimit mov eax,ds:[si+POLYSIDES] ;&POLYCOLOR mov ds:[di+POLYSIDES],eax inc ax mov cs:clipcount,ax mov eax,ds:[si+POLYFLAGS] ;&POLYVXSEG mov ds:[di+POLYFLAGS],eax mov fs,ds:[si+POLYVXSEG] mov word ptr ds:[di+POLYX-4],07fffh ;for CLIPADDVX to surely do it's work mov bx,ds:[si+POLYVX] cmp ecx,fs:[bx+vlist_z] jle @@2 @@1: ;LAST POINT HIDDEN ZCLIPGETVX cmp ecx,fs:[bx+vlist_z] jge @@1 ;this point visible, clip ZCLIPCLIP ;returns data in cx or cs:clipvisfl,ax ZCLIPADDVX mov ecx,gs:_projclipz[CLIPMIN] ;ECX was destroyed by ZCLIPCLIP @@2: ;LAST POINT VISIBLE ZCLIPADDVISVX ZCLIPGETVX cmp ecx,fs:[bx+vlist_z] jle @@2 ;this point hidden, clip ZCLIPCLIP ;returns data in cx or cs:clipvisfl,ax ZCLIPADDVX mov ecx,gs:_projclipz[CLIPMIN] ;ECX was destroyed by ZCLIPCLIP jmp @@1 ;to hidden @@0: pop bx sub di,bx shr di,2 mov ds:[bx+POLYSIDES],di ;Sides in clipped polygon mov di,bx pop si pop bp mov ax,cs:clipvisfl ret clipnear ENDP ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! newclipup PROC NEAR ;clips list DS:SI -> DS:DI (source list must NOT be empty) push bp push si push di mov cs:clipzero,si mov bp,word ptr gs:_projclipy[CLIPMIN] mov eax,ds:[si+POLYSIDES] ;&POLYCOLOR mov ds:[di+POLYSIDES],eax inc ax mov cs:clipcount,ax mov eax,ds:[si+POLYFLAGS] ;&POLYVXSEG mov ds:[di+POLYFLAGS],eax mov word ptr ds:[di+POLYX-4],07fffh ;for CLIPADDVX to surely do it's work ;bx=last, si=current cmp ds:[si+POLYY],bp jge @@2 @@1: ;LAST POINT HIDDEN NEWCLIPNEXT cmp ds:[si+POLYY],bp jle @@1 ;this point visible, clip NEWCLIPCALC POLYY,POLYX @@2: ;LAST POINT VISIBLE NEWCLIPCOPY ;copies always also texture & gouraud NEWCLIPNEXT cmp ds:[si+POLYY],bp jge @@2 ;this point hidden, clip NEWCLIPCALC POLYY,POLYX jmp @@1 ;to hidden @@0: pop bx sub di,bx shr di,2 mov ds:[bx+POLYSIDES],di ;Sides in clipped polygon mov di,bx pop si pop bp ret newclipup ENDP newclipdown PROC NEAR ;clips list DS:SI -> DS:DI (source list must NOT be empty) push bp push si push di mov cs:clipzero,si mov bp,word ptr gs:_projclipy[CLIPMAX] mov eax,ds:[si+POLYSIDES] ;&POLYCOLOR mov ds:[di+POLYSIDES],eax inc ax mov cs:clipcount,ax mov eax,ds:[si+POLYFLAGS] ;&POLYVXSEG mov ds:[di+POLYFLAGS],eax mov word ptr ds:[di+POLYX-4],07fffh ;for CLIPADDVX to surely do it's work ;bx=last, si=current cmp ds:[si+POLYY],bp jle @@2 @@1: ;LAST POINT HIDDEN NEWCLIPNEXT cmp ds:[si+POLYY],bp jge @@1 ;this point visible, clip NEWCLIPCALC POLYY,POLYX @@2: ;LAST POINT VISIBLE NEWCLIPCOPY ;copies always also texture & gouraud NEWCLIPNEXT cmp ds:[si+POLYY],bp jle @@2 ;this point hidden, clip NEWCLIPCALC POLYY,POLYX jmp @@1 ;to hidden @@0: pop bx sub di,bx shr di,2 mov ds:[bx+POLYSIDES],di ;Sides in clipped polygon mov di,bx pop si pop bp ret newclipdown ENDP newclipleft PROC NEAR ;clips list DS:SI -> DS:DI (source list must NOT be empty) push bp push si push di mov cs:clipzero,si mov bp,word ptr gs:_projclipx[CLIPMIN] mov eax,ds:[si+POLYSIDES] ;&POLYCOLOR mov ds:[di+POLYSIDES],eax inc ax mov cs:clipcount,ax mov eax,ds:[si+POLYFLAGS] ;&POLYVXSEG mov ds:[di+POLYFLAGS],eax mov word ptr ds:[di+POLYX-4],07fffh ;for CLIPADDVX to surely do it's work ;bx=last, si=current cmp ds:[si+POLYX],bp jge @@2 @@1: ;LAST POINT HIDDEN NEWCLIPNEXT cmp ds:[si+POLYX],bp jle @@1 ;this point visible, clip NEWCLIPCALC POLYX,POLYY @@2: ;LAST POINT VISIBLE NEWCLIPCOPY ;copies always also texture & gouraud NEWCLIPNEXT cmp ds:[si+POLYX],bp jge @@2 ;this point hidden, clip NEWCLIPCALC POLYX,POLYY jmp @@1 ;to hidden @@0: pop bx sub di,bx shr di,2 mov ds:[bx+POLYSIDES],di ;Sides in clipped polygon mov di,bx pop si pop bp ret newclipleft ENDP newclipright PROC NEAR ;clips list DS:SI -> DS:DI (source list must NOT be empty) push bp push si push di mov cs:clipzero,si mov bp,word ptr gs:_projclipx[CLIPMAX] mov eax,ds:[si+POLYSIDES] ;&POLYCOLOR mov ds:[di+POLYSIDES],eax inc ax mov cs:clipcount,ax mov eax,ds:[si+POLYFLAGS] ;&POLYVXSEG mov ds:[di+POLYFLAGS],eax mov word ptr ds:[di+POLYX-4],07fffh ;for CLIPADDVX to surely do it's work ;bx=last, si=current cmp ds:[si+POLYX],bp jle @@2 @@1: ;LAST POINT HIDDEN NEWCLIPNEXT cmp ds:[si+POLYX],bp jge @@1 ;this point visible, clip NEWCLIPCALC POLYX,POLYY @@2: ;LAST POINT VISIBLE NEWCLIPCOPY ;copies always also texture & gouraud NEWCLIPNEXT cmp ds:[si+POLYX],bp jle @@2 ;this point hidden, clip NEWCLIPCALC POLYX,POLYY jmp @@1 ;to hidden @@0: pop bx sub di,bx shr di,2 mov ds:[bx+POLYSIDES],di ;Sides in clipped polygon mov di,bx pop si pop bp ret newclipright ENDP newclip PROC NEAR ;ENTRY: ;ds:si=pointer to list to be clipped ;ds:di=pointer to temporary list ;dx=visibility flag for polygon ;ax=flags for polygon (determines if texture and/or gouraud is clipped) ;EXIT: ;ds:si=clipped list (could be either of the entry lists) xor bx,bx test ax,F_GOURAUD jz @@f1 mov bx,OFFSET newclip_grd @@f1: mov cs:newclipprog,bx ; LOADGS test dh,VF_FAR ;If *ANY* vertex is 'far', entire polygon is jnz @@cl7 ;skipped (no clipping visible far away) test dl,VF_NEAR ;ClipNear must be done first, for in NEAR case jz @@cl6 ;not all vertices are even calculated! cmp word ptr ds:[si+POLYSIDES],0 je @@cl6 push dx call clipnear xchg si,di pop dx ; clipnear return in ax the visfl for new vertices. or dl,al ;<-this is done so that if the new vertices are outside the screen they'll be clipped @@cl6: ; test dl,VF_UP jz @@cl1 cmp word ptr ds:[si+POLYSIDES],0 je @@cl1 push dx call newclipup xchg si,di pop dx @@cl1: ; test dl,VF_DOWN jz @@cl2 cmp word ptr ds:[si+POLYSIDES],0 je @@cl2 push dx call newclipdown xchg si,di pop dx @@cl2: ; test dl,VF_LEFT jz @@cl3 cmp word ptr ds:[si+POLYSIDES],0 je @@cl3 push dx call newclipleft xchg si,di pop dx @@cl3: ; test dl,VF_RIGHT jz @@cl4 cmp word ptr ds:[si+POLYSIDES],0 je @@cl4 push dx call newclipright xchg si,di pop dx ; @@cl4: ret @@cl7: ;polygon marked invisible: mov word ptr ds:[si+POLYSIDES],0 ret newclip ENDP