* * lib3d extensions * * A collection of routines which extends * the 3d library, adding routines for creating, * manipulating, and rendering objects. * * SLJ March/April 1999 * * * Idea: Maintain a list of objects. * Each object is of the following form: * * Object: * CenterX 2 bytes * CenterY 2 bytes * CenterZ 2 bytes * Obj data pointer 2 bytes * ID byte 1 byte * User byte 1 byte * Center position 1 byte * CenterXRem 1 byte * YRem 1 byte * ZRem 1 byte * Orientation matrix 18 bytes ObjCX = 0 ObjCY = 2 ObjCZ = 4 ObjData = 6 ObjID = 8 ObjUser = 9 ObCenPos = 10 ObjCXRem = 11 ObjCYRem = 12 ObjCZRem = 13 ObjMat = 14 ObjSize = 32 ;32 bytes total * * CenterX/Y/Z represents the object location * Data pointer points to object data, below. * ID and user byte is optional, to let the user assign an ID to an object * CenterX/Y/ZRem is the fractional part of the object centers, * used by the movement routines * Orientation matrix consists of 9-byte integer matrix and 9-byte remainder * * * Object data: There are two types of * objects, normal and compound, which * are objects made up of a number of * smaller "oblets". Normal object data * is of the following form: * * TypeID = 0 1 byte * # of points 1 byte * # of faces 1 byte * xcoords n bytes * ycoords n bytes * zcoords n bytes * faces: * # of points 1 byte * fill pattern 1 byte * point list m bytes * * that is, point data followed by a list of faces. * Fill pattern is an index into fill pattern list, used with solid polygons. * x/y/zcoords consist of p object points (-96..96) followed by q normals. * * Compound objects are of the form: * * TypeID = $80 1 byte * # of points 1 byte * # of oblets 1 byte * xcoords n bytes * ycoords n bytes * zcoords n bytes * oblets: * ref points p bytes * oblet 1 * oblet size (in bytes) * 1 byte * # of faces 1 byte * faces * oblet 2 ... * * Each oblet is similar to a normal object, but is associated with a point * in the point list -- the reference point. The oblets are drawn by first * depth-sorting these points and drawing from back to front. * org $5000 jmp Init3D ;Initialize lib3d jmp AddObj ;Add object to object list jmp DelObj ;Delete object from list jmp SetCurOb ;Set current object jmp GetCurOb ;Get current object jmp GetNextOb ;Get next object in list jmp GetObj ;Get pointer to object jmp SetMat ;Calculate and set object matrix jmp Pitch ;Pitch - rotate object around x-axis jmp Yaw ;Yaw - rotate around y-axis jmp Roll ;Roll - rotate around z-axis jmp MoveSide ;Move object jmp MoveDown jmp MoveForwards jmp GetSideVec ;Orientation vectors jmp GetDownVec ;(length=64) jmp GetFrontVec jmp SetParms ;Set rendering parameters jmp SetVisParms ;Set visibility parameters jmp CalcView ;Set viewpoint = object jmp SortVis ;Compute and sort visible objects jmp DrawAllVis ;Draw all visible objects jmp GetNextVis ;Draw next objesible object list jmp RotDraw ;Rotate and draw object jmp DrawFace ;Draw single face (polygon) NUMOBJS DFB 00 ;Number of objects NUMCENTS DFB 00 ;Number of object senter CUROBJ DFB 00 ;Current object LASTOBJ DFB 00 ZMAX DA $2000 ;Maximum range ZMIN DFB 100 ;Minimum range OBJECTS DA $0800 ;Object records 1227 = 3456 bytes = $0D80 *=============================== tempa = $55 tempx = $56 tempy = $57 temp = $58 ;two bytes point = $5a ;two bytes X1 = $60 ;Line x-coord Y1 = $62 X2 = $64 Y2 = $66 LINELO = $4F00 ;Lines drawn LINEHI = $4F68 ;speeds up wireframe MAXLINES = $67 OBLETS = $4FD0 ;Oblet list OBHEAD = $2F ;Head of list = $55FF OBJLO = $5600 ;Object pointers OBJHI = $5680 ;if 0 then empty VISOBJS = $5700 OBCEN = $5781 ;Center object # ;Note: will bug if 128 vis objs CX = $5800 ;Rotated/relativecenters HCX = $5880 CY = $5900 HCY = $5980 CZ = $5A00 HCZ = $5A80 PLISTX EQU $5B00 ;Point lists (projected) PLISTY EQU $5C00 PLISTZ EQU $5D00 MPROJ = $5E00 ;Two pages *=============================== * lib3d stuff CALCMAT EQU $8800 ACCROTX EQU $8803 ACCROTY EQU $8806 ACCROTZ EQU $8809 GLOBROT EQU $880C ROTPROJ EQU $880F POLYFILL EQU $8812 PLOT EQU $8815 DRAWLINE EQU $8818 VERSION EQU $881B PQ EQU $0200 ;Point queue MATRIX = $41 ;Local rotation matrix VIEWMAT = $4A ;Viewpoint rotation matrix XOFFSET EQU $53 YOFFSET EQU $54 MULTLO1 EQU $B1 ;Multiplication tables MULTLO2 EQU $B3 MULTHI1 EQU $B5 MULTHI2 EQU $B7 BITMAP EQU $B9 ;Page of bitmap base FILLPAT EQU $BB ;Pointer to fill pattern PLISTXLO EQU $BD ;Pointers to plotted points PLISTXHI EQU $BF PLISTYLO EQU $C1 PLISTYHI EQU $C3 PLISTZLO EQU $8B ;Rotated z-coords PLISTZHI EQU $8D C0XLO EQU $63 ;Pointers to centers to rotate C0XHI EQU $65 C0YLO EQU $67 C0YHI EQU $69 C0ZLO EQU $6B C0ZHI EQU $6D CXLO EQU $A3 ;Pointers to rotated centers CXHI EQU $A5 CYLO EQU $A7 CYHI EQU $A9 CZLO EQU $AB CZHI EQU $AD ROTMATH EQU $AF ;Pointer to rotation math table P0X EQU $69 ;Pointers to points to be rotated P0Y EQU $6B P0Z EQU $6D * * Initialize lib3d pointers, variables * * On entry: .AY = pointer to object records * Init3D STA OBJECTS STY OBJECTS+1 LDA #>MPROJ ;Table at $8000 STA ROTMATH+1 LDX #$C1 STX MULTLO1+1 DEX STX MULTLO2+1 LDX #$C4 STX MULTHI1+1 DEX STX MULTHI2+1 LDA #$FF STA CUROBJ LDA #00 STA NUMOBJS STA LASTOBJ STA PLISTXLO STA PLISTYLO STA PLISTZLO LDA #$80 STA PLISTXHI STA PLISTYHI STA PLISTZHI LDX #>PLISTX STX PLISTXLO+1 STX PLISTXHI+1 INX STX PLISTYLO+1 STX PLISTYHI+1 INX STX PLISTZLO+1 STX PLISTZHI+1 LDX #CX STX CXLO+1 LDX #>HCX STX CXHI+1 LDX #>CY STX CYLO+1 LDX #>HCY STX CYHI+1 LDX #>CZ STX CZLO+1 LDX #>HCZ STX CZHI+1 LDX #159 ;(0,0) = center of screen LDY #99 JSR VERSION BPL :NOM LDX #79 ;Multicolor :NOM STX XOFFSET STY YOFFSET LDY #00 ;Zero out object pointers TYA :L1 STA OBJHI,Y INY BPL :L1 ;128 entries RTS * * AddObj -- Add object to object list * * On entry: .AY = pointer to object point data * .X = optional ID byte * * On exit: .AY = pointer to object * .X = object number * C set indicates an error * AddObj sta tempa sty tempy stx tempx ldx #00 ;Find open slot txa sta temp clc :loop ldy objhi,x beq :found adc #ObjSize ;32 bytes per record bcc :c1 inc temp clc :c1 inx bpl :loop sec rts :found adc objects sta point sta objlo,x lda temp adc objects+1 sta point+1 sta objhi,x inc numobjs cpx lastobj bcc :init stx lastobj :init ldy #ObjSize-1 ;Init object lda #00 :l2 sta (point),y dey bpl :l2 lda #64 ;Identity matrix ldy #ObjMat sta (point),y ldy #ObjMat+4 sta (point),y ldy #ObjMat+8 sta (point),y ldy #ObjID lda tempx ;ID sta (point),y lda tempy ;Obj data pointer dey sta (point),y lda tempa dey sta (point),y SetCurOb stx curobj GetCurOb ldx curobj GetObj lda objlo,x ldy objhi,x rts * * DelObj -- Remove object from list * by setting high byte=0 * * On entry: .X = object number * C set means serious error! * DelObj LDA #00 STA OBJHI,X LDA NUMOBJS BEQ :RTS DEC NUMOBJS CPX LASTOBJ ;Last object in list BCC :RTS :L1 LDA OBJHI,X BNE :STX DEX BPL :L1 SEC ;Out of objects! INX :STX STX LASTOBJ :RTS RTS * * GetNextOb -- Get next object in list * * On exit: .X = object number * .AY= object pointer * C set indicates error * Current object set to .X * GetNextOb LDA NUMOBJS BEQ :ERR LDX CUROBJ BMI :ERR CPX LASTOBJ BCC :C1 LDX #$FF :C1 INX LDY OBJHI,X BEQ :C1 LDA OBJLO,X STX CUROBJ CLC RTS :ERR SEC RTS *------------------------------- * * Object manipulation routines * *------------------------------- * * SetMat -- Calculate matrix for current object * * On entry: .A = Angle around z-axis * .Y = Angle around y-axis * .X = Angle around x-axis * SetMat JSR CALCMAT ;Result -> MATRIX LDX CUROBJ BMI :RTS LDA OBJLO,X CLC ADC #ObjMat ;Matrix STA POINT LDA OBJHI,X ADC #00 STA POINT+1 LDA #00 LDY #17 :L2 STA (POINT),Y ;Zero remainder DEY CPY #8 BNE :L2 :LOOP LDA MATRIX,Y STA (POINT),Y DEY BPL :LOOP :RTS RTS * * Yaw/Pitch/Roll -- Accumulate a rotation on current object * * On entry: C clear -> positive rotation * C set -> negative rotation * GetCurMat PHP JSR GetCurOb CLC ADC #ObjMat BCC :plp INY :plp PLP RTS Pitch JSR GetCurMat JMP ACCROTX Yaw JSR GetCurMat JMP ACCROTY Roll JSR GetCurMat JMP ACCROTZ * * MoveDown/Side/Forwards -- Move object along its * (local) X Y or Z axis. * * Note that orientation matrix is inverse of object matrix * * On entry: .A = velocity (signed) * MOVRTS RTS MoveDown LDY #ObjMat ;Row 1 DFB $2C MoveSide LDY #ObjMat+3 ;Row 2 DFB $2C MoveForwards LDY #ObjMat+6 STY TEMPY ;Object offset CMP #00 BEQ MOVRTS STA MULTLO1 ;Plain signed multply STA MULTHI1 EOR #$FF CLC ADC #01 STA MULTLO2 STA MULTHI2 LDX CUROBJ BMI MOVRTS LDA OBJLO,X STA POINT LDA OBJHI,X STA POINT+1 LDA (POINT),Y TAY LDA #ObjCXRem LDX #ObjCX JSR MovMult LDY TEMPY INY STY TEMPY LDA (POINT),Y TAY LDA #ObjCYRem LDX #ObjCY JSR MovMult LDY TEMPY INY LDA (POINT),Y TAY LDA #ObjCZRem LDX #ObjCZ MovMult STX TEMPX ;Coord STA TEMPA ;Remainder LDA (MULTLO1),Y SEC SBC (MULTLO2),Y STA TEMP LDA (MULTHI1),Y SBC (MULTHI2),Y CPY #$80 ;Fix up signs BCC :POS1 SBC MULTLO1 :POS1 LDX MULTLO1 BPL :DIV STY TEMP+1 SEC SBC TEMP+1 :DIV STA TEMP+1 ;Now div by 16 LDY #00 AND #$FF BPL :POSA DEY ;High byte :POSA TYA ASL TEMP ROL TEMP+1 ROL ASL TEMP ROL TEMP+1 ROL ASL TEMP ROL TEMP+1 ROL ASL TEMP ROL TEMP+1 ROL TAX LDA TEMP LDY TEMPA ;Remainder CLC ADC (POINT),Y STA (POINT),Y LDY TEMPX ;Coord LDA TEMP+1 ADC (POINT),Y STA (POINT),Y INY TXA ADC (POINT),Y STA (POINT),Y RTS * * GetDown/Side/FrontVec * * Get orientation vector * On entry: Current object set * On exit: (.X,.Y,.A) = (X,Y,Z) signed * direction vector, length=64 * GetDownVec LDY #ObjMat ;Row 1 DFB $2C GetSideVec LDY #ObjMat+3 ;Row 2 DFB $2C GetFrontVec LDY #ObjMat+6 LDX CUROBJ BMI :RTS LDA OBJLO,X STA POINT LDA OBJHI,X STA POINT+1 LDA (POINT),Y TAX INY INY LDA (POINT),Y PHA DEY LDA (POINT),Y TAY PLA :RTS RTS *------------------------------- * * Visualization routines * *------------------------------- ViewObj DFB 00 ;Viewpoint object SOLIDPOL DFB 00 ;Solid/wireframe polygons PATTAB DA $1000 ;Pattern table * * SetParms -- Set rendering parameters * * On entry: .AY = Pointer to pattern table * .X = Bitmap page * C set -> solid polygons * C clear -> wireframe * SetParms ROR SOLIDPOL STA PATTAB STY PATTAB+1 STX BITMAP RTS * * SetVisParms -- Set visibility parms * * On entry: .AY = Maximum object range * .X = Minimum object range * SetVisParms STA ZMAX STY ZMAX+1 STX ZMIN RTS * * CalcView -- Calculate view (Set viewpoint, translate and rotate centers) * * On entry: .X = viewpoint object * * On exit: translated rotated centers * in CX/CY/CZ * CalcView STX ViewObj JSR SetCurOb STA POINT STY POINT+1 LDX #8 LDY #ObjMat+8 :loop LDA (POINT),Y ;Viewpoint matrix STA VIEWMAT,X DEY DEX BPL :loop LDX #11 ;Set up pointers :cl LDA CXLO,X STA C0XLO,X DEX BPL :cl LDX #00 STX TEMPX ;Object index :getloop JSR GetNextOb CPX ViewObj BEQ :done STA TEMP STY TEMP+1 TXA LDX TEMPX STA OBCEN,X ;Object number TXA LDY #ObCenPos ;Position in center list STA (TEMP),Y LDY #00 LDA (TEMP),Y ;Translate SEC SBC (POINT),Y STA CX,X INY LDA (TEMP),Y SBC (POINT),Y STA HCX,X INY LDA (TEMP),Y ;Translate SEC SBC (POINT),Y STA CY,X INY LDA (TEMP),Y SBC (POINT),Y STA HCY,X INY LDA (TEMP),Y ;Translate SEC SBC (POINT),Y STA CZ,X INY LDA (TEMP),Y SBC (POINT),Y STA HCZ,X INC TEMPX BPL :getloop :done LDY TEMPX ;# of objects STY NUMCENTS JMP GLOBROT ;off she goes! * * SortVis -- Compute and sort all visible objects * * On entry: centers stored in CX etc. * * On exit: VisObjs = linked list of visible objects * (farthest objects at start of list) * * Visibility conditions: * x+z>0, x-z<0 (within view area) * same for x+y/x-y * z > 8192 will be treated as too far away to see * z < 180 is treated as being too near. * NUMVIS DFB 00 SortVis LDA #00 STA NUMVIS LDA #$80 STA VISOBJS+$80 LDX NUMCENTS DEX BMI :rts :loop LDA HCZ,X ;high byte STA TEMP+1 LDA CZ,X ;low byte STA TEMP CMP ZMAX LDA TEMP+1 SBC ZMAX+1 ;Greater than 8192? BCS :SKIP ;(or negative) LDA TEMP CMP ZMIN LDA TEMP+1 SBC #00 BCC :SKIP LDA TEMP ;x+z>0 CLC ADC CX,X LDA TEMP+1 ADC HCX,X BMI :SKIP LDA TEMP ;z-x>0 CMP CX,X LDA TEMP+1 SBC HCX,X BMI :SKIP LDA TEMP ;y+z>0 CLC ADC CY,X LDA TEMP+1 ADC HCY,X BMI :SKIP LDA TEMP ;z-y>0 CMP CY,X LDA TEMP+1 SBC HCY,X BMI :SKIP LDY #$80 ;Head of list :l1 LDA VISOBJS,Y ;Linked list of objects BMI :link STY TEMPY TAY ;Next object LDA CZ,Y ;If farther, then CMP TEMP ;move down list LDA HCZ,Y SBC TEMP+1 BCS :l1 ;Nearest objects last in list TYA LDY TEMPY ;Insert into list :link STA VISOBJS,X ;X -> rest of list TXA STA VISOBJS,Y ;beginning of list -> X :skip DEX BPL :loop LDY #$80 STY COB ;Current object :rts RTS * * DrawAllVis -- Draw all visible objects * in linked list. * COB DFB 00 ;Current object DrawLoop STY COB *** * FIX ME!!! *** LDA OBCEN,Y ;Actual object number TAX JSR RotDraw DrawAllVis LDX COB ;Head = #$80 LDY VISOBJS,X BPL DrawLoop :done DrawRTS RTS * * GetNextVis -- Get next object in * visible list. * * On exit: N set indicates end of list * GetNextVis LDX COB LDY VISOBJS,X BMI DrawRTS STY COB * yet another FIX ME!!! DFB $BE DA OBCEN ;LDX OBCEN,Y LDA #00 STA NUMLINES JMP SetCurOb * * RotDraw -- Rotate and draw an object * * On entry: Object number in .X * SetParms already called. * DATAP DA 0 ;Temp pointer NPOINTS DFB 00 OBTYPE DFB 00 NFACES DFB 00 ;Faces/Oblets RotDraw LDA OBJLO,X STA POINT LDA OBJHI,X STA POINT+1 LDY #ObjMat ;Matrix -> ZP LDX #00 STX NUMLINES :mli STX TEMP LDA #3 STA TEMP+1 :ml LDA (POINT),Y ;Take transpose to get STA MATRIX,X ;orientation matrix INY INX INX INX DEC TEMP+1 BNE :ml LDX TEMP INX CPX #3 BNE :mli LDY #ObCenPos LDA (POINT),Y STA TEMPA ;Position of center in list LDY #ObjData ;Get data pointer for later LDA (POINT),Y STA DATAP TAX INY LDA (POINT),Y STA DATAP+1 STA POINT+1 STX POINT LDY #00 LDA (POINT),Y STA OBTYPE ;Normal/compound INY LDA (POINT),Y ;Number of points BEQ :rts STA NPOINTS INY LDA (POINT),Y STA NFACES INY ;Point pointers TYA CLC ADC POINT STA P0X LDX POINT+1 BCC :c1 INX CLC :c1 STX P0X+1 ADC NPOINTS STA P0Y BCC :c2 INX CLC :c2 STX P0Y+1 ADC NPOINTS STA P0Z BCC :c3 INX CLC :c3 STX P0Z+1 ADC NPOINTS STA FACEPTR TXA ADC #00 STA FACEPTR+1 LDY NPOINTS LDX TEMPA ;Center index SEC ;Rot and proj JSR ROTPROJ LDA NFACES ;Maybe just want tointsate p BEQ :rts LDA FACEPTR LDY FACEPTR+1 LDX OBTYPE BMI Compound :dloop JSR DrawFace DEC NFACES BNE :dloop :rts RTS * * Compound objects are made up of * a smaller number of "oblets", * drawn in order after sorting their * reference points. * COBLET DFB 00 ;Current oblet OBLPTR DA 00 ;Pointer to oblets Compound STA POINT STY POINT+1 CLC ADC NFACES STA OBLPTR TYA ADC #00 STA OBLPTR+1 LDA #OBHEAD STA OBLETS+OBHEAD ;Head of list DEC NFACES :sort LDY NFACES ;Number of oblets LDA (POINT),Y ;= # ref points TAX LDA PLISTZ,X STA TEMP LDA PLISTZ+$80,X STA TEMP+1 LDX NFACES ;Current oblet LDY #OBHEAD ;Head of list :l1 LDA OBLETS,Y ;Linked list CMP #OBHEAD BCS :link STY TEMPY TAY ;Next object LDA PLISTZ,Y ;If farther, then CMP TEMP ;move down list LDA PLISTZ+$80,Y SBC TEMP+1 BCS :l1 ;Nearest objects last in list TYA LDY TEMPY ;Insert into list :link STA OBLETS,X ;X -> rest of list TXA STA OBLETS,Y ;beginning of list -> X DEC NFACES BPL :sort ;Now draw them LDY #OBHEAD :loop LDA OBLETS,Y * * FIX ME! * TAX STX COBLET CPX #OBHEAD BCS :rts LDA OBLPTR+1 STA POINT+1 LDA OBLPTR ;Locate it STA POINT CPX #00 BEQ :draw LDY #00 CLC :l2 ADC (POINT),Y STA POINT BCC :dex INC POINT+1 CLC :dex DEX BNE :l2 :draw LDY #1 LDA (POINT),Y ;Number of faces STA NFACES LDY POINT+1 LDA POINT CLC ADC #2 BCC :dloop INY :dloop JSR DrawFace DEC NFACES BNE :dloop LDY COBLET BPL :loop :rts RTS * * DrawFace -- Draw a polygon * * On entry: .AY points to face data * On exit: .AY points to next face * * Wireframe: C clear -> face not drawn * NVERTS DFB 00 ;Number of vertices FACEPTR DA 00 ;Pointer to face DrawFace STA POINT STY POINT+1 LDY #00 LDA (POINT),Y STA NVERTS SEC ;N+1 in list ADC #2 ;(closes on itself) ADC POINT STA FACEPTR ;Next face LDA #00 STA TEMP ADC POINT+1 STA FACEPTR+1 LDY #1 ;Fill pattern LDA (POINT),Y ;index ASL ROL TEMP ASL ROL TEMP ASL ROL TEMP ADC PATTAB STA FILLPAT LDA TEMP ADC PATTAB+1 STA FILLPAT+1 LDX SOLIDPOL BPL :Wire LDX #$FF :pq INX INY LDA (POINT),Y ;Copy to queue STA PQ,X CPX NVERTS BNE :pq TXA ;Empty face BEQ :exit JSR POLYFILL :exit LDA FACEPTR LDY FACEPTR+1 RTS ;Wireframe routine :Wire ;JSR IsVis ;BCC :exit LDY #2 ;Connect the dots... :l2 LDA (POINT),Y TAX LDA PLISTX,X STA X1 LDA PLISTX+$80,X STA X1+1 LDA PLISTY,X STA Y1 LDA PLISTY+$80,X STA Y1+1 STX TEMPA INY LDA (POINT),Y TAX LDA PLISTX,X STA X2 LDA PLISTX+$80,X STA X2+1 LDA PLISTY,X STA Y2 LDA PLISTY+$80,X STA Y2+1 STY TEMPY * Check for line connections * Points in TEMPA and .X LDY #00 :loop CPY NUMLINES BEQ :store TXA CMP LINELO,Y BNE :test2 LDA TEMPA CMP LINEHI,Y BEQ :skip :iny INY BPL :loop :store LDA TEMPA STA LINELO,Y TXA STA LINEHI,Y CPY #MAXLINES BEQ :jsr INC NUMLINES :jsr JSR DrawLine :skip LDY TEMPY DEC NVERTS BNE :l2 SEC BCS :exit :test2 CMP LINEHI,Y BNE :iny LDA TEMPA CMP LINELO,Y BNE :iny BEQ :skip NUMLINES DFB 00 * * IsVis -- Compute whether face is * visible, using cross-products * * On entry: .AY = pointer to face * On exit: C set -> visible * C clear -> not visible * IsVis *------------------------------- do 0 STA POINT STY POINT+1 LDY #4 ;N+1 LDA (POINT),Y TAX DEY LDA (POINT),Y ;N TAY LDA PLISTX,X SEC SBC PLISTX,Y STA X1 LDA PLISTX+$80,X SBC PLISTX+$80,Y STA X1+1 ;DX LDA PLISTY,X SEC SBC PLISTY,Y STA Y1 LDA PLISTY+$80,X SBC PLISTY+$80,Y STA Y1+1 BPL :XCHK ;If > BEQ :XCHK fin *-------------------------------