; Marching cubes + field generator with dsp. Balltrajects done by host. ; Host is now some sort of slave. ; 12bit precision and 64*64 texture, but it looks decent enough.. ; coding by earx 2002 ; oops: inaccuracy, normalisation in some spots doesn't work causing ; intersection of normals to go wrong. the resultant shadevector will be ; too short. ; also the same approach causes many unneeded normalcalculations. ; still it's a damn amount faster than a cpu version, hahaha! ; You can change these to your likings, but beware of allowed limits! NUM_BALLS: = 3 ; #balls in blob ;ISOLEVEL: = 480 ; Change to your liking [0..4095] WIDTH: = 10 ; #points in gridside, <14 ! DISTANCE: = $A000 ; Not too small, no clipping! ROUND: = 1 ; rounding on sqrt (y/n) ; Don't touch the following equates. PLANE_SIZE: = WIDTH*WIDTH FIELD_SIZE: = WIDTH*WIDTH*WIDTH CUBES: = WIDTH-1 ; #cubes in a row GWIDTH: = $4000 ; width of entire grid CUBEWIDTH: = GWIDTH/CUBES HSR: = $FFE9 HTX: = $FFEB get: MACRO jclr #0,x:<DISTANCE-CUBEWIDTH,x0 move x0,x:-GWIDTH/2,x0 move x0,x:-GWIDTH/2,x0 move x0,x:PLANE_SIZE,n0 move x:(r0)+,b ; width move x:(r0)+n0,a b,y:(r4)+ ; 1+width move #>-WIDTH-PLANE_SIZE,n0 move x:(r0)-,b a,y:(r4)+ ; 1+width+planesize move x:(r0)+n0,a b,y:(r4)+ ; width+planesize move #>PLANE_SIZE,n0 move x:(r0)+,b a,y:(r4)+ ; 0 move x:(r0)+n0,a b,y:(r4)+ ; 1 move x:(r0)-,b a,y:(r4)+ ; 1+planesize move x:(r0)+,a b,y:(r4)+ ; planesize move a,y:(r4)+ ; move (r0)-n0 ; 1 (next cube) ; Get inside/outside flags.. move #ISOLEVEL,b clr a #>$100,x1 move y:(r4)+,x0 do #8,_side_loop cmp x0,b jlt <_nextside or x1,a _nextside: lsr a y:(r4)+,x0 _side_loop: ; Only polygonize if cube contains polygons. move #>edgeTable,r2 move a,n2 move a,x:CUBEWIDTH,x0 add x0,a (r1)+n1 ; Proceed to next cube. move #>CUBEWIDTH*CUBES-GWIDTH/2,x0 ; Compensate for steperror. cmp x0,a a,x:CUBEWIDTH,x0 add x0,a (r0)+ ; Proceed to next cube in y direction. move (r1)+n1 move #>CUBEWIDTH*CUBES-GWIDTH/2,x0 ; Compensate for steperror. cmp x0,a a,x:CUBEWIDTH,x0 sub x0,a (r0)+n0 ; Proceed to next cube in z direction. move (r1)+n1 move #>DISTANCE-CUBEWIDTH*CUBES,x0 cmp x0,a a,x:PLANE_SIZE*2-1,n1 move x:(r1)+,b a,y:(r4)+n4 ; 1+width move x:(r1)+n1,a b,y:(r4)+ move #>-3,n1 move x:(r1)+,b a,y:(r4)+n4 ; 1+width+planesize move x:(r1)+n1,a b,y:(r4)+ move #>-(WIDTH+PLANE_SIZE)*2-1,n1 move x:(r1)+,b a,y:(r4)+n4 ; width+planesize move x:(r1)+n1,a b,y:(r4)+ move x:(r1)+,b a,y:(r4)+n4 ; 0 move x:(r1)+,a b,y:(r4)+ move #>PLANE_SIZE*2-1,n1 move x:(r1)+,b a,y:(r4)+n4 ; 1 move x:(r1)+n1,a b,y:(r4)+ move #>-3,n1 move x:(r1)+,b a,y:(r4)+n4 ; 1+planesize move x:(r1)+n1,a b,y:(r4)+ move x:(r1)+,b a,y:(r4)+n4 ; planesize move x:(r1),a b,y:(r4)+ move a,y:(r4) ; Calculate intersected vertices. move #ISOLEVEL,b ; b=isolevel lua (r4)+n4,r1 ; r1: vector2 jsr 128,y1 move (r6)-n6 move y:(r6)+,x0 ; x0=X mpy y1,x0,a y:(r6)+,x1 ; x1=Y mpy y1,x1,a a0,x0 ; x0=X<<8 move a0,x1 ; x1=Y<<8 move #>1,a ; a=1 move y:(r6)-,y0 ; y0=Z [1..8192] andi #$FE,ccr rep #24 div y0,a ; a0=1/Z move a0,y0 ; y0=1/Z move #>100,a ; a=x_center move #>160,b ; b=y_center macr y0,x0,a (r6)- ; a=X' macr y0,x1,b a,y:(r6)+ ; b=Y', Store X'. move b,y:(r6)- ; Store Y'. move x:triTable,r0 move a0,n0 move #5,x0 ; End of triangle list? jmi <_end do #3,_trivertexloop ; Store (x,y) and unsign, scale and store (u,v). move x:(r0)+,x1 mpy x0,x1,a #$000800,y1 ; y1=upscalar move (r6)+n6 ; r6: vertex move y:(r6)+,a ; a= X' move a,x:(r1)+ y:(r6)+,b ; b= Y', Store X'. move b,x:(r1)+ y:(r6)+,a ; Store Y', dummy move. move y:(r6)+,y0 ; y0=u (12b) mpy y1,y0,a y:(r6),y0 ; a0=u (23b), y0=v (12b) mpy y1,y0,b a0,a ; b0=v (23b) eor x1,a b0,b ; Sign u. eor x1,b # cull it. ; Paint the triangle.. Note: no clipping! move #{n=24}=>123+(4/2) ; INPUT: ; b = isolevel ; x1= v1 ; a = v2 ; y:r3: vertex1 ; y:r1: vertex2 ; y:r6: dst vertex ; OUTPUT: ; y:r6: next dst vertex intersect: sub x1,b #>256,y0 ; b=isolevel-v1, y0=upscalar sub x1,a b,y1 ; a=v2-v1, y1=isolevel-v1 mpy y0,y1,b a,x0 ; b0=(isolevel-v1)<<(8+n), x0=v2-v1 (denominator) abs b y:(r3)+,x1 ; Make numerator positive (required by div), x1=p1[0] eor y1,a y:(r1)+,y0 ; Get sign (saved for jpl), y0=p2[0] andi #$FE,ccr ; Clear carrybit (required by div). rep #24 div x0,b ; b= (isolevel-v1)<<8/(v2-v1) = slope jpl <_signed ; Sign quotient if appropriate. neg b _signed:tfr y0,b b0,y1 ; b=p2[0], y1=slope sub x1,b #>1<<14,x0 ; a=p2[0]-p1[0]=d[0], x0=downscalar do #5,_loop tfr x1,a b,y0 ; a=p1[n], y0=d[n] mpy y1,y0,b y:(r3)+,x1 ; b=slope*d[n], x1=p1[n+1] move b0,y0 ; y0=slope*d[n] macr y0,x0,a y:(r1)+,b ; a=p1[n]+slope*d[n]=coord, b=p2[n+1] sub x1,b a,y:(r6)+ ; b=d[n+1], Store coord. _loop: rts ;- polygon routines -------------------------------------------------------- ; ; ; Not a subroutine, returns to polygonize_next_tri. ; Definetely the fastest scan converter around. ; USES: ; x:Polygon.vsize: 1=flat shade, 2=gouraud, 3=tmap, 4=gourtmap, 5=envtmap/bump ; INPUT: ; x:(r6): polygon table ; PRE: ; polygon must be wrapped paintTriangle: move #<3,n6 move #>InverseTable,r3 move #>Polygon.LeftEdge,r0 move #>Polygon.RightEdge,r1 move n6,n5 move n6,r4 move r6,r5 move (r4)+ move (r6)+n6 ; to next point move (r6)+ move r4,n4 ; n4= offset to next point ; r5: pt1, r6: next pt do x:Polygon.LeftEdge,r0 move #>Polygon.RightEdge,r1 move #>InverseTable,r2 move #>texture,r4 ; hline loop do n6,_yloop move y:(r0)+,x0 send x0 ; Send lx. move y:(r1)+,a ; a=rx. sub x0,a y:(r0)+,x0 ; x0=u_start move a1,n2 ; n2=width send a1 ; Send width. move y:(r1)+,x1 ; x1=u_end move y:(r0)+,y0 ; y0=v_start move y:(r1)+,b ; b=v_end tst a x1,a ; test for 0-width, a := u_end jle <_skip_line sub x0,a y:(r2+n2),x1 ; du=u_end-u_start, x1=divisor sub y0,b a1,y1 ; dv=v_end-v_start, y1=du mpy x1,y1,a b1,y1 ; a=u_step=du/divisor, y1=dv mpy x1,y1,b a1,x1 ; b=v_step=dv/divisor, x1=u_step tfr x0,a b1,x0 ; a1=u, x0=v_step move y0,a0 ; a0=v ; a1=u, a0=v, x1=u_step, x0=v_step move x:= 8 or 10 cycles ; total >= 18 or 20 cycles per pixel do n2,_send_pixel mpyr y1,y0,b l:$7FFFFF,a ; top := MAX_INT move #<$80,b ; bottom := MIN_INT move x:GWIDTH*2/9,x1 do #3*NUM_BALLS,_loop get x0 mpy x1,x0,a move a,x:(r0)+ ; Store coordinate. _loop: rts ; field and paint combined, no subrout, jumps back to main_loop. keepstacklow: ;--------------------------------------------------------------------------- ; Calculates a metaball field.. Pretty intense due to div and sqrt. ; ; n: amount of balls ; bi: ball number i ; ri: radius of ball ; ; 2 2 2 2 ; (ri) = (x-bi.x) + (y-bi.y) + (z-bi.z) ; ; -- n ; V(x,y,z) = \ -2 ; / (ri) ; -- 1 ; ; -- n ; \ -4 [bi.x-x] ; grad(V) = / 2*(ri) *[bi.y-y] (and then to normalise it..) ; -- 1 [bi.z-z] ; ;--------------------------------------------------------------------------- ; Preparations: calculate (squared) distances move #GWIDTH/2,a move #>CUBEWIDTH,x1 do #WIDTH,_widthloop tfr a,b #$000800,y0 ; a=r^2=dx^2+dy^2+dz^2, y0=downscalar move a0,b1 lsr b a1,x1 ; shift b for frac dumbness mpy y0,x1,b b,x0 ; b0=scaled r (int), x0=r (frac) mpy y0,x0,a b0,b ; a1=scaled r (frac), b=scaled r (int) addl b,a y0,b ; a1=scaled r, b=1<1,x1 ; b1 will be left_part(number) - (r0/2)**2 move b,r0 ; r0 will be sqrt(number) * 2 move a1,b0 ; b0= number [shifts left into b1] move #<2,n1 do #12+ROUND,_loop ; 2 bits at a time for 24 bits in total asl b r0,n0 asl b ; b1= left_part(number) tfr b,a (r0)+n0 ; a1/a0 is copy of b1/b0, r0:=2*r0 sub x1,a r0,r1 move r0,x0 sub x0,a (r1)+n1 ; a1=b1-r0-1, r1=r0+2 tpl a,b r1,r0 ; if b1>r0 then b1:=b1-r0-1, r0:=r0+2 _loop: move r0,a ; a1=r0 asr a x:$7FFFFF,a0 ; a=.999999 rep #24 div x0,a ; a0=1/sqrt(dx^2/r^8+dy^2/r^8+dz^2/r^8) move a0,x0 mpy x0,y0,a #>$000800,x1 ; a=dy/r^4*sqrt(dx^2/r^8+dy^2/r^8+dz^2/r^8)=n.x, x1=downscalar mpy x0,y1,b a0,y0 ; b=dx/r^4*sqrt(dx^2/r^8+dy^2/r^8+dz^2/r^8)=n.y, y0=n.x mpy x1,y0,a b0,y1 ; a=scaled n.x, y1=n.y mpy x1,y1,b a,x:(r1)+ ; b=scaled n.y, store n.x. move b,x:(r1)+ ; Store n.y. move r1,x:distSTable+2+NUM_BALLS*3*WIDTH,x0 cmp x0,a ; Done all? jlt <_zloop ; no -> loop jmp end and paint ;- various ----------------------------------------------------------------- ; ; ; Initialization routine.. init: ; Initialize poly stuff.. move #>3,x0 move x0,x:4096,n0 move #>texture,r0 do n0,_txtloop get y:(r0)+ _txtloop: move #>edgeTable,r0 do #256,_edgeloop get x:(r0)+ _edgeloop: move #>triTable,r0 do n0,_triloop get x:(r0)+ _triloop: ; Calculate inversetable. move #>InverseTable,r0 clr a #>1,x0 do #200,_invloop tfr x0,b a,x1 andi #$FE,ccr rep #24 div x1,b add x0,a b0,y:(r0)+ _invloop: rts ;= x memory ================================================================ org x:0 ; poly paint stuff texturewidth: dc 64 ; texture v width u0: ds 1 u0_step:ds 1 ; u_step storage texturesize: dc 64*64 ; texture size posx: ds 1 posy: ds 1 posz: ds 1 Polygon.top: ds 1 Polygon.height: ds 1 Polygon.points: ds 1 Polygon.vsize: ds 1 cubeIndex: ds 1 edgesCut: ds 1 tempR0: ds 1 tempR1: ds 1 saveR0: ds 1 zDistAdr: ds 1 val: ds 1 isolevel: ds 1 triangle: ds 4*4 posTable: ds NUM_BALLS*3 ; (x,y,z) distTable: ds WIDTH*NUM_BALLS*3 ; a00(x,y,z),b01(x,y,z),...., ;= external x memory ======================================================= org x:$300 distSTable: ds WIDTH*NUM_BALLS*3 ; long mem crap, must be in phase with y mem! edgeTable: ds 256 triTable: ds 4096 field: ds FIELD_SIZE+NUM_BALLS ; V, overflow required for opt! gradfield: ds FIELD_SIZE*2 ; (u,v) x_end: ;= internal y memory ======================================================= org y:0 ; poly paint stuff texturemask: dc $000FC0 ; v_frag mask v0: ds 1 v0_step:ds 1 ; v_step storage vertexTable: ds 12*5 ; intersected vertices (x,y,z,u,v) cubeSrcVertices: dc 0,CUBEWIDTH,CUBEWIDTH dc CUBEWIDTH,CUBEWIDTH,CUBEWIDTH dc CUBEWIDTH,CUBEWIDTH,0 dc 0,CUBEWIDTH,0 dc 0,0,CUBEWIDTH dc CUBEWIDTH,0,CUBEWIDTH dc CUBEWIDTH,0,0 dc 0,0,0 edgeRefTable: dc 0,1,1,2,3,2,0,3 ; front dc 4,5,5,6,7,6,4,7 ; back dc 0,4,1,5,2,6,3,7 ; joint cube: ds 8 cubeDstVertices: ds 8*5 ;= external y memory ======================================================= org y:$300 ;distSTable: ds WIDTH*NUM_BALLS*3 ; long mem crap, must be in phase with x mem! InverseTable: ds 200 texture:ds 4096 ; 64*64 highcolor texture Polygon.LeftEdge: ds 3*200 ; (x,u,v)*scans Polygon.RightEdge: ds 3*200 y_end: