* * The 3D section. * * These are routines for the 3d library, including * calculating the rotation matrix, rotating individual * points, rotating centers, and projection. * REL DSK 'rotmat' LST OFF *------------------------------- DO 0 ORG $6000 JMP CALCMAT LDA #00 STA $69 STA $6B STA $6D LDA #$50 ;Points at $5000 STA $6A LDA #$51 STA $6C LDA #$52 STA $6E JMP ROTPROJ LDA #00 ;Dorky setup routine STA $63 STA $65 STA $67 STA $69 STA $6B STA $6D LDX #$40 STX $64 INX STX $66 INX STX $68 INX STX $6A INX STX $6C INX STX $6E JMP GLOBROT FIN *------------------------------- SIN EQU $CF00 COS EQU $CF20 PROJTAB EQU $CA00 ;Projection table PROJREM EQU $CB00 ;remainder CDEL EQU $C600 ;x*cos(delta) CDELREM EQU $C700 ;remainder SDEL EQU $C800 SDELREM EQU $C900 XOFFSET EQU $53 ;Center of the screen YOFFSET EQU $54 MATMULT = $AF ;Pointer to matrix mult. tables CXLO = $A3 ;Pointers to list of (rotated) CXHI = $A5 ;centers. CYLO = $A7 CYHI = $A9 CZLO = $AB CZHI = $AD MULTLO1 EQU $F7 ;Same tables used by POLYFILL MULTLO2 EQU $F9 MULTHI1 EQU $FB MULTHI2 EQU $FD * Variables used by CALCMAT T1 EQU $57 ;Temporary variables T2 EQU $58 T3 EQU $59 T4 EQU $5A T5 EQU $5B T6 EQU $5C T7 EQU $5D T8 EQU $5E T9 EQU $5F T10 EQU $60 TEMP = $61 THETAX EQU $62 ;Angles THETAY EQU $63 THETAZ EQU $64 A11 EQU $B1 ;Matrix B12 EQU $B2 C13 EQU $B3 D21 EQU $B4 E22 EQU $B5 F23 EQU $B6 G31 EQU $B7 H32 EQU $B8 I33 EQU $B9 A11REM EQU $4A ;Remainders (accumulating B12REM EQU $4B ;matrices) C13REM EQU $4C D21REM EQU $4D E22REM EQU $4E F23REM EQU $4F G31REM EQU $50 H32REM EQU $51 I33REM EQU $52 * GLOBROT variables COUNT EQU $55 SIGN EQU $56 CX EQU $57 ;Temporary variables for centers CXSGN EQU $59 CY EQU $5A CYSGN EQU $5C CZ EQU $5D CZSGN EQU $5F TEMP1 = $60 TEMP2 = $61 TEMP3 = $62 C0XLO EQU $63 ;Centers, original points C0XHI EQU $65 C0YLO EQU $67 C0YHI EQU $69 C0ZLO EQU $6B C0ZHI EQU $6D TM1 EQU $6F ;Temporary storage for TM2 EQU $71 ;multiplication * ROTPROJ variables * COUNT EQU $55 INDEX EQU $56 ;Center index ;CX-CZ = $57-$5F ROTP0X = $59 ;If just rotating, then these ROTP0Y = $5B ;point to destinations. ROTP0Z = $5D ;Otherwise, they get clobbered ;by CX-CZ. P0X EQU $69 ;Points to be rotprojed P0Y EQU $6B ;(pointers) P0Z EQU $6D AUXP EQU $60 ;Auxiliary pointer TEMPX EQU $62 TEMPY EQU $64 TEMPZ EQU $66 ROTFLAG EQU $68 ;Rotate or rotate+project. ;Also used by ACCROTX etc. PLISTXLO EQU $BD ;Place to store rotprojed PLISTXHI EQU $BF ;point (same as used by POLYFILL) PLISTYLO EQU $C1 PLISTYHI EQU $C3 TXT 'khaaan!' * * Calculate the local matrix * * Pass in: A,X,Y = angles around z,x,y axis * * Strategy: M = Ry Rx Rz where Rz=roll, Rx=pitch, Ry=yaw * * Idea: Given * t1 = tx+ty * t2 = tx-ty * t3 = tx+tz * t4 = tx-tz * t5 = tx+ty+tz = t3+ty * t6 = tx-ty-tz = t4-ty * t7 = tx+ty-tz = t1-tz * t8 = tx-tt+tz = t2+tz * t9 = ty+tz * t10 = ty-tz * * then the rotation elements are * A11=.5(cos(t9)+c(t10))-.25(sin(t7)+s(t8)-s(t5)-s(t6)) * B12=.5(s(t9)-s(t10)) - .25(c(t8)-c(t7) + c(t6)-c(t5)) * C13=.5(sin(t2)-sin(t1)) * D21=.5(sin(t4)-sin(t3)) * E22=.5(cos(t3)+cos(t4)) * F23= sin(tx) * G31=.5(s(t9)+s(t10)) - .25(c(t7)-c(t8) + c(t6)-c(t5)) * H32=.5(c(t10)-c(t9)) - .25(s(t5)+s(t6) + s(t7)+s(t8)) * I33=.5(cos(t1)+cos(t2)) * CYC ON ;Let's count cycles CALCMAT ENT STA THETAZ STX THETAX STY THETAY CLC ADC THETAX AND #$7F TAX ;t3 LDA THETAX SEC SBC THETAZ AND #$7F TAY ;t4 LDA COS,X CLC ADC COS,Y STA E22 LDA SIN,Y SEC SBC SIN,X STA D21 ;These are the t3/t4 elements TXA CLC ADC THETAY AND #$7F TAX ;t5 TYA SEC SBC THETAY AND #$7F TAY ;t6 LDA SIN,X CLC ADC SIN,Y CMP #$80 ;Set C if negative, clear otw. ;(pretty sneaky, eh? :) ROR ;.25(sin(t5)+...) STA A11 ;partial result LDA COS,Y SEC SBC COS,X CMP #$80 ROR STA B12 ;partial result LDA THETAX CLC ADC THETAY AND #$7F TAX ;t1 LDA THETAX SEC SBC THETAY AND #$7F TAY ;t2 LDA SIN,Y SEC SBC SIN,X STA C13 LDA COS,X CLC ADC COS,Y STA I33 TXA SEC SBC THETAZ AND #$7F TAX ;t7 TYA CLC ADC THETAZ AND #$7F TAY ;t8 LDA SIN,X CLC ADC SIN,Y CMP #$80 ROR STA TEMP CLC ADC A11 STA H32 ;st5+st6+st7+st8 LDA TEMP SEC SBC A11 ;st7+st8-st5-st6 STA A11 LDA COS,X SEC SBC COS,Y CMP #$80 ROR STA TEMP CLC ADC B12 STA G31 ;ct7-ct8 + ct6-ct5 LDA B12 SEC SBC TEMP STA B12 ;ct6-ct5 + ct8-ct7 LDA THETAY CLC ADC THETAZ AND #$7F TAX ;t9 LDA THETAY SEC SBC THETAZ AND #$7F TAY ;t10 LDA COS,X CLC ADC COS,Y SEC SBC A11 STA A11 LDA COS,Y SEC SBC COS,X SEC SBC H32 STA H32 LDA SIN,X SEC SBC SIN,Y CLC ADC B12 STA B12 LDA SIN,X CLC ADC SIN,Y CLC ADC G31 STA G31 LDA THETAX ;Finally, little F23 AND #$7F TAX LDA SIN,X ASL STA F23 RTS ;Easy-peasy! CYC OFF DO 0 TXT '"when any mortal(even the most odd)/' TXT 'can justify the ways of man to God/' TXT 'ill think it strange that normal mortals can/' TXT 'not justify the ways of God to man"' TXT ' -- e.e.cummings' FIN DO 0 TXT 'klingon sons; you killed my bastard!' FIN * * Invert the rotation matrix, by simply transposing. * * Basically, this is a useless procedure, and has hence * been removed. * DO 0 INVERT ENT LDA B12 LDX D21 STA D21 STX B12 LDA C13 LDX G31 STA G31 STX C13 LDA F23 LDX H32 STA H32 STX F23 RTS FIN * * The next three procedures rotate the accumulation * matrix (multiply by Rx, Ry, or Rz). * * Carry clear means rotate by positive amount, clear * means rotate by negative amount. * ACCROTX ENT ROR ROTFLAG LDX #2 :LOOP STX COUNT LDA D21REM,X ;rows 2 and 3 STA AUXP LDA G31REM,X STA AUXP+1 LDY G31,X ;.Y = row 3 LDA D21,X ;.X = row 2 TAX JSR ROTXY LDX COUNT LDA TEMPX STA D21REM,X LDA TEMPX+1 STA D21,X LDA TEMPY STA G31REM,X LDA TEMPY+1 STA G31,X DEX BPL :LOOP RTS ACCROTY ENT ROR ROTFLAG LDX #2 :LOOP STX COUNT LDA G31REM,X ;rows 3 and 1 STA AUXP LDA A11REM,X STA AUXP+1 LDY A11,X ;.Y = row 1 LDA G31,X ;.X = row 3 TAX JSR ROTXY LDX COUNT LDA TEMPX STA G31REM,X LDA TEMPX+1 STA G31,X LDA TEMPY STA A11REM,X LDA TEMPY+1 STA A11,X DEX BPL :LOOP RTS ACCROTZ ENT ROR ROTFLAG LDX #2 :LOOP STX COUNT LDA A11REM,X ;rows 1 and 2 STA AUXP LDA D21REM,X STA AUXP+1 LDY D21,X ;.Y = row 2 LDA A11,X ;.X = row 1 TAX JSR ROTXY LDX COUNT LDA TEMPX STA A11REM,X LDA TEMPX+1 STA A11,X LDA TEMPY STA D21REM,X LDA TEMPY+1 STA D21,X DEX BPL :LOOP RTS * * Rotate .X,AUXP .Y,AUXP+1 -> TEMPX,+1 TEMPY,+1 * * If flag is set for negative rotations, swap X and Y * and swap destinations (TEMPX TEMPY) * ROTXY LDA ROTFLAG BPL :CONT STX TEMPX ;Swap X and Y STY TEMPY LDX AUXP LDY AUXP+1 STX AUXP+1 STY AUXP LDX TEMPY LDY TEMPX :CONT LDA CDELREM,X CLC ADC SDELREM,Y STA TEMPX LDA CDEL,X ;x*cos(delta) ADC SDEL,Y ;+y*sin(delta) STA TEMPX+1 LDA TEMPX CLC ADC AUXP STA TEMPX BCC :NEXT INC TEMPX+1 :NEXT LDA CDELREM,Y SEC SBC SDELREM,X STA TEMPY LDA CDEL,Y ;y*cos - x*sin SBC SDEL,X STA TEMPY+1 LDA TEMPY CLC ADC AUXP+1 STA TEMPY BCC :DONE INC TEMPY+1 :DONE LDX ROTFLAG BPL :RTS LDX TEMPX STA TEMPX STX TEMPY LDA TEMPX+1 LDX TEMPY+1 STA TEMPY+1 STX TEMPX+1 :RTS RTS * * Perform a global rotation, i.e. rotate the centers * (16-bit signed value) by the rotation matrix. * * The multiplication multiplies to get a 24-bit result * and then divides the result by 64 (mult by 4). To * perform the signed multiplication: * - multiply C*y as normal * - if y<0 then subtract 256*C * - if C<0 then subtract 2^16*y * * Parameters: .Y = number of points to rotate * MULTAY MAC ;Multiply A*Y, store in var1, A STA MULTLO1 ;A <> 0 STA MULTHI1 EOR #$FF CLC ADC #01 STA MULTLO2 STA MULTHI2 LDA (MULTLO1),Y SEC SBC (MULTLO2),Y STA ]1 LDA (MULTHI1),Y SBC (MULTHI2),Y DONE <<< QMULTAY MAC ;Assumes pointers already set up LDA (MULTLO1),Y SEC SBC (MULTLO2),Y STA ]1 LDA (MULTHI1),Y SBC (MULTHI2),Y <<< * Fix sign and divide by 64 DIVFIX MAC ;If Mij<0 subtract 256*C LDY MULTLO1 ;If C<0 subtract 2^16*Mij BPL POSM STA TEMP3 LDA TEMP2 SEC SBC ]1 ;Center STA TEMP2 LDA TEMP3 SBC ]1+1 ;high byte POSM LDY ]1+1 BPL DIV SEC SBC MULTLO1 ;Subtract Mij DIV ASL TEMP1 ;Divide by 64 ROL TEMP2 ROL ASL TEMP1 ROL TEMP2 ROL LDY TEMP2 <<< ;.A, .Y = final result * Main routine GLOBROT ENT GLOOP DEY STY COUNT LDA (C0XLO),Y STA CX LDA (C0XHI),Y STA CX+1 LDA (C0YLO),Y STA CY LDA (C0YHI),Y STA CY+1 LDA (C0ZLO),Y STA CZ LDA (C0ZHI),Y STA CZ+1 LDA A11 ;Row1 LDX B12 LDY C13 JSR MULTROW ;Returns result in .X .A = lo hi LDY COUNT STA (CXHI),Y TXA STA (CXLO),Y LDA D21 ;Row2 LDX E22 LDY F23 JSR MULTROW LDY COUNT STA (CYHI),Y TXA STA (CYLO),Y LDA G31 ;Row3 LDX H32 LDY I33 JSR MULTROW LDY COUNT STA (CZHI),Y TXA STA (CZLO),Y TYA BEQ :DONE JMP GLOOP :DONE RTS DO 0 TXT 'one of these days, ' TXT 'baby! milkshake! boom!' FIN TXT 'cracking toast, grommit!' LST ON CYC * * Multiply a row by CX CY CZ * (A Procedure to save at least a LITTLE memory...) * M1 EQU CXSGN ;CXSGN etc. no longer used. M2 EQU CYSGN M3 EQU CZSGN MULTROW STA M1 STX M2 STY M3 TAY BEQ :SKIP1 LDY CX+1 >>> MULTAY,TEMP2 STA TEMP3 LDY CX >>> QMULTAY,TEMP1 CLC ADC TEMP2 STA TEMP2 LDA TEMP3 ADC #00 >>> DIVFIX,CX ;Adjust result and /64 :SKIP1 STY TM1 STA TM1+1 LDA M2 BEQ :SKIP2 LDY CY+1 ;and multiply by CY >>> MULTAY,TEMP2 STA TEMP3 LDY CY >>> QMULTAY,TEMP1 CLC ADC TEMP2 STA TEMP2 LDA TEMP3 ADC #00 >>> DIVFIX,CY TAX TYA ;low byte CLC ADC TM1 STA TM1 TXA ;high byte ADC TM1+1 STA TM1+1 :SKIP2 LDA M3 BEQ :ZERO LDY CZ+1 >>> MULTAY,TEMP2 STA TEMP3 LDY CZ >>> QMULTAY,TEMP1 CLC ADC TEMP2 STA TEMP2 LDA TEMP3 ADC #00 >>> DIVFIX,CZ STA TEMP3 TYA CLC ADC TM1 TAX LDA TEMP3 ADC TM1+1 RTS :ZERO LDX TM1 LDA TM1+1 UPRTS RTS ;.X .A = lo hi bytes of row mult CYC OFF LST OFF * * ROTPROJ -- Perform local rotation and project points. * * Setup needs: * Rotation matrix * Pointer to math table (MATMULT = $AF-$B0) * Pointers to point list (P0X-P0Z = $69-$6E) * Pointers to final destinations (PLISTYLO ... = $BD...) * (Same as used by POLYFILL) * Pointers to lists of centers (CXLO CXHI... = $A3-$AE) * .Y = Number of points to rotate (0..N-1) * .X = Object center index (index to center of object) * * New addition: * C set means rotate and project, but C clear means just * rotate. If C=0 then need pointers to rotation * destinations ROTPX,ROTPY,ROTPZ=$59-$5E. * SMULT MAC ;Signed multiplication STA MATMULT EOR #$FF CLC ADC #01 STA AUXP LDA (MATMULT),Y SEC SBC (AUXP),Y <<< QMULT MAC ;Multiplication that assumes LDA (MATMULT),Y ;pointers are already initialized SEC SBC (AUXP),Y <<< ADD MAC ;Simple addition CLC ADC ]1 STA ]1 <<< LOCROT ENT ROTPROJ LDA MATMULT+1 STA AUXP+1 STX INDEX STY COUNT ROR ROTFLAG BPL ROTLOOP ;If C=0 then just rotate. LDY INDEX LDA (CXLO),Y ;Centers STA CX LDA (CXHI),Y STA CX+1 LDA (CYLO),Y STA CY LDA (CYHI),Y STA CY+1 LDA (CZLO),Y STA CZ LDA (CZHI),Y STA CZ+1 ROTLOOP LDY COUNT BEQ UPRTS DEY STY COUNT LDA (P0X),Y BNE :C1 STA TEMPX STA TEMPY STA TEMPZ BEQ :C2 :C1 LDY A11 ;Column 1 >>> SMULT STA TEMPX LDY D21 >>> QMULT STA TEMPY LDY G31 >>> QMULT STA TEMPZ LDY COUNT ;Column 2 :C2 LDA (P0Y),Y BEQ :C3 LDY B12 >>> SMULT >>> ADD,TEMPX LDY E22 >>> QMULT >>> ADD,TEMPY LDY H32 >>> QMULT >>> ADD,TEMPZ LDY COUNT ;Column 3 :C3 LDA (P0Z),Y BEQ ADDC LDY C13 >>> SMULT >>> ADD,TEMPX LDY F23 >>> QMULT >>> ADD,TEMPY LDY I33 >>> QMULT ADDC LDY #00 CLC ADC TEMPZ BPL :ROTCHK DEY ;Sign :ROTCHK LDX ROTFLAG BMI :POS1 LDY COUNT ;If just rotating, then just STA (ROTP0Z),Y ;store! LDA TEMPY STA (ROTP0Y),Y LDA TEMPX STA (ROTP0X),Y JMP ROTLOOP :POS1 CLC ;Add in centers ADC CZ STA TEMPZ TYA ADC CZ+1 STA TEMPZ+1 ;Assume this is positive! LDX #00 LDY #00 LDA TEMPY BPL :POS2 DEY :POS2 CLC ADC CY STA TEMPY TYA ADC CY+1 STA TEMPY+1 BPL :C1 DEX :C1 STX CYSGN ;Need sign for later LDX #00 LDY #00 LDA TEMPX BPL :POS3 DEY :POS3 CLC ADC CX STA TEMPX TYA ADC CX+1 STA TEMPX+1 BPL :C2 DEX :C2 STX CXSGN LDA TEMPZ+1 BEQ PROJ :BLAH LSR ;Shift everything until ROR TEMPZ ;Z=8-bits LSR CXSGN ROR TEMPX+1 ;Projection thus loses accuracy ROR TEMPX ;for far-away objects. LSR CYSGN ROR TEMPY+1 ;(Big whoop) ROR TEMPY TAX BNE :BLAH PROJ LDX TEMPZ LDA PROJTAB,X ;Projection constant BNE :C1 ;Lots of 0's and 1's, so special LDY XOFFSET ;case them. STY TM1 LDY YOFFSET STY TM2 LDY TEMPY+1 STA TM1+1 STA TM2+1 JMP :NOINT :EASY1 LDY TEMPX STY TM1 LDY TEMPX+1 STY TM1+1 LDY TEMPY STY TM2 LDY TEMPY+1 STY TM2+1 JMP :ADDOFF :C1 CMP #1 BEQ :EASY1 LDY TEMPX >>> MULTAY,TM1 ;al*N LDY TEMPX+1 CLC ADC (MULTLO1),Y ;+256*ah*N (middle byte) SEC SBC (MULTLO2),Y STA TM1+1 LDY TEMPY >>> QMULTAY,TM2 LDY TEMPY+1 CLC ADC (MULTLO1),Y SEC SBC (MULTLO2),Y STA TM2+1 :ADDOFF LDA XOFFSET ;Screen offsets CLC ADC TM1 STA TM1 BCC :NOC1 INC TM1+1 CLC :NOC1 LDA YOFFSET ADC TM2 STA TM2 BCC :NOINT INC TM2+1 :NOINT LDA PROJREM,X BEQ :NOREM STA MULTLO1 STA MULTHI1 EOR #$FF CLC ADC #01 STA MULTLO2 STA MULTHI2 LDA (MULTLO1),Y ;ah*r SEC SBC (MULTLO2),Y TAX LDA (MULTHI1),Y SBC (MULTHI2),Y CPY #$80 BCC :POSREM SBC MULTLO1 ;Subtract 256*r if neg ;(clears carry) :POSREM TAY TXA ADC TM2 STA TM2 TYA ADC TM2+1 STA TM2+1 LDY TEMPY LDA (MULTLO1),Y SEC SBC (MULTLO2),Y LDA (MULTHI1),Y ;al*r, hi byte SBC (MULTHI2),Y CLC ADC TM2 ;Add remainder LDY COUNT STA (PLISTYLO),Y LDA TM2+1 ;and sign+carry ADC #00 STA (PLISTYHI),Y * Do the same for x LDY TEMPX+1 LDA (MULTLO1),Y ;ah*r SEC SBC (MULTLO2),Y TAX LDA (MULTHI1),Y SBC (MULTHI2),Y CPY #$80 BCC :POSXREM SBC MULTLO1 ;Subtract 65536*r if neg ;(clears carry) :POSXREM TAY TXA ADC TM1 STA TM1 TYA ADC TM1+1 STA TM1+1 LDY TEMPX LDA (MULTLO1),Y SEC SBC (MULTLO2),Y LDA (MULTHI1),Y ;al*r, hi byte SBC (MULTHI2),Y CLC ADC TM1 ;Add remainder LDY COUNT ;and store STA (PLISTXLO),Y LDA TM1+1 ADC #00 STA (PLISTXHI),Y JMP ROTLOOP ;And on to the next point! :NOREM LDY COUNT LDA TM1 STA (PLISTXLO),Y LDA TM1+1 STA (PLISTXHI),Y LDA TM2 STA (PLISTYLO),Y LDA TM2+1 STA (PLISTYHI),Y JMP ROTLOOP TXT 'i hate broccoli. and yet, in a certain ' TXT 'sense, i am broccoli. -tick'