Actions

SCHG How-to

Improve the fade in\fade out progression routines in Sonic 1

From Sonic Retro

Revision as of 06:11, 30 December 2011 by MarkeyJester (Talk | contribs) (Created page with "{{GuideBy|MarkeyJester}} The palette fading routines in Sonic 1 and Sonic 2 (and possibly to a degree Sonic 3 & Knuckles) known as "Pal_FadeTo" and "Pal_FadeFrom", are not 100% ...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

(Original guide by MarkeyJester)

The palette fading routines in Sonic 1 and Sonic 2 (and possibly to a degree Sonic 3 & Knuckles) known as "Pal_FadeTo" and "Pal_FadeFrom", are not 100% true to their name. Here is a screenshot of Sonic 1's title screen 6 frames during fade in:

FadeInS1Old.png

From Sonic Team's point of view, it may not be incorrect and is possibly intentional, however, from a logical point of view, this is incorrect fading, what happens here is it fades the blue parts in first, then fades the green parts in, and then finally fades the red parts in, the same goes for fading out, red first, then green, finally blue. Strictly speaking for a the nearest possible perfect fade, all colours need to be fading in and out simultaneously (At the correct timing of course), so for example the colour 06E4 should fade in the pattern of:

0020 0040 0060 0080 02A0 04C2 06E4

And fade out in the pattern of:

04C2 02A0 0080 0060 0040 0020 0000

To make the above function for Sonic 1, you'll need to go to the routine "Pal_FadeTo" and replace everything from there down to "; End of function Pal_DecColor" with this:

<asm>Pal_FadeTo: move.w #$3F,($FFFFF626).w

Pal_FadeTo2: moveq #0,d0 lea ($FFFFFB00).w,a0 move.b ($FFFFF626).w,d0 adda.w d0,a0 moveq #0,d1 move.b ($FFFFF627).w,d0

Pal_ToBlack: move.w d1,(a0)+ dbf d0,Pal_ToBlack ; fill pallet with $000 (black) moveq #$0E,d4 ; MJ: prepare maximum colour check moveq #$00,d6 ; MJ: clear d6

loc_1DCE: bsr.w RunPLC_RAM move.b #$12,($FFFFF62A).w bsr.w DelayProgram bchg #$00,d6 ; MJ: change delay counter beq loc_1DCE ; MJ: if null, delay a frame bsr.s Pal_FadeIn subq.b #$02,d4 ; MJ: decrease colour check bne loc_1DCE ; MJ: if it has not reached null, branch move.b #$12,($FFFFF62A).w ; MJ: wait for V-blank again (so colours transfer) bra DelayProgram ; MJ:

End of function Pal_FadeTo
---------------------------------------------------------------------------
Pallet fade-in subroutine
---------------------------------------------------------------------------
||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||


Pal_FadeIn: ; XREF: Pal_FadeTo moveq #0,d0 lea ($FFFFFB00).w,a0 lea ($FFFFFB80).w,a1 move.b ($FFFFF626).w,d0 adda.w d0,a0 adda.w d0,a1 move.b ($FFFFF627).w,d0

loc_1DFA: bsr.s Pal_AddColor dbf d0,loc_1DFA cmpi.b #1,($FFFFFE10).w bne.s locret_1E24 moveq #0,d0 lea ($FFFFFA80).w,a0 lea ($FFFFFA00).w,a1 move.b ($FFFFF626).w,d0 adda.w d0,a0 adda.w d0,a1 move.b ($FFFFF627).w,d0

loc_1E1E: bsr.s Pal_AddColor dbf d0,loc_1E1E

locret_1E24: rts

End of function Pal_FadeIn


||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||


Pal_AddColor: ; XREF: Pal_FadeIn move.b (a1),d5 ; MJ: load blue move.w (a1)+,d1 ; MJ: load green and red move.b d1,d2 ; MJ: load red lsr.b #$04,d1 ; MJ: get only green andi.b #$0E,d2 ; MJ: get only red move.w (a0),d3 ; MJ: load current colour in buffer cmp.b d5,d4 ; MJ: is it time for blue to fade? bhi FCI_NoBlue ; MJ: if not, branch addi.w #$0200,d3 ; MJ: increase blue

FCI_NoBlue: cmp.b d1,d4 ; MJ: is it time for green to fade? bhi FCI_NoGreen ; MJ: if not, branch addi.b #$20,d3 ; MJ: increase green

FCI_NoGreen: cmp.b d2,d4 ; MJ: is it time for red to fade? bhi FCI_NoRed ; MJ: if not, branch addq.b #$02,d3 ; MJ: increase red

FCI_NoRed: move.w d3,(a0)+ ; MJ: save colour rts ; MJ: return

End of function Pal_AddColor


||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||


Pal_FadeFrom: move.w #$3F,($FFFFF626).w moveq #$07,d4 ; MJ: set repeat times moveq #$00,d6 ; MJ: clear d6

loc_1E5C: bsr.w RunPLC_RAM move.b #$12,($FFFFF62A).w bsr.w DelayProgram bchg #$00,d6 ; MJ: change delay counter beq loc_1E5C ; MJ: if null, delay a frame bsr.s Pal_FadeOut dbf d4,loc_1E5C rts

End of function Pal_FadeFrom
---------------------------------------------------------------------------
Pallet fade-out subroutine
---------------------------------------------------------------------------
||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||


Pal_FadeOut: ; XREF: Pal_FadeFrom moveq #0,d0 lea ($FFFFFB00).w,a0 move.b ($FFFFF626).w,d0 adda.w d0,a0 move.b ($FFFFF627).w,d0

loc_1E82: bsr.s Pal_DecColor dbf d0,loc_1E82

moveq #0,d0 lea ($FFFFFA80).w,a0 move.b ($FFFFF626).w,d0 adda.w d0,a0 move.b ($FFFFF627).w,d0

loc_1E98: bsr.s Pal_DecColor dbf d0,loc_1E98 rts

End of function Pal_FadeOut


||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||


Pal_DecColor: ; XREF: Pal_FadeOut move.w (a0),d5 ; MJ: load colour move.w d5,d1 ; MJ: copy to d1 move.b d1,d2 ; MJ: load green and red move.b d1,d3 ; MJ: load red andi.w #$0E00,d1 ; MJ: get only blue beq FCO_NoBlue ; MJ: if blue is finished, branch subi.w #$0200,d5 ; MJ: decrease blue

FCO_NoBlue: andi.w #$00E0,d2 ; MJ: get only green (needs to be word) beq FCO_NoGreen ; MJ: if green is finished, branch subi.b #$20,d5 ; MJ: decrease green

FCO_NoGreen: andi.b #$0E,d3 ; MJ: get only red beq FCO_NoRed ; MJ: if red is finished, branch subq.b #$02,d5 ; MJ: decrease red

FCO_NoRed: move.w d5,(a0)+ ; MJ: save new colour rts ; MJ: return

End of function Pal_DecColor</asm>

This will ensure that the colour fading scheme fades normally and smoothly, here is the new fading routine in action, 6 frames after fading in:

FadeInS1New.png