*      
* tetrattack!
*
* Mini-3D rendering package
*
* - Motion in the x-z plane => rotations about one axis only
* - Plots to charmap
*
* SLJ 9/01
*

                          ;         org $1000
         org $0ef0

NUMOBJS  = 9

temp     = $02
dx       = $03
dy       = $04
point    = $05

AUX      = $03
ACC      = $04

CX       = $07
CZ       = $08
rottemp  = $09            ;0 initially

zpoint   = $0a            ;low byte already set to zero
zpoint2  = $0c

count    = $0e
angle    = $0f

cenx     = $14

Py       = $40

XCoord   = $50
YCoord   = $60

theta    = $70

cenz     = $7d

                          ; $ac taken by screen setup routine
                          ; final value = $10

Pz       = $ab


base     = $ce            ;$20 initially
                          ;alternate: ($81)

p4000    = $8f            ;$4000 initially
p6000    = $89            ;$60xx initially
p8000    = $9c            ;$8000

tagged   = $e0

sin      = $f7            ;0 low byte
cos      = $f9

curobj   = $ff


bitp     = $1c00
bitplo   = $1d00
bitphi   = $1e00
bitphi2  = $1f00
SINTAB   = $4000
PROJTAB  = $8000


DEY      = $88
INY      = $c8
INX      = $e8
ADC      = $65
STA      = $85

start    
         sta $8f          ;set up p4000

*
* Set up VIC
*
         sta $d021
         sta $0286        ;clear color
         jsr $e544        ;clr scr
         lda #$18
         sta $d018


*
* Line drawing tables
*

         ldx #$90
         ldy #$7f
         lda #$01
:l1      sta bitp,y
         cmp #$80
         rol

         pha
         tya
         lsr
         lsr
         lsr
         lsr
         sta bitphi,y
         lda #00
         sta bitp+128,y   ;0 = dont draw
         ror
         sta bitplo,y

*
* Extend sin table to 0..31
*
         lda sin0,y
         sta sin0+17,x
                          ;sta sin0+32,x
         inx

         pla

         dey
         bpl :l1
                          ;.y=$ff
                          ;.x=$10

*
* Set up sin tables
*
InitRot  

         iny
         sty p6000        ;rats :(

                          ;         ldy #00      ;rats :(
                          ;
                          ;         sty temp
                          ;:l3      ldx rottemp
                          ;         lda sin0,x
                          ;         sta aux      ;sin(theta)
                          ;
                          ;:l4
                          ;
                          ;         clc
                          ;         jsr MULT8    ;.Y * AUX

                          ;
                          ; AUX*.Y -> ACC,.A (low,hi) 16-bit result
                          ; AUX, .Y unaffected
                          ; .Y can be negative
                          ;

:Mult8   
         sty temp

                          ;dumb multiply
                          ;         sty acc
                          ;         lda #00
                          ;         tay
                          ;:mloop   clc
                          ;         adc sin0-$10,x
                          ;         bcc :skip
                          ;         iny
                          ;:skip    dec acc
                          ;         bne :mloop
                          ;         tya

         sty acc
         lda #00
         ldy #9
         clc
:mloop   
         ror
         ror acc
         bcc :mul2
                          ;         clc
                          ;dec sin0 table by 1 instead
         adc sin0-$10,x
:mul2    dey
         bne :mloop

         ldy temp
         bpl :pos
         sec
         sbc sin0-$10,x
:pos     

         sta (p4000),y
         eor #$ff
         clc
         adc #1

         STA (p6000),y
         iny
         bne :mult8
         inx
         inc p4000+1
         inc p6000+1
         bpl :mult8       ;to $8000

                          ;.x=$20
                          ;.y=0

*
* Set up Screen
*


                          ;         lda #00      ;bah!
                          ;         tya
:l2a     
                          ;         pha
         jsr $e8ea        ;scroll up
                          ;         pla
                          ;.A = ($AC)
                          ;.X=00

         clc              ;necessary?
:l2                       ;set one line
         sta $0720+12,x
         inc $db20+12,x
         inx
         adc #16
         bcc :l2
                          ;         adc #$00
         inc $ac

         cmp #15
         bne :l2a
:done                     ;.X=$10

         stx $40          ;rats :(
                          ;init Py

*
* Main program loop:
*   - get input
*   - update positions/angles
*   - render
*   - swap buffers
*

MainLoop 

                          ; Clear buffer and swap

         lda base
         eor #$08
         sta base

         sta zpoint+1
         ldy #00
         tya
         ldx #8
:l0      sta (zpoint),y
         iny
         bne :l0
         inc zpoint+1
         dex
         bne :l0

                          ; Get Input
                          ; .X=0

         lda $dc00
         lsr
         lsr
         lsr
         bcs :c1
         inc theta
:c1      lsr
         bcs :c2
         dec theta
:c2      and #$01
         sta tagged
         eor #$01
         ora $23c0+6
         sta $23c0+6      ;shot fired



                          ;         lda $cb
                          ;         and #3
                          ;         beq :skip
                          ;         lsr
                          ;         bcc :inc
                          ;         dec theta
                          ;         lsr
                          ;        bcc :skip
                          ;         jsr Forwards
                          ;:inc     inc theta
                          ;:skip

ObjLoop  

                          ; Compute relative center

         inx
         stx curobj

         dec cenz,x       ;Update pos

         lda cenx,x
                          ;         sec
                          ;         sbc cenx
         sta Px+4
         lda cenz,x
                          ;         sbc cenz
         sta Pz+4


                          ; Rotate
Rot      

         lda theta,x
         adc theta
         sta angle

         lda theta
         ldx #4
         ldy #STA
         jsr RotProj
         lda cz
         sbc #14
                          ;         bmi :skip
         cmp #125
         bcs NoDraw
         cmp cx
         bmi NoDraw
         adc cx
         bmi NoDraw

                          ; If in view, rotate project & plot

         dex
         stx count
:loop    lda angle
         ldy #ADC
         jsr RotProj
         sta YCoord,X
         dex
         bpl :loop

                          ; Plot

:ploop   ldy count
:l2      ldx count
         dey
         tya
         pha
         jsr DrawLine
         pla
         tay
         bne :l2
         dec count
         bne :ploop
                          ;.y=0
NoDraw   
         ldx curobj

                          ; Update

         lda tagged,x
         beq :zip
         lda cx
         ora tagged
         sta tagged,x
         dfb $2c
:zip     inc theta,x


         cpx #NUMOBJS
         bcc ObjLoop

         jsr $eb59        ;Swap buffer
                          ;.Y=1 .A=$7F

         jmp MainLoop


*
* Line routine
*  - Draws from L to R
*  - Forces dx>0 (x1 < x2)
*  - Numbers are +128 offset, to allow
*  - DX and DY to be 0..255 for long lines
*  - Uses same core routine for stepinx
*    and stepiny by changing variables
*
* On input:
*  .X = index into point list, point 1
*  .Y = index of point 2
*

Pswap    
         sty temp
         txa
         tay
         ldx temp
DrawLine 
         lda xcoord,y
         sec
         sbc xcoord,x
         bcc Pswap        ;x2 >= x1
         sta dx
         lda ycoord,y
         sbc ycoord,x     ;dy = y2-y1
         bcs :posy
         ldy #DEY
         eor #$ff
         adc #1
         dfb $2c
:posy    ldy #INY
         sta dy
         cmp dx
         lda #INX
                          ;         bcs stepiny
         bcs :noswap
         tya
         ldy #INX
:noswap  sty mod5
         sta mod4
stepinx  
                          ;         sta mod5
                          ;         sty mod4     ;INY/DEY
         lda dy
         ldy dx
         bcc mod
stepiny  
                          ;         sta mod4
                          ;         sty mod5     ;iny/dey
         lda dx
         ldy dy
mod      
                          ;         sty mod1+1
         sty temp
         sty mod3+1
         sta mod2+1

Draw     
         lda ycoord,x
         sec
         sbc #64
         tay
         lda xcoord,x
         sec
         sbc #64
         tax
                          ;mod1     lda #dy
         lda temp
         beq done         ;no steps!
                          ;         sta temp
         lsr
plot     
         pha
         tya
         bmi calcline
         lda bitphi,x
         ora base
         sta point+1
         lda bitplo,x
         sta point
         lda bitp,x
         beq calcline
         ora (point),y
         sta (point),y
calcline 
         pla
mod2     sbc #dx
         bcs mod5
mod3     adc #dy
mod4     inx
mod5     iny
         dec temp
         bne plot
done     
         rts

*
* Rotate and project point
*
* On entry:
*  .X = index into point list
*  .A = rotation angle
*  .Y = ADC/STA for points/centers
*  CX,CZ = location of object
*
* On exit:
*  Points stored in xcoord,x ycoord,x
*
RotProj  
         AND #$3F
         ORA #>SINTAB
         STA sin+1
         SBC #$2F         ;-3*pi/4
                          ;         ADC #$10
                          ;         AND #$3F
         ORA #>SINTAB
         STA cos+1
         STY RotM1
         STY RotM2
RotProj2 
         LDY Pz,X
         LDA (sin),Y
         PHA
         LDA (cos),Y
         LDY Px,X
         SEC
         SBC (sin),Y
         CLC
RotM1    ADC CZ
         STA aux

                          ;         LDY Px,X
                          ;         LDA (cos),Y
                          ;         LDY Pz,X
                          ;         CLC
                          ;         ADC (sin),Y
         PLA
         CLC
         ADC (cos),Y
         CLC
RotM2    ADC CX
         JSR Div8
         STA XCoord,X

         LDA Py,X
                          ;         JSR Div8
                          ;         STA YCoord,X
                          ;         RTS

*
* Signed division routine
*
* 64*.A/AUX -> .A
* Only valid for .Y/AUX < 1
* .A pos or neg, AUX > 0
* AUX, .X unaffected
*

DIV8     
                          ;         STY ACC
                          ;         tya
         php
         bpl :pos         ;.A just loaded
         eor #$ff
:pos     sta acc
         LDA #0
         LDY #14
:DLOOP   ASL ACC

         ROL
         CMP AUX
         BCC :DIV2
         SBC AUX
         INC ACC
:DIV2    
         DEY
         BNE :DLOOP
                          ;RTS

         lda acc
         plp
         bpl :pos2
         eor #$ff
:pos2    
         eor #$80         ;+128 offset
         rts

*
* Point list
* Last point is for relative cx,cz
*

                          ;Pz       dfb 0,16,0,-16,0
                          ;Py       dfb 16,0,8,0
Px       dfb 0,-4,16,-4

                          ;note: px+4 intrudes on table below

*
* 128*sin(t), t=0..15
*
* Table must be at end of code!
*

                          ;sin0     dfb 0,13,25,37,49,60,71,81
                          ;         dfb 91,99,106,113
                          ;         dfb 118,122,126,127,128

                          ;sin0     dfb 0,25,50,74,98,120,142,162
                          ;         dfb 180,197,212,225,236,244,250,254,255
sin0     dfb 0,24,49,73,97,119,141,161
         dfb 179,196,211,224,235,243,249,253,255


end      

