-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtwist.s
827 lines (702 loc) · 13.1 KB
/
twist.s
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
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
.include "global.i"
;-------------------------------------------------------------------------------
.segment "ZEROPAGE": zeropage
TextDrawPtr: .res 2
TextOAMPtr: .res 2
TextDrawWait: .res 2
TwistPos: .res 2
; control which scanlines each twister is actually visible on
; (for transtions)
Twist1MinY: .res 2
Twist1MaxY: .res 2
Twist2MinY: .res 2
Twist2MaxY: .res 2
;-------------------------------------------------------------------------------
.segment "LORAM"
; X+Y scroll HDMA tables for BG1 and BG2
TwistPosTable1: .res 224*4 ; 2 x bytes + 2 y bytes
TwistPosTable2: .res 224*4 ; 2 x bytes + 2 y bytes
; color math enable table for BG2 (controls bg2 blend switching)
TwistMapTable: .res 224
; palette HDMA tables
TwistColorTable1: .res 224*2
TwistColorTable2: .res 224*2
TwistColorTable3: .res 224*2
TwistColorTable4: .res 224*2
;-------------------------------------------------------------------------------
.segment "ROM0" ; putting here to save space in ROM1
incbin TwistTiles, "data/twist.png.tiles.lz4"
incbin TwistMap, "data/twist.png.map.lz4"
;-------------------------------------------------------------------------------
.segment "RODATA"
IntroText:
.include "data/introtext.i"
TwistPosPtrTable1:
.byte $80+127
.word .loword(TwistPosTable1)
.byte $80+97
.word .loword(TwistPosTable1+508)
.byte 0
TwistPosPtrTable2:
.byte $80+127
.word .loword(TwistPosTable2)
.byte $80+97
.word .loword(TwistPosTable2+508)
.byte 0
TwistMapPtrTable:
.byte $80+127
.word .loword(TwistMapTable)
.byte $80+97
.word .loword(TwistMapTable+127)
.byte 0
TwistColorClearTable:
.repeat 2
.byte $ff
.repeat 127
.byte 4
.endrepeat
.endrepeat
.byte 0
TwistColorPtrTable1:
.byte $80+127
.word .loword(TwistColorTable1)
.byte $80+97
.word .loword(TwistColorTable1+254)
.byte 0
TwistColorPtrTable2:
.byte $80+127
.word .loword(TwistColorTable2)
.byte $80+97
.word .loword(TwistColorTable2+254)
.byte 0
TwistColorPtrTable3:
.byte $80+127
.word .loword(TwistColorTable3)
.byte $80+97
.word .loword(TwistColorTable3+254)
.byte 0
TwistColorPtrTable4:
.byte $80+127
.word .loword(TwistColorTable4)
.byte $80+97
.word .loword(TwistColorTable4+254)
.byte 0
TwistSineTable:
.include "data/twistsine.i"
; color tables
.include "data/twistcolor.i"
;-------------------------------------------------------------------------------
.segment "CODE"
; VRAM addresses for twister texture
VRAM_TILEMAP = $0000
VRAM_TILEMAP2 = $1000
VRAM_CHARSET = $2000
;-------------------------------------------------------------------------------
proc InitTextSprites
jsl ClearMainSprites
; use all but the last four OAM slots for text
; which gives us 28 chars per line, 9 lines per page
LINE_SPACING = 16
LETTER_SPACING = 10
; sprite X coords
ldx #0
clc
lda #28
:
sta OAM_low,x
sta OAM_low+(20*4),x
sta OAM_low+(20*8),x
sta OAM_low+(20*12),x
sta OAM_low+(20*16),x
sta OAM_low+(20*20),x
adc #LETTER_SPACING
inx
inx
inx
inx
cpx #20*4
bcc :-
; sprite Y coords
ldx #0
clc
:
lda #48
sta OAM_low+1,x
adc #LINE_SPACING
sta OAM_low+1+(20*4),x
adc #LINE_SPACING
sta OAM_low+1+(20*8),x
adc #LINE_SPACING
sta OAM_low+1+(20*12),x
adc #LINE_SPACING
sta OAM_low+1+(20*16),x
adc #LINE_SPACING
sta OAM_low+1+(20*20),x
inx
inx
inx
inx
cpx #20*4
bcc :-
; sprite attributes (max priority, palette #0, low tile num)
lda #%00110000
ldx #0
:
sta OAM_low+3,x
sta OAM_low+3+(20*4),x
sta OAM_low+3+(20*8),x
sta OAM_low+3+(20*12),x
sta OAM_low+3+(20*16),x
sta OAM_low+3+(20*20),x
inx
inx
inx
inx
cpx #20*4
bcc :-
rts
endproc
;-------------------------------------------------------------------------------
proc InitTwistGfx
; load twister graphics
LZ4_decompress TwistMap, EXRAM, y
WAIT_vbl
VRAM_memcpy VRAM_TILEMAP, EXRAM, y
LZ4_decompress TwistTiles, EXRAM, y
WAIT_vbl
VRAM_memcpy VRAM_CHARSET, EXRAM, y
rts
endproc
;-------------------------------------------------------------------------------
proc UpdateText
ldx z:TextDrawWait
beq :+
dex
stx z:TextDrawWait
bra end
; get next char
:
ldx z:TextOAMPtr
ldy z:TextDrawPtr
lda IntroText,y
bne :+
; end of text - exit part
VBL_task VBLTask_HideTwisters
lda #$40
tsb z:PartStatus
bra end
:
; otherwise set sprite char
sta OAM_low+2,x
iny
sty z:TextDrawPtr
inx
inx
inx
inx
stx z:TextOAMPtr
cpx #(20*6*4)
bcc end
; end of page - wait a while
ldx #0
stx z:TextOAMPtr
ldx IntroText,y
stx z:TextDrawWait
iny
iny
sty z:TextDrawPtr
end:
rts
endproc
; -----------------------------------------------------
; vblank thread - manage DMA/HDMA, perform effect tasks
; -----------------------------------------------------
;-------------------------------------------------------------------------------
proc TwistPartVBL
; make sure DB is correct (will apply to VBLTask too)
phk
plb
; enable HDMA
HDMA_set_absolute 0, 0, CGADD, TwistColorClearTable
HDMA_set_indirect 1, 2, CGDATA, TwistColorPtrTable1, TwistColorTable1
HDMA_set_indirect 2, 2, CGDATA, TwistColorPtrTable2, TwistColorTable2
HDMA_set_indirect 3, 2, CGDATA, TwistColorPtrTable3, TwistColorTable3
HDMA_set_indirect 4, 2, CGDATA, TwistColorPtrTable4, TwistColorTable4
HDMA_set_indirect 5, 3, BG1HOFS, TwistPosPtrTable1, TwistPosTable1
HDMA_set_indirect 6, 3, BG2HOFS, TwistPosPtrTable2, TwistPosTable2
HDMA_set_indirect 7, 0, CGADSUB, TwistMapPtrTable, TwistMapTable
RW a8
lda #$ff
sta HDMAEN
bit z:PartStatus
bvs :+
jsr UpdateText
:
rtl
endproc
;-------------------------------------------------------------------------------
; vblank task 1 - fade screen in
proc VBLTask_FadeIn
lda z:SFX_tick
; increase brightness on every 2nd tick
and #$01
bne end
lda z:SFX_inidisp
and #$7f
; fade in done?
cmp #$0f
beq :+
inc
sta z:SFX_inidisp
rtl
:
; next task
; show first twister after a few seconds
VBL_task VBLTask_ShowTwister1, 60*6
end:
rtl
endproc
;-------------------------------------------------------------------------------
; vblank task 2 - introduce first twister
proc VBLTask_ShowTwister1
ldx z:Twist1MinY
dex
dex
stx z:Twist1MinY
bne end
; next task
; show first twister after a few more seconds
VBL_task VBLTask_ShowTwister2, 60*6
end:
rtl
endproc
;-------------------------------------------------------------------------------
; vblank task 3 - introduce second twister
proc VBLTask_ShowTwister2
ldx z:Twist2MinY
dex
dex
stx z:Twist2MinY
bne end
; last task will be set once text ends
VBL_task_stop
end:
rtl
endproc
;-------------------------------------------------------------------------------
; final vblank task - remove twisters
proc VBLTask_HideTwisters
ldx z:Twist1MinY
inx
inx
stx z:Twist1MinY
ldx z:Twist2MaxY
dex
dex
stx z:Twist2MaxY
bne end
VBL_task_stop
lda #$80 ; signal to exit part
tsb z:PartStatus
end:
rtl
endproc
; ----------------------------------------------
; main thread - do all init & run twister effect
; ----------------------------------------------
proc TwistPartMain
phb
phk
plb
VBL_part_stop
jsr InitTwistGfx
WAIT_vbl
; BG1 is used for the main twister, BG2 is used for the translucent twister
; and color math settings is switched to do 'in front/behind' effect
; set up screen (mode 1, all 8x8 tiles)
lda #bgmode(BG_MODE_1, BG3_PRIO_NORMAL, BG_SIZE_8X8, BG_SIZE_8X8, BG_SIZE_8X8, BG_SIZE_8X8)
sta BGMODE
; set up layer 1 + 2 tilemaps
lda #bgsc(VRAM_TILEMAP, SC_SIZE_64X32)
sta BG1SC
lda #bgsc(VRAM_TILEMAP2, SC_SIZE_64X32)
sta BG2SC
; set up tileset for layers 1 + 2
lda #bg12nba(VRAM_CHARSET, VRAM_CHARSET)
sta BG12NBA
; disable any previous HDMA stuff
stz HDMAEN
; enable layer 1, 3 and sprites on mainscreen
lda #tm(ON, OFF, ON, OFF, ON)
sta TM
; enable layer and 2 on subscreen (for the blend)
lda #tm(OFF, ON, OFF, OFF, OFF)
sta TS
; set up color math
lda #$00 ; color math on entire screen
sta WOBJSEL
lda #$02 ; enable sub screen BG/OBJ color math
sta CGSWSEL
lda #$e0
sta COLDATA
; clear Y-offset tables
RW_push set:a16
lda #$ffff
ldx #0
:
stz TwistPosTable1,x ; X
stz TwistPosTable2,x ; X
inx
inx
sta TwistPosTable1,x ; Y
sta TwistPosTable2,x ; Y
inx
inx
dec
cpx #(224*4)
bcc :-
RW_pull
; clear BG2 map table
ldx #0
lda #0
:
sta TwistMapTable,x
inx
cpx #224
bcc :-
jsr InitTextSprites
jsr TwistPosPrecalc
; set initial vblank task
VBL_part TwistPartVBL
VBL_task VBLTask_FadeIn
; set initial text delay
ldx #60
stx z:TextDrawWait
; reset text
ldx #0
stx z:TextDrawPtr
stx z:TextOAMPtr
; set initial twist positions
ldx #224
stx z:Twist1MinY
stx z:Twist1MaxY
stx z:Twist2MinY
stx z:Twist2MaxY
loop:
WAIT_vbl
jsr UpdateTwistPos1
WAIT_vbl
jsr UpdateTwistPos2
bit z:PartStatus
bpl loop
WAIT_vbl
; turn off twist graphics
lda #tm(OFF, OFF, ON, OFF, ON)
sta TM
stz TS
VBL_part_stop
stz z:PartStatus
plb
rtl
endproc
;-------------------------------------------------------------------------------
; ----------------------------------
; calculate some twister sine tables
; ----------------------------------
TwistPosBase = HIRAM
TwistPosBaseAdd = HIRAM+$1000
proc TwistPosPrecalc
php
RW a16i16
ldx #0
:
txa
lsr
pha
asl
pha
asl
clc
adc 1,s
adc 3,s
ply
ply
and #$7fe
tay
lda TwistSineTable,y
sta f:TwistPosBase,x
inx
inx
cpx #$1000
bcc :-
ldx #0
:
txa
asl
tay
lda TwistSineTable,y
; lsr
clc
; adc TwistSineTable,y
; lsr
lsr
lsr
sta f:TwistPosBaseAdd,x
inx
inx
cpx #$400
bcc :-
plp
rts
endproc
;-------------------------------------------------------------------------------
; --------------------------
; BG1 twister update routine
; --------------------------
cy = ZPAD+0 ; decrements each line
cy2 = ZPAD+2 ; increments each line
sin1 = ZPAD+4
PhaseColor = ZPAD+6
proc UpdateTwistPos1
php
RW a16i16
dec z:TwistPos
stz z:cy
stz z:cy2
ldy #0
loop:
; make sure we want to display this line right now
ldx z:cy2
cpx z:Twist1MinY
bcc :+ ; less than min = don't show
cpx z:Twist1MaxY
bcc :++ ; less than max = do show
:
lda #$100
sta TwistPosTable1,y
sta TwistPosTable1+4,y
jmp end
:
; calc x for line
; get base x value
lda z:TwistPos
asl
and #$ffe
tax
lda f:TwistPosBase,x
sta z:sin1
; double sine with added y-term
clc
adc z:SFX_tick
adc z:SFX_tick
adc z:cy
asl
and #$3fe
tax
lda f:TwistPosBaseAdd,x
lsr
lsr
sta TwistPosTable1,y
sta TwistPosTable1+4,y
; interpolate inbetween lines
cpy #0
beq :++
pha
adc TwistPosTable1-4,y
cmp #$0100 ; was previous line offscreen?
bcs :+
lsr
sta TwistPosTable1-4,y
:
pla
:
; calc y for line
; get base twist value
lda z:TwistPos
clc
adc z:sin1
adc z:cy2
adc z:cy2
lsr
lsr
lsr
clc
adc z:sin1
asl
and #$7fe
tax
lda TwistSineTable,x
; account for current scanline in scroll value
pha
clc
adc z:cy
sta TwistPosTable1+2,y
dec
sta TwistPosTable1+6,y
; get color values
pla
and #$ff
asl
sta z:PhaseColor
eor #$0100
tax
lda TwistColor1,x
pha
ldx z:PhaseColor
lda TwistColor1,x
pha
; store color values to HDMA tables
tya
lsr
tax
pla
sta TwistColorTable2,x
sta TwistColorTable2+2,x
pla
sta TwistColorTable1,x
sta TwistColorTable1+2,x
end:
dec z:cy
dec z:cy
inc z:cy2
inc z:cy2
clc
tya
adc #8
tay
cpy #224*4
jcc loop
plp
rts
endproc
;-------------------------------------------------------------------------------
; --------------------------
; BG2 twister update routine
; --------------------------
; table of distance/layer priority values
PRIO_TABLE_PHASE = 256
TwistPrioTest:
.repeat 512-PRIO_TABLE_PHASE
.byte %00101100
.endrepeat
.repeat 512
.byte %00101101
.endrepeat
.repeat PRIO_TABLE_PHASE
.byte %00101100
.endrepeat
proc UpdateTwistPos2
php
RW a16i16
; dec z:TwistPos
stz z:cy
stz z:cy2
ldy #0
loop:
; make sure we want to display this line right now
ldx z:cy2
cpx z:Twist2MinY
bcc :+ ; less than min = don't show
cpx z:Twist2MaxY
bcc :++ ; less than max = do show
:
lda #$100
sta TwistPosTable2,y
sta TwistPosTable2+4,y
jmp end
:
; calc x for line
; get base x value
lda z:TwistPos
asl
and #$ffe
tax
lda f:TwistPosBase,x
sta z:sin1
; double sine with added y-term
clc
adc z:SFX_tick
adc z:SFX_tick
adc z:cy
adc #$100 ; phase shift for #2
asl
and #$3fe
tax
; use the current sine position to determine layer visibility on this line
phx
lda TwistPrioTest,x
ldx z:cy2
sta TwistMapTable,x
plx
; and then update X position using same index
lda f:TwistPosBaseAdd,x
; lsr
lsr
sta TwistPosTable2,y
sta TwistPosTable2+4,y
; interpolate inbetween lines
cpy #0
beq :++
pha
adc TwistPosTable2-4,y
cmp #$0100 ; was previous line offscreen?
bcs :+
lsr
sta TwistPosTable2-4,y
:
pla
:
; calc y for line
; get base twist value
lda z:cy
lsr
lsr
clc
adc z:sin1
asl
and #$7fe
tax
lda TwistSineTable,x
; account for current scanline in scroll value
pha
clc
adc z:cy
sta TwistPosTable2+2,y
dec
sta TwistPosTable2+6,y
; get color values
pla
and #$ff
asl
sta z:PhaseColor
eor #$0100
tax
lda TwistColor2,x
pha
ldx z:PhaseColor
lda TwistColor2,x
pha
; store color values to HDMA tables
tya
lsr
tax
pla
sta TwistColorTable4,x
sta TwistColorTable4+2,x
pla
sta TwistColorTable3,x
sta TwistColorTable3+2,x
end:
dec z:cy
dec z:cy
inc z:cy2
inc z:cy2
clc
tya
adc #8
tay
cpy #224*4
jcc loop
plp
rts
endproc