*      
* The 3D section.
*
* These are routines for the 3d library, including
* calculating the rotation matrix, rotating individual
* points, rotating centers, and projection.
*
* Version 2.0: 2/99
*   - Accumulating routines now use pointer to matrix
*   - GLOBROT redone to be more efficient
*   - ROTPROJ performs two matrix multiplications,
*             to calculate R' M P + R' C
*   - Multicolor
*

         REL
         DSK '@0: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

CXLO     = $A3            ;Pointers to list of (rotated)
CXHI     = $A5            ;centers.
CYLO     = $A7
CYHI     = $A9
CZLO     = $AB
CZHI     = $AD

MATMULT  = $AF            ;Pointer to matrix mult. tables

MULTLO1  EQU $B1          ;Same tables used by POLYFILL
MULTLO2  EQU $B3
MULTHI1  EQU $B5
MULTHI2  EQU $B7

* 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 $41          ;Local rotation matrix
B12      EQU $42
C13      EQU $43
D21      EQU $44
E22      EQU $45
F23      EQU $46
G31      EQU $47
H32      EQU $48
I33      EQU $49

VA11     EQU $4A          ;Viewpoint rotation matrix
VB12     EQU $4B
VC13     EQU $4C
VD21     EQU $4D
VE22     EQU $4E
VF23     EQU $4F
VG31     EQU $50
VH32     EQU $51
VI33     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

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.

P0X      EQU $69          ;Points to be rotprojed
P0Y      EQU $6B          ;(pointers)
P0Z      EQU $6D

PLISTZLO EQU $8B          ;Place to store rotated z-coords
PLISTZHI EQU $8D          ;used for depth-sorting, etc.

PLISTXLO EQU $BD          ;Place to store rotprojed
PLISTXHI EQU $BF          ;point (same as used by POLYFILL)
PLISTYLO EQU $C1
PLISTYHI EQU $C3


         DO 0
         TXT 'khaaan!'
         FIN

*
* 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

*
* 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.
*
* On entry: (.A,.Y) = (lo,hi) pointer to matrix
*   (bytes 0-8 = integer, 9-17=remainder)
*

MATP     = T1
REMP     = T3

COMROT                    ;Common to all rotations
         ROR ROTFLAG
         STA MATP
         STY MATP+1
         CLC
         ADC #9
         STA REMP
         TYA
         ADC #00
         STA REMP+1
         RTS

ACCROTZ  ENT              ;rows 1 and 2
         JSR COMROT
         LDY #00
         LDX #3
         BNE ACCROTX2

ACCROTX  ENT
         JSR COMROT
         LDY #3
         LDX #6
ACCROTX2                  ;ACCROTX and ACCROTZ function
                          ;identically
         STX :CPY+1
:LOOP    STY COUNT
         LDA (REMP),Y     ;row 2, remainder
         STA AUXP
         LDA (MATP),Y
         TAX              ;.X = row 2, integer

         INY              ;+3
         INY
         INY
         LDA (REMP),Y     ;row 3, remainder
         STA AUXP+1
         LDA (MATP),Y     ;.Y = row 3
         TAY
         JSR ROTXY
         LDA TEMPX
         LDY COUNT
         STA (REMP),Y
         LDA TEMPX+1
         STA (MATP),Y

         INY
         INY
         INY
         LDA TEMPY
         STA (REMP),Y
         LDA TEMPY+1
         STA (MATP),Y

         DEY
         DEY
:CPY     CPY #6
         BCC :LOOP
         RTS


ACCROTY  ENT              ;rows 3 and 1
         JSR COMROT
         LDY #6
:LOOP    STY COUNT
         LDA (REMP),Y     ;row 3, remainder
         STA AUXP
         LDA (MATP),Y
         TAX              ;.X = row 3, integer

         TYA
         SEC
         SBC #6
         TAY
         LDA (REMP),Y     ;row 1, remainder
         STA AUXP+1
         LDA (MATP),Y     ;.Y = row 1
         TAY
         JSR ROTXY
         LDA TEMPX
         LDY COUNT
         STA (REMP),Y
         LDA TEMPX+1
         STA (MATP),Y

         TYA
         SEC
         SBC #6
         TAY
         LDA TEMPY
         STA (REMP),Y
         LDA TEMPY+1
         STA (MATP),Y

         LDY COUNT
         INY
         CPY #9
         BCC :LOOP
         RTS

*-------------------------------
         DO 0
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
         FIN
*-------------------------------

*
* 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
*
* v2 -- rewritten for efficiency.  Old version computed
*              1/64 row1*(cx,cy,cz) + 1/64 row2*(cx,cy,cz) + ...
*       New version computes
*              [ cx*column1 + cy*column2 + cz*column3 ] / 64
* Actually, above seems complicated, and doesn't offer
* a huge advantage, so has been skipped for now 3/5/99.
*

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 VA11         ;Row1
         LDX VB12
         LDY VC13
         JSR MULTROW      ;Returns result in .X .A = lo hi
         LDY COUNT
         STA (CXHI),Y
         TXA
         STA (CXLO),Y

         LDA VD21         ;Row2
         LDX VE22
         LDY VF23
         JSR MULTROW
         LDY COUNT
         STA (CYHI),Y
         TXA
         STA (CYLO),Y

         LDA VG31         ;Row3
         LDX VH32
         LDY VI33
         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
         DO 0
         TXT 'cracking toast, grommit!'
         FIN

         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.
*
* v2: Now two rotation matrices, local and viewpoint.
*     Points are rotated by local matrix; if projecting,
*     points are now rotated by viewpoint matrix, then
*     projected.
*
*     Rotated z-coordinates are now stored in PLISTZLO/HI
*     ($6F/$71)
*
*     If C=0, then coords just stored in PLISTXLO etc.,
*     as this now seems to be a pretty useless function.
*     (low bytes only!).
*


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

         LDX #00          ;Use local matrix
         LDA (P0Z),Y      ;This way, can re-use routine
         PHA
         LDA (P0Y),Y
         PHA
         LDA (P0X),Y
ROTLOOP2 BNE :C1
         STA TEMPX
         STA TEMPY
         STA TEMPZ
         BEQ :C2
:C1      LDY A11,X        ;Column 1
         >>> SMULT
         STA TEMPX
         LDY D21,X
         >>> QMULT
         STA TEMPY
         LDY G31,X
         >>> QMULT
         STA TEMPZ

                          ;Column 2
:C2      PLA              ;Py
         BEQ :C3
         LDY B12,X
         >>> SMULT
         >>> ADD,TEMPX
         LDY E22,X
         >>> QMULT
         >>> ADD,TEMPY
         LDY H32,X
         >>> QMULT
         >>> ADD,TEMPZ

                          ;Column 3
:C3      PLA              ;Pz
         BEQ ADDC
         LDY C13,X
         >>> SMULT
         >>> ADD,TEMPX
         LDY F23,X
         >>> QMULT
         >>> ADD,TEMPY
         LDY I33,X
         >>> QMULT
ADDC     CLC
         ADC TEMPZ

         LDY ROTFLAG
         BMI :ROT2
         LDY COUNT        ;If just rotating, then just
         STA (PLISTZLO),Y ;store!
         LDA TEMPY
         STA (PLISTYLO),Y
         LDA TEMPX
         STA (PLISTXLO),Y
         JMP ROTLOOP

:ROT2    CPX #9
         BEQ :PROJ
         LDX #9           ;Use viewpoint matrix
         PHA
         LDA TEMPY
         PHA
         LDA TEMPX
         JMP ROTLOOP2

:PROJ    LDY #00          ;.Y = sign
         TAX
         BPL :POS1
         DEY
: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

         LDY COUNT
         LDA TEMPZ
         STA (PLISTZLO),Y
         LDA TEMPZ+1
         STA (PLISTZHI),Y
         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

         DO 0
         TXT 'i hate broccoli.  and yet, in a certain '
         TXT 'sense, i am broccoli. -tick'
         FIN
ain '
