-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathscene_lissajous.z80
264 lines (222 loc) · 4.8 KB
/
scene_lissajous.z80
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
INCLUDE "Hardware.inc"
INCLUDE "rgbgrafx/rgbgrafx.inc"
Section "Robot image data",DATA
INCLUDE "imagedata/robot.inc"
Section "Lissajous curve scene",CODE
scene_lissajous::
xor A
ld [slide_done], A
ld [frame_number], A
ld [rotation], A
; Set all palette colors to black for the duration of loading image data
RGBG_WaitForVRAM
ld A, $FF
ld [rBGP], A
ld [rOBP0], A
; Initialize high byte of the tileset starting address
ld A, $88
ld [RGBG_tileset], A
; Load tile patterns to VRAM
ld BC, robot_tile_data
ld D, $FF
ld E, 0
RGBG_WaitForVRAM
call RGBG_LoadTiles
; Initialize high byte of the tilemap starting address
ld A, $98
ld [RGBG_tilemap], A
; Set tilemap offset
ld A, 128
ld [RGBG_map_offset], A
; Load tile map
RGBG_WaitForVRAM
ld BC, robot_map_data
ld H, $0
ld L, $0
ld E, robot_tile_map_width
ld D, robot_tile_map_height
call RGBG_SetTileMap
; Position background image
xor A
ld [rSCX], A
di ; Disable interrupts during setup
; Reset interrupt handlers
call initialize_interrupts
; Enable V-blank and timer interrupts
ld A, IEF_VBLANK | IEF_TIMER
ld [rIE], A
; When timer interrupt triggers, load 0 to TIMA
xor A
ld [rTMA], A
; Initialize timer variable to zero
ld [timer], A
; Set timer to increment 4096 times a second
ld A, 4
ld [rTAC], A
; Set timer interrupt
ld BC, lissajous_timer
call set_timer_interrupt
; Configure LCD controller
ld A, (LCDCF_ON | LCDCF_WINOFF | LCDCF_BG8800 | LCDCF_BG9800 | LCDCF_BGON | LCDCF_OBJ8 | LCDCF_OBJON)
ld [rLCDC], A
; Initialize high byte of the sprite tileset starting address
ld A, $80
ld [RGBG_tileset], A
; Load point sprite tile into VRAM
ld BC, point_sprite
ld D, 1
ld E, 0
call RGBG_LoadTiles
call RGBG_ZeroOAM
call RGBG_CopyDMARoutine
; Set all 40 sprites to show same pattern
xor A
ld B, A
.sprite_creation_loop:
push AF
call RGBG_SetSpriteTile
pop AF
inc A
cp 40
jr c, .sprite_creation_loop
; Set all sprites to 0,0
xor A
ld B, A
ld C, A
.sprite_initial_position_loop:
push AF
call RGBG_SetSpritePos
pop AF
inc A
cp 40
jr c, .sprite_initial_position_loop
RGBG_WaitVBL
call RGBG_DoDMA ; Send sprite data to OAM
; Set interrupt handler
ld BC, lissajous_vblank
call set_vblank_interrupt
; Reset color palette to default
RGBG_WaitForVRAM
ld A, %11100100
ld [rBGP], A
ld [rOBP0], A
ld [rOBP1], A
ei ; Enable interrupts again
.loop:
halt
ld A, [timer]
; Start fading out after 160 / 16 = 10 seconds
cp 160
jr nz, .loop
.fade1_loop:
halt
ld A, [timer]
cp 162
jr nz, .fade1_loop
call fade_to_black
.fade2_loop:
halt
ld A, [timer]
cp 164
jr nz, .fade2_loop
call fade_to_black
.fade3_loop:
halt
ld A, [timer]
cp 166
jr nz, .fade3_loop
call fade_to_black
; Disable sprites
ld A, [rLCDC]
and %11111101
ld [rLCDC], A
ret
lissajous_timer:
ld A, [timer]
inc A
ld [timer], A
ret
lissajous_vblank:
ld A, [rotation]
ld H, A ; Set rotation to H
ld A, [frame_number] ; Get frame number to index LUTs
ld D, A ; Save frame number to D
; Slide robot image in
ld A, [slide_done]
cp 0
jr nz, .slide_end
ld A, D
cp 64
jr c, .keep_sliding
ld A, 1
ld [slide_done], A
jr .slide_end
.keep_sliding:
call get_sine
add A
sub 25
ld [rSCX], A
.slide_end:
ld E, 40 ; Use E as sprite counter
.loop_start:
swap E ; Multiply sprite counter with 16 to use as offset
ld A, D ; Load frame number to A
add E
add A
add H
; Total index is now 2 * frame_number + 16 * sprite_counter + rotation
call get_sine
add 20 ; Position resulting curve by offsetting with 20 pixels
ld B, A ; Set first sine value to X coordinate
ld A, D ; Load frame number to A
add E
; Total index is now frame_number + 16 * sprite_counter
call get_sine ; Get sine value and save it to A
add 40 ; Position resulting curve by offsetting with 50 pixels
ld C, A ; Set second sine value to Y coordinate
swap E ; Restore sprite number by dividing with 16
ld A, E
push HL
call RGBG_SetSpritePos ; Save sprite position
pop HL
dec E
jr nz, .loop_start
push HL
call RGBG_DoDMA ; Execute DMA
pop HL
ld A, D ; Return frame number to A
inc A ; Increment frame number
ld [frame_number], A ; Save frame number
ld A, H
inc A
ld [rotation], A
ret
; A = index from $00 to $FF
get_sine:
push HL
ld H, $2F
ld L, A
ld A, [HL]
pop HL
ret
point_sprite:
DW `00000000
DW `00000000
DW `00033000
DW `00333300
DW `00333300
DW `00033000
DW `00000000
DW `00000000
Section "Sine lookup-table",HOME[$2F00] ; Alignment to 00 important
sine_lut:
ANGLE SET 0.0
REPT 256
DB (MUL(30.0,SIN(ANGLE))+30.0)>>16
ANGLE SET ANGLE+256.0
ENDR
Section "Lissajous variables",BSS
frame_number: DS 1
rotation: DS 1
timer: DS 1
slide_done: DS 1