;A (quite) simple 3D-starfield
; By Andreas Ess
;    Tufers 156
;    A-6811 Goefis
;    Austria/Europe
;I hope I get internet access soon...
;-----------------------------------------------------------------------------

#INCLUDE "TI-85.H"

;-----------------------------------------------------------------------------
;Variables in TEXTMEM
;-----------------------------------------------------------------------------
Stars = TEXT_MEM      ;90 bytes -> 30 star's x, y, z position
XPos = TEXT_MEM+90
YPos = TEXT_MEM+91
ZPos = TEXT_MEM+92
SQUOT = TEXT_MEM+93
SREM = TEXT_MEM+94

GRAPH_MEM = $8641 ;this points to the graph mem

.org 0
.db "3D Starfield by AE",0

Start:
 ld   a, 4        ;set memory page 4 (graphic routines are here)
 out  (5), a      ;needed if FIND_PIXEL is going to be used
 ;-- Load pre-calculated numbers into Stars
 ld   hl, (PROGRAM_ADDR)
 ld   de, RStars
 add  hl, de
 ld   de, Stars
 ld   bc, 90
 ldir
 ;-- Now, let's begin!
 ROM_CALL(CLEARLCD)
NoKey:
 ld   a, (KEY_1)
 cp   0
 jr   nz, NoKey
StarLoop:
 ld   a, 0
 ld   bc, 1024
 ld   hl, GRAPH_MEM
ClearL:
 ld   a, 0
 ld   (hl), a
 inc  hl
 dec  bc
 ld   a, b
 or   c
 jr   nz, ClearL
 CALL_(DoStars)
 CALL_(Delay)
 ;show buffer:
 ld   bc, 1024
 ld   hl, GRAPH_MEM
 ld   de, VIDEO_MEM
 ldir
 ld   a, (KEY_1)
 cp   0
 jr   z, StarLoop
 ret

;-----------------------------------------------------------------------------
;DoStars
;-----------------------------------------------------------------------------
DoStars:
 ld   b, 30
 ld   hl, Stars
DoStarLoop:
 push bc
 ;recalculate it's position
 ld   a, (hl)
 ld   (XPos), a
 inc  hl
 ld   a, (hl)
 ld   (YPos), a
 inc  hl
 ld   a, (hl)
 ld   (ZPos), a
 dec  a
 jr   nz, IncHL
 ld   a, 32
IncHL:
 ld   (hl), a
 inc  hl
 push hl
 ;Calculate 2D-XPos by saying XPos2D = 4*XPos3D/ZPos3D
 ld   de, 64
 ld   a, (XPos)
 ld   h, 0
 ld   l, a
 or   a      ;clear carry
 sbc  hl, de
 add  hl, hl
 ld   a, (ZPos)
 ld   d, 0
 ld   e, a
 CALL_(SDIV16)
 ld   de, 64
 add  hl, de
 ld   b, l          ;B now contains X-Pos
 ;Calculate 2D-YPos by saying YPos2D = 4*YPos3D/ZPos3D
 ld   de, 32
 ld   a, (YPos)
 ld   h, 0
 ld   l, a
 or   a
 sbc  hl, de
 add  hl, hl
 ld   a, (ZPos)
 ld   d, 0
 ld   e, a
 CALL_(SDIV16)
 ld   de, 32
 add  hl, de
 ld   c, l          ;C now contains X-Pos
 ;finally, show it:
 CALL_(PointOn)
 pop  hl
 pop  bc
 djnz DoStarLoop
 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

;-----------------------------------------------------------------------------
;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, GRAPH_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

;-----------------------------------------------------------------------------
;Pre-calculated stars
;-----------------------------------------------------------------------------
RStars:
 ;    X   Y   Z
 .db $1,$0,$A
 .db $4,$16,$6
 .db $44,$C,$16
 .db $78,$11,$E
 .db $D,$2B,$12
 .db $5,$A,$1A
 .db $57,$30,$1A
 .db $79,$D,$D
 .db $78,$34,$1D
 .db $66,$1C,$13
 .db $54,$25,$11
 .db $5B,$7,$C
 .db $F,$2A,$F
 .db $3E,$23,$B
 .db $6E,$10,$5
 .db $35,$2B,$5
 .db $44,$28,$13
 .db $0,$31,$8
 .db $3A,$18,$C
 .db $49,$26,$8
 .db $15,$32,$9
 .db $2A,$19,$7
 .db $34,$3,$F
 .db $7C,$0,$D
 .db $8,$4,$8
 .db $7B,$16,$C
 .db $19,$C,$6
 .db $1F,$2F,$1C
 .db $72,$2E,$E
 .db $43,$2,$4

.end
