-
Notifications
You must be signed in to change notification settings - Fork 2
/
sprite.asm
650 lines (628 loc) · 11.6 KB
/
sprite.asm
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
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
.ifndef SPRITE_INC
SPRITE_INC = 1
.include "x16.inc"
.include "tilelib.asm"
.include "debug.asm"
.include "globals.asm"
__sprattr: ; A: sprite index
stz VERA_ctrl
pha
asl
asl
asl
sta VERA_addr_low
pla
lsr
lsr
lsr
lsr
lsr
ora #>VRAM_sprattr
sta VERA_addr_high
lda #(^VRAM_sprattr | $10)
sta VERA_addr_bank
rts
sprite_frame: ; A: frame
; X: sprite index
; Y: flip (0: none, 1: H, 2: V, 3: H&V)
asl
asl
pha
txa
jsr __sprattr
pla
clc
adc #<(VRAM_SPRITES >> 5)
sta VERA_data0
lda #0
adc #>(VRAM_SPRITES >> 5)
sta VERA_data0
lda VERA_data0
lda VERA_data0
lda VERA_data0
lda VERA_data0
tya
ora #$0C
sta VERA_data0
rts
tile_collision: .byte 0
sprite_getpos: ; Input:
; A: sprite index
; X: tile layer (0,1)
; Output:
; A: tile overlap (n:ne:e:se:s:sw:w:nw)
; X: tile x
; Y: tile y
; tile_collision: 1 if sprite collided, 0 otherwise
bra @start
@xpos: .word 0
@ypos: .word 0
@halfwidth: .byte 4
@halfheight: .byte 4
@tilew: .byte 0
@tileh: .byte 0
@overlap: .byte 0
@start:
cpx #1
php
stz tile_collision
stz @overlap
ldx #4
stx @halfwidth
stx @halfheight
jsr __sprattr
lda VERA_data0 ; ignore
lda VERA_data0 ; ignore
lda VERA_data0
sta @xpos
lda VERA_data0
sta @xpos+1
lda VERA_data0
sta @ypos
lda VERA_data0
sta @ypos+1
lda VERA_data0 ; ignore
lda VERA_data0
bit #$10
beq @check_high_width
asl @halfwidth
@check_high_width:
bit #$20
beq @check_height
asl @halfwidth
asl @halfwidth
@check_height:
bit #$40
beq @check_high_height
asl @halfheight
@check_high_height:
bit #$80
beq @calc_center
asl @halfheight
asl @halfheight
@calc_center:
lda @xpos
clc
adc @halfwidth
sta @xpos
tax
lda @xpos+1
adc #0
sta @xpos+1
lda @ypos
clc
adc @halfheight
sta @ypos
tay
lda @ypos+1
adc #0
sta @ypos+1
lda @xpos+1
asl
asl
ora @ypos+1
plp
bne @get_tile
ora #$10
@get_tile:
jsr pix2tilexy
phx
phy
pha
and #$F0
lsr
lsr
lsr
sta @tilew
; TODO handle sprites wider than tiles
dec
and @xpos ; A = xpos % TILEW
tax
cmp @halfwidth
bmi @west ; overlaps to west
lda @tilew
sec
sbc @halfwidth
sta @xpos+1
cpx @xpos+1
bmi @test_north ; entire width of sprite inside tile
beq @test_north
lda @overlap
ora #$20 ; overlaps to east
sta @overlap
bra @test_north
@west:
lda @overlap
ora #$02
sta @overlap
@test_north:
pla
and #$0F
asl
sta @tileh
; TODO handle sprites taller than tiles
dec
and @ypos ; A = ypos % TILEH
tay
cmp @halfheight
bmi @north ; overlaps to north
lda @tileh
sec
sbc @halfheight
sta @ypos+1
cpy @ypos+1
bmi @return ; entire height of sprite inside tile
beq @return
lda @overlap
ora #$08 ; overlaps to south
sta @overlap
bra @test_se
@north:
lda @overlap
ora #$80
sta @overlap
and #$A0
cmp #$A0
bne @test_se
lda @overlap
ora #$40
sta @overlap ; overlaps NE
bra @return
@test_se:
lda @overlap
and #$28
cmp #$28
bne @test_sw
lda @overlap
ora #$10
sta @overlap ; overlaps SE
bra @return
@test_sw:
lda @overlap
and #$0A
cmp #$0A
bne @test_nw
lda @overlap
ora #$04
sta @overlap ; overlaps SW
bra @return
@test_nw:
lda @overlap
and #$82
cmp #$82
bne @return
lda @overlap
ora #$01
sta @overlap ; overlaps NW
@return:
dec @halfwidth
dec @halfwidth
dec @halfwidth
dec @halfheight
dec @halfheight
dec @halfheight
txa
sec
sbc @xpos+1
cmp @halfwidth
bpl @pull_output
tya
sec
sbc @ypos+1
cmp @halfheight
bpl @pull_output
lda #1
sta tile_collision
@pull_output:
lda @overlap
ply
plx
rts
move_sprite_right: ; A: sprite index
; X: pixels
bra @start
@xpos: .word 0
@start:
pha
phx
jsr __sprattr
lda VERA_data0
lda VERA_data0
lda VERA_data0
sta @xpos
lda VERA_data0
sta @xpos+1
plx
txa
clc
adc @xpos
sta @xpos
lda @xpos+1
adc #0
sta @xpos+1
pla
jsr __sprattr
lda VERA_data0
lda VERA_data0
lda @xpos
sta VERA_data0
lda @xpos+1
sta VERA_data0
rts
move_sprite_left: ; A: sprite index
; X: pixels
bra @start
@xpos: .word 0
@pixels: .byte 0
@start:
pha
stx @pixels
jsr __sprattr
lda VERA_data0
lda VERA_data0
lda VERA_data0
sta @xpos
lda VERA_data0
sta @xpos+1
lda @xpos
sec
sbc @pixels
sta @xpos
lda @xpos+1
sbc #0
bmi @return
sta @xpos+1
pla
jsr __sprattr
lda VERA_data0
lda VERA_data0
lda @xpos
sta VERA_data0
lda @xpos+1
sta VERA_data0
@return:
rts
move_sprite_down: ; A: sprite index
; X: pixels
bra @start
@ypos: .word 0
@start:
pha
phx
jsr __sprattr
lda VERA_data0
lda VERA_data0
lda VERA_data0
lda VERA_data0
lda VERA_data0
sta @ypos
lda VERA_data0
sta @ypos+1
plx
txa
clc
adc @ypos
sta @ypos
lda @ypos+1
adc #0
sta @ypos+1
pla
jsr __sprattr
lda VERA_data0
lda VERA_data0
lda VERA_data0
lda VERA_data0
lda @ypos
sta VERA_data0
lda @ypos+1
sta VERA_data0
rts
move_sprite_up: ; A: sprite index
; X: pixels
bra @start
@ypos: .word 0
@pixels: .byte 0
@start:
pha
stx @pixels
jsr __sprattr
lda VERA_data0
lda VERA_data0
lda VERA_data0
lda VERA_data0
lda VERA_data0
sta @ypos
lda VERA_data0
sta @ypos+1
lda @ypos
sec
sbc @pixels
sta @ypos
lda @ypos+1
sbc #0
bmi @return
sta @ypos+1
pla
jsr __sprattr
lda VERA_data0
lda VERA_data0
lda VERA_data0
lda VERA_data0
lda @ypos
sta VERA_data0
lda @ypos+1
sta VERA_data0
@return:
rts
; Macro: SPRITE_GET_SCREEN_POS
; Input:
; idx_addr: address of byte containing sprite index
; xpos_addr: address of writable word
; ypos_addr: address of writable word
; Output:
; A: z-depth (0=disabled)
; xpos_addr: address of word containing sprite X position
; ypos_addr: address of word containing sprite Y position
.macro SPRITE_GET_SCREEN_POS idx_addr, xpos_addr, ypos_addr
lda idx_addr
jsr __sprite_get_screen_pos
ldx __sprite_sp_x
stx xpos_addr
ldx __sprite_sp_x+1
stx xpos_addr+1
ldx __sprite_sp_y
stx ypos_addr
ldx __sprite_sp_y+1
stx ypos_addr+1
.endmacro
__sprite_sp_x: .word 0
__sprite_sp_y: .word 0
__sprite_get_screen_pos: ; Input: A: sprite index
; Output:
; A: z-depth
; __sprite_sp_x: sprite X position
; __sprite_sp_y: sprite Y position
jsr __sprattr
lda VERA_data0 ; ignore
lda VERA_data0 ; ignore
lda VERA_data0
sta __sprite_sp_x
lda VERA_data0
sta __sprite_sp_x+1
lda VERA_data0
sta __sprite_sp_y
lda VERA_data0
sta __sprite_sp_y+1
lda VERA_data0
and #$0C
lsr
lsr
rts
; Macro: SPRITE_CHECK_BOX
; Input:
; max: Maximum pixels in either direction between positions
; x1_addr: address of word containing X coordinate of position 1
; y1_addr: address of word containing Y coordinate of position 1
; x2_addr: address of word containing X coordinate of position 2
; y2_addr: address of word containing Y coordinate of position 2
; Output:
; A: 0=outside box; 1: inside box
.macro SPRITE_CHECK_BOX max, x1_addr, y1_addr, x2_addr, y2_addr
lda x1_addr
sta __sprite_cb_x1
lda x1_addr+1
sta __sprite_cb_x1+1
lda y1_addr
sta __sprite_cb_y1
lda y1_addr+1
sta __sprite_cb_y1+1
lda x2_addr
sta __sprite_cb_x2
lda x2_addr+1
sta __sprite_cb_x2+1
lda y2_addr
sta __sprite_cb_y2
lda y2_addr+1
sta __sprite_cb_y2+1
lda #max
jsr __sprite_check_box
.endmacro
__sprite_cb_x1: .word 0
__sprite_cb_y1: .word 0
__sprite_cb_x2: .word 0
__sprite_cb_y2: .word 0
__sprite_check_box: ; Input:
; A: Max pixels in either direction between positions
; __sprite_cb_x1: X coordinate of position 1
; __sprite_cb_y1: X coordinate of position 1
; __sprite_cb_x2: X coordinate of position 2
; __sprite_cb_y1: X coordinate of position 2
; Output:
; A: 0=outside box; 1: inside box
bra @start
@max: .byte 0
@minx: .word 0
@miny: .word 0
@maxx: .word 0
@maxy: .word 0
@start:
sta @max
ldx #0
sec
lda __sprite_cb_x2
sbc @max
sta @minx
lda __sprite_cb_x2+1
sbc #0
sta @minx+1
sec
lda __sprite_cb_y2
sbc @max
sta @miny
lda __sprite_cb_y2+1
sbc #0
sta @miny+1
inc @max
clc
lda __sprite_cb_x2
adc @max
sta @maxx
lda __sprite_cb_x2+1
adc #0
sta @maxx+1
clc
lda __sprite_cb_y2
adc @max
sta @maxy
lda __sprite_cb_y2+1
adc #0
sta @maxy+1
lda __sprite_cb_x1
cmp @minx
lda __sprite_cb_x1+1
sbc @minx+1
bmi @outside
lda __sprite_cb_y1
cmp @miny
lda __sprite_cb_y1+1
sbc @miny+1
bmi @outside
lda @maxx
cmp __sprite_cb_x1
lda @maxx+1
sbc __sprite_cb_x1+1
bmi @outside
lda @maxy
cmp __sprite_cb_y1
lda @maxy+1
sbc __sprite_cb_y1+1
bmi @outside
lda #1
bra @return
@outside:
lda #0
bra @return
@return:
rts
sprite_disable: ; A: sprite index
jsr __sprattr
lda #<(VRAM_TILES >> 5)
sta VERA_data0 ; set to black tile
lda #>(VRAM_TILES >> 5)
sta VERA_data0
lda VERA_data0 ; leave position alone
lda VERA_data0
lda VERA_data0
lda VERA_data0
stz VERA_data0 ; disable
rts
sprite_set_po: ; A: sprite index
; X: palette offset
jsr __sprattr
lda VERA_data0 ; ignore
lda VERA_data0 ; ignore
lda VERA_data0 ; ignore
lda VERA_data0 ; ignore
lda VERA_data0 ; ignore
lda VERA_data0 ; ignore
lda VERA_data0 ; ignore
txa
ora #$50
sta VERA_data0
rts
sprite_setpos: ; A: Bit 7: tile layer, Bits 6-0: sprite index
; X: tile x
; Y: tile y
bra @start
@xpos: .word 0
@ypos: .word 0
@start:
pha
stx @xpos
stz @xpos+1
asl @xpos
rol @xpos+1
asl @xpos
rol @xpos+1
asl @xpos
rol @xpos+1
sty @ypos
stz @ypos+1
asl @ypos
rol @ypos+1
asl @ypos
rol @ypos+1
asl @ypos
rol @ypos+1
and #$80
bne @layer1
lda VERA_L0_tilebase
bra @get_regs
@layer1:
lda VERA_L1_tilebase
@get_regs:
pha
bit #$02
beq @check_tilew
asl @ypos
rol @ypos+1
@check_tilew:
pla
bit #$01
beq @move_sprite
asl @xpos
rol @xpos+1
@move_sprite:
pla
and #$7F
jsr __sprattr
lda VERA_data0 ; ignore
lda VERA_data0
lda @xpos
sta VERA_data0
lda @xpos+1
sta VERA_data0
lda @ypos
sta VERA_data0
lda @ypos+1
sta VERA_data0
rts
.macro SPRITE_SET_SCREEN_POS index_addr, xpos_addr, ypos_addr
; Input:
; idx_addr: address of byte containing sprite index
; xpos_addr: address of word containing X position
; ypos_addr: address of word containing Y position
lda index_addr
jsr __sprattr
lda VERA_data0 ; use current frame for now
lda VERA_data0
lda xpos_addr
sta VERA_data0
lda xpos_addr+1
sta VERA_data0
lda ypos_addr
sta VERA_data0
lda ypos_addr+1
sta VERA_data0
.endmacro
.endif