#include "global.h" #include "palette.h" #include "util.h" #include "decompress.h" #include "gpu_regs.h" #include "task.h" #include "constants/rgb.h" // include/palette.h struct PaletteFadeControl { /* 0x00 */ u32 multipurpose1; /* 0x04 */ u8 delayCounter:6; /* 0x04 */ u16 mode:2; /* 0x05 */ u16 deltaY:6; // rate of change of blend coefficient /* 0x05 */ bool16 active:1; /* 0x05 */ bool16 yDec:1; // whether blend coefficient is decreasing /* 0x06 */ u16 targetY:6; // target blend coefficient /* 0x06 */ bool16 bufferTransferDisabled:1; /* 0x06 */ bool16 shouldResetBlendRegisters:1; /* 0x07 */ u16 multipurpose2:6; /* 0x07 */ bool16 hardwareFadeFinishing:1; /* 0x07 */ bool16 objPaletteToggle:1; /* 0x08 */ u16 blendColor:15; /* 0x08 */ u8 yChanged:1; /* 0x09 */ u16 softwareFadeFinishingCounter:3; /* 0x09 */ u16 doEndDelay:1; /* 0x0a */ u16 y; // blend coefficient /* 0x0c */ u16 denominator; }; // src/palette.c static bool8 BeginNormalPaletteFadeInternal(u32 selectedPalettes, u8 startY, u8 targetY, u16 blendColor, u32 denominator, u32 doEndDelay, u32 dontCopy); enum { NORMAL_FADE, FAST_FADE, HARDWARE_FADE, }; bool8 BeginNormalPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targetY, u16 blendColor) { // all this is to make fades more smooth // while keeping the same delay as vanilla // in case some code relies on timing u8 diff; u16 denominator; if (startY < targetY) { diff = targetY - startY; } else { diff = startY - targetY; } if (delay >= 0) { if (delay > 63) { delay = 63; } denominator = ((diff + 1)/2) * (delay + 2) + 1; } else { u8 i; u8 deltaY; s8 y; if (delay < -14) { delay = -14; } deltaY = 2 + (delay * -1); y = startY; if (y < targetY) { for (i = 0; y < targetY; i++) { y += deltaY; } } else { for (i = 0; y > targetY; i++) { y -= deltaY; } } denominator = i * 2 + 1; } return BeginNormalPaletteFadeInternal(selectedPalettes, startY * 2, targetY * 2, blendColor, denominator, TRUE, FALSE); } static bool8 BeginNormalPaletteFadeForDuration_Common(u32 selectedPalettes, u16 fadeDuration, u8 startY, u8 targetY, u16 blendColor, u32 doEndDelay, bool32 dontCopy); bool8 BeginNormalPaletteFadeForDuration_DontImmediatelyCopy(u32 selectedPalettes, u16 fadeDuration, u8 startY, u8 targetY, u16 blendColor, u32 doEndDelay) { return BeginNormalPaletteFadeForDuration_Common(selectedPalettes, fadeDuration, startY, targetY, blendColor, doEndDelay, TRUE); } bool8 BeginNormalPaletteFadeForDuration(u32 selectedPalettes, u16 fadeDuration, u8 startY, u8 targetY, u16 blendColor, u32 doEndDelay) { return BeginNormalPaletteFadeForDuration_Common(selectedPalettes, fadeDuration, startY, targetY, blendColor, doEndDelay, FALSE); } static bool8 BeginNormalPaletteFadeForDuration_Common(u32 selectedPalettes, u16 fadeDuration, u8 startY, u8 targetY, u16 blendColor, u32 doEndDelay, bool32 dontCopy) { if (fadeDuration > 1) { fadeDuration--; } else { fadeDuration = 1; } return BeginNormalPaletteFadeInternal(selectedPalettes, startY, targetY, blendColor, fadeDuration, doEndDelay, dontCopy); } static bool8 BeginNormalPaletteFadeInternal(u32 selectedPalettes, u8 startY, u8 targetY, u16 blendColor, u32 denominator, u32 doEndDelay, u32 dontCopy) { u8 temp; u16 color = blendColor; if (gPaletteFade.active) { return FALSE; } else { gPaletteFade_selectedPalettes = selectedPalettes; gPaletteFade.y = startY * denominator; gPaletteFade.targetY = targetY; gPaletteFade.denominator = denominator; gPaletteFade.blendColor = color; gPaletteFade.active = TRUE; gPaletteFade.mode = NORMAL_FADE; gPaletteFade.objPaletteToggle = 0; gPaletteFade.yChanged = TRUE; gPaletteFade.doEndDelay = doEndDelay; if (startY < targetY) { gPaletteFade.deltaY = targetY - startY; gPaletteFade.yDec = 0; } else { gPaletteFade.deltaY = startY - targetY; gPaletteFade.yDec = 1; } UpdatePaletteFade(); temp = gPaletteFade.bufferTransferDisabled; gPaletteFade.bufferTransferDisabled = TRUE; if (!dontCopy) { CpuFastCopy(gPlttBufferFaded, (void *)PLTT, PLTT_SIZE); } sPlttBufferTransferPending = 0; if (gPaletteFade.mode == HARDWARE_FADE && gPaletteFade.active) UpdateBlendRegisters(); gPaletteFade.bufferTransferDisabled = temp; return TRUE; } } void ResetPaletteFadeControl(void) { gPaletteFade.multipurpose1 = 0; gPaletteFade.multipurpose2 = 0; gPaletteFade.delayCounter = 0; gPaletteFade.y = 0; gPaletteFade.targetY = 0; gPaletteFade.blendColor = 0; gPaletteFade.active = 0; gPaletteFade.multipurpose2 = 0; // assign same value twice gPaletteFade.yDec = 0; gPaletteFade.bufferTransferDisabled = 0; gPaletteFade.shouldResetBlendRegisters = 0; gPaletteFade.hardwareFadeFinishing = 0; gPaletteFade.softwareFadeFinishingCounter = 0; gPaletteFade.objPaletteToggle = 0; gPaletteFade.deltaY = 2; } static u8 UpdateNormalPaletteFade(void) { if (!gPaletteFade.active) return PALETTE_FADE_STATUS_DONE; if (IsSoftwarePaletteFadeFinishing()) { return gPaletteFade.active ? PALETTE_FADE_STATUS_ACTIVE : PALETTE_FADE_STATUS_DONE; } else { u16 targetY = gPaletteFade.targetY * gPaletteFade.denominator; u16 yWholeValue = gPaletteFade.y / gPaletteFade.denominator; if (gPaletteFade.yChanged) { BlendPalettesFine(gPaletteFade_selectedPalettes, yWholeValue, gPaletteFade.blendColor); } if (gPaletteFade.y == targetY) { gPaletteFade_selectedPalettes = 0; gPaletteFade.softwareFadeFinishingCounter = 1; if (!gPaletteFade.doEndDelay) { gPaletteFade.active = 0; gPaletteFade.softwareFadeFinishingCounter = 0; } } else { u16 newY; if (!gPaletteFade.yDec) { newY = gPaletteFade.y + gPaletteFade.deltaY; if (newY > targetY) { newY = targetY; } } else { newY = gPaletteFade.y - gPaletteFade.deltaY; if (newY < targetY) { newY = targetY; } } gPaletteFade.yChanged = (newY / gPaletteFade.denominator) != yWholeValue; gPaletteFade.y = newY; } // gPaletteFade.active cannot change since the last time it was checked. So this // is equivalent to `return PALETTE_FADE_STATUS_ACTIVE;` return gPaletteFade.active ? PALETTE_FADE_STATUS_ACTIVE : PALETTE_FADE_STATUS_DONE; } } static bool8 IsSoftwarePaletteFadeFinishing(void) { if (gPaletteFade.softwareFadeFinishingCounter > 0) { if (!gPaletteFade.doEndDelay || gPaletteFade.softwareFadeFinishingCounter == 5) { gPaletteFade.active = 0; gPaletteFade.softwareFadeFinishingCounter = 0; } else { gPaletteFade.softwareFadeFinishingCounter++; } return TRUE; } else { return FALSE; } }