SecondReality/VISU/ADRAW.ASM
2017-09-24 01:45:36 +02:00

608 lines
No EOL
12 KiB
NASM
Raw Permalink Blame History

;/****************************************************************************
;** MODULE: adraw.asm
;** AUTHOR: Sami Tammilehto / Fennosoftec OY
;** DOCUMENT: ?
;** VERSION: 1.0
;** REFERENCE: -
;** REVISED BY: -
;*****************************************************************************
;**
;** Object drawing (and polygon calculations & clipping (included))
;**
;****************************************************************************/
include a.inc
asm_code SEGMENT para public use16 'CODE'
ASSUME cs:asm_code
ALIGN 2
newlight dw 12118,10603,3030
;entry: AX=polyflags,ES:DI=normal for which to calculate light
; exit: AX=colorshade (based 0)
calclight PROC NEAR
and ax,F_SHADE32 ;=F_SHADE* orred together)
jz @@nc
;lightsource
push ax
call normallight
pop dx
shr dx,10
mov cx,6
sub cx,dx
shr ax,cl ;0400=5, 0800=4, 0C00=3
@@mm: cmp ax,1
jg @@m1
mov ax,1
@@m1: cmp ax,30
jl @@m2
mov ax,30
@@m2: ret
@@nc: xor ax,ax
jmp @@mm
calclight ENDP
normallight PROC NEAR
;return: ax=relative brightness 0..255
push bp
mov ax,es:[di+nlist_x]
imul cs:newlight[0]
mov bp,ax
mov cx,dx
mov ax,es:[di+nlist_y]
imul cs:newlight[2]
add bp,ax
adc cx,dx
mov ax,es:[di+nlist_z]
imul cs:newlight[4]
add ax,bp
adc dx,cx
mov ax,dx
sar ax,2*unitshr-7-16
add ax,128
cmp ax,255
jle @@1
mov ax,255
@@1: cmp ax,0
jge @@2
mov ax,0
@@2: pop bp
ret ;ax=0..255
normallight ENDP
checkculling PROC NEAR
;es:di=normal
;fs:si=vertex
;ret: carry=1=hidden
push bp
movsx eax,word ptr es:[di+nlist_x]
imul dword ptr fs:[si+vlist_x]
mov ebp,eax
mov ecx,edx
movsx eax,word ptr es:[di+nlist_y]
imul dword ptr fs:[si+vlist_y]
add ebp,eax
adc ecx,edx
movsx eax,word ptr es:[di+nlist_z]
imul dword ptr fs:[si+vlist_z]
add ebp,eax
adc ecx,edx
rcl ecx,1 ;if cx<0, carry=1=visible
cmc ;now carry=1 when invisible
pop bp
ret
checkculling ENDP
ALIGN 16
poly1 LABEL WORD
db POLYSIZE dup(0)
ALIGN 16
poly2 LABEL WORD
db POLYSIZE dup(0)
include adrawclp.asm
ALIGN 16
drawfill_routine dd _vid_drawfill
drawfill_routine0 dd _vid_drawfill ;nrm ;original (=NULL)
polyomin dw 0
polyomax dw 0
polycury dw 0
polylhig dw 0
polyrhig dw 0
polyoversample16 db 0
polyoversamplea db 0
polyoversamples db 0
polyoversample db 0
POLYSIDECALC MACRO fr,to
local l1,l2
;when entering, AX should be heigth
push ax
mov word ptr es:[bp-2],07777h
movsx edx,word ptr ds:[fr+POLYX]
movzx ecx,byte ptr cs:polyoversample16 ;sets ECX hi to zero
shl edx,cl
mov dx,32768 ;NOOVERSAMPLECENTER
mov es:[bp+0],edx ;Xstart
movsx eax,word ptr ds:[to+POLYX]
shl eax,cl
mov ax,32768 ;NOOVERSAMPLECENTER
sub eax,edx
cdq
pop cx
idiv ecx
mov cl,byte ptr cs:polycury
and cl,cs:polyoversamplea
jz l1
l2: sub es:[bp+0],eax
dec cl
jnz l2
l1: mov cl,cs:polyoversample
shl eax,cl
mov es:[bp+4],eax ;Xadd
add bp,8
ENDM
poly_nrm PROC NEAR
;handles a normal polygon (preclipped one)
;polydata at DS:SI. SIDES must be >=3
;drawing orders written to ES:DI
;-------Calculate bounds for SI
mov bx,ds:[si+POLYSIDES]
shl bx,2
lea ax,[bx-4+si]
mov cs:polyomax,ax
mov cs:polyomin,si
;the SI should always be in range POLYOMIN..POLYOMAX
;-------Find uppermost vertex in polygon
push si
mov bx,si
mov dx,ds:[si+POLYY]
mov bp,dx
mov cx,ds:[si+POLYSIDES]
@@11: add si,4
dec cx
jz @@2
@@1: mov ax,ds:[si+POLYY]
cmp ax,bp
jle @@13
mov bp,ax
@@13: cmp ax,dx
jge @@11
mov dx,ax
mov bx,si
jmp @@11
@@2: mov cx,bp
;DS:BX=uppermost vertex, DX=uppermost Y, CX=lowermost Y
mov cs:polycury,dx
pop si
;-------Write the startup info to drawinfo
push cx
mov bp,di ;es:di was to drawinfo, now ES:BP is
mov ax,ds:[si+POLYCOLOR]
mov es:[bp],ax
mov cl,cs:polyoversample
mov ax,dx
sar ax,cl
mov es:[bp+2],ax
add bp,4+2
pop cx
cmp dx,cx
je @@d0 ;heigth zero, nothing to do
sub bp,2
;-------Set up SI for left edge (--), DI for right edge (++)
mov si,bx
mov di,bx
;-------Loop
@@l1: mov word ptr es:[bp],0
add bp,2
mov ax,ds:[si+POLYY]
cmp ax,cs:polycury
jne @@a2
@@a4: ;Left side reload
lea bx,[si-4] ;BX=SI--
cmp bx,cs:polyomin
jge @@a1
mov bx,cs:polyomax
@@a1: mov ax,ds:[bx+POLYY]
sub ax,ds:[si+POLYY]
jc @@d0 ;turned upwards, end of polygon
jnz @@a3
mov si,bx
jmp @@a4
@@a3: mov cs:polylhig,ax
POLYSIDECALC si,bx
mov si,bx
@@a2: ;
mov word ptr es:[bp],0
add bp,2
mov ax,ds:[di+POLYY]
cmp ax,cs:polycury
jne @@b2
@@b4: ;Right side reload
lea bx,[di+4] ;BP=DI++
cmp bx,cs:polyomax
jle @@b1
mov bx,cs:polyomin
@@b1: mov ax,ds:[bx+POLYY]
sub ax,ds:[di+POLYY]
jc @@d0 ;turned upwards, end of polygon
jnz @@b3
mov di,bx
jmp @@b4
@@b3: mov cs:polyrhig,ax
POLYSIDECALC di,bx
mov di,bx
@@b2: ;
mov ax,cs:polylhig
cmp ax,cs:polyrhig
jl @@c1
;right shorter
mov ax,cs:polyrhig
@@c1: ;AX=shorter
mov cl,cs:polyoversample
mov dx,ax
sar dx,cl
mov es:[bp],dx ;Ycount
sub cs:polylhig,ax
sub cs:polyrhig,ax
add bp,2
add cs:polycury,ax
jmp @@l1
@@d0: mov word ptr es:[bp-2],0ffffh
ret
poly_nrm ENDP
POLYSIDECALC_GRD MACRO fr,to
local l1,l2
;when entering, AX should be heigth
push ax
mov word ptr es:[bp-2],07777h
;
mov cx,ax
mov ax,word ptr ds:[to+POLYGR]
mov dx,word ptr ds:[fr+POLYGR]
mov es:[bp+0],dx ;COLORstart
sub ax,dx
cwd
idiv cx
mov es:[bp+2],ax ;COLORadd
;
movsx edx,word ptr ds:[fr+POLYX]
xor ecx,ecx
mov cl,byte ptr cs:polyoversample16
shl edx,cl
mov dx,32768 ;NOOVERSAMPLECENTER
mov es:[bp+4],edx ;Xstart
movsx eax,word ptr ds:[to+POLYX]
shl eax,cl
mov ax,32768 ;NOOVERSAMPLECENTER
sub eax,edx
cdq
pop cx
idiv ecx
mov cl,byte ptr cs:polycury
and cl,cs:polyoversamplea
jz l1
l2: sub es:[bp+0],eax
dec cl
jnz l2
l1: mov cl,cs:polyoversample
shl eax,cl
mov es:[bp+8],eax ;Xadd
add bp,12
ENDM
poly_grd PROC NEAR
;handles a gouraud polygon (preclipped one)
;polydata at DS:SI. SIDES must be >=3
;drawing orders written to ES:DI
;-------Calculate bounds for SI
mov bx,ds:[si+POLYSIDES]
shl bx,2
lea ax,[bx-4+si]
mov cs:polyomax,ax
mov cs:polyomin,si
;the SI should always be in range POLYOMIN..POLYOMAX
;-------Find uppermost vertex in polygon
push si
mov bx,si
mov dx,ds:[si+POLYY]
mov bp,dx
mov cx,ds:[si+POLYSIDES]
@@11: add si,4
dec cx
jz @@2
@@1: mov ax,ds:[si+POLYY]
cmp ax,bp
jle @@13
mov bp,ax
@@13: cmp ax,dx
jge @@11
mov dx,ax
mov bx,si
jmp @@11
@@2: mov cx,bp
;DS:BX=uppermost vertex, DX=uppermost Y, CX=lowermost Y
mov cs:polycury,dx
pop si
;-------Write the startup info to drawinfo
push cx
mov bp,di ;es:di was to drawinfo, now ES:BP is
mov ax,ds:[si+POLYCOLOR]
mov es:[bp],ax
mov cl,cs:polyoversample
mov ax,dx
sar ax,cl
mov es:[bp+2],ax
add bp,4+2
pop cx
cmp dx,cx
je @@d0 ;heigth zero, nothing to do
sub bp,2
;-------Set up SI for left edge (--), DI for right edge (++)
mov si,bx
mov di,bx
;-------Loop
@@l1: mov word ptr es:[bp],0
add bp,2
mov ax,ds:[si+POLYY]
cmp ax,cs:polycury
jne @@a2
@@a4: ;Left side reload
lea bx,[si-4] ;BX=SI--
cmp bx,cs:polyomin
jge @@a1
mov bx,cs:polyomax
@@a1: mov ax,ds:[bx+POLYY]
sub ax,ds:[si+POLYY]
jc @@d0 ;turned upwards, end of polygon
jnz @@a3
mov si,bx
jmp @@a4
@@a3: mov cs:polylhig,ax
POLYSIDECALC_GRD si,bx
mov si,bx
@@a2: ;
mov word ptr es:[bp],0
add bp,2
mov ax,ds:[di+POLYY]
cmp ax,cs:polycury
jne @@b2
@@b4: ;Right side reload
lea bx,[di+4] ;BP=DI++
cmp bx,cs:polyomax
jle @@b1
mov bx,cs:polyomin
@@b1: mov ax,ds:[bx+POLYY]
sub ax,ds:[di+POLYY]
jc @@d0 ;turned upwards, end of polygon
jnz @@b3
mov di,bx
jmp @@b4
@@b3: mov cs:polyrhig,ax
POLYSIDECALC_GRD di,bx
mov di,bx
@@b2: ;
mov ax,cs:polylhig
cmp ax,cs:polyrhig
jl @@c1
;right shorter
mov ax,cs:polyrhig
@@c1: ;AX=shorter
mov cl,cs:polyoversample
mov dx,ax
sar dx,cl
mov es:[bp],dx ;Ycount
sub cs:polylhig,ax
sub cs:polyrhig,ax
add bp,2
add cs:polycury,ax
jmp @@l1
@@d0: mov word ptr es:[bp-2],0ffffh
ret
poly_grd ENDP
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> _draw_setfillroutine(void (*fillroutine)(int *)) <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;entry: Pointer to a routine to handle polygon filling
; exit: -
;descr: The specified function will be called for each polygon drawed
; with a pointer to {NORMAL-FILL-DATA} of the polygon.
_draw_setfillroutine PROC FAR
CBEG
movpar eax,0
or ax,ax
jnz @@1
mov eax,cs:drawfill_routine0
@@1: mov dword ptr cs:drawfill_routine,eax
CEND
_draw_setfillroutine ENDP
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> _draw_polylist(polylist *l,polydata *d,vlist *v,pvlist *pv,
; nlist *n,int f) <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;entry: 0 l=pointer to a polygon list (in polylist format)
; 2 d=pointer to polygon data (to which polylist points using indices)
; 4 v=pointer to rotated 3D vertices (for 3D clipping)
; 6 pv=pointer to projected vertices (for drawing)
; 8 n=pointer to normals (for culling)
; 10 f=object flags
; exit: -
;descr: draw the contents of the polylist.
_draw_polylist PROC FAR
CBEG
movpar ax,10
test ax,1
jz @@invi ;F_VISIBLE not set
;set poly oversampling
mov ax,16
mov cx,ds:_projoversampleshr
mov cs:polyoversample,cl
sub ax,cx
mov cs:polyoversample16,al
mov al,1
shl al,cl
mov cs:polyoversamples,al
dec al
mov cs:polyoversamplea,al
;start with the actual work
movpar si,0+0
add si,4 ;skip count - sort vertex
@@1: movpar ds,0+1
push si
mov si,ds:[si]
cmp si,0
je @@0 ;end of list
movpar ax,2+0
add si,ax
movpar ds,2+1
;ds:si points to polydata/polygon we are now drawing
mov cx,ds:[si+0]
movpar ax,10
or ax,0f00h
and ax,cx
mov cs:poly1[POLYFLAGS],ax
and cx,0ffh
mov cs:poly1[POLYSIDES],cx
push si
mov ax,ds:[si+4] ;normal
mov bx,ds:[si+6] ;first point
cmp word ptr ds:[si+2],-1 ;color
je @@cull2
shl bx,vlist_sizeshl
lfspar si,4 ;rotated vertices
add si,bx
mov bx,ax ;normal
shl bx,nlist_sizeshl
lespar di,8 ;rotated normals
add di,bx
test cs:poly1[POLYFLAGS],F_2SIDE
jnz @@2side
call checkculling
pop si
jc @@cull
jmp @@nocl
@@cull2: pop si
jmp @@cull
;es:di=still normal
@@2side: pop si
@@nocl: ;lightsource
mov ax,cs:poly1[POLYFLAGS]
test ax,F_GOURAUD
jnz @@nosh
call calclight
add al,ds:[si+2]
mov byte ptr cs:poly1[POLYCOLOR],al
jmp @@yosh
@@nosh: mov al,ds:[si+2]
mov byte ptr cs:poly1[POLYCOLOR],al
@@yosh: ;
mov cx,cs:poly1[POLYSIDES]
lespar di,6 ;projected vertices
mov dx,0ff00h ;for vf calc
push bp
movpar ax,4+1
movpar bp,4+0
xchg bp,di
mov cs:poly1[POLYVXSEG],ax
;ds:bp=projected vertices
;??:di=rotated vertices
zzs=0
zzd=0
REPT MAXPOLYSIDES ;max sides in polygon
mov bx,ds:[si+6+zzs]
shl bx,pvlist_sizeshl ;==vlist_sizeshl (required) [!!]
lea ax,[bx+di]
mov word ptr cs:poly1[POLYVX+zzd],ax
add bx,bp
mov al,es:[bx+pvlist_vf]
and dh,al ;if anded!=0, out of screen
or dl,al ;if orred!=0, must clip
mov eax,es:[bx+pvlist_x]
mov dword ptr cs:poly1[POLYX+zzd],eax
dec cx
jz @@2
zzs=zzs+2
zzd=zzd+4
ENDM
@@2: pop bp
push bp
push dx
;gouraud color calcs
mov ax,cs:poly1[POLYFLAGS]
test ax,F_GOURAUD
jz @@nogr
;
mov cx,cs:poly1[POLYSIDES]
lespar di,8 ;rotated normals
mov fs,cs:poly1[POLYVXSEG]
mov bp,OFFSET poly1
@@gr1: push cx
push di
mov bx,cs:[POLYVX+bp]
mov bx,fs:[bx+vlist_normal]
shl bx,nlist_sizeshl
add di,bx
;es:di=now normal for which to calculate
mov ax,cs:poly1[POLYFLAGS]
call calclight
add al,byte ptr cs:poly1[POLYCOLOR]
shl ax,8
mov cs:[POLYGR+bp],ax
pop di
pop cx
add bp,4
loop @@gr1
@@nogr: ;
pop dx
pop bp
LOADDS
push bp
push ds
mov ax,cs
mov ds,ax
mov si,OFFSET poly1
or dh,dh ;dh=visfl anded
jnz @@cl0 ;entire polygon invisible
or dl,dl ;dl=visfl orred
jz @@cl4 ;no clipping
mov di,OFFSET poly2
mov ax,ds:[si+POLYFLAGS]
call newclip
cmp word ptr ds:[si+POLYSIDES],0
je @@cl0 ;entire polygon clipped away, nothing to draw
;
@@cl4: LOADES
mov di,OFFSET _polydrw
test word ptr ds:[si+POLYFLAGS],F_GOURAUD
jz @@ngrd
mov word ptr es:[di],1 ;gouraud fill
add di,2
call poly_grd
jmp @@pgdn
@@ngrd: mov word ptr es:[di],0 ;normal fill
add di,2
call poly_nrm
@@pgdn:
push es
push OFFSET _polydrw
call cs:drawfill_routine
add sp,4
@@cl0: pop ds
pop bp
@@cull: pop si
add si,2
jmp @@1
@@0: pop si
@@invi: CEND
_draw_polylist ENDP
asm_code ENDS
END