       
*
* UPD8ROT -- A second rotation matrix is maintained
*   to rotate some objects locally.  Several permutations
*   of this matrix are also computed, to give a variety
*   of rotation matrices to choose from.
*
UPD8ROT  
         JSR ISTORE       ;Save accumulation matrix
         INC THX1
         LDX THX1
         LDA THY1
         CLC
         ADC #5
         STA THY1
         TAY
         LDA THZ1
         SEC
         SBC #2
         STA THZ1
         JSR CALCMAT
         JSR RSTORE       ;Save rotation matrix
         JMP IFETCH       ;Restore acc. matrix


*
* Inverse matrix grunt routines -- all they do is
* copy INVMAT->zp and zp->INVMAT
*
* The fractional parts are left in place, as they are
* not modified in this particular program.
*
INVMAT   DS 9             ;Storage for inverse matrix
INVREM   DS 9

ISTORE   LDX #8
:LOOP    LDA MATRIX,X
         STA INVMAT,X
* LDA MATREM,X
* STA INVREM,X
         DEX
         BPL :LOOP
         RTS

IFETCH   LDA INVMAT
         STA MATRIX
         LDA INVMAT+1
         STA MATRIX+1
         LDA INVMAT+2
         STA $B3
         LDA INVMAT+3
         STA $B4
         LDA INVMAT+4
         STA $B5
         LDA INVMAT+5
         STA $B6
         LDA INVMAT+6
         STA $B7
         LDA INVMAT+7
         STA $B8
         LDA INVMAT+8
         STA $B9
         RTS

ROTMAT   DS 9             ;Storage for rotation matrix

RSTORE   LDX #8
:LOOP    LDA MATRIX,X
         STA ROTMAT,X
         DEX
         BPL :LOOP
         RTS

* Permutation matrices are simply done during the fetch.
* In this way inverts, row exchanges, etc. are a breeze
* and take no extra time or storage!

RFETCH   LDA ROTMAT
         STA MATRIX
         LDA ROTMAT+1
         STA MATRIX+1
         LDA ROTMAT+2
         STA $B3
         LDA ROTMAT+3
         STA $B4
         LDA ROTMAT+4
         STA $B5
         LDA ROTMAT+5
         STA $B6
         LDA ROTMAT+6
         STA $B7
         LDA ROTMAT+7
         STA $B8
         LDA ROTMAT+8
         STA $B9
         RTS

R2FETCH  LDA ROTMAT       ;First permutation: the inverse
         STA MATRIX       ;i.e. the transpose
         LDA ROTMAT+1
         STA MATRIX+3
         LDA ROTMAT+2
         STA MATRIX+6
         LDA ROTMAT+3
         STA MATRIX+1
         LDA ROTMAT+4
         STA MATRIX+4
         LDA ROTMAT+5
         STA MATRIX+7
         LDA ROTMAT+6
         STA MATRIX+2
         LDA ROTMAT+7
         STA MATRIX+5
         LDA ROTMAT+8
         STA MATRIX+8
         RTS

R3FETCH  LDA ROTMAT       ;Second permutation: row exchange
         STA MATRIX+3     ;i.e. let x->y y->z z->x
         LDA ROTMAT+1
         STA MATRIX+4
         LDA ROTMAT+2
         STA MATRIX+5
         LDA ROTMAT+3
         STA MATRIX+6
         LDA ROTMAT+4
         STA MATRIX+7
         LDA ROTMAT+5
         STA MATRIX+8
         LDA ROTMAT+6
         STA MATRIX
         LDA ROTMAT+7
         STA MATRIX+1
         LDA ROTMAT+8
         STA MATRIX+2
         RTS


*
* Update object centers.  Add/sub deltas to all centers
* in object list.  Rotation is left to main routine.
*
UPCENT   
         LDX NUMOBJS
         DEX
         BMI :EXIT        ;No objects
:C0      LDA MOVCZ        ;<0 means decrease object
         BMI CENTDEC

:LOOP    LDY #00          ;Y will be bits 8-15
         LDA DELTACX
         BPL :C1
         DEY
:C1      CLC
         ADC C0X,X
         STA C0X,X
         TYA
         ADC C0X+256,X    ;High bytes
         STA C0X+256,X

         LDY #00
         LDA DELTACY
         BPL :C2
         DEY
:C2      CLC
         ADC C0Y,X
         STA C0Y,X
         TYA
         ADC C0Y+256,X
         STA C0Y+256,X

         LDY #00
         LDA DELTACZ
         BPL :C3
         DEY
:C3      CLC
         ADC C0Z,X
         STA C0Z,X
         TYA
         ADC C0Z+256,X
         STA C0Z+256,X

         DEX
         BPL :LOOP
:EXIT    RTS

CENTDEC                   ;Same thing, but subtract
:LOOP    LDY #00          ;Y will be bits 8-15
         LDA DELTACX
         BPL :C1
         DEY
:C1      STY TEMP1
         LDA C0X,X
         SEC
         SBC DELTACX
         STA C0X,X
         LDA C0X+256,X    ;High bytes
         SBC TEMP1
         STA C0X+256,X

         LDY #00
         LDA DELTACY
         BPL :C2
         DEY
:C2      STY TEMP1
         LDA C0Y,X
         SEC
         SBC DELTACY
         STA C0Y,X
         LDA C0Y+256,X
         SBC TEMP1
         STA C0Y+256,X

         LDY #00
         LDA DELTACZ
         BPL :C3
         DEY
:C3      STY TEMP1
         LDA C0Z,X
         SEC
         SBC DELTACZ
         STA C0Z,X
         LDA C0Z+256,X
         SBC TEMP1
         STA C0Z+256,X

         DEX
         BPL :LOOP
         RTS

*
* Update position and orientation vector.  Originally
* pointer is in z-direction, i.e. PO=(0,0,1).  Thus,
* rotation*PO is just third column of rotation matrix.
* Since the inverse matrix is what is calculated,
* the third row is used.
*
* Values must be accumulated in order to preserve
* accuracy, i.e. this is really drawing a line, and
* if the slope is <1 we need to hang on to the fractional
* parts.
*
* So: if need to rotate points, then compute new direction
* vector, inverse orientation matrix, and rotate centers.
* If need to move my center, then accumulate, compute new
* deltas, and update centers.
*

ACCX     DFB 00
ACCY     DFB 00
ACCZ     DFB 00
XDIR     DFB 00           ;Orientation vector
YDIR     DFB 00
ZDIR     DFB 64

UPD8POS  
         LDA #00
         STA DELTACX
         STA DELTACY
         STA DELTACZ

         LDA THETSTEP     ;Are we even moving?
         BEQ :RTS1
         LDA NEWANG       ;Do we need to rotate?
         BEQ :NOROT
         LDA MATRIX+6     ;Third row is rotated orientation
         STA XDIR         ;vector
         LDA MATRIX+7
         STA YDIR
         LDA MATRIX+8
         STA ZDIR
         JMP ROTCENT      ;and recompute (rotate) centers.

:NOROT   LDA MOVCZ        ;Do we need to change position?
         BNE :C0
:RTS1    RTS
:C0      
         LDX CDIV         ;Number of times to acc/2
         BNE :BLAH
         LDA XDIR         ;Use straight values
         STA DELTACX      ;for fly.
         LDA YDIR
         STA DELTACY
         LDA ZDIR
         STA DELTACZ
         LDA #00
         STA ACCX         ;with no accumulation
         STA ACCY
         STA ACCZ
         JMP ADDDELTA     ;And add to centers

:BLAH    LDA XDIR         ;Accumulate direction vector
         CLC
         ADC ACCX
         STA TEMP1
         LDA YDIR
         CLC
         ADC ACCY
         STA TEMP2
         LDA ZDIR
         CLC
         ADC ACCZ
         STA TEMP3

         LDY #00          ;Sign
         LDA TEMP1
         BPL :C1
         INY
         EOR #$FF         ;Do everything positive
         CLC              ;otherwise -1's and such crop up
         ADC #01
:C1      LSR
         DEX
         BNE :C1
         STA DELTACX      ;"Integer" part

         LDA CMASK
         AND TEMP1        ;remainder
         STA ACCX
         DEY
         BNE :POS1
         EOR #$FF
         CLC
         ADC #01
         STA ACCX
         LDA DELTACX
         EOR #$FF
         CLC
         ADC #01
         STA DELTACX
:POS1    
         LDX CDIV
         LDY #00          ;Sign
         LDA TEMP2
         BPL :C2
         INY
         EOR #$FF         ;Do everything positive
         CLC              ;otherwise -1's and such crop up
         ADC #01
:C2      LSR
         DEX
         BNE :C2
         STA DELTACY      ;"Integer" part

         LDA CMASK
         AND TEMP1        ;remainder
         STA ACCY
         DEY
         BNE :POS2
         EOR #$FF
         CLC
         ADC #01
         STA ACCY
         LDA DELTACY
         EOR #$FF
         CLC
         ADC #01
         STA DELTACY
:POS2    
         LDX CDIV
         LDY #00          ;Sign
         LDA TEMP3
         BPL :C3
         INY
         EOR #$FF         ;Do everything positive
         CLC              ;otherwise -1's and such crop up
         ADC #01
:C3      LSR
         DEX
         BNE :C3
         STA DELTACZ      ;"Integer" part

         LDA CMASK
         AND TEMP1        ;remainder
         STA ACCZ
         DEY
         BNE :SKIP
         EOR #$FF
         CLC
         ADC #01
         STA ACCZ
         LDA DELTACZ
         EOR #$FF
         CLC
         ADC #01
         STA DELTACZ
:SKIP    
ADDDELTA JSR UPCENT       ;Add in deltas...
ROTCENT  
         LDA #00
         STA C0XLO
         STA C0XHI
         STA C0YLO
         STA C0YHI
         STA C0ZLO
         STA C0ZHI
         LDX #>C0X
         STX C0XLO+1
         INX
         STX C0XHI+1
         LDX #>C0Y
         STX C0YLO+1
         INX
         STX C0YHI+1
         LDX #>C0Z
         STX C0ZLO+1
         INX
         STX C0ZHI+1
         LDY NUMOBJS
         JMP GLOBROT      ;...and rotate centers


*
* Read keyboard, process data etc.
*
READKEY  
         JSR GETIN
         BNE :C0
         RTS
:C0      CMP #'0'         ;Speed
         BNE :C1
         LDA #00
         STA THETSTEP
         RTS
:C1      CMP #'1'
         BNE :C2
         LDA #CRAWL
         STA THETSTEP
         LDA #4           ;Div 16 (-4..4)
         STA CDIV
         LDA #$0F         ;Low 4 bits will be fractional
         STA CMASK
         RTS
:C2      CMP #'2'
         BNE :C3
         LDA #WALK
         STA THETSTEP
         LDA #3           ;-8..8
         STA CDIV
         LDA #$05         ;low 3 bits
         STA CMASK
         RTS
:C3      CMP #'3'
         BNE :C4
         LDA #RUN
         STA THETSTEP
         LDA #1           ;-32..32
         STA CDIV
         LDA #01          ;Just one bit
         STA CMASK
         RTS
:C4      CMP #'4'
         BNE :C6
         LDA #FLY
         STA THETSTEP
         LDA #00
         STA CDIV
         STA CMASK
:RTS2    RTS

:C6      CMP #'a'
         BNE :C7
         DEC MOVCZ        ;Will move center backwards
         JMP STARADDZ     ;Advance stars
:C7      CMP #'z'
         BNE :C8
         INC MOVCZ
         JMP STARSUBZ

:C8      CMP #';'
         BNE :C9
         LDA THETSTEP
         BEQ :RTS2
         INC NEWANG
         STA TEMPSTEP
         JSR STARSUBX     ;"Rotate" stars
:L8      CLC
         JSR ACCROTY      ;Rotate in y-direction.
         DEC TEMPSTEP
         BNE :L8
         RTS
:C9      CMP #':'
         BNE :C10
         LDA THETSTEP
         BEQ :RTS2
         INC NEWANG
         STA TEMPSTEP
         JSR STARADDX
:L9      SEC
         JSR ACCROTY
         DEC TEMPSTEP
         BNE :L9
         RTS

:C10     CMP #'@'
         BNE :C11
         LDA THETSTEP
         BEQ :RTS2
         INC NEWANG
         STA TEMPSTEP
         JSR STARSUBY
:L10     SEC
         JSR ACCROTX
         DEC TEMPSTEP
         BNE :L10
         RTS

:C11     CMP #'/'
         BNE :C12
         LDA THETSTEP
         BEQ :RTS
         INC NEWANG
         STA TEMPSTEP
         JSR STARADDY
:L11     CLC
         JSR ACCROTX
         DEC TEMPSTEP
         BNE :L11
         RTS

:C12     CMP #'q'
         BNE :C13
         LDA THETSTEP
         BEQ :RTS
         INC NEWANG
         STA TEMPSTEP
:L12     JSR STARROTM
         SEC
         JSR ACCROTZ
         DEC TEMPSTEP
         BNE :L12
         RTS
:C13     CMP #'w'
         BNE :C14
         LDA THETSTEP
         BEQ :RTS
         INC NEWANG
         STA TEMPSTEP
:L13     JSR STARROTP
         CLC
         JSR ACCROTZ
         DEC TEMPSTEP
         BNE :L13
         RTS
:C14     
:RTS     RTS

*
* Buffer clear routines
* Note to self: make intelligent.
*

CLBUF1   
         LDA #00          ;Clear bitmap
         LDY #00
:LOOP    STA $6000,Y
         STA $6100,Y
         STA $6200,Y
         STA $6300,Y
         STA $6400,Y
         STA $6500,Y
         STA $6600,Y
         STA $6700,Y
         STA $6800,Y
         STA $6900,Y
         STA $6A00,Y
         STA $6B00,Y
         STA $6C00,Y
         STA $6D00,Y
         STA $6E00,Y
         STA $6F00,Y
         STA $7000,Y
         STA $7100,Y
         STA $7200,Y
         STA $7300,Y
         STA $7400,Y
         STA $7500,Y
         STA $7600,Y
         STA $7700,Y
         STA $7800,Y
         STA $7900,Y
         STA $7A00,Y
         STA $7B00,Y
         STA $7C00,Y
         STA $7D00,Y
         STA $7E00,Y
         STA $7F00,Y
         DEY
         BNE :LOOP
         RTS

CLBUF2   
         LDA #00          ;Clear bitmap
         LDY #00
:LOOP    STA $A000,Y
         STA $A100,Y
         STA $A200,Y
         STA $A300,Y
         STA $A400,Y
         STA $A500,Y
         STA $A600,Y
         STA $A700,Y
         STA $A800,Y
         STA $A900,Y
         STA $AA00,Y
         STA $AB00,Y
         STA $AC00,Y
         STA $AD00,Y
         STA $AE00,Y
         STA $AF00,Y
         STA $B000,Y
         STA $B100,Y
         STA $B200,Y
         STA $B300,Y
         STA $B400,Y
         STA $B500,Y
         STA $B600,Y
         STA $B700,Y
         STA $B800,Y
         STA $B900,Y
         STA $BA00,Y
         STA $BB00,Y
         STA $BC00,Y
         STA $BD00,Y
         STA $BE00,Y
         STA $BF00,Y
         DEY
         BNE :LOOP
         RTS

*
* INITRAND -- Grab a seed value for random number
*   generator
*
INITRAND 
         LDA $D012
         STA RANDOM
         LDA $DC04
         STA RANDOM+1
         RTS


*-------------------------------
*
* GETRAND
*
* Generate a somewhat random repeating sequence.  I use
* a typical linear congruential algorithm
*      I(n+1) = (I(n)*a + c) mod m
* with m=65536, a=17, and c=13841 ($3611).  c was chosen
* to be a prime number near (1/2 - 1/6 sqrt(3))*m.
*
* Note that in general the higher bits are "more random"
* than the lower bits, so for instance in this program
* since only small integers (0..15, 0..39, etc.) are desired,
* they should be taken from the high byte RANDOM+1, which
* is returned in A.
*
GETRAND  
         LDA RANDOM+1
         STA TEMP1
         LDA RANDOM
         ASL
         ROL TEMP1
         ASL
         ROL TEMP1
         ASL
         ROL TEMP1
         ASL
         ROL TEMP1
         CLC
         ADC RANDOM
         STA RANDOM
         LDA TEMP1
         ADC RANDOM+1
         STA RANDOM+1
         LDA RANDOM
         CLC
         ADC #$11
         STA RANDOM
         LDA RANDOM+1
         ADC #$36
         STA RANDOM+1
         RTS

* Misc. tables

XBIT     DFB $80,$40,$20,$10,$08,$04,$02,$01
POWER    DFB 1,2,4,8,16,32,64,128

         DS ^

*
* Bitmap row offsets
*

BROWLO   
         LUP 6
         DFB 0,1,2,3,4,5,6,7
         HEX 4041424344454647
         HEX 8081828384858687
         HEX C0C1C2C3C4C5C6C7
         --^
         DFB 0,1,2,3,4,5,6,7
         DS ^,0

BROWHI   
]B       = 0
         LUP 6
         DFB ]B,]B,]B,]B,]B,]B,]B,]B
]B       = ]B+1
         DFB ]B,]B,]B,]B,]B,]B,]B,]B
]B       = ]B+1
         DFB ]B,]B,]B,]B,]B,]B,]B,]B
]B       = ]B+1
         DFB ]B,]B,]B,]B,]B,]B,]B,]B
]B       = ]B+2
         --^
         DFB ]B,]B,]B,]B,]B,]B,]B,]B
         DS ^,0
