don't click here

Utility DynaWater - Math Calculated Water Palettes

Discussion in 'Engineering & Reverse Engineering' started by Kilo, May 26, 2024.

  1. Kilo

    Kilo

    The Scatterbrained Hacker Tech Member
    1,362
    1,299
    93
    Canada
    Sonic 1 Source Code Recration
    So DeltaW's new hack just reminded me that I never actually made a proper release for this thing, so I decided to take the time to clean it up and make this thread.
    For context, back in 2021 while I was part of the Isle of the Magnetic Artifacts team while planning out gimmicks and features, one of the features I believe we wanted to do was a glowing effect for players. The problem was SHIMA was going to have a lot of characters, and dedicating ROM space to 5 or 6 extra palettes was kind of dumb. So I came up with the solution of doing it by math, and we realized it could also be used for water palettes, and that's how DynaWater was born.

    First of all you need 2 free words of RAM to hold the colour modifier values.
    Then just plop this down somewhere. Or keep it in it's own ASM file.
    Code (Text):
    1. ; ====================================================================================================
    2. ; DynaWater
    3. ; Created August 10, 2021 by Kilo, ProjectFM
    4. ; ====================================================================================================
    5.  
    6. pal_wateradd = $FFFFXXXX
    7. pal_watersub = $FFFFYYYY
    8.  
    9.  
    10. DynaWater_Init:
    11.         moveq   #0,d0
    12.         move.b  (zoneID).w,d0
    13.         asl.w   #2,d0                           ; Multiply zone ID by 4, since there's 4 acts.
    14.         add.b  (actID).w,d0
    15.         add.w   d0,d0                           ; Multiply by 2, since palette entries are word sized.
    16.         move.w  DynaWater_AddTable(pc,d0.w),d1
    17.         move.w  d1,(pal_wateradd).w             ; Load addition value.
    18.         move.w  DynaWater_SubTable(pc,d0.w),d1
    19.         move.w  d1,(pal_watersub).w             ; Load subtraction value.
    20.         bra.w   DynaWater_Update
    21.  
    22. DynaWater_AddTable:
    23.         ; Act   1,    2,    3,    4
    24.         dc.w    $000, $000, $000, $000  ; GHZ
    25.         dc.w    $040, $040, $040, $600  ; LZ
    26.         dc.w    $000, $000, $000, $000  ; MZ
    27.         dc.w    $000, $000, $000, $000  ; SLZ
    28.         dc.w    $000, $000, $000, $000  ; SYZ
    29.         dc.w    $000, $000, $000, $000  ; SBZ
    30.         dc.w    $000, $000, $000, $000  ; Ending
    31.         even
    32.  
    33. DynaWater_SubTable:
    34.         ; Act   1,    2,    3,    4
    35.         dc.w    $000, $000, $000, $000  ; GHZ
    36.         dc.w    $006, $006, $006, $002  ; LZ
    37.         dc.w    $000, $000, $000, $000  ; MZ
    38.         dc.w    $000, $000, $000, $000  ; SLZ
    39.         dc.w    $000, $000, $000, $000  ; SYZ
    40.         dc.w    $000, $000, $000, $000  ; SBZ
    41.         dc.w    $000, $000, $000, $000  ; Ending
    42.         even
    43.  
    44. ; Here's a list of registers to help you keep track of what is what
    45. ; a1 - Normal palette buffer.
    46. ; a2 - Water palette buffer.
    47. ; d0 - Red additional value.
    48. ; d1 - Green additional value.
    49. ; d2 - Blue additional value.
    50. ; d3 - Red subtraction value.
    51. ; d4 - Green subtraction value.
    52. ; d5 - Blue subtraction value.
    53. ; d6 - Loop value.
    54. ; d7 - General register for storing color values temporarily.
    55.  
    56. DynaWater_Update:
    57.         tst.w   (pal_wateradd).w    ; Is there any addition values for this level?
    58.         bne.s   @Cont               ; If so, pass.
    59.         tst.w   (pal_watersub).w    ; If not, is there any subtraction values?
    60.         beq.w   DynaWater_Return             ; If not, exit, there's no work to be done.
    61.  
    62. @Cont:
    63.         lea     (pal_buffer).w,a1   ; Get our palette for this frame.
    64.         lea     (pal_water).w,a2
    65.         moveq   #64-1,d6            ; Set the loop count.
    66.  
    67.         move.w  (pal_wateradd).w,d7 ; Fetch our addition value.
    68.         move.w  d7,d0               ; Red.
    69.         move.w  d7,d1               ; Green.
    70.         move.w  d7,d2               ; Blue.
    71.         and.w  #$00E,d0             ; Mask out any other channels.
    72.         and.w  #$0E0,d1
    73.         and.w  #$E00,d2
    74.         move.w  (pal_watersub).w,d7 ; Repeat for subtraction value.
    75.         move.w  d7,d3
    76.         move.w  d7,d4
    77.         move.w  d7,d5
    78.         and.w  #$00E,d3
    79.         and.w  #$0E0,d4
    80.         and.w  #$E00,d5
    81.  
    82. @Loop:
    83. @RedAdd:
    84.         move.w  (a1),d7             ; Get palette entry for this iteration.
    85.         andi.w  #$E,d7              ; Mask in red channel.
    86.         add.w   d0,d7               ; Apply addition value.
    87.         cmpi.w  #$E,d7              ; Is it the max color value?
    88.         bls.s   @RedSub             ; If not, continue.
    89.         moveq   #$E,d7              ; Cap the color value.
    90.  
    91. @RedSub:
    92.         sub.w   d3,d7               ; Apply subtraction value.
    93.         bcc.s   @GreenAdd
    94.         moveq   #0,d7
    95.  
    96. @GreenAdd:
    97.         move.w  d7,-(sp)            ; We'll store our modified color in the stack until we're done.
    98.         move.w  (a1),d7
    99.         andi.w  #$E0,d7
    100.         add.w   d1,d7
    101.         cmpi.w  #$E0,d7
    102.         bls.s   @GreenSub
    103.         move.w  #$E0,d7
    104.  
    105. @GreenSub:
    106.         sub.w   d4,d7
    107.         bcc.s   @BlueAdd
    108.         moveq   #0,d7
    109.  
    110. @BlueAdd:
    111.         add.w   d7,(sp)
    112.         move.w  (a1)+,d7
    113.         andi.w  #$E00,d7
    114.         add.w   d2,d7
    115.         cmpi.w  #$E00,d7
    116.         bls.s   @BlueSub
    117.         move.w  #$E00,d7
    118.  
    119. @BlueSub:
    120.         sub.w   d5,d7
    121.         bcc.s   @UpdatePalette
    122.         moveq   #0,d7
    123.  
    124. @UpdatePalette:
    125.         add.w   (sp)+,d7
    126.         move.w  d7,(a2)+    ; Send to water palette buffer.
    127.         dbf     d6,@Loop    ; Loop.
    128.  
    129. DynaWater_Return:
    130.         rts
    Now replace any call to PalLoad3 or PalLoad4 or whatever the routines to load water palettes are in your disasm with DynaWater_Init.
    And any time you update the palette, say with palette cycles or scripting, call DynaWater_Update.

    And like that you've got math based water palettes! No more time spent making water palettes for extra characters or super forms!
    upload_2024-5-26_9-21-59.png

    If you want to change how the water looks, modify the addition table to chose which colors to make brighter and by how much, and the subtraction table to make colors darker. And as you can tell it's already set up for non-LZ levels and per-act palettes!

    But not only that, with some basic scripting you can do fun things like this:
    ezgif-6-dfc7c7d65a.gif
    Worth keeping in mind is that it's not particularly fast, so calling it a lot can cause lag, not helped by how laggy the water transfer stuff already is. Although if someone smarter than me with more time on their hands wants to take a crack at optimizing it I'd be more than appreciative.

    Enjoy!

    Edit: Check Markey's reply for an optimized version!
     
    Last edited: May 26, 2024
    • Useful Useful x 9
    • Like Like x 4
    • List
  2. Hivebrain

    Hivebrain

    Administrator
    3,086
    212
    43
    53.4N, 1.5W
    Github
    Very interesting. I did a similar thing a while ago, with a couple of differences:
    1. Instead of adding/subtracting a value, each colour is anded (so the output colour is never brighter than the original). Your method might be preferable, if slower.
    2. A "keep list" prevents some colours from being modified, so the HUD doesn't get obscured.
     
    • Like Like x 3
    • Useful Useful x 1
    • List
  3. penBorefield

    penBorefield

    Badniks, attack! Member
    376
    66
    28
    Basement
    Conquering the world
    IIRC Sonic 2/3 & Knux used this method.
     
  4. Kilo

    Kilo

    The Scatterbrained Hacker Tech Member
    1,362
    1,299
    93
    Canada
    Sonic 1 Source Code Recration
    They do not. Sonic 2 uses the same method as Sonic 1 of loading separate palettes from the palette index. I believe Sonic 3 does something different, but it's still not math based and still stored in the ROM.
     
  5. penBorefield

    penBorefield

    Badniks, attack! Member
    376
    66
    28
    Basement
    Conquering the world
    In the past, just checked in a certain level editor and I realized there's two 64 color palettes (the second is for the water). My bad.
     
  6. DigitalDuck

    DigitalDuck

    Arriving four years late. Member
    5,461
    508
    93
    Lincs, UK
    TurBoa, S1RL
    I did something similar for S1RL because of the day/night cycle and changes in level palette (all of which are also calculated). I don't remember if I ever actually applied it to water palettes though.
     
  7. MarkeyJester

    MarkeyJester

    You smash your heart against the rocks Resident Jester
    2,316
    565
    93
    Japan
    It's a reasonable idea I think; making a water version can sometimes just be annoying, and having a quicker limited option would actually be quite the pleasure :thumbsup:

    Sure, I'll bite.

    Let's challenge this by avoiding look up tables:

    Code (Text):
    1. DynaWater_Init:
    2.         move.w  (zoneID).w,d0
    3.         ror.b   #$02,d0
    4.         lsr.w   #$05,d0
    5.         move.w  DynaWater_AddTable(pc,d0.w),(pal_wateradd).w
    6.         move.w  DynaWater_SubTable(pc,d0.w),(pal_watersub).w
    7.         bra.w   DynaWater_Update
    8.  
    9. DynaWater_AddTable:
    10.         ; Act   1,    2,    3,    4
    11.         dc.w    $000, $000, $000, $000  ; GHZ
    12.         dc.w    $040, $040, $040, $600  ; LZ
    13.         dc.w    $000, $000, $000, $000  ; MZ
    14.         dc.w    $000, $000, $000, $000  ; SLZ
    15.         dc.w    $000, $000, $000, $000  ; SYZ
    16.         dc.w    $000, $000, $000, $000  ; SBZ
    17.         dc.w    $000, $000, $000, $000  ; Ending
    18.         even
    19.  
    20. DynaWater_SubTable:
    21.         ; Act   1,    2,    3,    4
    22.         dc.w    $000, $000, $000, $000  ; GHZ
    23.         dc.w    $006, $006, $006, $002  ; LZ
    24.         dc.w    $000, $000, $000, $000  ; MZ
    25.         dc.w    $000, $000, $000, $000  ; SLZ
    26.         dc.w    $000, $000, $000, $000  ; SYZ
    27.         dc.w    $000, $000, $000, $000  ; SBZ
    28.         dc.w    $000, $000, $000, $000  ; Ending
    29.         even
    30.  
    31. DynaWater_Update:
    32.  
    33.         move.w  (pal_wateradd).w,d0
    34.         or.w    (pal_watersub).w,d0
    35.         beq.w   .Return
    36.  
    37.         lea ($FFFFFB00).w,a1
    38.         lea ($FFFFFA80).w,a2
    39.  
    40.         move.w  #$0EEE,d3
    41.         move.w  (pal_wateradd).w,d2
    42.         and.w   d3,d2
    43.         and.w   (pal_watersub).w,d3
    44.         moveq   #64-1,d7
    45.         move.w  #$1110,d4
    46.         move.w  d4,d5
    47.         not.w   d5
    48.  
    49.     .Loop:
    50.         move.w  (a1)+,d0
    51.         add.w   d2,d0
    52.         move.w  d0,d1
    53.         and.w   d4,d1
    54.         beq.s   .NoCapUp
    55.         move.w  d1,d6
    56.         lsr.w   #$03,d6
    57.         sub.w   d6,d1
    58.         or.w    d1,d0
    59.  
    60.     .NoCapUp:
    61.         or.w    d4,d0
    62.         sub.w   d3,d0
    63.         move.w  d0,d1
    64.         or.w    d5,d1
    65.         addq.w  #1,d1
    66.         beq.s   .NoCapDown
    67.         subq.w  #1,d1
    68.         move.w  d1,d6
    69.         asr.w   #$03,d6
    70.         not.w   d6
    71.         add.w   d6,d1
    72.         and.w   d1,d0
    73.  
    74.     .NoCapDown:
    75.         move.w  d0,(a2)+
    76.         dbf d7,.Loop
    77.  
    78.     .Return:
    79.         rts
     
    • Like Like x 8
    • Useful Useful x 1
    • List
  8. Kilo

    Kilo

    The Scatterbrained Hacker Tech Member
    1,362
    1,299
    93
    Canada
    Sonic 1 Source Code Recration
    Wow. This optimization blows my mind- :psyduck:
    Great stuff as always Markey!
     
  9. MarkeyJester

    MarkeyJester

    You smash your heart against the rocks Resident Jester
    2,316
    565
    93
    Japan
    You're welcome, though I did think of a slightly quicker way by fusing the add and sub together as a single value.

    This one is faster if there's no over/underflow, though slightly slower if there is. Probability there's less chance of overflow, so it should be overall faster:

    EDIT: Please ignore... it's not working quite right, the carry is preventing it from functioning. Oh well, at least I tried...

    Code (Text):
    1. DynaWater_Init:
    2.         move.w    (zoneID).w,d0
    3.         ror.b    #$02,d0
    4.         lsr.w    #$05,d0
    5.         move.w    DynaWater_AddTable(pc,d0.w),d1
    6.         move.w    DynaWater_SubTable(pc,d0.w),d0
    7.         eori.w    #$EEE,d0
    8.         addi.w    #$222,d0
    9.         eori.w    #$1110,d0
    10.         or.w    d0,d1
    11.         move.w    d1,(pal_wateradd).w
    12.         bra.w    DynaWater_Update
    13.  
    14. DynaWater_AddTable:
    15.         ; Act   1,    2,    3,    4
    16.         dc.w    $000, $000, $000, $000  ; GHZ
    17.         dc.w    $040, $040, $040, $600  ; LZ
    18.         dc.w    $000, $000, $000, $000  ; MZ
    19.         dc.w    $000, $000, $000, $000  ; SLZ
    20.         dc.w    $000, $000, $000, $000  ; SYZ
    21.         dc.w    $000, $000, $000, $000  ; SBZ
    22.         dc.w    $000, $000, $000, $000  ; Ending
    23.         even
    24.  
    25. DynaWater_SubTable:
    26.         ; Act   1,    2,    3,    4
    27.         dc.w    $000, $000, $000, $000  ; GHZ
    28.         dc.w    $006, $006, $006, $002  ; LZ
    29.         dc.w    $000, $000, $000, $000  ; MZ
    30.         dc.w    $000, $000, $000, $000  ; SLZ
    31.         dc.w    $000, $000, $000, $000  ; SYZ
    32.         dc.w    $000, $000, $000, $000  ; SBZ
    33.         dc.w    $000, $000, $000, $000  ; Ending
    34.         even
    35.  
    36. DynaWater_Update:
    37.         move.w    (pal_wateradd).w,d2
    38.         beq.w    .Return
    39.         move.w    #$1110,d4
    40.         move.w    d2,d3
    41.         and.w    d4,d3
    42.         lea    ($FFFFFB00).w,a1
    43.         lea    ($FFFFFA80).w,a2
    44.         moveq    #64-1,d7
    45.  
    46.     .Loop:
    47.         move.w    (a1)+,d0
    48.         add.w    d2,d0
    49.         move.w    d0,d1
    50.         and.w    d4,d1
    51.         beq.s    .NoCap
    52.         move.w    d1,d5
    53.         and.w    d3,d5
    54.         beq.s    .No0
    55.         eor.w    d5,d1
    56.         not.w    d5
    57.         move.w    d5,d6
    58.         asr.w    #$03,d6
    59.         not.w    d6
    60.         add.w    d6,d5
    61.         and.w    d5,d0
    62.     .No0:    move.w    d1,d6
    63.         beq.s    .NoE
    64.         lsr.w    #$03,d6
    65.         sub.w    d6,d1
    66.         or.w    d1,d0
    67.     .NoE:    or.w    d3,d0
    68.  
    69.     .NoCap:
    70.         sub.w    d3,d0
    71.         move.w    d0,(a2)+
    72.         dbf    d7,.Loop
    73.  
    74.     .Return:
    75.         rts
     
    Last edited: May 26, 2024
  10. BenoitRen

    BenoitRen

    Tech Member
    956
    580
    93
    Why avoid look-up tables? I've seen that saving cycles is often done using them.
     
  11. MarkeyJester

    MarkeyJester

    You smash your heart against the rocks Resident Jester
    2,316
    565
    93
    Japan
    It was just a mild challenge, I'm usually one of the worst for abusing ROM space in projects, and my team members tend to hate me for it.

    But here's a LUT version for your curiosity:

    Code (Text):
    1.         dc.b    $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0
    2. LUTB:   dc.b    $0,$0,$2,$2,$4,$4,$6,$6,$8,$8,$A,$A,$C,$C,$E,$E
    3.         dc.b    $E,$E,$E,$E,$E,$E,$E,$E,$E,$E,$E,$E,$E,$E,$E,$E
    4.  
    5.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    6.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    7.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    8.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    9.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    10.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    11.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    12.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    13.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    14.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    15.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    16.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    17.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    18.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    19.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    20.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    21. LUTG:   dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    22.         dc.b    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
    23.         dc.b    $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20
    24.         dc.b    $20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20,$20
    25.         dc.b    $40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40
    26.         dc.b    $40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40
    27.         dc.b    $60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60
    28.         dc.b    $60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60,$60
    29.         dc.b    $80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80
    30.         dc.b    $80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80,$80
    31.         dc.b    $A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0
    32.         dc.b    $A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0
    33.         dc.b    $C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0
    34.         dc.b    $C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0
    35.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    36.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    37.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    38.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    39.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    40.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    41.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    42.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    43.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    44.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    45.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    46.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    47.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    48.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    49.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    50.         dc.b    $E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0,$E0
    51.  
    52.  
    53. DynaWater_Init:
    54.         move.w  (zoneID).w,d0
    55.         ror.b   #$02,d0
    56.         lsr.w   #$02,d0
    57.         lea DynaWaterTable(pc,d0.w),a0
    58.         lea (pal_wateradd).w,a1
    59.         move.l  (a0)+,(a1)+
    60.         move.l  (a0)+,(a1)+
    61.         move.l  (a0)+,(a1)+
    62.         bra.w   DynaWater_Update
    63.  
    64. DynaWaterTable: dc.l    LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0
    65.         dc.l    LUTB+$0,LUTG+$4,LUTB-$6,0, LUTB+$0,LUTG+$4,LUTB-$6,0, LUTB+$0,LUTG+$4,LUTB-$6,0, LUTB+$6,LUTG+$0,LUTB-$2,0
    66.         dc.l    LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0
    67.         dc.l    LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0
    68.         dc.l    LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0
    69.         dc.l    LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0
    70.         dc.l    LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0, LUTB+$0,LUTG+$0,LUTB+$0,0
    71.  
    72. DynaWater_Update:
    73.         lea (pal_wateradd).w,a4
    74.         move.l  (a4)+,a0
    75.         move.l  (a4)+,a3
    76.         move.l  (a4),a4
    77.         lea ($FFFFFB00).w,a1
    78.         lea ($FFFFFA80).w,a2
    79.         moveq   #64-1,d7
    80.         moveq   #$00,d0
    81.  
    82.     .Loop:
    83.         move.b  (a1)+,d0
    84.         move.b  (a0,d0.w),(a2)+
    85.         move.b  (a1)+,d0
    86.         moveq   #$0E,d1
    87.         and.b   d0,d1
    88.         sub.b   d1,d0
    89.         move.b  (a3,d0.w),d0
    90.         or.b    (a4,d1.w),d0
    91.         move.b  d0,(a2)+
    92.         dbf d7,.Loop
    93.         rts
     
  12. Devon

    Devon

    pfp by @litchui on Twitter Tech Member
    1,582
    1,958
    93
    your mom
    Just my personal opinion, but I don't think the LUT version is that bad at all, with what looks to be 1232 bytes for the tables in total (if I did my counting right). I think it'd be more concerning if it were like 50 times that lol
     
  13. Kilo

    Kilo

    The Scatterbrained Hacker Tech Member
    1,362
    1,299
    93
    Canada
    Sonic 1 Source Code Recration
    Yeah I'm personally all for that LUT version. While it doesn't do much for ROM space (Actually it does more harm because it's 5 times more data than the water palette data in Sonic 1 :V) it still saves on dev time actually making the palettes, mostly in cases such as having multiple characters with super forms and the such. And still with my rainbow example, it allows for scripting effects. One usage I saw back when I made it was actually making the water darker as you got deeper which I thought was a really good use.
     
  14. Jeffery Mewtamer

    Jeffery Mewtamer

    Blind Bookworm Member
    2,024
    143
    43
    I don't know the first thing about 68k assembly, so I haven't a clue what these code snippets actually do, but I'm also guessing this could be used to automate characters and objects going into different fluids(e.g. clean water versus algae infested water versus muddy water versus toxic ooze).
     
  15. Kilo

    Kilo

    The Scatterbrained Hacker Tech Member
    1,362
    1,299
    93
    Canada
    Sonic 1 Source Code Recration
    Not particularly, all this does is make changing the colour of water easier. It doesn't gain properties, stuff like that would require it's own routines.
     
  16. Jeffery Mewtamer

    Jeffery Mewtamer

    Blind Bookworm Member
    2,024
    143
    43
    Well, I was thinking along the lines of clean water giving everything a cyan tint, algae tinting things green, muddy water being brown, toxic ooze being purple ala Chemical Plant Zone, etc. Presumably, giving those liquids non-visual distinctions(such as mud slowing you down more than clean water or the toxic ooze draining rings because its poisonous) would be a separate thing.
     
  17. RetroFlare

    RetroFlare

    Member
    21
    1
    3
    I followed all the steps but unfortunately the water turned out like this :(
    upload_2024-6-17_0-20-41.png
    [​IMG]
     
  18. TDRR

    TDRR

    Member
    I actually ran into this just today lol, but with Hivebrain's WaterFilter from S1Squared. Either way, the issue is the exact same for both.
    In S1Squared, palette fades are handled differently, so this just works out of the box. You either have to transplant those changes, or do a simpler hack, which is putting the call to DynaWater_Init right before "dbf d4, .mainloop" in PaletteFadeIn. You might not need to check for Labyrinth Zone in your case, I just did it to avoid the extra work, and calling the function unconditionally probably doesn't cause any issues.

    Here's an example. I marked my additions with ++. You might need to backup some registers to the stack since DynaWater_Init uses a lot more registers, some of which overlap with the ones used here.
    Code (Text):
    1. PaletteFadeIn:
    2.         move.w    #$003F,(v_pfade_start).w ; set start position = 0; size = $40
    3.  
    4. PalFadeIn_Alt:                ; start position and size are already set
    5.         moveq    #0,d0
    6.         lea    (v_pal_dry).w,a0
    7.         move.b    (v_pfade_start).w,d0
    8.         adda.w    d0,a0
    9.         moveq    #cBlack,d1
    10.         move.b    (v_pfade_size).w,d0
    11.  
    12. .fill:
    13.         move.w    d1,(a0)+
    14.         dbf    d0,.fill     ; fill palette with black
    15.  
    16.         move.w    #$15,d4
    17.  
    18. .mainloop:
    19.         move.b    #$12,(v_vbla_routine).w
    20.         bsr.w    WaitForVBla
    21.         bsr.s    FadeIn_FromBlack
    22.         bsr.w    RunPLC
    23.         cmpi.b    #id_LZ,(v_zone).w ; is level LZ? ; ++
    24.         bne        .NoWater ; ++
    25.         bsr        WaterFilter ; generate underwater palette ; ++
    26. .NoWater:   ; ++
    27.         dbf    d4,.mainloop
    28.         rts  
    29. ; End of function PaletteFadeIn
     
    Last edited: Jun 17, 2024
  19. RetroFlare

    RetroFlare

    Member
    21
    1
    3
    It worked! Thank you so much
     
  20. SaneWay

    SaneWay

    Member
    Sorry to bother, but I'm having trouble getting this to work. For context, I'm pretty new to ASM, and I was having the same orange water issue as RetroFlare. After using your fix, the water appeared to be the correct colour but after the fade in the game freezes up. I understand what you mean by backing up the registers used in the fade subroutine to the stack, but I'm unsure how to go about writing this. If you have the time, could you provide an example of the instructions I could use to fix this?