;/**************************************************************************** ;** 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 ;北北北北 _draw_setfillroutine(void (*fillroutine)(int *)) 北北北北 ;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 ;北北北北 _draw_polylist(polylist *l,polydata *d,vlist *v,pvlist *pv, ; nlist *n,int f) 北北北北 ;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