; gouraud lines on dsp: ; ; rotation + translation ; -> ; z clipping and culling (also depthculling!) ; -> ; perspectivation ; -> ; x/y clipping ; -> ; sorting ; -> ; transmission ; ; yep, host only does actual bresenham + some interpolation. ; ; todo: z intersection in x/y clip.. ; ; quite well optimised, even max optimised cpu always has to wait.. ;======== GLOBAL EQUATES ======== PBC: = $FFE0 ; Port B Control Register HSR: = $FFE9 ; Host Status Register HTX: = $FFEB ; Host Transmit Register ; Host Status Register Bit Flags HRDF: = 0 ; Host Receive Data Full HTDE: = 1 ; Host Transmit Data Empty INVBUF_SIZE: = 4095 MAX_LINES: = 1000 MAX_VERTICES: = 1000 CULLDIST: = 1550 ;======= Vertex ; That's right. For speedreasons the Y comes before the X! Vertex.Y: = 0 Vertex.X: = 1 Vertex.Z: = 2 Vertex.SIZE: = 3 ;======== Matrix Matrix.MAX_DEPTH: = 8 ; max number of rotations in the world Matrix.XX: = 0 Matrix.XY: = 1 Matrix.XZ: = 2 Matrix.YX: = 3 Matrix.YY: = 4 Matrix.YZ: = 5 Matrix.ZX: = 6 Matrix.ZY: = 7 Matrix.ZZ: = 8 Matrix.SIZE: = 9 ;======== GLOBAL MACROS ======== get: MACRO jclr #0,X:<-8,n4 move #>transformedVertices,r5 move #>vertices,r0 move #-2,n1 move x:(r1)+,a ; a=TX move x:(r0)+,x0 y:(r4)+,y0 do x:lines,r0 move #>transformedVertices,r4 move #>ZCenterTable,r1 ; count=0 move #>TransformedLines,r5 move #-2,n1 do x:CULLDIST,x1 cmp x1,b jlt <_bla move (r6)+ move y:(r6)+,y1 ; y1=v2.y move y:(r6)-,a ; a=v2.z cmp x1,a y:-(r6),x1 ; x1=v2.x move (r6)+n6 jge <_next tst a r5,r6 ; r6: current trans. line jmi <_clip2 ; just cull.. jsr <_store jmp <_next ENDC _bla: move y:(r6)+,x1 ; x1=v2.x move y:(r6)+,y1 ; y1=v2.y tst b y:(r6)+,a ; a=v2.z jmi <_clip tst a r5,r6 ; r6: current trans. line jmi <_clip2 ; just cull.. jsr <_store _next: move r1,a ; a=zlineadr _loop: move n4,x0 ; x0=zlinebuf sub x0,a ; a=zlineoffset lsr a ; a=#lines move a,x:TransformedLines,r0 move #$80,y1 move x:InverseTable+$100,r1 do a,_loop IFNE 1 move y:(r0)+,x0 ; x0=X mpy x0,y1,a y:(r0)+,x0 ; a=$100X,x0=Y move y:(r0)-,n1 ; n1=Z mpy x0,y1,a a0,x0 ; a=$100Y, x0=$100X move a0,y0 clr b x:(r1+n1),x1 ; x1=1/(Z+$100) move x1,y1 mpy x1,y1,a #>$80,y1 rep #15 asr a move a0,x1 clr a #<100,b1 mac x1,y0,b #<160,a1 ; b=Y'=$100Y/(Z+$100) mac x1,x0,a b,y:(r0)- ; a=X'=$100X/(Z+$100), Store Y'. move a,y:(r0)+n0 ; Store X'. ELSE move y:(r0)+,x0 ; x0=X mpy x0,y1,a y:(r0)+,x0 ; a=$100X,x0=Y move y:(r0)-,n1 ; n1=Z mpy x0,y1,a a0,x0 ; a=$100Y, x0=$100X move a0,y0 clr b x:(r1+n1),x1 ; x1=1/(Z+$100) clr a #<100,b1 mac x1,y0,b #<160,a1 ; b=Y'=$100Y/(Z+$100) mac x1,x0,a b,y:(r0)- ; a=X'=$100X/(Z+$100), Store Y'. move a,y:(r0)+n0 ; Store X'. ENDC _loop: rts ; Cull out unwanted edges.. cullShit: ; 3: collapse z_avg table to remove culled lines.. move #<0,r3 ; visible count=0 move #>ZCenterTable,r0 ; y:(r0):source move #<1,n0 move r0,r1 ; y:(r1):dest move y:(r0)+,a do x:ZCenterTable,r0 move #>-2,n0 move #>CULLDIST,y0 ; y0=culling depth move #<2,n1 move y:(r0)+,a ; a=z(cullflag) do x:TransformedLines,r0 move #>ZCenterTable,r5 move #<2,n5 move #320-1,x0 ; x0='cut_y' move y:(r0)+,a cmp x0,a y:(r0+n0),b jgt <_right1st cmp x0,b jle <_right_done move a,x1 y:(r0)+n0,y1 ; x1='ystart'=v1.x, y1='xstart'=v1.y move y:(r0)+,a ; a='yend'=v2.x sub x1,a y:(r0)-,b ; a='dy', b='xend'=v2.y jsr cull it! or x1,a x1,a jpl <_above_done tst a (r0)-n0 jpl <_above2nd move a,x1 y:(r0)+n0,y1 ; x1='ystart'=v1.y, y1='xstart'=v1.x move y:(r0+n0),a ; a='yend'=v2.y sub x1,a y:(r1+n1),b ; a='dy', b='xend'=v2.x jsr 200-1,x0 ; x0='cut_y' move (r0)+ move y:(r0)+,a cmp x0,a y:(r0+n0),b jle <_under2nd cmp x0,b (r0)-n0 jgt <_cull ; Both under -> cull! move y:(r0)+n0,b ; b='xend'=v1.x move y:(r0+n0),x1 ; x1='ystart'=v2.y sub x1,a y:(r1+n1),y1 ; a='dy', y1='xstart'=v2.x jsr leave it! move a,x1 y:(r0)+n0,y1 ; x1='ystart'=v1.y, y1='xstart'=v1.x move y:(r0+n0),a ; a='yend'=v2.y sub x1,a y:(r1+n1),b ; a='dy', b='xend'=v2.x jsr 320,x0 cmp x0,a y:(r1+n1),b jhs <_cull cmp x0,b jhs <_cull _inc: move (r1)+n1 move (r1)+n1 ; y:(r1): next edge move r1,r0 ; y:(r0): next edge move (r5)+n5 ; y:(r5): next z_avg _lineloop: ; z culling was here! _end: rts _cull: move #<$FF,x0 move x0,y:(r5) ; Mark as invisible. jmp <_inc ; Generic intersection routine. ; INPUT: ; x0: cut_y ; x1: ystart ; y1: xstart ; a: yend - ystart (=dy) ; b: xend ; OUTPUT: ; a0: intersected coord intersect: IFNE 1 ; Warning, we assume r2,n2 isn't used! sub y1,b x0,x:$000040,x0 b,y0 ; x0=scalar, y0=dx mpy x0,y0,b #$008000,x1 move a0,y0 mpy x1,y0,a ELSE sub y1,b a,x:$000080,x0 b,y0 ; x0=scalar, y0=abs(dx) mpy x0,y0,b x:ZCenterTable,r0 lsr b b,y0 ; b=gapsize[0]=#elements/2 jmp <_end_calculate_gap _loop: cmp x0,b #>0.769230769,y1 tlt x0,b move b,x1 mpy y1,x1,b ; b=gapsize _end_calculate_gap: tfr y0,a b,x1 sub x1,a n3,x0 mpy x0,x1,a a,n6 asr a #<0,r4 ; r4=swapcount=0 move a0,n0 move r0,r2 lua (r0)+n0,r1 do n6,_element_loop move y:(r2)+n2,a ; a=z1 move y:(r1)+n1,x0 ; b=z2 cmp x0,a ; Decrement swapcount (assuming we'll correct it later).. jge <_no_swap move y:-(r2),x1 ; x1=adr1 move y:-(r1),y1 ; y1=adr2 move x1,y:(r1)- ; Store adr1. move y1,y:(r2)- ; Store adr2. move a,y:(r1)+n1 ; Store z1. move x0,y:(r2)+n2 ; Store z2. move (r4)+ ; Increment swapcount. _no_swap: nop _element_loop: move r4,a tst a #>2,x0 jne <_loop cmp x0,b jge <_loop _end: rts ; Send lines (2*[x,y,z]) to host.. sendLines: move #>ZCenterTable+1,r0 move #5,y1 ; Scalar to transform to fixedpoint. move #<2,n0 move x: b.. tgt x0,b ; .. d=dX, else d=dY abs b y:(r1)+n1,x0 ; b=|d|, x0=g1 mpy x0,y0,a b,n2 ; a=g1 (int), n2=|d| send a ; Send g1 (int). mpy -x0,y1,a y:(r1)+,x0 ; a0=-g1 (fp), x0=g2 mac +x0,y1,a x:(r2+n2),x0 ; a0=dg=g2-g1 (fp), x0=1/|d| move a0,x1 ; x1=dg (fp) mpy x0,x1,a ; a=g_step=dg/|d| (fp) send a ; Send g_step. _edgeloop: _end: rts ;======== non time-crucial stuff, all in external P-RAM ======== ; This initialises the pipeline in pixel-mode. InitPipeline: ; Set to linear addressing! movec #$FFFF,m0 movec m0,m1 movec m0,m2 movec m0,m3 movec m0,m4 movec m0,m5 movec m0,m6 jsr 1,x0 do #INVBUF_SIZE,_loop move a,x1 move x0,b rep #24 div x1,b add x0,a b0,x:(r0)+ _loop: rts ; Gets wireframe object from host.. GetObject: get a lsl a a,x0 add x0,a x0,x:vertices,r0 do a,_vloop get x:(r0)+ _vloop: get a move a,x:lines,r0 ; a=2*#lines do a,_lloop get x:(r0)+ _lloop: rts ;======== Matrix ; This is perfection. ; Total cycles on 56001: 58 (!) ; INPUT: ; r0: X-sine ; r1: X-cosine ; r2: Y-sine ; r3: Y-cosine ; r4: Z-sine ; r5: Z-cosine Matrix.generate: move #