SHOW:
|
|
- or go back to the newest paste.
1 | @include | |
2 | ;=============================================================================== | |
3 | ; LazyHDMA by ExoticMatter | |
4 | ; | |
5 | ; This libraryis a simple way to manage multiple HDMA effects without having | |
6 | ; to copy/paste a lot of code. | |
7 | ; | |
8 | ; To use LazyHDMA, incsrc lazyhdma.asm once from uberASM or levelASM. Then, use | |
9 | ; code such as the following: | |
10 | ; | |
11 | ; level105init: | |
12 | ; %LazyInitEffect(MyGradient) | |
13 | ; RTS | |
14 | ; | |
15 | ; MyGradient: | |
16 | ; %LazyBGDouble(3, .RedGreen) | |
17 | ; %LazyBGSingle(4, .Blue) | |
18 | ; %LazyEnd() | |
19 | ; | |
20 | ; .RedGreen and .Blue are HDMA tables. Using sublabels is not required. | |
21 | ; To use a table that is in a different bank, use the _Long suffix. Otherwise, | |
22 | ; the table must be in the same bank as the descriptor. | |
23 | ; | |
24 | ; Make sure to apply IceMan's HDMA patch to prevent common HDMA problems | |
25 | ; including disappearing HDMA, flickering, and gradients that briefly appear | |
26 | ; when going through a pipe or door. | |
27 | ; http://www.smwcentral.net/?p=section&a=details&id=4176 | |
28 | ;=============================================================================== | |
29 | ; Main macros: | |
30 | ; | |
31 | ; %LazyInitEffect[_Tail](effect) - Initializes an HDMA effect. | |
32 | ; This macro will set A, X, and Y to 8-bit and overwrite scratch RAM. | |
33 | ; The _Tail suffix causes the subroutine to not return. This can only be | |
34 | ; used where RTS can be used. (Or RTL, if !LongCall is nonzero.) | |
35 | ; %LazyInitEffect only needs to be called once. Initializing an effect | |
36 | ; that contains a scrolling gradient every frame will induce slowdown. | |
37 | ; | |
38 | ; %LazyRunEffect[_Tail](effect) - Runs an HDMA effect. | |
39 | ; Like %LazyInitEffect, this macro sets A, X, and Y to 8-bit and overwrite | |
40 | ; scratch RAM. | |
41 | ; Only scrolling gradients need to be run every frame. | |
42 | ; LazyHDMA does not update parallax effects at this point in time. | |
43 | ;=============================================================================== | |
44 | ; Definition macros: | |
45 | ; | |
46 | ; %LazyBaseBG(color) - Defines the background color in BGR15 format. | |
47 | ; Use rgb(r, g, b) to create a BGR15 color: | |
48 | ; %LazyBaseBG(rgb(31,31,31)) | |
49 | ; | |
50 | ; %LazyHDMA[_Long](channel, parameters, register, address) - Defines an HDMA | |
51 | ; channel with the specified properties. | |
52 | ; <register> must be between $2100-$21FF, although $00-$FF are also | |
53 | ; allowed. | |
54 | ; | |
55 | ; %LazyBGSingle[_Long](channel, address) - Defines a background HDMA channel | |
56 | ; that writes once per scanline, i.e. transfer mode 0. | |
57 | ; | |
58 | ; %LazyBGDouble[_Long](channel, address) - Defines a background HDMA channel | |
59 | ; that writes twice per scanline, i.e. transfer mode 2. | |
60 | ; | |
61 | ; %LazyCGRAM[_Long](channel, address) - Defines a palette HDMA channel that | |
62 | ; writes to two registers twice per scanline, i.e. transfer mode 3. | |
63 | ; | |
64 | ; %LazyBrightness[_Long](channel, address) - Defines a brightness HDMA channel | |
65 | ; that writes to one register once per scanline, i.e. transfer mode 0. | |
66 | ; | |
67 | ; %LazyScroll[_Long](channelAB, channelC, address) - Defines a scrolling | |
68 | ; background HDMA gradient that is decompressed into memory. | |
69 | ; For the scrolling to occur, you must call %Lazy | |
70 | ; | |
71 | ; %LazyEnd() - Marks the end of the effect. | |
72 | ;=============================================================================== | |
73 | ; Configuration: | |
74 | ; | |
75 | ; !LongCall: If set to a nonzero value, LazyHDMA will use JSL/JSR, allowing | |
76 | ; LazyHDMA to be called from a different bank. Off by default. | |
77 | ; | |
78 | ; !IncludeScrollingGradientCode: If set to a nonzero value, the scrolling | |
79 | ; gradient routines will be included. Off by default. | |
80 | ; | |
81 | ; !ScrollingFreeRAM_(AB|C): The location to put decompressed scrolling gradient | |
82 | ; tables. By default, $7F:B260 and $7F:B830 are used, respectively. | |
83 | ; | |
84 | ; To configure LazyHDMA, set one or more of these defines before incsrc. | |
85 | ;=============================================================================== | |
86 | !LongCall ?= 0 | |
87 | !IncludeScrollingGradientCode ?= 0 | |
88 | ||
89 | !ScrollingFreeRAM_AB ?= $7FB260 | |
90 | !ScrollingFreeRAM_C ?= $7FB830 | |
91 | ||
92 | if !LongCall | |
93 | !LazyHDMA_Call = JSL : !LazyHDMA_CallS = "JSL " | |
94 | !LazyHDMA_Tail = JML : !LazyHDMA_TailS = "JML " | |
95 | !LazyHDMA_Return = RTL : !LazyHDMA_ReturnS = "RTL " | |
96 | else | |
97 | !LazyHDMA_Call = JSR.w : !LazyHDMA_CallS = "JSR.w " | |
98 | !LazyHDMA_Tail = JMP.w : !LazyHDMA_TailS = "JMP.w " | |
99 | !LazyHDMA_Return = RTS : !LazyHDMA_ReturnS = "RTS " | |
100 | endif | |
101 | ||
102 | macro _LazyHDMA_LoadLong(effect) | |
103 | SEP #$30 | |
104 | LDA.b #<effect> | |
105 | LDY.b #<effect>>>8 | |
106 | LDX.b #<effect>>>16 | |
107 | endmacro | |
108 | ||
109 | _LazyHDMA: | |
110 | ||
111 | macro LazyInitEffect(effect) | |
112 | %_LazyHDMA_LoadLong(<effect>) | |
113 | !LazyHDMA_Call .InitializeEffect | |
114 | endmacro | |
115 | ||
116 | macro LazyInitEffect_Tail(effect) | |
117 | %_LazyHDMA_LoadLong(<effect>) | |
118 | !LazyHDMA_Tail .InitializeEffect | |
119 | endmacro | |
120 | ||
121 | if !IncludeScrollingGradientCode | |
122 | macro LazyRunEffect(effect) | |
123 | %_LazyHDMA_LoadLong(<effect>) | |
124 | !LazyHDMA_Call .RunEffect | |
125 | endmacro | |
126 | ||
127 | macro LazyRunEffect_Tail(effect) | |
128 | %_LazyHDMA_LoadLong(<effect>) | |
129 | !LazyHDMA_Tail .RunEffect | |
130 | endmacro | |
131 | else | |
132 | macro LazyRunEffect(effect) | |
133 | endmacro | |
134 | macro LazyRunEffect_Tail(effect) | |
135 | endmacro | |
136 | endif | |
137 | ||
138 | !HDMA_ColorData = $2132 | |
139 | !HDMA_Brightness = $2100 | |
140 | !HDMA_CGRAM = $2121 | |
141 | ||
142 | !LazyHDMA_CommandMask = $1F | |
143 | !LazyHDMA_ChannelMask = $E0 | |
144 | ||
145 | macro _LazyHDMA_LoadArgs() | |
146 | STA $00 ; Descriptor pointer, LSB | |
147 | STY $01 ; Descriptor pointer, MSB | |
148 | STX $02 ; Descriptor pointer, Bank | |
149 | ; STX $03 ; Other address bank (initialization only) | |
150 | ||
151 | ; $04 ; HDMA index (channel << 4) | |
152 | ; $05 ; second HDMA index (scrolling gradients only) | |
153 | endmacro | |
154 | ||
155 | .InitializeEffect | |
156 | %_LazyHDMA_LoadArgs() | |
157 | STX $03 | |
158 | ||
159 | - SEP #$30 ; 8-bit A, X, Y | |
160 | LDA [$00] | |
161 | AND #!LazyHDMA_CommandMask | |
162 | BEQ + | |
163 | ASL | |
164 | TAX | |
165 | LDA [$00] | |
166 | AND #!LazyHDMA_ChannelMask | |
167 | LSR | |
168 | STA $04 | |
169 | ||
170 | REP #$20 ; 16-bit A | |
171 | INC $00 | |
172 | JSR (.Subroutines-2, X) | |
173 | BRA - | |
174 | ||
175 | + !LazyHDMA_Return | |
176 | ||
177 | !_LazySubroutine = 1 | |
178 | !_LazySubroutineSizes = 1 | |
179 | ||
180 | macro _LazySubroutine(name, size) | |
181 | assert !_LazySubroutine <= !LazyHDMA_CommandMask | |
182 | !LazyHDMA_<name> #= !_LazySubroutine | |
183 | !_LazySubroutine #= !_LazySubroutine+1 | |
184 | !_LazySubroutineSizes += ,<size> | |
185 | dw .Set<name> | |
186 | endmacro | |
187 | ||
188 | macro _LazySkip() | |
189 | dw $0000 | |
190 | !_LazySubroutine #= !_LazySubroutine+1 | |
191 | !_LazySubroutineSizes += ,<size> | |
192 | endmacro | |
193 | ||
194 | .Subroutines | |
195 | %_LazySubroutine(LongPtr, 2) | |
196 | %_LazySubroutine(BG, 3) | |
197 | %_LazySubroutine(BGDouble, 3) | |
198 | %_LazySubroutine(CGRAM, 3) | |
199 | %_LazySubroutine(Brightness, 3) | |
200 | if !IncludeScrollingGradientCode | |
201 | %_LazySubroutine(ScrollGradient, 4) | |
202 | else | |
203 | %_LazySkip(4) | |
204 | endif | |
205 | %_LazySubroutine(HDMA, 5) | |
206 | %_LazySubroutine(BGFill, 3) | |
207 | ||
208 | if !IncludeScrollingGradientCode | |
209 | .SubroutineSizes db !_LazySubroutineSizes | |
210 | endif | |
211 | ||
212 | !LazyHDMA_Invalid = !_LazySubroutine | |
213 | ||
214 | .SetLongPtr | |
215 | SEP #$20 ; \ 8-bit A | |
216 | LDA [$00] ; | \ Set the source bank number | |
217 | STA $03 ; | / | |
218 | REP #$20 ; / 16-bit A | |
219 | INC $00 ; Next | |
220 | RTS | |
221 | ||
222 | .SetBGFill | |
223 | LDA [$00] | |
224 | STA $0701 | |
225 | INC $00 | |
226 | INC $00 | |
227 | RTS | |
228 | ||
229 | .SetBG | |
230 | LDA.w #!HDMA_ColorData<<8 | |
231 | .SimpleCommon | |
232 | LDX $04 | |
233 | STA $4300,X | |
234 | LDA [$00] | |
235 | STA $4302,X | |
236 | SEP #$20 ; 8-bit A | |
237 | LDA $03 | |
238 | STA $4304,X | |
239 | TXA | |
240 | LSR #4 | |
241 | TAX | |
242 | LDA .Bits,X | |
243 | TSB $0D9F | |
244 | REP #$20 ; 16-bit A | |
245 | INC $00 | |
246 | INC $00 | |
247 | LDX $02 ; \ Restore the data table bank | |
248 | STX $03 ; / to the same bank as the descriptor | |
249 | RTS | |
250 | ||
251 | .SetBGDouble | |
252 | LDA.w #(!HDMA_ColorData<<8)|2 | |
253 | BRA .SimpleCommon | |
254 | .SetCGRAM | |
255 | LDA.w #(!HDMA_CGRAM<<8)|3 | |
256 | BRA .SimpleCommon | |
257 | .SetBrightness | |
258 | LDA.w #!HDMA_Brightness<<8 | |
259 | BRA .SimpleCommon | |
260 | .SetHDMA | |
261 | LDA [$00] | |
262 | INC $00 | |
263 | INC $00 | |
264 | BRA .SimpleCommon | |
265 | ||
266 | .Bits db %00000001,%00000010,%00000100,%00001000,%00010000,%00100000,%01000000,%10000000 | |
267 | ||
268 | if !IncludeScrollingGradientCode | |
269 | .SetScrollGradient | |
270 | LDY #$02 ; \ | |
271 | LDA [$00],Y ; | Load the second HDMA channel | |
272 | TAX ; | number and store it to scratch RAM | |
273 | STX $05 ; / | |
274 | ||
275 | LDA $04 ; \ | |
276 | PHA ; | | |
277 | LDX $02 ; | | |
278 | PHX ; | | |
279 | LDA $00 ; | Preserve scratch RAM | |
280 | INC A ; | \ | |
281 | INC A ; | | Advance the command pointer | |
282 | INC A ; | / | |
283 | PHA ; / | |
284 | LDA [$00] ; Load table pointer | |
285 | PHB ; Preserve data bank | |
286 | LDX $03 ; \ | |
287 | PHX ; | Set data bank | |
288 | PLB ; / | |
289 | ||
290 | REP #$30 ; 16-bit A, X, Y | |
291 | STA $02 | |
292 | INC | |
293 | STA $04 | |
294 | INC | |
295 | STA $06 | |
296 | INC | |
297 | STA $08 | |
298 | LDA.w #!ScrollingFreeRAM_AB | |
299 | STA $0A | |
300 | LDA.w #!ScrollingFreeRAM_C | |
301 | STA $0D | |
302 | SEP #$20 ; 8-bit A | |
303 | LDA #!ScrollingFreeRAM_AB>>16 | |
304 | STA $0C | |
305 | if !ScrollingFreeRAM_AB>>16 != !ScrollingFreeRAM_C>>16 | |
306 | LDA #!ScrollingFreeRAM_C>>16 | |
307 | endif | |
308 | STA $0F | |
309 | - LDA ($02) | |
310 | BEQ + | |
311 | STA $00 | |
312 | -- LDA #$01 | |
313 | STA [$0A] | |
314 | STA [$0D] | |
315 | LDY #$0001 | |
316 | LDA ($04) | |
317 | STA [$0A],y | |
318 | LDA ($08) | |
319 | STA [$0D],y | |
320 | INY | |
321 | LDA ($06) | |
322 | STA [$0A],y | |
323 | REP #$20 | |
324 | INC $0A | |
325 | INC $0A | |
326 | INC $0A | |
327 | INC $0D | |
328 | INC $0D | |
329 | SEP #$20 | |
330 | DEC $00 | |
331 | BPL -- | |
332 | REP #$20 | |
333 | LDA $02 | |
334 | CLC | |
335 | ADC #$0004 | |
336 | STA $02 | |
337 | INC | |
338 | STA $04 | |
339 | INC | |
340 | STA $06 | |
341 | INC | |
342 | STA $08 | |
343 | SEP #$20 | |
344 | BRA - | |
345 | ||
346 | + PLB ; Restore previous data bank number | |
347 | SEP #$10 ; Restore 8-bit X, Y | |
348 | REP #$20 ; Restore 16-bit A | |
349 | PLA ; \ | |
350 | STA $00 ; | | |
351 | PLX ; | | |
352 | STX $02 ; | Restore scratch RAM | |
353 | STX $03 ; | | Restore the data source bank | |
354 | PLA ; | | |
355 | STA $04 ; / | |
356 | ||
357 | TAX ; \ Load the HDMA indexes | |
358 | LDY $05 ; / | |
359 | ||
360 | LDA.w #(!HDMA_ColorData<<8)|2 ; \ | |
361 | STA $4300,X ; | Set HDMA channel types | |
362 | LDA.w #!HDMA_ColorData<<8 ; | | |
363 | STA $4300,Y ; / | |
364 | ||
365 | SEP #$20 ; 8-bit A | |
366 | TXA ; \ | |
367 | LSR #4 ; | | |
368 | TAX ; | Enable gradient A | |
369 | LDA .Bits,X ; | | |
370 | TSB $0D9F ; / | |
371 | TYA ; \ | |
372 | LSR #4 ; | | |
373 | TAX ; | Enable gradient B | |
374 | LDA .Bits,X ; | | |
375 | TSB $0D9F ; / | |
376 | REP #$20 ; 16-bit A | |
377 | ||
378 | .ScrollGradient: | |
379 | LDA $20 ; \ Load the Y-position of BG2 | |
380 | LDX $1414 ; | \ Check how much the gradient should be shifted upward | |
381 | CPX #$01 ; | | \ | |
382 | BEQ .Const ; | | / #$01: Constant | |
383 | CPX #$02 ; | | \ | |
384 | BEQ .Var ; | | / #$02: Variable | |
385 | CPX #$03 ; | | \ | |
386 | BEQ .Slow ; | | / #$03: Slow | |
387 | ; | | | |
388 | .None ; | | \ No scrolling (consider using fixed HDMA) | |
389 | SEC ; | | | | |
390 | SBC #$00C0 ; | | | shift 192 pixels downward | |
391 | BRA .Const ; | | / Continue | |
392 | ; | | | |
393 | .Slow ; | | \ Slow scrolling (consider using fixed HDMA) | |
394 | SEC ; | | | | |
395 | SBC #$00A8 ; | | | shift 168 pixels downward | |
396 | BRA .Const ; | | / | |
397 | ; | | | |
398 | .Var ; | | \ Variable scrolling | |
399 | SEC ; | | | | |
400 | SBC #$0060 ; | | / shift 96 pixels downward | |
401 | ; | | | |
402 | .Const ; | / < Constant scrolling (BG2:Camera = 1:1) | |
403 | ; | | |
404 | ; | \ Put an LSR/ASL or two here to change the rate at which | |
405 | ; | / the gradient scrolls. | |
406 | ; | | |
407 | STA $06 ; / and store it to scratch RAM. | |
408 | ||
409 | LDX $04 ; \ Load the HDMA indexes | |
410 | LDY $05 ; / | |
411 | ||
412 | LDA $06 | |
413 | ASL ; \ | |
414 | CLC ; | This transforms the Y-pos of BG2 | |
415 | ADC $06 ; | into the address at which the HDMA | |
416 | CLC ; | gradient should start | |
417 | ADC.w #!ScrollingFreeRAM_AB | |
418 | STA $4302,X ; HDMA Channel A table starting address. | |
419 | ||
420 | LDA $06 ; \ | |
421 | ASL ; | Y-pos of BG2 to | |
422 | CLC ; | HDMA table offset | |
423 | ADC.w #!ScrollingFreeRAM_C | |
424 | STA $4302,Y ; HDMA Channel B table starting address. | |
425 | ||
426 | SEP #$20 ; 8-bit A | |
427 | LDA.b #!ScrollingFreeRAM_AB>>16 | |
428 | STA $4304,X | |
429 | if !ScrollingFreeRAM_AB>>16 != !ScrollingFreeRAM_C>>16 | |
430 | LDA.b #!ScrollingFreeRAM_C>>16 | |
431 | endif | |
432 | STA $4304,Y | |
433 | ||
434 | RTS | |
435 | ||
436 | .RunEffect: | |
437 | %_LazyHDMA_LoadArgs() | |
438 | ||
439 | - SEP #$30 ; 8-bit A, X, Y | |
440 | LDA [$00] | |
441 | AND #!LazyHDMA_CommandMask | |
442 | BEQ + | |
443 | CMP.b #!LazyHDMA_ScrollGradient | |
444 | BEQ ++ | |
445 | TAX | |
446 | LDA .SubroutineSizes,X | |
447 | CLC | |
448 | REP #$20 ; 16-bit A | |
449 | AND #$00FF | |
450 | ADC $00 | |
451 | STA $00 | |
452 | BRA - ; Repeat | |
453 | ||
454 | ++ LDA [$00] | |
455 | AND #!LazyHDMA_ChannelMask | |
456 | LSR | |
457 | STA $04 | |
458 | ||
459 | LDY #$04 ; \ | |
460 | LDA [$00],Y ; | Load the second channel number | |
461 | STA $05 ; / | |
462 | ||
463 | REP #$20 ; 16-bit A | |
464 | INC $00 | |
465 | JSR .ScrollGradient | |
466 | REP #$20 ; 16-bit A | |
467 | INC $00 | |
468 | INC $00 | |
469 | INC $00 | |
470 | BRA - | |
471 | ||
472 | + !LazyHDMA_Return | |
473 | endif | |
474 | ||
475 | macro LazyBaseBG(color) | |
476 | assert <color> >= 0 && <color> < $8000, "Invalid color" | |
477 | db !LazyHDMA_BGFill | |
478 | dw <color> | |
479 | endmacro | |
480 | ||
481 | function rgb(r, g, b) = r|(g<<5)|(b<<10) | |
482 | ||
483 | macro LazyHDMA(channel, params, register, address) | |
484 | assert <channel> >= 0 && <channel> < 8, "Invalid HDMA channel" | |
485 | assert <params> >= 0 && <params> < $100, "Invalid HDMA parameters" | |
486 | if <register> >= $00 && <register> < $100 | |
487 | elseif <register> >= $2100 && <register> < $2200 | |
488 | else | |
489 | error "Invalid HDMA target register" | |
490 | endif | |
491 | db !LazyHDMA_HDMA|(<channel><<5) | |
492 | db <params>, <register> | |
493 | dw <address> | |
494 | endmacro | |
495 | ||
496 | macro LazyHDMA_Long(channel, params, register, address) | |
497 | db !LazyHDMA_LongPtr, (<address>>>16) | |
498 | %LazyHDMA(channel, params, register, address) | |
499 | endmacro | |
500 | ||
501 | macro LazySimple(type, channel, address) | |
502 | assert <type> > 0 && <type> < !LazyHDMA_Invalid, "Invalid channel type" | |
503 | assert <channel> >= 0 && <channel> < 8, "Invalid HDMA channel" | |
504 | db <type>|(<channel><<5) | |
505 | dw <address> | |
506 | endmacro | |
507 | ||
508 | macro LazyBGSingle(channel, address) | |
509 | %LazySimple(!LazyHDMA_BG, <channel>, <address>) | |
510 | endmacro | |
511 | macro LazyBGDouble(channel, address) | |
512 | %LazySimple(!LazyHDMA_BGDouble, <channel>, <address>) | |
513 | endmacro | |
514 | macro LazyCGRAM(channel, address) | |
515 | %LazySimple(!LazyHDMA_CGRAM, <channel>, <address>) | |
516 | endmacro | |
517 | macro LazyBrightness(channel, address) | |
518 | %LazySimple(!LazyHDMA_Brightness, <channel>, <address>) | |
519 | endmacro | |
520 | ||
521 | macro LazySimple_Long(type, channel, address) | |
522 | db !LazyHDMA_LongPtr, (<address>>>16) | |
523 | %LazySimple(<type>, <channel>, <address>) | |
524 | endmacro | |
525 | ||
526 | macro LazyBGSingle_Long(channel, address) | |
527 | %LazySimple_Long(!LazyHDMA_BG, <channel>, <address>) | |
528 | endmacro | |
529 | macro LazyBGDouble_Long(channel, address) | |
530 | %LazySimple_Long(!LazyHDMA_BGDouble, <channel>, <address>) | |
531 | endmacro | |
532 | macro LazyCGRAM_Long(channel, address) | |
533 | %LazySimple_Long(!LazyHDMA_CGRAM, <channel>, <address>) | |
534 | endmacro | |
535 | macro LazyBrightness_Long(channel, address) | |
536 | %LazySimple_Long(!LazyHDMA_Brightness, <channel>, <address>) | |
537 | endmacro | |
538 | ||
539 | if !IncludeScrollingGradientCode | |
540 | macro LazyScroll(channel, secondchannel, address) | |
541 | %LazySimple(!LazyHDMA_ScrollGradient, <channel>, <address>) | |
542 | db <secondchannel><<4 | |
543 | endmacro | |
544 | macro LazyScroll_Long(channel, secondchannel, address) | |
545 | %LazySimple_Long(!LazyHDMA_ScrollGradient, <channel>, <address>) | |
546 | db <secondchannel><<4 | |
547 | endmacro | |
548 | endif | |
549 | ||
550 | macro LazyEnd() | |
551 | db $00 | |
552 | endmacro |