;3D Rotate
; (C)1996 by Andreas Ess
;Hmm... There seems to be an error. I couldn't find it. Perhaps you are able to.
;If so, please send me a letter:
; Andreas Ess
; Tufers 156
; A-6811 Goefis
; Austria/Europe
;-----------------------------------------------------------------------------

#INCLUDE "TI-85.H"

;-----------------------------------------------------------------------------
;TEXT-MEM Vars:
;-----------------------------------------------------------------------------
XSin = TEXT_MEM
XCos = TEXT_MEM+2
YSin = TEXT_MEM+4
YCos = TEXT_MEM+6
ZSin = TEXT_MEM+8
ZCos = TEXT_MEM+10
Temp = TEXT_MEM+12
HelpX = TEXT_MEM+14
HelpY = TEXT_MEM+16
HelpZ = TEXT_MEM+18
RotatePoint = TEXT_MEM+20
RotateAngel = TEXT_MEM+37
SREM = TEXT_MEM+38
SQUOT = TEXT_MEM+39
XDeg = TEXT_MEM+40
YDeg = TEXT_MEM+42
ZDeg = TEXT_MEM+44

;-----------------------------------------------------------------------------
;The program:
;-----------------------------------------------------------------------------
.org 0
.db "3D ROTATION v0.1 BY AE",0

Start:
 di
 ROM_CALL(CLEARLCD)
 ld   a, 4        ;set memory page 4 (graphic routines are here)
 out  (5), a      ;needed if FIND_PIXEL is going to be used
 ld   b, 8
 ld   hl, (PROGRAM_ADDR)
 ld   de, Cube
 add  hl, de
 ex   de, hl
 ld   hl, RotatePoint
 CALL_(RotatePrj)
WaitFirst:
 ld   hl, RotatePoint
 ld   b, 8
 CALL_(DrawPoints)
 call GET_KEY
 cp   0
 jr   z, WaitFirst
WaitKey:
 ld   hl, (XDeg)
 inc  hl
 ld   de, 359
 and  a
 sbc  hl, de
 jr   nz, SaveXDeg
 ld   hl, 0
SaveXDeg:
 ld   (XDeg), hl
 ld   b, 8
 ld   hl, (PROGRAM_ADDR)
 ld   de, Cube
 add  hl, de
 ex   de, hl
 ld   hl, RotatePoint
 CALL_(RotatePrj)
 ROM_CALL(CLEARLCD)
 ld   hl, RotatePoint
 ld   b, 8
 CALL_(DrawPoints)
 CALL_(Delay)
 CALL_(Delay)
 CALL_(Delay)
 CALL_(Delay)
 CALL_(Delay)
 CALL_(Delay)
 call GET_KEY
 cp   0
 jr   z, WaitKey
 ei
 ret

;-----------------------------------------------------------------------------
;RotatePrj: This rotates a 3D-object and projects it
; INPUT:                                OUTPUT:
;  DE - Base Address of 3D-              HL - pointer to list where
;       coordinates saved as                  the rotated and projected
;       x byte,y byte,z byte,x byte,...       2D-points are(not base address!)
;  HL - Where to save the 2D-points in
;       x byte,y byte,x byte,...
;  B  - number of points
;  (XDeg) - X-Rotation
;  (YDeg) - Y-Rotation
;  (ZDeg) - Rotation around Z-Axis
;-----------------------------------------------------------------------------
RotatePrj:
 ;First, get the offset in the sine & cosine table for A(x-rot):
 push hl                        ;save registers
 push de
 ld   hl, (XDeg)                ;compute offset in SineTable
 add  hl, hl                    ;correct offset = 2*XDeg,
 ld   de, (PROGRAM_ADDR)        ;add it to the address of program
 add  hl, de                    ;and
 ld   de, SineTable             ;finally to the offset of SineTable
 add  hl, de
 call LD_HL_MHL                 ;load contents of HL into HL
 ld   (XSin), hl                ;Save the sine into TEXT_MEM
 ld   hl, (XDeg)
 add  hl, hl                    ;multiply by 2...
 ld   de, (PROGRAM_ADDR)        ;add to program address,
 add  hl, de
 ld   de, CosineTable           ;to cosine table offset
 add  hl, de
 call LD_HL_MHL
 ld   (XCos), hl                ;we won't need it any more.
 pop  de                        ;get original registers again
 pop  hl
;- Rotate Points around X-Axis -----------------------------------------------
; HelpX = X*XCos-Y*XSin
; HelpY = Y*XCos+X*XSin
;  DE - Source WORDS
;  HL - Destination BYTES
;-----------------------------------------------------------------------------
RotatePointsL:                  ;now, rotate points...
 push bc
 push hl
 ld   h, d                      ;let HL point to DE
 ld   l, e
 call LD_HL_MHL                 ;and load the contents of DE into HL...
  push de
  ld   de, (XCos)               ;so, multiply X with
  CALL_(MUL16)                  ;XCos...
  ld   (Temp), hl
  pop  de
 inc  de                        ;process next word...
 inc  de
 ld   h, d
 ld   l, e
 call LD_HL_MHL
  push de
  ld   de, (XSin)
  CALL_(MUL16)
  ld   de, (Temp)
  ex   de, hl
  or   a
  sbc  hl, de
  ld   (HelpX), hl
  pop  de
				;Rotate Y now
 ld   h, d
 ld   l, e
 call LD_HL_MHL
  push de
  ld   de, (XCos)
  CALL_(MUL16)
  ld   (Temp), hl
  pop  de
 dec  de
 dec  de
 call LD_HL_MHL
  push de
  ld   de, (XSin)
  CALL_(MUL16)
  ld   de, (Temp)
  add  hl, de
  ld   (HelpY), hl
  pop  de
				;Now we have rotated the points
 inc  de                        ;process
 inc  de                        ;Z or X byte(regarding what's X and
 inc  de                        ;what's the Z-axis...
 inc  de                        ;
 ld   h, d
 ld   l, e
 call LD_HL_MHL
  push de
  ld   de, 20                   ;so we've got a viewing space from(-10,-10,-10)
				;to (10,10,10)
  add  hl, de
  add  hl, hl
  add  hl, hl
  add  hl, hl
  add  hl, hl
  ld   (HelpZ), hl
  ;PROJECT IT!
  ld   hl, (HelpX)
  ld   de, (HelpZ)
  CALL_(SDIV16)
  ld   de, 64
  add  hl, de
  ld   (Temp), hl
  pop  de
  inc  de
  inc  de
 pop  hl
 ld   a, (Temp)
 ld   (hl), a
 inc  hl
  push hl
  push de
  ld   hl, (HelpY)
  ld   de, (HelpZ)
  CALL_(SDIV16)
  ld   de, 32
  add  hl, de
  ld   (Temp), hl
  pop  de
  pop  hl
 ld   a, (Temp)
 ld   (hl), a
 inc  hl
 pop  bc                        ;
 dec  b                         ;another point?
 JUMP_NZ(RotatePointsL)         ;
 ret

;-----------------------------------------------------------------------------
;MUL16 : multiplies 2 16-Bit numbers
;-----------------------------------------------------------------------------
MUL16:
 ld   c, l    ;BC = MULTIPLIER
 ld   b, h
 ld   hl, 0   ;PRODUCT = 0
 ld   a, 15   ;COUNT = BIT LENGTH - 1
 ;Shift and Add-Algorithm
 ;If MSB of Multiplier is 1, add multipliand to prtial
 ;product. Shift partial product, multiplier left 1 bit
MLP:
 sla  e
 rl   d
 jr   nc, MLP1
 add  hl, bc
MLP1:
 add  hl, hl
 dec  a
 jr   nz, MLP

 or   d
 ret  p
 add  hl, bc
 ret

;-----------------------------------------------------------------------------
;SDIV16: signed division, uses UDIV16
;-----------------------------------------------------------------------------
SDIV16:
 push  bc
 ld    a, h
 ld    (SREM), a
 xor   d
 ld    (SQUOT), a

 bit   7, d
 jr    z, CheckDE
 or    a
 sub   a
 sub   e
 ld    e, a
 sbc   a, a
 sub   d
 ld    d, a

CheckDE:
 bit   7, h
 jr    z, DoDiv
 or    a
 sub   a
 sub   l
 ld    l, a
 sbc   a, a
 sub   h
 ld    h, a

DoDiv:
 CALL_(UDIV16)

 ld    a, (SQUOT)
 bit   7, a
 jr    z, DoRem    ;!
 or    a
 sub   a
 sub   l
 ld    l, a
 sbc   a, a
 sub   h
 ld    h, a

DoRem:
 pop   bc
 ret

;-----------------------------------------------------------------------------
;UDIV16: divides HL trough DE
; quotient in HL
; remainder in DE
; carry = 0
;-----------------------------------------------------------------------------
UDIV16:

Divide:
 ld    c, l
 ld    a, h
 ld    hl, 0       ;hl = remainder
 ld    b, 16       ;16 bits in dividend
 or    a           ;clear carry

DivLoop:
 rl    c
 rla
 rl    l
 rl    h

 push  hl
 sbc   hl, de
 ccf

 jr    c, Drop
 ex    (sp), hl
Drop:
 inc   sp
 inc   sp
 djnz  DivLoop

 ex    de, hl
 rl    c
 ld    l, c
 rla
 ld    h, a
 or    a
 ret

;-----------------------------------------------------------------------------
;DrawPoints
;-----------------------------------------------------------------------------
DrawPoints:
DrawLoop:
 push bc
 ld   b, (hl)
 inc  hl
 ld   c, (hl)
 inc  hl
 CALL_(PointOn)
 pop  bc
 djnz DrawLoop
 ret

;-----------------------------------------------------------------------------
;PointOn: draws point at b=x, c=y
;-----------------------------------------------------------------------------
PointOn:
 push hl
 push bc
 push de
 ROM_CALL(FIND_PIXEL)  ;HL=byte offset in video buffer, A=2^(bit to change)
 ld   de, VIDEO_MEM
 add  hl, de
 or   (hl)
 ld   (hl), a
 pop  de
 pop  bc
 pop  hl
 ret

;-----------------------------------------------------------------------------
;Delay: waits
;-----------------------------------------------------------------------------
Delay:
 ld bc, $1000
DelayLoop:
 dec bc
 ld a, b
 or c
 jr nz, DelayLoop
 ret

;-----------------------------------------------------------------------------
;A Cube
;-----------------------------------------------------------------------------
;     Z   Y   X
Cube:
 .dw  10, -10,  10
 .dw -10, -10,  10
 .dw -10,  10,  10
 .dw  10,  10,  10
 .dw  10, -10, -10
 .dw -10, -10, -10
 .dw -10,  10, -10
 .dw  10,  10, -10

;-----------------------------------------------------------------------------
;Sine & Cosine Tables shifted by 8
;-----------------------------------------------------------------------------
SineTable:
 .dw $0000,$0004,$0008,$000D,$0011,$0016,$001A,$001F,$0023,$0028,$002C,$0030,$0035,$0039,$003D,$0042
 .dw $0046,$004A,$004F,$0053,$0057,$005B,$005F,$0064,$0068,$006C,$0070,$0074,$0078,$007C,$007F,$0083
 .dw $0087,$008B,$008F,$0092,$0096,$009A,$009D,$00A1,$00A4,$00A7,$00AB,$00AE,$00B1,$00B5,$00B8,$00BB
 .dw $00BE,$00C1,$00C4,$00C6,$00C9,$00CC,$00CF,$00D1,$00D4,$00D6,$00D9,$00DB,$00DD,$00DF,$00E2,$00E4
 .dw $00E6,$00E8,$00E9,$00EB,$00ED,$00EE,$00F0,$00F2,$00F3,$00F4,$00F6,$00F7,$00F8,$00F9,$00FA,$00FB
 .dw $00FC,$00FC,$00FD,$00FE,$00FE,$00FF,$00FF,$00FF,$00FF,$00FF,$0100,$00FF,$00FF,$00FF,$00FF,$00FF
 .dw $00FE,$00FE,$00FD,$00FC,$00FC,$00FB,$00FA,$00F9,$00F8,$00F7,$00F6,$00F4,$00F3,$00F2,$00F0,$00EE
 .dw $00ED,$00EB,$00E9,$00E8,$00E6,$00E4,$00E2,$00DF,$00DD,$00DB,$00D9,$00D6,$00D4,$00D1,$00CF,$00CC
 .dw $00C9,$00C6,$00C4,$00C1,$00BE,$00BB,$00B8,$00B5,$00B1,$00AE,$00AB,$00A7,$00A4,$00A1,$009D,$009A
 .dw $0096,$0092,$008F,$008B,$0087,$0083,$0080,$007C,$0078,$0074,$0070,$006C,$0068,$0064,$005F,$005B
 .dw $0057,$0053,$004F,$004A,$0046,$0042,$003D,$0039,$0035,$0030,$002C,$0028,$0023,$001F,$001A,$0016
 .dw $0011,$000D,$0008,$0004,$0000,$FFFC,$FFF8,$FFF3,$FFEF,$FFEA,$FFE6,$FFE1,$FFDD,$FFD8,$FFD4,$FFD0
 .dw $FFCB,$FFC7,$FFC3,$FFBE,$FFBA,$FFB6,$FFB1,$FFAD,$FFA9,$FFA5,$FFA1,$FF9C,$FF98,$FF94,$FF90,$FF8C
 .dw $FF88,$FF84,$FF81,$FF7D,$FF79,$FF75,$FF71,$FF6E,$FF6A,$FF66,$FF63,$FF5F,$FF5C,$FF59,$FF55,$FF52
 .dw $FF4F,$FF4B,$FF48,$FF45,$FF42,$FF3F,$FF3C,$FF3A,$FF37,$FF34,$FF31,$FF2F,$FF2C,$FF2A,$FF27,$FF25
 .dw $FF23,$FF21,$FF1E,$FF1C,$FF1A,$FF18,$FF17,$FF15,$FF13,$FF12,$FF10,$FF0E,$FF0D,$FF0C,$FF0A,$FF09
 .dw $FF08,$FF07,$FF06,$FF05,$FF04,$FF04,$FF03,$FF02,$FF02,$FF01,$FF01,$FF01,$FF01,$FF01,$FF00,$FF01
 .dw $FF01,$FF01,$FF01,$FF01,$FF02,$FF02,$FF03,$FF04,$FF04,$FF05,$FF06,$FF07,$FF08,$FF09,$FF0A,$FF0C
 .dw $FF0D,$FF0E,$FF10,$FF12,$FF13,$FF15,$FF17,$FF18,$FF1A,$FF1C,$FF1E,$FF21,$FF23,$FF25,$FF27,$FF2A
 .dw $FF2C,$FF2F,$FF31,$FF34,$FF37,$FF3A,$FF3C,$FF3F,$FF42,$FF45,$FF48,$FF4B,$FF4F,$FF52,$FF55,$FF59
 .dw $FF5C,$FF5F,$FF63,$FF66,$FF6A,$FF6E,$FF71,$FF75,$FF79,$FF7D,$FF80,$FF84,$FF88,$FF8C,$FF90,$FF94
 .dw $FF98,$FF9C,$FFA1,$FFA5,$FFA9,$FFAD,$FFB1,$FFB6,$FFBA,$FFBE,$FFC3,$FFC7,$FFCB,$FFD0,$FFD4,$FFD8
 .dw $FFDD,$FFE1,$FFE6,$FFEA,$FFEF,$FFF3,$FFF8,$FFFC

CosineTable:
 .dw $0100,$00FF,$00FF,$00FF,$00FF,$00FF,$00FE,$00FE,$00FD,$00FC,$00FC,$00FB,$00FA,$00F9,$00F8,$00F7
 .dw $00F6,$00F4,$00F3,$00F2,$00F0,$00EE,$00ED,$00EB,$00E9,$00E8,$00E6,$00E4,$00E2,$00DF,$00DD,$00DB
 .dw $00D9,$00D6,$00D4,$00D1,$00CF,$00CC,$00C9,$00C6,$00C4,$00C1,$00BE,$00BB,$00B8,$00B5,$00B1,$00AE
 .dw $00AB,$00A7,$00A4,$00A1,$009D,$009A,$0096,$0092,$008F,$008B,$0087,$0083,$0080,$007C,$0078,$0074
 .dw $0070,$006C,$0068,$0064,$005F,$005B,$0057,$0053,$004F,$004A,$0046,$0042,$003D,$0039,$0035,$0030
 .dw $002C,$0028,$0023,$001F,$001A,$0016,$0011,$000D,$0008,$0004,$0000,$FFFC,$FFF8,$FFF3,$FFEF,$FFEA
 .dw $FFE6,$FFE1,$FFDD,$FFD8,$FFD4,$FFD0,$FFCB,$FFC7,$FFC3,$FFBE,$FFBA,$FFB6,$FFB1,$FFAD,$FFA9,$FFA5
 .dw $FFA1,$FF9C,$FF98,$FF94,$FF90,$FF8C,$FF88,$FF84,$FF81,$FF7D,$FF79,$FF75,$FF71,$FF6E,$FF6A,$FF66
 .dw $FF63,$FF5F,$FF5C,$FF59,$FF55,$FF52,$FF4F,$FF4B,$FF48,$FF45,$FF42,$FF3F,$FF3C,$FF3A,$FF37,$FF34
 .dw $FF31,$FF2F,$FF2C,$FF2A,$FF27,$FF25,$FF23,$FF21,$FF1E,$FF1C,$FF1A,$FF18,$FF17,$FF15,$FF13,$FF12
 .dw $FF10,$FF0E,$FF0D,$FF0C,$FF0A,$FF09,$FF08,$FF07,$FF06,$FF05,$FF04,$FF04,$FF03,$FF02,$FF02,$FF01
 .dw $FF01,$FF01,$FF01,$FF01,$FF00,$FF01,$FF01,$FF01,$FF01,$FF01,$FF02,$FF02,$FF03,$FF04,$FF04,$FF05
 .dw $FF06,$FF07,$FF08,$FF09,$FF0A,$FF0C,$FF0D,$FF0E,$FF10,$FF12,$FF13,$FF15,$FF17,$FF18,$FF1A,$FF1C
 .dw $FF1E,$FF21,$FF23,$FF25,$FF27,$FF2A,$FF2C,$FF2F,$FF31,$FF34,$FF37,$FF3A,$FF3C,$FF3F,$FF42,$FF45
 .dw $FF48,$FF4B,$FF4F,$FF52,$FF55,$FF59,$FF5C,$FF5F,$FF63,$FF66,$FF6A,$FF6E,$FF71,$FF75,$FF79,$FF7D
 .dw $FF80,$FF84,$FF88,$FF8C,$FF90,$FF94,$FF98,$FF9C,$FFA1,$FFA5,$FFA9,$FFAD,$FFB1,$FFB6,$FFBA,$FFBE
 .dw $FFC3,$FFC7,$FFCB,$FFD0,$FFD4,$FFD8,$FFDD,$FFE1,$FFE6,$FFEA,$FFEF,$FFF3,$FFF8,$FFFC,$0000,$0004
 .dw $0008,$000D,$0011,$0016,$001A,$001F,$0023,$0028,$002C,$0030,$0035,$0039,$003D,$0042,$0046,$004A
 .dw $004F,$0053,$0057,$005B,$005F,$0064,$0068,$006C,$0070,$0074,$0078,$007C,$007F,$0083,$0087,$008B
 .dw $008F,$0092,$0096,$009A,$009D,$00A1,$00A4,$00A7,$00AB,$00AE,$00B1,$00B5,$00B8,$00BB,$00BE,$00C1
 .dw $00C4,$00C6,$00C9,$00CC,$00CF,$00D1,$00D4,$00D6,$00D9,$00DB,$00DD,$00DF,$00E2,$00E4,$00E6,$00E8
 .dw $00E9,$00EB,$00ED,$00EE,$00F0,$00F2,$00F3,$00F4,$00F6,$00F7,$00F8,$00F9,$00FA,$00FB,$00FC,$00FC
 .dw $00FD,$00FE,$00FE,$00FF,$00FF,$00FF,$00FF,$00FF

.end
