; -------------------------------------------------------------------------- ; ; human fly - dsp part ; ; Global: ; ; This is useable as both: ; - a serial CPU<->DSP pipeline ; - a parallel CPU<->DSP pipeline ; ; This program leaves enough DSP RAM free to enable the use of a dsp module ; player. Some sacrifices had to be made. ; ; Limitations: ; - max viewport width = 320 ; - max viewport height = 200 ; ; NOTE: you can increase these when you decrease #polys or don't want dsp ; mixer! ; ; Remote Procedure Calls and a command stack are provided to provide ; generic behaviour. ; ; Please note there are two ways to do texturemapping. The first is storing ; textures in dsp ram and sending pixels. This enables the fastest ; texturemapping. The second is sending offsets, which is somewhat slower. ; "Polygon.storeTexture" can store two highcolor and two 7bpp ; 64*64 textures. ; ; TODO: Optimise texture-vertex table -> in poly stuff ; This would save loads of space! ; TODO: Optimize MeshElement to only 2 words. This saves alot of ; X RAM. Requires changing TransformObject.transform, ; PrimitiveMesh.sort and PrimitiveMesh.paint. ; $oopppp:$--zzzz (o: object handle, p: primitive address, z: depth) ;======== GLOBAL EQUATES ======== PBC: = $FFE0 ; Port B Control Register HSR: = $FFE9 ; Host Status Register HRX: = $FFEB ; Host Receive 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: = 320 ; = max(MAX_X,MAX_Y) INCLUDE H_FLYRPC.I ;======== Dispatcher Dispatcher.MAX_COMMANDS: = 512 ;======== ObjectRegistry Object.CAPACITY: = 8192 Object.MAX_OBJECTS: = 32 ; max. amount of transformed objects ;======== BoundingBox ; yes it's true, there are 8 corners in a box, now go somewhere else, ; fartface. i.e. 2 corner notation.. BoundingBox.SIZE: = 3*2 ;======== Viewport Viewport.MAX_Y: = 200 ; Unfortunate... But this eats mem! Viewport.SIZE: = Viewport.settingsTableEnd-Viewport.settingsTable ;======== Polygon Polygon.TEXTUREBUFFER_SIZE: = 64*64*2 ; able to store two 64*64 bitmaps ; wrappable texturing on/off WRAPCRAP: = 1 ;======== PrimitiveMesh PrimitiveMesh.MAX_ELEMENTS: = 1000 PrimitiveMesh.MAX_VERTICES: = 900 ; Depends on MAX_Y. ;======= Vertex ; That's right. For speedreasons the Y comes before the X! Vertex.Y: = 0 Vertex.X: = 1 Vertex.Z: = 2 Vertex.SIZE: = 3 ;======= Primitive Primitive.TYPE: = 0 ; primitive/shading/extended type ;======= Line Line.TYPE: = 0 ; primitive/shading/extended type Line.VERTEX1: = 1 ; offset to vertex 1 Line.VERTEX2: = 2 ; offset to vertex 2 Line.SIZE: = 3 ;======= Sprite Sprite.TYPE: = 0 ; primitive/shading/extended type Sprite.VERTEX: = 1 ; offset to vertex Sprite.SIZE: = 2 Primitive.SHADEMASK: = %1110000000000000 Primitive.SHADEMUL: = %10000000000 ; Shade types for sprites Sprite.REPLACED: = %0000000000000000 Sprite.MIXED: = %0010000000000000 ; Shade types for polygons Line.FLATSHADED: = %0000000000000000 Line.GOURAUDSHADED: = %0010000000000000 Line.PHONGSHADED: = %0100000000000000 ; Shade types for polygons Polygon.FLATSHADED: = %0000000000000000 Polygon.GOURAUDSHADED: = %0010000000000000 Polygon.PHONGSHADED: = %0100000000000000 Polygon.TEXTUREMAPPED: = %0110000000000000 Polygon.ENVMAPPED: = %1000000000000000 Polygon.ALPHATEXTURED: = %1010000000000000 Polygon.BUMPMAPPED: = %1100000000000000 ; Primitive types Primitive.TYPEMASK: = %0001110000000000 Primitive.TYPESHIFT: = 10 Primitive.TYPEMUL: = 1<<(-(Primitive.TYPESHIFT-23)) Primitive.SPRITETYPE: = %0000000000000000 Primitive.LINETYPE: = %0000010000000000 ; Other types are polygons, %10 :== triangle, %11 :== quadrangle, etc. ; TableLookup mask Primitive.TEXTUREMASK: = %0000001111111111 ;======== MeshElement MeshElement.BASE: = 0 ; startaddress of vertex table MeshElement.REF: = 1 ; address of element MeshElement.Z: = 2 ; Z coordinate of element MeshElement.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.TX: = 9 Matrix.TY: = 10 Matrix.TZ: = 11 Matrix.SIZE: = 12 ;======== GLOBAL MACROS ======== get: MACRO jclr #0,X:< 550.000 rotate-perspectivations / sec. ; calc z mac x0,y0,a x:(r0)+,x1 y:(r4)+,y0 mac x1,y0,a x:(r0)-,x1 y:(r4)+n4,y0 macr x1,y0,a x:PrimitiveMesh.baseHandle,a move #>1,x0 add x0,a x:>PrimitiveMesh.nextVertex,r5 move a,x:>PrimitiveMesh.baseHandle move x:(r0)+,b ; a= #vertices+#normals move x:(r0)+,x0 ; x0= #normals sub x0,b x0,n0 ; b= #vertices, n0= #normals jsr PrimitiveMesh.nextVertex,r6 move r5,x:>PrimitiveMesh.nextVertex ; Store address for next transformed vertices. move #>PrimitiveMesh.primitiveTable,r2 move x:(r0)+,a ; a= number of 2d vertices asl a r0,y:(r6) ; Store address of 2d vertices. move a,n0 move x:(r2)+,a ; a= primitivecounter move a,r3 asl a a,x0 add x0,a r6,r5 ; r5= address of transformed vertices move a,n2 ; n2= offset to next primitive in mesh move (r0)+n0 ; r0= primitivetable move (r2)+n2 ; r2= address of next primitive in mesh move #>PrimitiveMesh.baseTable,r1 move x:>PrimitiveMesh.baseHandle,n1 move #<2,n2 move r5,x:(r1+n1) ; Store address of vertexbase in table. do x:(r0)+,_calc_z_loop IFNE 1 move r5,x:(r2)+ ; Store pointer to vertices-base. clr a r0,x:(r2)+ ; Store object primitive address in the mesh. ELSE ; TODO: possibly introduce the efficient prim-table handling here. move x:>PrimitiveMesh.baseHandle,x0 move #>$008000,x1 mpy x0,x1,b r0,a move b1,x0 or x0,a clr a a,x:(r2)+ ; Store vertexbasehandle|primitive address ENDC move x:(r0)+,a1 ; a1= primitivetype move a1,n3 ; n3= primitivetype move #>Primitive.TYPEMASK,x0 and x0,a #>Primitive.LINETYPE,x0 move a1,n1 move r0,y:Vertex.SIZE,x0 ; / Get offset to sprite vertex. mpy x0,y0,a (r5)+ ; | asr a (r5)+ ; | move a0,n5 ; \ move (r5)+ move y:(r5+n5),x0 ; x0= z move (r5)- tfr x0,b (r5)- ; b= z tst b #<1,n0 jle <_dont_store jmp <_store_primitive _not_sprite: cmp x0,a #>Vertex.SIZE,x0 ; Get offset to line vertex. jne <_not_line mpy x0,y0,a #<3,n5 asr a move (r5)+n5 move a0,n5 move x:(r0)+,a asl a a,y0 add y0,a y:(r5+n5),b move a1,n5 move #<2,n0 tfr b,a y:(r5+n5),x0 or x0,a (r5)- ; v1 or v2 behind cam -> out move (r5)- jmi <_dont_store add x0,b asr b ; b=(v1.z+v2.z)/2 move b,x0 jmp <_store_primitive _not_line: _polygon: ;move #>Vertex.SIZE,x0 ; / Get offset to p0 vertex. mpy x0,y0,a (r5)+ ; | asr a x:(r0)+,y0 ; | move a0,n5 ; \ mpy x0,y0,a lua (r5)+n5,r1 asr a x:(r0)+,y0 ; move a0,n5 ; mpy x0,y0,b y:(r1)+,a ; a := p0.y lua (r5)+n5,r6 nop asr b y:(r6)+,x0 ; x0= p1.y move b0,n5 ; sub x0,a y:(r6)+,y1 ; a= p0.y - p1.y, y1= p1.x move y:(r6),b ; x1= p1.z lua (r5)+n5,r6 tst b b,x:InverseTable,r4 move (r1)+ move r1,n4 move x:1,b move #>Primitive.SHADEMASK,x0 and x0,a b,x1 jeq <_got_size add x1,b #>Polygon.ALPHATEXTURED,x0 cmp x0,a jlt <_got_size add x1,b _got_size: move y: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:64*64/2,y1 move r4,a0 mac y0,y1,a move a0,r4 ; hline loop do n6,_yloop move y:(r0)+,x0 ; x0=lx move y:(r1)+,a ; a=rx send x0 ; Send lx. sub x0,a y:(r0)+,x0 ; x0=u_start move y:(r0)+,y0 ; y0=v_start move a1,n2 ; n2=width send a1 ; Send width. move y:(r1)+,a ; a=u_end move y:(r1)+,b ; b=v_end jle <_skip_line IFNE WRAPCRAP 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 a,n5 ; b=v_step=dv/divisor, n5=u_step move y:texturesize) mpy y1,y0,a b,x1 ; a=v (12b), x1=v_step mpy y1,x1,b x0,r5 ; b=v_step (12b), r5=u move b1,x1 tfr a,b #<0,x0 ;b0,x0 ; b=v (12b), x=v_step (12b) move x: int) move #<0,b0 ELSE 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,x:= 8 or 10 cycles ; total >= 18 or 20 cycles per pixel do n2,_send_pixel IFNE WRAPCRAP tfr b,a y:64*64,y0 move y:PrimitiveMesh.primitiveTable,r0 move #2,x0 cmp x0,b jgt <_calculate_gap tfr x0,b _calculate_gap: move #>0.769230769,x0 move b,x1 mpy x0,x1,b _end_calculate_gap: tfr y0,a b,x1 sub x1,a n3,x0 mpy x0,x1,a a,n6 asr a #<0,r4 ; swapcount := 0 move a0,n0 move #2,x0 jne <_loop cmp x0,b jge <_loop _end: rts ;======== non time-crucial stuff, all in external P-RAM ======== START: jsr Dispatcher.commandTable,x0 move x0,x:>Dispatcher.commandTablePosition _storebigloop: move #>Dispatcher.commandSizeTable,r0 move x:>Dispatcher.commandTablePosition,r1 move #>RPC_PAINT_PRIMITIVES,x0 ; First store all received commands including arguments. _storeloop: get n0 move n0,a cmp x0,a x:(r0+n0),b jeq <_end_store tst b a,x:(r1)+ jeq <_storeloop jmi <_execute_direct ; This is for asynchronous commands. They are stored and executed later on ; in parallel. do b,_store_word_loop get x:(r1)+ _store_word_loop: jmp <_storeloop ; Some commands have to be completed synchronously! i.e. texture/object- ; storage!!!! _execute_direct: move #>Dispatcher.rpcTable,r2 move n0,n2 move (r1)- ; Correct last store (not needed!). move x:(r2+n2),r2 move r1,x:>Dispatcher.commandTablePosition jsr (r2) jmp <_storebigloop _end_store: move a,x:(r1)+ move #>Dispatcher.commandTable,x0 move x0,x:>Dispatcher.commandTablePosition ; Then execute all commands. _execute_loop move x:>Dispatcher.commandTablePosition,r0 move #>Dispatcher.commandSizeTable,r1 move x:(r0)+,a move #>RPC_PAINT_PRIMITIVES,x0 ; Check for a paint command.. cmp x0,a a,n1 jeq <_complete move x:(r1+n1),n0 ; Fetch command size. move #>Dispatcher.storedRpcTable,r1 lua (r0)+n0,r2 ; Jump to next command. move x:(r1+n1),r1 ; Store next command position and execute current. move r2,x:>Dispatcher.commandTablePosition jsr (r1) jmp <_execute_loop _complete: jsr 1,x1 sub x1,a #>Matrix.SIZE,x0 move a,x1 mpy x0,x1,a #-8,n4 ; n4 := jumpbackvalue for matrix move #>-2,n6 ; n6 := jumpbackvalue for translation move #>InverseTable,r3 ; r3 := start of 1/Z table move #<128,n3 move r3,r2 ; r2 := start of 1/Z table move (r3)+n3 move y:(r6)+n6,a ; a := TZ move x:(r0)+,x0 y:(r4)+,y0 move #<127,n3 jmp Primitive.TEXTUREMASK,x0 ; Get texturenumber. and x0,a a1,b1 move a,x:Primitive.TYPEMASK,x0 and x0,b #>Primitive.TYPEMUL,x1 move x:(r2)+,a1 move b,y0 move #>1,b mac y0,x1,b (r1)+ move b,x:Primitive.SHADEMASK,x0 and x0,a #>Primitive.SHADEMUL,x1 move a,x0 mpy x0,x1,a #>Polygon.shadeJumpTable,r6 move a,n6 ; Fill the polygon table... ; y:(r1): vertices ; x:(r2): 1st index in primitive ; y:(r4): polygon table nop move p:(r6+n6),r6 nop jmp (r6) Polygon.shadeJumpTable: DC Polygon.decodeFlatshaded DC Polygon.decodeGouraudshaded DC Polygon.decodePhongshaded DC Polygon.decodeTextured DC Polygon.decodeEnvmapped DC Polygon.decodeAlphatextured DC Polygon.decodeBumpmapped ; INPUT: ; x:(r4): end of polygon data Polygon.copyLast: ; Copy the first point (wrap-crap). move #2-1,x0 move x0,x:3-1,x0 move x0,x:RPC_GOURAUDSHADED,x0 move x0,x:$8000,y0 do x:3-1,x0 move x0,x:RPC_GOURAUDSHADED,x0 move x0,x:127,x1 move #>$3FFF,y0 do x:4-1,x0 move x0,x:RPC_TEXTUREMAPPED,x0 move x0,x:1<<7,x1 ; 1<<14 do x:1<<7,x1 move #>$008000,y1 ELSE move #>1<<14,x1 move #>$400000,y1 ENDC do x:RPC_ALPHATEXTURED,x0 move x0,x:RPC_BUMPMAPPED,x0 move x0,x:1<<14,x1 move #>$400000,y1 do n2,_loop move x:(r2)+,a ; Get index of Vertex. asl a a,x0 add x0,a x:(r0)+,b ; Fetch 2d vertex index. asl b a,n1 move x:(r0)+,a ; Fetch normal index. lua (r1)+n1,r3 ; r3 := Vertex asl a a,x0 add x0,a b,n5 move a,n1 lua (r5)+n5,r6 ; r6 := 2d vertex ; Write points to the polygontable. do #2,_coordloop move y:(r3)+,x0 move x0,x:(r4)+ _coordloop: move x:(r6)+,x0 ; Fetch u1. mpy x0,x1,a x:(r6),x0 ; Fetch v1. mpy x0,x1,b a0,x:(r4)+ ; Write u1. lua (r1)+n1,r6 ; r6 := Normal clr a b0,x:(r4)+ ; Write v1. clr b y1,a0 move y1,b0 move y:(r6)+,y0 ; Fetch Normal.X (=u2). mac y0,x1,a y:(r6),y0 ; Fetch Normal.Y (=v2). mac y0,x1,b a0,x:(r4)+ ; Write u2. move b0,x:(r4)+ ; Write v2. _loop: jmp 0 onscreen Polygon.clip: ; First of all we check which sides of the viewport this baby clips against. move #_top,r4 bclr #0,x:_bottom,r4 bclr #1,x:_left,r4 bclr #2,x:_right,r4 bclr #3,x: / \ ; \ / --> \ / ; \ / \ / ; \/ \/ ; ; This clips an edge against the top of the Viewport. ; _top: move x:(r0)+,a ; a := ystart cmp x0,a x:(r0+n0),b ; b := yend jlt <_top_check_2ndout ; if 1st point is outside, jump. cmp x0,b r0,r2 jge <_inside ; if 2nd point is inside, jump. ; The source edge goes from inside to outside. ; Write the clipped point. _top_inout: move x0,x:(r1)+ move (r0)- do x: / \ ; \ / --> \ / ;------------ ------------ ; \/ ; ; This clips an edge against the bottom of the Viewport. ; _bottom: move x:(r0)+,a ; a := ystart cmp x0,a x:(r0+n0),b ; b := yend jge <_bottom_check_2ndout ; if 1st point is outside, jump. cmp x0,b r0,r2 jlt <_inside ; if 2nd point is inside, jump. ; The source edge goes from inside to outside. ; Write the clipped point. _bottom_inout: move x0,x:(r1)+ move (r0)- do x: | \ ; \| / --> | / ; | / | / ; |\/ |\/ ; ; This clips an edge against the left side of the Viewport. ; _left: move (r0)+ move r0,r2 move x:(r0)+,a ; a := xstart move x:(r0+n0),b ; b := xend cmp x0,a (r0)- jlt <_left_check_2ndout ; if 1st point is outside, jump. cmp x0,b jge <_inside ; if 2nd point is inside, jump. ; The source edge goes from inside to outside. ; Write the clipped point. _left_inout: move (r0)- ; x:(r0) : source y start move (r1)+ ; x:(r1) : dest. x start move x0,x:(r1)- ; X := Viewport.XStart ; x:(r1) : dest. y start ; Prepare for intersection with preset side. move x:(r2)+,a ; y1 := xstart move x:(r2+n2),x1 ; a := xend sub x1,a x:(r0)+,b ; a := xend - xstart (=dx), y1 := ystart move x:(r0+n0),y1 ; b := yend ; a := ystart - xi(frac) * slope(fixedpoint) jsr <_intersect add y1,a (r0)+ ; Add ystart. move a,x:(r1)+ ; Store new y, x:(r1) : dest. x coord ; loopcounter = amount of coords except x,y move x:1,x1 sub x1,a (r1)+ ; Proceed to next dest. coord. jeq <_end_left_inout do a,_left_inoutloop ; Prepare for intersection with preset side. move x:(r0)+,x1 ; x1 := xstart move x:(r0+n0),a ; a := xend sub x1,a x:(r2)+,y1 ; a := xend - xstart (=dx), y1 := ustart move x:(r2+n2),b ; b := uend ; a := ustart - xi(frac) * slope(fixedpoint) jsr <_intersect neg a add y1,a ; Add ustart. move a,x:(r1)+ ; Store new u. _left_inoutloop: _end_left_inout: move (r3)+ ; Increase pointcount. move r2,r0 jmp <_end_loop _left_check_2ndout: cmp x0,b jge <_left_outin ; Source edge is outside. Don't write it out. move (r0)+n0 jmp <_end_loop ; The source edge goes from outside to inside. ; Write the clipped point and the inside point as well. _left_outin: move (r1)+ move x0,x:(r1)- ; X := Viewport.XStart move (r0)- ; Prepare for intersection with preset side. move x:(r2)+,x1 ; y1 := xstart move x:(r2+n2),a ; a := xend sub x1,a x:(r0)+,y1 ; a := xend - xstart (=dx), y1 := ystart move x:(r0+n0),b ; b := yend ; a := xstart - yi(frac) * slope(fixedpoint) jsr <_intersect add y1,a (r0)+ ; Add ystart. move a,x:(r1)+ ; Store new y. ; loopcounter = amount of coords except x,y move x:1,x1 sub x1,a (r1)+ ; Proceed to next dest. coord. jeq <_end_left_outin do a,_left_outinloop ; Prepare for intersection with preset side. move x:(r0)+,x1 ; x1 := xstart move x:(r0+n0),a ; a := xend sub x1,a x:(r2)+,y1 ; a := xend - xstart (=dx), y1 := ustart move x:(r2+n2),b ; b := uend ; a := ustart + xi(frac) * slope(fixedpoint) jsr <_intersect add y1,a ; Add ustart. move a,x:(r1)+ ; Store new u. _left_outinloop: _end_left_outin: move (r3)+ ; Increase pointcount. jmp <_inside ; ; /\| /\| ; / | / | ; / |\ --> / | ; \ |/ --> \ | ; \ | \ | ; \/| \/| ; ; This clips an edge against the right side of the Viewport. ; _right: move (r0)+ move r0,r2 move x:(r0)+,a ; a := xstart move x:(r0+n0),b ; b := xend cmp x0,a (r0)- jge <_right_check_2ndout ; if 1st point is outside, jump. cmp x0,b jlt <_inside ; if 2nd point is inside, jump. ; The source edge goes from inside to outside. ; Write the clipped point. _right_inout: move (r0)- ; x:(r0) : source y start move (r1)+ ; x:(r1) : dest. x start move x0,x:(r1)- ; X := Viewport.XStart ; x:(r1) : dest. y start ; Prepare for intersection with preset side. move x:(r2)+,a ; y1 := xstart move x:(r2+n2),x1 ; a := xend sub x1,a x:(r0)+,b ; a := xend - xstart (=dx), y1 := ystart move x:(r0+n0),y1 ; b := yend ; a := ystart - xi(frac) * slope(fixedpoint) jsr <_intersect neg a add y1,a (r0)+ ; Add ystart. move a,x:(r1)+ ; Store new y, x:(r1) : dest. x coord ; loopcounter = amount of coords except x,y move x:1,x1 sub x1,a (r1)+ ; Proceed to next dest. coord. jeq <_end_right_inout do a,_right_inoutloop ; Prepare for intersection with preset side. move x:(r0)+,x1 ; x1 := xstart move x:(r0+n0),a ; a := xend sub x1,a x:(r2)+,y1 ; a := xend - xstart (=dx), y1 := ustart move x:(r2+n2),b ; b := uend ; a := ustart - xi(frac) * slope(fixedpoint) jsr <_intersect add y1,a ; Add ustart. move a,x:(r1)+ ; Store new u. _right_inoutloop: _end_right_inout: move (r3)+ ; Increase pointcount. move r2,r0 jmp <_end_loop _right_check_2ndout: cmp x0,b jlt <_right_outin ; Source edge is outside. Don't write it out. move (r0)+n0 jmp <_end_loop ; The source edge goes from outside to inside. ; Write the clipped point and the inside point as well. _right_outin: move (r1)+ move x0,x:(r1)- ; X := Viewport.XStart move (r0)- ; Prepare for intersection with preset side. move x:(r2)+,x1 ; y1 := xstart move x:(r2+n2),a ; a := xend sub x1,a x:(r0)+,y1 ; a := xend - xstart (=dx), y1 := ystart move x:(r0+n0),b ; b := yend ; a := xstart - yi(frac) * slope(fixedpoint) jsr <_intersect neg a add y1,a (r0)+ ; Add ystart. move a,x:(r1)+ ; Store new y. ; loopcounter = amount of coords except x,y move x:1,x1 sub x1,a (r1)+ ; Proceed to next dest. coord. jeq <_end_right_outin do a,_right_outinloop ; Prepare for intersection with preset side. move x:(r0)+,x1 ; x1 := xstart move x:(r0+n0),a ; a := xend sub x1,a x:(r2)+,y1 ; a := xend - xstart (=dx), y1 := ustart move x:(r2+n2),b ; b := uend ; a := ustart + xi(frac) * slope(fixedpoint) jsr <_intersect neg a add y1,a ; Add ustart. move a,x:(r1)+ ; Store new u. _right_outinloop: _end_right_outin: move (r3)+ ; Increase pointcount. jmp <_inside ; The source edge is inside -> write the second point to the destination. _inside: move (r0)+n0 ; Proceed to next point. move r0,r2 move (r3)+ ; Increase pointcount. move x:(r2)+,x1 move x1,x:(r1)+ do x:$7fffff,a ; top := MAX_INT move #>$800000,b ; bottom := MIN_INT move x:Polygon.LeftEdge,r0 move #>Polygon.RightEdge,r1 move #>1,x0 sub x0,b #>InverseTable,r2 jeq Polygon.texture,r4 ; r4= (color) texture jeq HTX,r3 jeq Polygon.texture+64*64,r5 ; r5= alpha texture jmp Polygon.textureNumber ; Get texturenumber. get x:(r0) ; Get number of points in polygon. get x:(r1) ; Get number of coordinates-1 in point. move x:(r1),r3 move #>$7fffff,a ; top := MAX_INT move #>$800000,b ; bottom := MIN_INT do x:(r0),_receiveloop get y0 cmp y0,a y0,x:(r2)+ ; Store y. tgt y0,a ; If new value is lower, set new top. cmp y0,b tlt y0,b ; If new value is higher, set new bottom. do r3,_receivecoord get x:(r2)+ _receivecoord: nop _receiveloop: ; Copy first point as last also. (wrap-crap) move (r3)+ move #8192,n6 move #>$7F0000,x0 move #>Polygon.texture,r0 ; We do this one for the alpha's. 8bpp -> 7bpp (for signed sillyness). do n6,_rescale7bitloop get a asr a a,b and x0,a #>$00FFFF,x1 and x1,b move b,y0 or y0,a move a1,y:(r0)+ _rescale7bitloop: ; Sets texturing to pixel-mode. Implies 64*64 mapping! Polygon.setPixelMode: move #>64,x0 move x:256,x0 move x:Polygon.paintTextured_pixelinstruction mpy x0,x0,a x0,x:1,x1 tfr x0,b a0,a sub x1,a a,x:64,y1 mpy x0,y1,a b1,y: 6 or 8:8 -> 8) : ; $002000 for 64 ; $008000 for 256 move a0,x: 6:6 or 8:8 -> 8:8) : ; $080000 for 64x64 $1000 ; $800000 for 256x256 $10000 (isn't this negative?) move #>$40,y1 move x:PrimitiveMesh.shadowOn,b tst b x:InverseTable,r0 clr a #>1,x0 move #>$7FFF00,y0 do #INVBUF_SIZE,_loop move a1,x1 move #>1,b rep #24 div x1,b move b0,b and y0,b ; And to get same low precision as 68K add x0,a b,y:(r0)+ _loop: rts ;======== Viewport ; Get new viewport settings from cpu. Viewport.update: move #Matrix.MAX_DEPTH,x0 jeq <_first_entry cmp x0,a #>Matrix.SIZE,x0 jhs <_end ; The stack is not full.. _not_first_entry: move a,x1 mpy x0,x1,a asr a move a0,n0 ; n0 := offset to dest. matrix move x0,n1 move (r0)+n0 ; r0 := dest. matrix move r0,r1 move r0,r3 ; r3 := dest. matrix move (r1)-n1 ; r1 := source matrix move r1,r0 ; r0 := source matrix jsr 1,x0 add x0,a move a,x:1,x0 jle <_end sub x0,a move a,x:PrimitiveMesh.shadowOn ; Reset pointers.. clr a #>PrimitiveMesh.vertexTable,x0 move x0,x:>PrimitiveMesh.nextVertex move a,x:>PrimitiveMesh.primitiveTable move a,x:>BoundingBox.rectangleCount move a,x:>PrimitiveMesh.baseHandle rts ; Paints all primitives. PrimitiveMesh.paint: move #Primitive.TYPEMASK,x0 IFNE 1 move x:(r0)+,r1 ; r1= base of primitive's vertices move x:(r0)+,r2 ; r2= address of primitive ELSE move x:(r0)+,x1 move #>$000080,x0 mpy x0,x1,a #>PrimitiveMesh.baseTable,r1 move a1,n1 ; r1= vertexbase handle move x1,r2 ; r2= address of primitive move x:(r1+n1),r1 ; r1= vertex base address ENDC clr a (r0)+ move x:(r2),a1 ; a= primitive's type move r0,p:>PrimitiveMesh.currentElement and x0,a #>Primitive.SPRITETYPE,x0 cmp x0,a #>Primitive.LINETYPE,x0 jgt _test_line ; Handle a sprite. _is_sprite: send #RPC_SPRITE move (r1)+ send x:(r2)+ move x:(r2)+,a ; Fetch vertex index. asl a a,x0 add x0,a r1,b add a,b move b,r1 do #3,_spriteloop send y:(r1)+ _spriteloop: move (r1)- jmp <_end_loop _test_line: cmp x0,a jgt _is_polygon ; Handle a line. _is_line: send #RPC_LINE move (r1)+ move x:(r2)+,x1 send x1 do #2,_lineloop move x:(r2)+,a ; Fetch vertex index. asl a a,x0 add x0,a r1,b add a,b r1,r3 move b,r1 do #2,_linecoordloop send y:(r1)+ _linecoordloop: move r3,r1 _lineloop: tfr x1,a #>Primitive.SHADEMASK,x0 and x0,a #>Line.GOURAUDSHADED,x0 cmp x0,a jeq <_gouraudshaded jgt <_phongshaded _flatshaded: move (r1)- jmp <_end_loop _gouraudshaded: move (r1)- send x:(r2)+ send x:(r2)+ jmp <_end_loop _phongshaded: move #$80,x1 do #2,_phongloop move x:(r2)+,a ; Fetch vertex index. asl a a,x0 add x0,a r1,b add a,b r1,r3 move b,r1 nop move y:(r1+n1),a add x1,a asr a r3,r1 send a _phongloop: move (r1)- jmp <_end_loop ; Handle a polygon. _is_polygon: jsr PrimitiveMesh.currentElement,r0 _loop: ; All primitives are painted, now send the terminator: "I'll be back"... ;) _end: move #>$ffffff,x0 send x0 ; Now send them bounding rectangle critters. move x:>BoundingBox.rectangleCount,a send a ; Send rectanglecount. lsl a #>BoundingBox.rectangles,r0 jeq <_die lsl a do a,_rectloop send x:(r0)+ _rectloop: _die: rts PrimitiveMesh.currentElement: DS 1 ;======== TransformObject ; RPC call routine! TransformObject.rpcTransform: get n0 jmp Object.newHandleAddress,r1 get a ; Get #objwords+#bufwords. move #>Object.CAPACITY,x0 cmp x0,a x:(r1)+,r0 ; Get designated address in object-buffer. jgt <_error move r0,r2 ; backup start of object move #>Object.handlesEnd,b move r1,x0 cmp x0,b #<0,x0 ; Inform the host the object is accepted (result = 0).. send x0 get a ; Get #objwords do a,_get_object_loop get x:(r0)+ ; Receive one object word from cpu. _get_object_loop: ; Store pointer to next handle.. move r1,x:>Object.newHandleAddress move #>Object.handleTable,n1 move r0,x:(r1)- ; Store start of free space. move (r1)-n1 move r1,x0 ; x0=boundingbox handle jmp -1,a send a rts ; Returns the objectaddress of the specified handle. ; No checking for invalid handles!! ; INPUT: ; n0: ObjectHandle ; OUTPUT: ; r0: ObjectAddress Object.get: move #>Object.handleTable,r0 nop move x:(r0+n0),r0 rts ; Clears the registry. All handles become invalid. Object.clear: move #Object.handleTable,x0 move x0,x:>Object.newHandleAddress move #Object.buffer,x0 move x0,x:>Object.handleTable rts ; Replaces object's primitives/vertices/normals/texels. ; Reads these from the host. Object.replace: move #>Object.handleTable,r0 get n0 ; n0=handle get a ; a=replacemode move x:(r0+n0),r0 ; r0=object move n0,n6 ; n6=handle move r0,r6 ; r6=object ; Calculate addresses of tables and lists. move x:(r0)+,b ; b=#vertices+#normals lsl b b,x0 add x0,b x:(r0)+,x0 ; x0=#normals move b1,n0 ; n0=(#vertices+#normals)*3=offset to texels move x0,b lua (r0)+n0,r2 asl b add x0,b move b1,n2 ; n2=#normals*3 move x:(r2)+,n3 ; n3=#texels lua (r2)-n2,r1 move r2,r3 nop move (r3)+n3 move (r3)+n3 ; r0=vertices ; r1=normals ; r2=texels ; r3=primitives ; Get vertices.. lsr a jcc <_end_vertices get b ; b=#words tst b jeq <_end_vertices do b,_ver_loop get x:(r0)+ _ver_loop: _end_vertices: ; Get normals.. lsr a jcc <_end_normals get b ; b=#words tst b jeq <_end_normals do b,_nor_loop get x:(r1)+ _nor_loop: _end_normals: ; Get texels.. lsr a jcc <_end get b ; b=#words tst b jeq <_end do b,_tex_loop get x:(r2)+ _tex_loop: ; Get primitives.. lsr a jcc <_end get b ; b=#words tst b jeq <_end do b,_prim_loop get x:(r3)+ _prim_loop: _end: move n6,x0 ; x0=handle move r6,r2 ; r2=object jmp BoundingBox.SIZE,x1 mpy x0,x1,a x1,n0 asr a #>BoundingBox.table,x0 move a0,a add x0,a #>$800000,b ; initial highest move a,r0 move #>$7fffff,a ; initial lowest do #3,_resetloop move a,x:(r0)+ move b,x:(r0)+ _resetloop: move x:(r2)+,x0 move (r2)+ move (r0)-n0 do x0,_vertexloop do #3,_coordloop move x:(r0)+,a ; a= lowest move x:(r2)+,x0 ; x0= coord cmp x0,a x:(r0)-,b ; b= highest tgt x0,a cmp x0,b a,x:(r0)+ tlt x0,b move b,x:(r0)+ _coordloop move (r0)-n0 _vertexloop: rts ; Transforms a bounding box into a bounding rectangle. ; INPUT: ; n0: objecthandle ; OUTPUT: ; a: 1=visible, 0=invisible BoundingBox.calcRectangle: move n0,x0 move #>BoundingBox.SIZE,x1 mpy x0,x1,a #>BoundingBox.decoded,r1 asr a #>BoundingBox.table,r2 move a0,n2 clr a #>1,x1 move (r2)+n2 move #<5,n2 ; x:r0 = address of encoded box (src) ; x:r1 = address of decoded box (dst) move #>%111,b do #8,_loop _do_x: move x:(r2)+,a move x:(r2)+,x0 jclr #0,b,_no_x tfr x0,a _no_x: move a,x:(r1)+ _do_y: move x:(r2)+,a move x:(r2)+,x0 jclr #1,b,_no_y tfr x0,a _no_y: move a,x:(r1)+ _do_z: move x:(r2)+,a move x:(r2)-n2,x0 jclr #2,b,_no_z tfr x0,a _no_z: sub x1,b a,x:(r1)+ _loop: move #>BoundingBox.decoded,r0 move #>BoundingBox.transformed-1,r5 move #>8,b jsr BoundingBox.transformed+2,r2 move #<3,n2 clr a move y:(r2)+n2,x0 rep #7 or x0,a y:(r2)+n2,x0 tst a jmi <_invisible ; Transform the box into a rectangle... ; dim??? D1m??!?!?! That's sounds like *yich* BASIC! :P move x:>BoundingBox.rectangleCount,a lsl a #>BoundingBox.transformed,r2 lsl a #>BoundingBox.rectangles,x0 add x0,a #<8*3-1,n2 move a,r1 ; r1= new rectangle move a,r3 do #2,_outloop move #>$7fffff,a ; a= min move #<$80,b ; b= max do #8,_dimloop move y:(r2)+,x0 ; x0= coord cmp x0,a (r2)+ tgt x0,a cmp x0,b (r2)+ tlt x0,b _dimloop: move a,x:(r1)+ ; Store min. move b,x:(r1)+ ; Store max. move (r2)-n2 _outloop: ; Store rectangle.... move #<0,r0 move x:(r3)+,a move x:(r3)+,b move x:BoundingBox.rectangleCount,r0 move #>1,a move (r0)+ move r0,x:>BoundingBox.rectangleCount rts p_memory_end: ;======== X-Memory Code ======== ORG X:$0000 texturewidth: DS 1 ; texture v width u_scale:DS 1 u0: DS 1 u0_step:DS 1 ; u_step storage u1: DS 1 u1_step:DS 1 ; u_step storage colorshift: DC $008000 alphashift: DC $000100 texturesize: DS 1 ; texture size spaceometer: DC Polygon.TEXTUREBUFFER_SIZE SineX: DS 1 CosineX:DS 1 SineY: DS 1 CosineY:DS 1 ;======== Matrix Matrix.stackTop: DC 0 ;======== TransformObject TransformObject.vertexadr: DS 1 ;======== Viewport Viewport.settingsTable: Viewport.XScreen: DS 1 Viewport.YScreen: DS 1 Viewport.XStart: DS 1 Viewport.XEnd: DS 1 Viewport.YStart: DS 1 Viewport.YEnd: DS 1 Viewport.XCenter: DS 1 Viewport.YCenter: DS 1 Viewport.Focal: DS 1 Viewport.Aspect: DS 1 ; 8:8 Y scale Viewport.settingsTableEnd: ;======== Polygon Polygon.points: DS 1 Polygon.vsize: DS 1 Polygon.z: DS 1 Polygon.clipFlags: DS 1 Polygon.height: DS 1 Polygon.top: DS 1 Polygon.shadeType: DS 1 Polygon.textureNumber: DS 1 Polygon.sendPixelInstruction: movep y:(r4+n4),x:<