; common routines between 3d1.asm and 3d2.asm public poly_fill public clear_fill public initpages public flip_page public fakeline public set_clip_absolute public set_clip_offset public updvectors ; clears a block from active display page ; ; this routine works only if borders of xclip land on even nybbles ; eg minimum x is 32 - works fine. but if minimum x is 37, this ; routine will clear all the way to 32 just the same. for better clearing, ; call fill_block routine with lxupdate and lyupdate parameters on stack ; ; routine was originally written by matt prichard. routine was then modified ; to clear using dwords, and clear to integer borders. ; ; entry: lxupdate+0 = left x position of area to fill ; lxupdate+2 = top y position of area to fill ; lyupdate+0 = right x position of area to fill ; lyupdate+2 = bottom y position of area to fill align 4 clear_fill: if useborders eq yes cmp use_clear,no je tf_exit ; don't use clear routine mov edi, current_page ; point to active vga page cld ; direction flag = forward out_8 sc_index, map_mask ; set up for plane select out_8 sc_data, all_planes ; write to all planes mov ax,lxupdate+0 mov bx,lxupdate+2 mov cx,lyupdate+0 mov dx,lyupdate+2 add ax,xcent ; center on screen add bx,xcent add cx,ycents1 add dx,ycentp1 and ax,0fff8h and bx,0fff8h add bx,7 cmp ax,cliplt ; clip to inside borders jge s tf_noclip1 mov ax,cliplt tf_noclip1: cmp bx,xmaxxcent jl s tf_noclip2 mov bx,cliprt tf_noclip2: cmp cx,cliptp jge s tf_noclip3 mov cx,cliptp tf_noclip3: cmp dx,ymaxycent jl s tf_noclip4 mov dx,ymaxycent tf_noclip4: mov lxupdate+0,ax mov lxupdate+2,bx mov lyupdate+0,cx mov lyupdate+2,dx cmp ax,bx jg tf_exit ; nothing to do! cmp cx,dx jg tf_exit ; nothing to do! mov ax,cx mov bx,dx sub bx,ax ; get y width mov lyupdate+2,bx ; save in ypos2 mov si,ax shl si,1 movzx eax,w [si+fastimultable] ; mul y1 by bytes per line add edi,eax ; di = start of line y1 mov dx,lxupdate ; dx = x1 (pixel position) shr dx,2 ; dx/4 = bytes into line movzx edx,dx add edi,edx ; di = addr of upper-left corner mov cx,lxupdate+2 ; cx = x2 (pixel position) sub cx,lxupdate shr cx,3 ; cx/4 = bytes into line inc cx ; di = addr of upper left block to fill ; cx = # of bands to fill in (width) mov dx,xactual/4 ; dx = di increment sub dx,cx ; = screen_width-# planes filled sub dx,cx movzx ecx,cx mov ebx,ecx ; bx = quick refill for cx mov si,lyupdate+2 ; si = # of lines to fill mov ax,background ; get fill color push ax ; make 32 bit shl eax,16 pop ax shr ecx,1 shr ebx,1 jnc s tf_middle_loop2 align 4 tf_middle_loop1: stosw rep stosd ; fill in entire line mov ecx, ebx ; recharge cx (line width) add edi, edx ; point to start of next line loopx si, tf_middle_loop1 ; loop until all lines drawn ret align 4 tf_middle_loop2: rep stosd ; fill in entire line, doubleword store mov ecx, ebx ; recharge cx (line width) add edi, edx ; point to start of next line loopx si, tf_middle_loop2 ; loop until all lines drawn tf_exit: endif ret ; exit ; fill starting at oney, from firstbyte to lastbyte align 4 poly_fill: mov edi, current_page ; point to active vga page out_8 sc_index, map_mask ; set up for plane select mov ax,oney ; ax=y1 cmp ax,ymins jge s pf_okmin xor ax,ax jmp s pf_missub align 4 pf_okmin: cmp ax,ymaxs jge pf_outearly sub ax,ymins pf_missub: if usesteel eq yes cmp steel,no ; test to use steel texture je s pf_skipsteel mov bl,colq ; yes, save colour offset and 16 block mov steelc,bl and steelc,0f0h ; save base offset of 16 colour block shl bl,2 ; colour offset is *2 (small) *4 (large) add bl,al ; make steel always constant and bl,03fh ; colour indexer (so sides look different) mov steel ,bl pf_skipsteel: endif mov bp,ax ; indexer to line shl bp,1 add ax, cliptp mov si,ax shl si,1 movzx eax,w [si+fastimultable] ; mul y1 by bytes per line add edi,eax ; di = start of line y1 pf_more_lines: push edi ; save right hand position mov ax, [firstbyte+bp] cmp ax,xmaxs ; check if fill done jge pf_done if usesteel eq yes mov bl,steel ; use steel texture? cmp bl,no je s pf_no_steel xor bh,bh mov dl,pf_updown[bx] add dl,steelc mov colq,dl inc bl and bl,03fh ; 16 colours, 32 positions for steel texture mov steel,bl pf_no_steel: endif mov bx,[lastbyte+bp] add ax,xcent add bx,xcent mov dx,ax ; dx = x1 (pixel position) shr dx,2 ; dx/4 = bytes into line movzx edx,dx add edi,edx ; di = addr of upper-left corner movzx ecx,bx ; cx = x2 (pixel position) shr cx,2 ; cx/4 = bytes into line cmp dx,cx ; start and end in same band? jg pf_exit ; skip if fakeline fails connection jne s pf_normal ; if not, check for l & r edges jmp pf_one_band_only ; if so, then special processing pf_done: pop eax pf_outearly: mov oney,1000 ; reset for next polygon call ret pf_normal: sub cx,dx ; cx = # bands -1 mov si,ax ; si = plane#(x1) and si,plane_bits ; if left edge is aligned then jz s pf_l_plane_flush ; no special processing.. ; draw "left edge" of 1-3 pixels... out_8 sc_data, left_clip_mask[si] ; set left edge plane mask mov al,colq ; get fill color mov [edi], al ; fill in left edge pixels inc edi ; point to middle (or right) block dec cx ; reset cx instead of jmp pf_right pf_l_plane_flush: inc cx ; add in left band to middle block ; di = addr of 1st middle pixel (band) to fill ; cx = # of bands to fill -1 pf_right: mov si,bx ; get xpos2 and si,plane_bits ; get plane values cmp si,0003 ; plane = 3? je s pf_r_edge_flush ; hey, add to middle ; draw "right edge" of 1-3 pixels... out_8 sc_data, right_clip_mask[si] ; right edge plane mask mov esi,edi ; get addr of left edge add esi,ecx ; add width-1 (bands) dec esi ; to point to top of right edge mov al,colq ; get fill color pf_right_loop: mov [esi], al ; fill in right edge pixels dec cx ; minus 1 for middle bands jz s pf_exit ; uh.. no middle bands... pf_r_edge_flush: ; di = addr of upper left block to fill ; cx = # of bands to fill in (width) out_8 sc_data, all_planes ; write to all planes mov dx, xactual/4 ; dx = di increment sub dx, cx ; = screen_width-# planes filled mov al, colq ; get fill color mov ah, al ; colour is in high and low for stosw push ax ; make colour 32 bit shl eax,16 pop ax pf_middle_loop: shr cx,1 ; use doubleword transfer jnc s pf_ord stosb ; if cx odd, store byte first jcxz s pf_exit ; no words after stosb pf_ord: shr cx,1 jnc s pf_dord stosw jcxz s pf_exit ; no doublewords after stosw pf_dord: rep stosd ; fill in entire line pf_exit: pop edi mov [firstbyte+bp],1000 ; reset table for next polygon mov [lastbyte+bp],-1000 add bp,2 add edi,xactual/4 jmp pf_more_lines pf_one_band_only: cmp ax, cliplt jne s pf_nexit cmp bx,ax je s pf_exit pf_nexit: cmp ax, cliprt je s pf_exit mov si,ax ; get left clip mask, save x1 and si,plane_bits ; mask out row # mov al,left_clip_mask[si] ; get left edge mask mov si,bx ; get right clip mask, save x2 and si,plane_bits ; mask out row # and al,right_clip_mask[si] ; get right edge mask byte out_8 sc_data, al ; clip for left & right masks mov al, colq ; get fill color mov [edi], al ; fill in pixels jmp s pf_exit ; outa here, for this line ; small steel texture, make sure to set shl bl,*1* before skip_steel: ;pf_updown db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ; db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 ; db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ; db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 ; large steel texture, make sure to set shl bl,*2* before skip_steel: pf_updown db 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9 db 10,10,11,11,12,12,13,13,14,14,15,15 db 15,15,14,14,13,13,12,12,11,11,10,10 db 9,9,8,8,7,7,6,6,5,5,4,4,3,3,2,2,1,1,0,0 fastimultable label word i=0 rept yactual dw i*(xactual/4) i=i+1 endm resetupd: ; make old update equal current update if useborders eq yes mov ax,xupdate[0] ; and reset current update mov lxupdate[0],ax mov ax,xupdate[2] mov lxupdate[2],ax mov ax,yupdate[0] mov lyupdate[0],ax mov ax,yupdate[2] mov lyupdate[2],ax mov ax,xmaxs mov bx,xmins1 mov cx,ymaxs mov dx,ymins1 mov xupdate[0],ax mov xupdate[2],bx mov yupdate[0],cx mov yupdate[2],dx endif ret ; hey! where is my postcard! see readme.doc file and send me that postcard! initpages: pushw 0 call set_display_page pushw 0 call set_active_page pushw 0 call clear_vga_screen pushw 1 call set_active_page pushw 0 call clear_vga_screen ret flip_page: call get_display_page xor ax,1 push ax call set_display_page call get_active_page xor ax,1 push ax call set_active_page ret ; draw a line in tables firstbyte,lastbyte ; ; line is not drawn on screen but is drawn in memory tables. to use, ; tables must be clear, (default is always clear), just draw ; line around screen, in any order, then call poly_fill. the polygon will ; be drawn and checked in memory, then poly_fill will plop it on the current ; page. poly_fill routine clears tables during plot so tables are ready for ; more lines and more polygons. align 4 fakeline: mov ax,y1 cmp y2,ax ; flip order of points if drawing up jg s okorder mov bx,x1 xchg bx,x2 xchg bx,x1 xchg ax,y2 xchg ax,y1 okorder: mov ax,y1 ; set starting point for fill cmp ax,oney jge s nonewoney mov oney,ax nonewoney: if useborders eq yes cmp ax,yupdate+0 ; update borders for clearing routine jge s up_no1 mov yupdate+0,ax up_no1: mov ax,y2 cmp ax,yupdate+2 jng s up_no2 mov yupdate+2,ax up_no2: mov dx,xupdate+0 mov cx,xupdate+2 mov ax,x1 mov bx,x2 cmp ax,dx jge s up_no3 dec ax mov xupdate+0,ax mov dx,ax inc ax up_no3: cmp bx,cx jle s up_no4 inc bx mov xupdate+2,bx mov cx,bx dec bx up_no4: cmp bx,dx jge s up_no5 dec bx mov xupdate+0,bx up_no5: cmp ax,cx jle s up_no6 inc ax mov xupdate+2,ax up_no6: endif mov ax,x2 ; ax=x sub ax,x1 mov bx,y2 ; bx=y sub bx,y1 jle sliver mov rise,bx movsx ebx,bx shl eax,16 cdq idiv ebx mov ebp,eax ; ebp = slope*65536 (allows decimals) mov ax,ymins cmp y1,ax ; check if above screen jge s li_abov1 sub ax,y1 ; ax = abs(difference of ymin-y1) sub rise,ax ; dec counter jle li_out ; line totally off screen movsx eax,ax ; prepare for 32bit mul imul ebp shr eax,16 ; get top word add x1,ax ; set new x1,y1 pair mov ax,ymins mov y1,ax li_abov1: movsx edx,x1 shl edx,16 mov cx,rise mov ax,y1 mov bx,ax ; bx pointer first/lastbyte table sub bx,ymins shl bx,1 ; bx now word add ax,cx ; will line go off bottom of screen? cmp ax,ymaxs jl s linep ; no... sub ax,ymaxs ; yes, truncate cx for early exit sub cx,ax jle s li_out ; right off screen linep: mov eax,edx movzx ecx,cx mov di,xmins mov si,xmaxs1 align 4 lineloop: shr edx,16 ; main line drawing loop!!! cmp dx,di jge s nou mov dx,di nou: cmp dx,si jle s noq mov dx,si noq: cmp dx,firstbyte[bx] ; fix first and lastbyte table jge s ci1 mov firstbyte[bx],dx ci1: cmp dx,lastbyte[bx] jng s ci2 mov lastbyte[bx],dx ci2: add eax,ebp mov edx,eax add bx,2 loop s lineloop li_out: ret sliver: mov cx,x1 mov ax,y1 call checkin ; if off bottom of screen, never returns mov cx,x2 mov ax,y1 checkin: ; cx,ax=x,y... cmp ax,ymaxs jge s ci9q cmp ax,ymins ; clip to borders jl s ci6q cmp cx,xmins jge s nouq mov cx,xmins nouq: cmp cx,xmaxs jl s noqq mov cx,xmaxs1 noqq: mov bx,ax ; bx pointer first/lastbyte table sub bx,ymins shl bx,1 ; bx now word cmp cx,firstbyte[bx] ; fix first and lastbyte table jg s ci1q mov firstbyte[bx],cx ci1q: cmp cx,lastbyte[bx] jng s ci6q mov lastbyte[bx],cx ci6q: ret ci9q: add esp,4 ; off bottom of screen, exit now! ret ; set new clipping parameters where center is in middle of points ax,bx cx,dx ; where points are absolutes! eg (10,10) (50,50) would be a small window in ; the top corner of the screen. set_clip_absolute: mov si,cx ; calc center based on points sub si,ax shr si,1 add si,ax mov di,dx sub di,bx shr di,1 add di,bx sub ax,si ; now make points offset from center sub cx,si sub bx,di sub dx,di ; set new clipping parameters. does all pre-calculation for variables and ; resets oney, firstbyte and lastbyte table. si,di is center of screen. ax,bx ; and cx,dx are topleft and botright points to clip to. clipping will include ; minimum clip variables but will exclude maximum clip variables. eg -160,-100 ; +160,+100, with center 160,100 are valid clip parameters. points are offsets ; from center, not absolutes! this allows you to have the camera looking to the ; left or right of where the pilot/plane is moving without having to change ; the camera angle. note: this can only change slightly as distortion occures ; with too large an offset. make sure to assemble the original file with the ; maximum y size you will ever need so tables are set to correct size. set_clip_offset: mov bp,dx sub bp,bx cmp bp,ymax-ymin ; check input parameters with assembley restraints jg you_must_assemble_original_file_with_larger_clipping_to_achieve_this mov xmins,ax mov xmaxs,cx mov ymins,bx mov ymaxs,dx mov xcent,si mov ycent,di mov cliptp,di add cliptp,bx mov ycentp1,di inc ycentp1 mov ycents1,di dec ycents1 mov clipbt,di add clipbt,dx dec clipbt mov cliplt,si add cliplt,ax mov cliprt,si add cliprt,cx dec cliprt mov xmaxxcent,si add xmaxxcent,cx mov ymaxycent,di add ymaxycent,dx mov xmins1,ax dec xmins1 mov xmaxs1,cx dec xmaxs1 mov ymins1,bx dec ymins1 movsx eax,ax movsx ebx,bx movsx ecx,cx movsx edx,dx mov xmit,eax mov xmat,ecx mov ymit,ebx mov ymat,edx sub xmit,tolerance add xmat,tolerance sub ymit,tolerance add ymat,tolerance you_must_assemble_original_file_with_larger_clipping_to_achieve_this: ret align 4 ; update vector list based on traces_past ; i could have used a loop but shl ax,cl works faster ; ; what i am really doing is: ; ; for i = 1 to traces_past ; call updvectors ; next i ; ; but instead i am shifting and adding (if bit present) for a faster method ; you get the idea right? ; ; this way, the slower the machine, the faster we move the objects to ; maintaine a universal speed from 486dx66 machine to 386sx33 machine updvectors: mov bx, traces_past mov traces_past,0 mov dx,1 mov cl,0 up_loop: shr bl,1 jnc not_call call updvectors2 not_call: shl dx,1 ; dx = 1,2,4,8.. add cl,1 ; cx = 0,1,2,3,4,5,6... cmp bl,0 ; all bits clear? jne up_loop cmp wfollow,no ; check if camera has reached follow object je s nretest ; nothing to follow cmp eyeacount,0 jne s nretest ; not reached yet mov si,wfollow ; looking at it, re-call newfollow mov di,oldspeed cmp di,0 jne newfollow ; re-calculate in case its accelerating jmp just_look_at_it_now_instead_of_calculating nretest: ret align 4 updvectors2: ; update vector list - shifted by cl ; and dec'ed by dx i=0 rept maxobjects+1 ; generate unrolled update loop local nupang, nuploc, nuder, nuuder cmp acount+i*2,0 je s nupang sub acount+i*2,dx jnc s nuder mov acount+i*2,0 nuder: mov ax,vxadds+i*2 ; update angles shl ax,cl add ax,vxs+i*2 mov vxs+i*2,ax mov ax,vyadds+i*2 shl ax,cl add ax,vys+i*2 mov vys+i*2,ax mov ax,vzadds+i*2 shl ax,cl add ax,vzs+i*2 mov vzs+i*2,ax nupang: cmp lcount+i*2,0 je s nuploc sub lcount+i*2,dx jnc s nuuder mov lcount+i*2,0 nuuder: mov eax,xadds+i*4 ; update position shl eax,cl add eax,xs+i*4 mov xs+i*4,eax mov eax,yadds+i*4 shl eax,cl add eax,ys+i*4 mov ys+i*4,eax mov eax,zadds+i*4 shl eax,cl add eax,zs+i*4 mov zs+i*4,eax nuploc: i=i+1 endm ret