1047 lines
26 KiB
C
1047 lines
26 KiB
C
|
#include "global.h"
|
||
|
#include "palette.h"
|
||
|
#include "util.h"
|
||
|
#include "decompress.h"
|
||
|
#include "gpu_regs.h"
|
||
|
#include "task.h"
|
||
|
#include "constants/rgb.h"
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
NORMAL_FADE,
|
||
|
FAST_FADE,
|
||
|
HARDWARE_FADE,
|
||
|
};
|
||
|
|
||
|
// These are structs for some unused palette system.
|
||
|
// The full functionality of this system is unknown.
|
||
|
|
||
|
#define NUM_PALETTE_STRUCTS 16
|
||
|
|
||
|
struct PaletteStructTemplate
|
||
|
{
|
||
|
u16 id;
|
||
|
u16 *src;
|
||
|
bool16 pst_field_8_0:1;
|
||
|
u16 unused:9;
|
||
|
u16 size:5;
|
||
|
u8 time1;
|
||
|
u8 srcCount:5;
|
||
|
u8 state:3;
|
||
|
u8 time2;
|
||
|
};
|
||
|
|
||
|
struct PaletteStruct
|
||
|
{
|
||
|
const struct PaletteStructTemplate *template;
|
||
|
bool32 active:1;
|
||
|
bool32 flag:1;
|
||
|
u32 baseDestOffset:9;
|
||
|
u32 destOffset:10;
|
||
|
u32 srcIndex:7;
|
||
|
u8 countdown1;
|
||
|
u8 countdown2;
|
||
|
};
|
||
|
|
||
|
static void PaletteStruct_Copy(struct PaletteStruct *, u32 *);
|
||
|
static void PaletteStruct_Blend(struct PaletteStruct *, u32 *);
|
||
|
static void PaletteStruct_TryEnd(struct PaletteStruct *);
|
||
|
static void PaletteStruct_Reset(u8);
|
||
|
static u8 PaletteStruct_GetPalNum(u16);
|
||
|
static u8 UpdateNormalPaletteFade(void);
|
||
|
static void BeginFastPaletteFadeInternal(u8);
|
||
|
static u8 UpdateFastPaletteFade(void);
|
||
|
static u8 UpdateHardwarePaletteFade(void);
|
||
|
static void UpdateBlendRegisters(void);
|
||
|
static bool8 IsSoftwarePaletteFadeFinishing(void);
|
||
|
static void Task_BlendPalettesGradually(u8 taskId);
|
||
|
|
||
|
// palette buffers require alignment with agbcc because
|
||
|
// unaligned word reads are issued in BlendPalette otherwise
|
||
|
ALIGNED(4) EWRAM_DATA u16 gPlttBufferUnfaded[PLTT_BUFFER_SIZE] = {0};
|
||
|
ALIGNED(4) EWRAM_DATA u16 gPlttBufferFaded[PLTT_BUFFER_SIZE] = {0};
|
||
|
EWRAM_DATA struct PaletteStruct sPaletteStructs[NUM_PALETTE_STRUCTS] = {0};
|
||
|
EWRAM_DATA struct PaletteFadeControl gPaletteFade = {0};
|
||
|
static EWRAM_DATA u32 sFiller = 0;
|
||
|
static EWRAM_DATA u32 sPlttBufferTransferPending = 0;
|
||
|
EWRAM_DATA u8 gPaletteDecompressionBuffer[PLTT_DECOMP_BUFFER_SIZE] = {0};
|
||
|
|
||
|
static const struct PaletteStructTemplate gDummyPaletteStructTemplate = {
|
||
|
.id = 0xFFFF,
|
||
|
.state = 1
|
||
|
};
|
||
|
|
||
|
static const u8 sRoundedDownGrayscaleMap[] = {
|
||
|
0, 0, 0, 0, 0,
|
||
|
5, 5, 5, 5, 5,
|
||
|
11, 11, 11, 11, 11,
|
||
|
16, 16, 16, 16, 16,
|
||
|
21, 21, 21, 21, 21,
|
||
|
27, 27, 27, 27, 27,
|
||
|
31, 31
|
||
|
};
|
||
|
|
||
|
void LoadCompressedPalette(const u32 *src, u16 offset, u16 size)
|
||
|
{
|
||
|
LZDecompressWram(src, gPaletteDecompressionBuffer);
|
||
|
CpuCopy16(gPaletteDecompressionBuffer, &gPlttBufferUnfaded[offset], size);
|
||
|
CpuCopy16(gPaletteDecompressionBuffer, &gPlttBufferFaded[offset], size);
|
||
|
}
|
||
|
|
||
|
void LoadPalette(const void *src, u16 offset, u16 size)
|
||
|
{
|
||
|
CpuCopy16(src, &gPlttBufferUnfaded[offset], size);
|
||
|
CpuCopy16(src, &gPlttBufferFaded[offset], size);
|
||
|
}
|
||
|
|
||
|
void FillPalette(u16 value, u16 offset, u16 size)
|
||
|
{
|
||
|
CpuFill16(value, &gPlttBufferUnfaded[offset], size);
|
||
|
CpuFill16(value, &gPlttBufferFaded[offset], size);
|
||
|
}
|
||
|
|
||
|
void TransferPlttBuffer(void)
|
||
|
{
|
||
|
if (!gPaletteFade.bufferTransferDisabled)
|
||
|
{
|
||
|
void *src = gPlttBufferFaded;
|
||
|
void *dest = (void *)PLTT;
|
||
|
DmaCopy16(3, src, dest, PLTT_SIZE);
|
||
|
sPlttBufferTransferPending = FALSE;
|
||
|
if (gPaletteFade.mode == HARDWARE_FADE && gPaletteFade.active)
|
||
|
UpdateBlendRegisters();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
u8 UpdatePaletteFade(void)
|
||
|
{
|
||
|
u8 result;
|
||
|
u8 dummy = 0;
|
||
|
|
||
|
if (sPlttBufferTransferPending)
|
||
|
return PALETTE_FADE_STATUS_LOADING;
|
||
|
|
||
|
if (gPaletteFade.mode == NORMAL_FADE)
|
||
|
result = UpdateNormalPaletteFade();
|
||
|
else if (gPaletteFade.mode == FAST_FADE)
|
||
|
result = UpdateFastPaletteFade();
|
||
|
else
|
||
|
result = UpdateHardwarePaletteFade();
|
||
|
|
||
|
sPlttBufferTransferPending = gPaletteFade.multipurpose1 | dummy;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void ResetPaletteFade(void)
|
||
|
{
|
||
|
u8 i;
|
||
|
|
||
|
for (i = 0; i < NUM_PALETTE_STRUCTS; i++)
|
||
|
PaletteStruct_Reset(i);
|
||
|
|
||
|
ResetPaletteFadeControl();
|
||
|
}
|
||
|
|
||
|
static void ReadPlttIntoBuffers(void)
|
||
|
{
|
||
|
u16 i;
|
||
|
u16 *pltt = (u16 *)PLTT;
|
||
|
|
||
|
for (i = 0; i < PLTT_SIZE / 2; i++)
|
||
|
{
|
||
|
gPlttBufferUnfaded[i] = pltt[i];
|
||
|
gPlttBufferFaded[i] = pltt[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool8 BeginNormalPaletteFade(u32 selectedPalettes, s8 delay, u8 startY, u8 targetY, u16 blendColor)
|
||
|
{
|
||
|
u8 temp;
|
||
|
u16 color = blendColor;
|
||
|
|
||
|
if (gPaletteFade.active)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gPaletteFade.deltaY = 2;
|
||
|
|
||
|
if (delay < 0)
|
||
|
{
|
||
|
gPaletteFade.deltaY += (delay * -1);
|
||
|
delay = 0;
|
||
|
}
|
||
|
|
||
|
gPaletteFade_selectedPalettes = selectedPalettes;
|
||
|
gPaletteFade.delayCounter = delay;
|
||
|
gPaletteFade_delay = delay;
|
||
|
gPaletteFade.y = startY;
|
||
|
gPaletteFade.targetY = targetY;
|
||
|
gPaletteFade.blendColor = color;
|
||
|
gPaletteFade.active = TRUE;
|
||
|
gPaletteFade.mode = NORMAL_FADE;
|
||
|
|
||
|
if (startY < targetY)
|
||
|
gPaletteFade.yDec = 0;
|
||
|
else
|
||
|
gPaletteFade.yDec = 1;
|
||
|
|
||
|
UpdatePaletteFade();
|
||
|
|
||
|
temp = gPaletteFade.bufferTransferDisabled;
|
||
|
gPaletteFade.bufferTransferDisabled = FALSE;
|
||
|
CpuCopy32(gPlttBufferFaded, (void *)PLTT, PLTT_SIZE);
|
||
|
sPlttBufferTransferPending = FALSE;
|
||
|
if (gPaletteFade.mode == HARDWARE_FADE && gPaletteFade.active)
|
||
|
UpdateBlendRegisters();
|
||
|
gPaletteFade.bufferTransferDisabled = temp;
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Unused
|
||
|
static bool8 BeginPlttFade(u32 selectedPalettes, u8 delay, u8 startY, u8 targetY, u16 blendColor)
|
||
|
{
|
||
|
ReadPlttIntoBuffers();
|
||
|
return BeginNormalPaletteFade(selectedPalettes, delay, startY, targetY, blendColor);
|
||
|
}
|
||
|
|
||
|
// Unused
|
||
|
static void PaletteStruct_Run(u8 a1, u32 *unkFlags)
|
||
|
{
|
||
|
u8 i;
|
||
|
|
||
|
for (i = 0; i < NUM_PALETTE_STRUCTS; i++)
|
||
|
{
|
||
|
struct PaletteStruct *palstruct = &sPaletteStructs[i];
|
||
|
if (palstruct->active)
|
||
|
{
|
||
|
if (palstruct->template->pst_field_8_0 == a1)
|
||
|
{
|
||
|
if (palstruct->srcIndex == palstruct->template->srcCount)
|
||
|
{
|
||
|
PaletteStruct_TryEnd(palstruct);
|
||
|
if (!palstruct->active)
|
||
|
continue;
|
||
|
}
|
||
|
if (palstruct->countdown1 == 0)
|
||
|
PaletteStruct_Copy(palstruct, unkFlags);
|
||
|
else
|
||
|
palstruct->countdown1--;
|
||
|
|
||
|
PaletteStruct_Blend(palstruct, unkFlags);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void PaletteStruct_Copy(struct PaletteStruct *a1, u32 *unkFlags)
|
||
|
{
|
||
|
s32 srcIndex;
|
||
|
s32 srcCount;
|
||
|
u8 i = 0;
|
||
|
u16 srcOffset = a1->srcIndex * a1->template->size;
|
||
|
|
||
|
if (!a1->template->pst_field_8_0)
|
||
|
{
|
||
|
while (i < a1->template->size)
|
||
|
{
|
||
|
gPlttBufferUnfaded[a1->destOffset] = a1->template->src[srcOffset];
|
||
|
gPlttBufferFaded[a1->destOffset] = a1->template->src[srcOffset];
|
||
|
i++;
|
||
|
a1->destOffset++;
|
||
|
srcOffset++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
while (i < a1->template->size)
|
||
|
{
|
||
|
gPlttBufferFaded[a1->destOffset] = a1->template->src[srcOffset];
|
||
|
i++;
|
||
|
a1->destOffset++;
|
||
|
srcOffset++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
a1->destOffset = a1->baseDestOffset;
|
||
|
a1->countdown1 = a1->template->time1;
|
||
|
a1->srcIndex++;
|
||
|
|
||
|
srcIndex = a1->srcIndex;
|
||
|
srcCount = a1->template->srcCount;
|
||
|
|
||
|
if (srcIndex >= srcCount)
|
||
|
{
|
||
|
if (a1->countdown2)
|
||
|
a1->countdown2--;
|
||
|
a1->srcIndex = 0;
|
||
|
}
|
||
|
|
||
|
*unkFlags |= 1 << (a1->baseDestOffset >> 4);
|
||
|
}
|
||
|
|
||
|
static void PaletteStruct_Blend(struct PaletteStruct *a1, u32 *unkFlags)
|
||
|
{
|
||
|
if (gPaletteFade.active && ((1 << (a1->baseDestOffset >> 4)) & gPaletteFade_selectedPalettes))
|
||
|
{
|
||
|
if (!a1->template->pst_field_8_0)
|
||
|
{
|
||
|
if (gPaletteFade.delayCounter != gPaletteFade_delay)
|
||
|
{
|
||
|
BlendPalette(
|
||
|
a1->baseDestOffset,
|
||
|
a1->template->size,
|
||
|
gPaletteFade.y,
|
||
|
gPaletteFade.blendColor);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!gPaletteFade.delayCounter)
|
||
|
{
|
||
|
if (a1->countdown1 != a1->template->time1)
|
||
|
{
|
||
|
u32 srcOffset = a1->srcIndex * a1->template->size;
|
||
|
u8 i;
|
||
|
|
||
|
for (i = 0; i < a1->template->size; i++)
|
||
|
gPlttBufferFaded[a1->baseDestOffset + i] = a1->template->src[srcOffset + i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void PaletteStruct_TryEnd(struct PaletteStruct *pal)
|
||
|
{
|
||
|
if (pal->countdown2 == 0)
|
||
|
{
|
||
|
s32 state = pal->template->state;
|
||
|
|
||
|
if (state == 0)
|
||
|
{
|
||
|
pal->srcIndex = 0;
|
||
|
pal->countdown1 = pal->template->time1;
|
||
|
pal->countdown2 = pal->template->time2;
|
||
|
pal->destOffset = pal->baseDestOffset;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (state < 0)
|
||
|
return;
|
||
|
if (state > 2)
|
||
|
return;
|
||
|
PaletteStruct_ResetById(pal->template->id);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pal->countdown2--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void PaletteStruct_ResetById(u16 id)
|
||
|
{
|
||
|
u8 paletteNum = PaletteStruct_GetPalNum(id);
|
||
|
if (paletteNum != NUM_PALETTE_STRUCTS)
|
||
|
PaletteStruct_Reset(paletteNum);
|
||
|
}
|
||
|
|
||
|
static void PaletteStruct_Reset(u8 paletteNum)
|
||
|
{
|
||
|
sPaletteStructs[paletteNum].template = &gDummyPaletteStructTemplate;
|
||
|
sPaletteStructs[paletteNum].active = FALSE;
|
||
|
sPaletteStructs[paletteNum].baseDestOffset = 0;
|
||
|
sPaletteStructs[paletteNum].destOffset = 0;
|
||
|
sPaletteStructs[paletteNum].srcIndex = 0;
|
||
|
sPaletteStructs[paletteNum].flag = 0;
|
||
|
sPaletteStructs[paletteNum].countdown1 = 0;
|
||
|
sPaletteStructs[paletteNum].countdown2 = 0;
|
||
|
}
|
||
|
|
||
|
void ResetPaletteFadeControl(void)
|
||
|
{
|
||
|
gPaletteFade.multipurpose1 = 0;
|
||
|
gPaletteFade.multipurpose2 = 0;
|
||
|
gPaletteFade.delayCounter = 0;
|
||
|
gPaletteFade.y = 0;
|
||
|
gPaletteFade.targetY = 0;
|
||
|
gPaletteFade.blendColor = 0;
|
||
|
gPaletteFade.active = FALSE;
|
||
|
gPaletteFade.multipurpose2 = 0; // assign same value twice
|
||
|
gPaletteFade.yDec = 0;
|
||
|
gPaletteFade.bufferTransferDisabled = FALSE;
|
||
|
gPaletteFade.shouldResetBlendRegisters = FALSE;
|
||
|
gPaletteFade.hardwareFadeFinishing = FALSE;
|
||
|
gPaletteFade.softwareFadeFinishing = FALSE;
|
||
|
gPaletteFade.softwareFadeFinishingCounter = 0;
|
||
|
gPaletteFade.objPaletteToggle = 0;
|
||
|
gPaletteFade.deltaY = 2;
|
||
|
}
|
||
|
|
||
|
static void PaletteStruct_SetUnusedFlag(u16 id)
|
||
|
{
|
||
|
u8 paletteNum = PaletteStruct_GetPalNum(id);
|
||
|
if (paletteNum != NUM_PALETTE_STRUCTS)
|
||
|
sPaletteStructs[paletteNum].flag = TRUE;
|
||
|
}
|
||
|
|
||
|
static void PaletteStruct_ClearUnusedFlag(u16 id)
|
||
|
{
|
||
|
u8 paletteNum = PaletteStruct_GetPalNum(id);
|
||
|
if (paletteNum != NUM_PALETTE_STRUCTS)
|
||
|
sPaletteStructs[paletteNum].flag = FALSE;
|
||
|
}
|
||
|
|
||
|
static u8 PaletteStruct_GetPalNum(u16 id)
|
||
|
{
|
||
|
u8 i;
|
||
|
|
||
|
for (i = 0; i < NUM_PALETTE_STRUCTS; i++)
|
||
|
if (sPaletteStructs[i].template->id == id)
|
||
|
return i;
|
||
|
|
||
|
return NUM_PALETTE_STRUCTS;
|
||
|
}
|
||
|
|
||
|
static u8 UpdateNormalPaletteFade(void)
|
||
|
{
|
||
|
u16 paletteOffset;
|
||
|
u16 selectedPalettes;
|
||
|
|
||
|
if (!gPaletteFade.active)
|
||
|
return PALETTE_FADE_STATUS_DONE;
|
||
|
|
||
|
if (IsSoftwarePaletteFadeFinishing())
|
||
|
{
|
||
|
return gPaletteFade.active ? PALETTE_FADE_STATUS_ACTIVE : PALETTE_FADE_STATUS_DONE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!gPaletteFade.objPaletteToggle)
|
||
|
{
|
||
|
if (gPaletteFade.delayCounter < gPaletteFade_delay)
|
||
|
{
|
||
|
gPaletteFade.delayCounter++;
|
||
|
return 2;
|
||
|
}
|
||
|
gPaletteFade.delayCounter = 0;
|
||
|
}
|
||
|
|
||
|
paletteOffset = 0;
|
||
|
|
||
|
if (!gPaletteFade.objPaletteToggle)
|
||
|
{
|
||
|
selectedPalettes = gPaletteFade_selectedPalettes;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
selectedPalettes = gPaletteFade_selectedPalettes >> 16;
|
||
|
paletteOffset = 256;
|
||
|
}
|
||
|
|
||
|
while (selectedPalettes)
|
||
|
{
|
||
|
if (selectedPalettes & 1)
|
||
|
BlendPalette(
|
||
|
paletteOffset,
|
||
|
16,
|
||
|
gPaletteFade.y,
|
||
|
gPaletteFade.blendColor);
|
||
|
selectedPalettes >>= 1;
|
||
|
paletteOffset += 16;
|
||
|
}
|
||
|
|
||
|
gPaletteFade.objPaletteToggle ^= 1;
|
||
|
|
||
|
if (!gPaletteFade.objPaletteToggle)
|
||
|
{
|
||
|
if (gPaletteFade.y == gPaletteFade.targetY)
|
||
|
{
|
||
|
gPaletteFade_selectedPalettes = 0;
|
||
|
gPaletteFade.softwareFadeFinishing = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s8 val;
|
||
|
|
||
|
if (!gPaletteFade.yDec)
|
||
|
{
|
||
|
val = gPaletteFade.y;
|
||
|
val += gPaletteFade.deltaY;
|
||
|
if (val > gPaletteFade.targetY)
|
||
|
val = gPaletteFade.targetY;
|
||
|
gPaletteFade.y = val;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
val = gPaletteFade.y;
|
||
|
val -= gPaletteFade.deltaY;
|
||
|
if (val < gPaletteFade.targetY)
|
||
|
val = gPaletteFade.targetY;
|
||
|
gPaletteFade.y = val;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void InvertPlttBuffer(u32 selectedPalettes)
|
||
|
{
|
||
|
u16 paletteOffset = 0;
|
||
|
|
||
|
while (selectedPalettes)
|
||
|
{
|
||
|
if (selectedPalettes & 1)
|
||
|
{
|
||
|
u8 i;
|
||
|
for (i = 0; i < 16; i++)
|
||
|
gPlttBufferFaded[paletteOffset + i] = ~gPlttBufferFaded[paletteOffset + i];
|
||
|
}
|
||
|
selectedPalettes >>= 1;
|
||
|
paletteOffset += 16;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void TintPlttBuffer(u32 selectedPalettes, s8 r, s8 g, s8 b)
|
||
|
{
|
||
|
u16 paletteOffset = 0;
|
||
|
|
||
|
while (selectedPalettes)
|
||
|
{
|
||
|
if (selectedPalettes & 1)
|
||
|
{
|
||
|
u8 i;
|
||
|
for (i = 0; i < 16; i++)
|
||
|
{
|
||
|
struct PlttData *data = (struct PlttData *)&gPlttBufferFaded[paletteOffset + i];
|
||
|
data->r += r;
|
||
|
data->g += g;
|
||
|
data->b += b;
|
||
|
}
|
||
|
}
|
||
|
selectedPalettes >>= 1;
|
||
|
paletteOffset += 16;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void UnfadePlttBuffer(u32 selectedPalettes)
|
||
|
{
|
||
|
u16 paletteOffset = 0;
|
||
|
|
||
|
while (selectedPalettes)
|
||
|
{
|
||
|
if (selectedPalettes & 1)
|
||
|
{
|
||
|
u8 i;
|
||
|
for (i = 0; i < 16; i++)
|
||
|
gPlttBufferFaded[paletteOffset + i] = gPlttBufferUnfaded[paletteOffset + i];
|
||
|
}
|
||
|
selectedPalettes >>= 1;
|
||
|
paletteOffset += 16;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BeginFastPaletteFade(u8 submode)
|
||
|
{
|
||
|
gPaletteFade.deltaY = 2;
|
||
|
BeginFastPaletteFadeInternal(submode);
|
||
|
}
|
||
|
|
||
|
static void BeginFastPaletteFadeInternal(u8 submode)
|
||
|
{
|
||
|
gPaletteFade.y = 31;
|
||
|
gPaletteFade_submode = submode & 0x3F;
|
||
|
gPaletteFade.active = TRUE;
|
||
|
gPaletteFade.mode = FAST_FADE;
|
||
|
|
||
|
if (submode == FAST_FADE_IN_FROM_BLACK)
|
||
|
CpuFill16(RGB_BLACK, gPlttBufferFaded, PLTT_SIZE);
|
||
|
|
||
|
if (submode == FAST_FADE_IN_FROM_WHITE)
|
||
|
CpuFill16(RGB_WHITE, gPlttBufferFaded, PLTT_SIZE);
|
||
|
|
||
|
UpdatePaletteFade();
|
||
|
}
|
||
|
|
||
|
static u8 UpdateFastPaletteFade(void)
|
||
|
{
|
||
|
u16 i;
|
||
|
u16 paletteOffsetStart;
|
||
|
u16 paletteOffsetEnd;
|
||
|
s8 r0;
|
||
|
s8 g0;
|
||
|
s8 b0;
|
||
|
s8 r;
|
||
|
s8 g;
|
||
|
s8 b;
|
||
|
|
||
|
if (!gPaletteFade.active)
|
||
|
return PALETTE_FADE_STATUS_DONE;
|
||
|
|
||
|
if (IsSoftwarePaletteFadeFinishing())
|
||
|
return gPaletteFade.active ? PALETTE_FADE_STATUS_ACTIVE : PALETTE_FADE_STATUS_DONE;
|
||
|
|
||
|
|
||
|
if (gPaletteFade.objPaletteToggle)
|
||
|
{
|
||
|
paletteOffsetStart = 256;
|
||
|
paletteOffsetEnd = 512;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
paletteOffsetStart = 0;
|
||
|
paletteOffsetEnd = 256;
|
||
|
}
|
||
|
|
||
|
switch (gPaletteFade_submode)
|
||
|
{
|
||
|
case FAST_FADE_IN_FROM_WHITE:
|
||
|
for (i = paletteOffsetStart; i < paletteOffsetEnd; i++)
|
||
|
{
|
||
|
struct PlttData *unfaded;
|
||
|
struct PlttData *faded;
|
||
|
|
||
|
unfaded = (struct PlttData *)&gPlttBufferUnfaded[i];
|
||
|
r0 = unfaded->r;
|
||
|
g0 = unfaded->g;
|
||
|
b0 = unfaded->b;
|
||
|
|
||
|
faded = (struct PlttData *)&gPlttBufferFaded[i];
|
||
|
r = faded->r - 2;
|
||
|
g = faded->g - 2;
|
||
|
b = faded->b - 2;
|
||
|
|
||
|
if (r < r0)
|
||
|
r = r0;
|
||
|
if (g < g0)
|
||
|
g = g0;
|
||
|
if (b < b0)
|
||
|
b = b0;
|
||
|
|
||
|
gPlttBufferFaded[i] = RGB(r, g, b);
|
||
|
}
|
||
|
break;
|
||
|
case FAST_FADE_OUT_TO_WHITE:
|
||
|
for (i = paletteOffsetStart; i < paletteOffsetEnd; i++)
|
||
|
{
|
||
|
struct PlttData *data = (struct PlttData *)&gPlttBufferFaded[i];
|
||
|
r = data->r + 2;
|
||
|
g = data->g + 2;
|
||
|
b = data->b + 2;
|
||
|
|
||
|
if (r > 31)
|
||
|
r = 31;
|
||
|
if (g > 31)
|
||
|
g = 31;
|
||
|
if (b > 31)
|
||
|
b = 31;
|
||
|
|
||
|
gPlttBufferFaded[i] = RGB(r, g, b);
|
||
|
}
|
||
|
break;
|
||
|
case FAST_FADE_IN_FROM_BLACK:
|
||
|
for (i = paletteOffsetStart; i < paletteOffsetEnd; i++)
|
||
|
{
|
||
|
struct PlttData *unfaded;
|
||
|
struct PlttData *faded;
|
||
|
|
||
|
unfaded = (struct PlttData *)&gPlttBufferUnfaded[i];
|
||
|
r0 = unfaded->r;
|
||
|
g0 = unfaded->g;
|
||
|
b0 = unfaded->b;
|
||
|
|
||
|
faded = (struct PlttData *)&gPlttBufferFaded[i];
|
||
|
r = faded->r + 2;
|
||
|
g = faded->g + 2;
|
||
|
b = faded->b + 2;
|
||
|
|
||
|
if (r > r0)
|
||
|
r = r0;
|
||
|
if (g > g0)
|
||
|
g = g0;
|
||
|
if (b > b0)
|
||
|
b = b0;
|
||
|
|
||
|
gPlttBufferFaded[i] = RGB(r, g, b);
|
||
|
}
|
||
|
break;
|
||
|
case FAST_FADE_OUT_TO_BLACK:
|
||
|
for (i = paletteOffsetStart; i < paletteOffsetEnd; i++)
|
||
|
{
|
||
|
struct PlttData *data = (struct PlttData *)&gPlttBufferFaded[i];
|
||
|
r = data->r - 2;
|
||
|
g = data->g - 2;
|
||
|
b = data->b - 2;
|
||
|
|
||
|
if (r < 0)
|
||
|
r = 0;
|
||
|
if (g < 0)
|
||
|
g = 0;
|
||
|
if (b < 0)
|
||
|
b = 0;
|
||
|
|
||
|
gPlttBufferFaded[i] = RGB(r, g, b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gPaletteFade.objPaletteToggle ^= 1;
|
||
|
|
||
|
if (gPaletteFade.objPaletteToggle)
|
||
|
// 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;
|
||
|
|
||
|
if (gPaletteFade.y - gPaletteFade.deltaY < 0)
|
||
|
gPaletteFade.y = 0;
|
||
|
else
|
||
|
gPaletteFade.y -= gPaletteFade.deltaY;
|
||
|
|
||
|
if (gPaletteFade.y == 0)
|
||
|
{
|
||
|
switch (gPaletteFade_submode)
|
||
|
{
|
||
|
case FAST_FADE_IN_FROM_WHITE:
|
||
|
case FAST_FADE_IN_FROM_BLACK:
|
||
|
CpuCopy32(gPlttBufferUnfaded, gPlttBufferFaded, PLTT_SIZE);
|
||
|
break;
|
||
|
case FAST_FADE_OUT_TO_WHITE:
|
||
|
CpuFill32(0xFFFFFFFF, gPlttBufferFaded, PLTT_SIZE);
|
||
|
break;
|
||
|
case FAST_FADE_OUT_TO_BLACK:
|
||
|
CpuFill32(0x00000000, gPlttBufferFaded, PLTT_SIZE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
gPaletteFade.mode = NORMAL_FADE;
|
||
|
gPaletteFade.softwareFadeFinishing = TRUE;
|
||
|
}
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
void BeginHardwarePaletteFade(u8 blendCnt, u8 delay, u8 y, u8 targetY, u8 shouldResetBlendRegisters)
|
||
|
{
|
||
|
gPaletteFade_blendCnt = blendCnt;
|
||
|
gPaletteFade.delayCounter = delay;
|
||
|
gPaletteFade_delay = delay;
|
||
|
gPaletteFade.y = y;
|
||
|
gPaletteFade.targetY = targetY;
|
||
|
gPaletteFade.active = TRUE;
|
||
|
gPaletteFade.mode = HARDWARE_FADE;
|
||
|
gPaletteFade.shouldResetBlendRegisters = shouldResetBlendRegisters & 1;
|
||
|
gPaletteFade.hardwareFadeFinishing = FALSE;
|
||
|
|
||
|
if (y < targetY)
|
||
|
gPaletteFade.yDec = 0;
|
||
|
else
|
||
|
gPaletteFade.yDec = 1;
|
||
|
}
|
||
|
|
||
|
static u8 UpdateHardwarePaletteFade(void)
|
||
|
{
|
||
|
if (!gPaletteFade.active)
|
||
|
return PALETTE_FADE_STATUS_DONE;
|
||
|
|
||
|
if (gPaletteFade.delayCounter < gPaletteFade_delay)
|
||
|
{
|
||
|
gPaletteFade.delayCounter++;
|
||
|
return PALETTE_FADE_STATUS_DELAY;
|
||
|
}
|
||
|
|
||
|
gPaletteFade.delayCounter = 0;
|
||
|
|
||
|
if (!gPaletteFade.yDec)
|
||
|
{
|
||
|
gPaletteFade.y++;
|
||
|
if (gPaletteFade.y > gPaletteFade.targetY)
|
||
|
{
|
||
|
gPaletteFade.hardwareFadeFinishing++;
|
||
|
gPaletteFade.y--;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s32 y = gPaletteFade.y--;
|
||
|
if (y - 1 < gPaletteFade.targetY)
|
||
|
{
|
||
|
gPaletteFade.hardwareFadeFinishing++;
|
||
|
gPaletteFade.y++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (gPaletteFade.hardwareFadeFinishing)
|
||
|
{
|
||
|
if (gPaletteFade.shouldResetBlendRegisters)
|
||
|
{
|
||
|
gPaletteFade_blendCnt = 0;
|
||
|
gPaletteFade.y = 0;
|
||
|
}
|
||
|
gPaletteFade.shouldResetBlendRegisters = FALSE;
|
||
|
}
|
||
|
|
||
|
// 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 void UpdateBlendRegisters(void)
|
||
|
{
|
||
|
SetGpuReg(REG_OFFSET_BLDCNT, (u16)gPaletteFade_blendCnt);
|
||
|
SetGpuReg(REG_OFFSET_BLDY, gPaletteFade.y);
|
||
|
if (gPaletteFade.hardwareFadeFinishing)
|
||
|
{
|
||
|
gPaletteFade.hardwareFadeFinishing = FALSE;
|
||
|
gPaletteFade.mode = 0;
|
||
|
gPaletteFade_blendCnt = 0;
|
||
|
gPaletteFade.y = 0;
|
||
|
gPaletteFade.active = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool8 IsSoftwarePaletteFadeFinishing(void)
|
||
|
{
|
||
|
if (gPaletteFade.softwareFadeFinishing)
|
||
|
{
|
||
|
if (gPaletteFade.softwareFadeFinishingCounter == 4)
|
||
|
{
|
||
|
gPaletteFade.active = FALSE;
|
||
|
gPaletteFade.softwareFadeFinishing = FALSE;
|
||
|
gPaletteFade.softwareFadeFinishingCounter = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gPaletteFade.softwareFadeFinishingCounter++;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BlendPalettes(u32 selectedPalettes, u8 coeff, u16 color)
|
||
|
{
|
||
|
u16 paletteOffset;
|
||
|
|
||
|
for (paletteOffset = 0; selectedPalettes; paletteOffset += 16)
|
||
|
{
|
||
|
if (selectedPalettes & 1)
|
||
|
BlendPalette(paletteOffset, 16, coeff, color);
|
||
|
selectedPalettes >>= 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void BlendPalettesUnfaded(u32 selectedPalettes, u8 coeff, u16 color)
|
||
|
{
|
||
|
void *src = gPlttBufferUnfaded;
|
||
|
void *dest = gPlttBufferFaded;
|
||
|
DmaCopy32(3, src, dest, PLTT_SIZE);
|
||
|
BlendPalettes(selectedPalettes, coeff, color);
|
||
|
}
|
||
|
|
||
|
void TintPalette_GrayScale(u16 *palette, u16 count)
|
||
|
{
|
||
|
s32 r, g, b, i;
|
||
|
u32 gray;
|
||
|
|
||
|
for (i = 0; i < count; i++)
|
||
|
{
|
||
|
r = GET_R(*palette);
|
||
|
g = GET_G(*palette);
|
||
|
b = GET_B(*palette);
|
||
|
|
||
|
gray = (r * Q_8_8(0.3) + g * Q_8_8(0.59) + b * Q_8_8(0.1133)) >> 8;
|
||
|
|
||
|
*palette++ = RGB2(gray, gray, gray);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void TintPalette_GrayScale2(u16 *palette, u16 count)
|
||
|
{
|
||
|
s32 r, g, b, i;
|
||
|
u32 gray;
|
||
|
|
||
|
for (i = 0; i < count; i++)
|
||
|
{
|
||
|
r = GET_R(*palette);
|
||
|
g = GET_G(*palette);
|
||
|
b = GET_B(*palette);
|
||
|
|
||
|
gray = (r * Q_8_8(0.3) + g * Q_8_8(0.59) + b * Q_8_8(0.1133)) >> 8;
|
||
|
|
||
|
if (gray > 31)
|
||
|
gray = 31;
|
||
|
|
||
|
gray = sRoundedDownGrayscaleMap[gray];
|
||
|
|
||
|
*palette++ = RGB2(gray, gray, gray);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void TintPalette_SepiaTone(u16 *palette, u16 count)
|
||
|
{
|
||
|
s32 r, g, b, i;
|
||
|
u32 gray;
|
||
|
|
||
|
for (i = 0; i < count; i++)
|
||
|
{
|
||
|
r = GET_R(*palette);
|
||
|
g = GET_G(*palette);
|
||
|
b = GET_B(*palette);
|
||
|
|
||
|
gray = (r * Q_8_8(0.3) + g * Q_8_8(0.59) + b * Q_8_8(0.1133)) >> 8;
|
||
|
|
||
|
r = (u16)((Q_8_8(1.2) * gray)) >> 8;
|
||
|
g = (u16)((Q_8_8(1.0) * gray)) >> 8;
|
||
|
b = (u16)((Q_8_8(0.94) * gray)) >> 8;
|
||
|
|
||
|
if (r > 31)
|
||
|
r = 31;
|
||
|
|
||
|
*palette++ = RGB2(r, g, b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void TintPalette_CustomTone(u16 *palette, u16 count, u16 rTone, u16 gTone, u16 bTone)
|
||
|
{
|
||
|
s32 r, g, b, i;
|
||
|
u32 gray;
|
||
|
|
||
|
for (i = 0; i < count; i++)
|
||
|
{
|
||
|
r = GET_R(*palette);
|
||
|
g = GET_G(*palette);
|
||
|
b = GET_B(*palette);
|
||
|
|
||
|
gray = (r * Q_8_8(0.3) + g * Q_8_8(0.59) + b * Q_8_8(0.1133)) >> 8;
|
||
|
|
||
|
r = (u16)((rTone * gray)) >> 8;
|
||
|
g = (u16)((gTone * gray)) >> 8;
|
||
|
b = (u16)((bTone * gray)) >> 8;
|
||
|
|
||
|
if (r > 31)
|
||
|
r = 31;
|
||
|
if (g > 31)
|
||
|
g = 31;
|
||
|
if (b > 31)
|
||
|
b = 31;
|
||
|
|
||
|
*palette++ = RGB2(r, g, b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define tCoeff data[0]
|
||
|
#define tCoeffTarget data[1]
|
||
|
#define tCoeffDelta data[2]
|
||
|
#define tDelay data[3]
|
||
|
#define tDelayTimer data[4]
|
||
|
#define tPalettes 5 // data[5] and data[6], set/get via Set/GetWordTaskArg
|
||
|
#define tColor data[7]
|
||
|
#define tId data[8]
|
||
|
|
||
|
// Blend the selected palettes in a series of steps toward or away from the color.
|
||
|
// Only used by the Groudon/Kyogre fight scene to flash the screen for lightning.
|
||
|
// One call is used to fade the bg from white, while another fades the duo from black
|
||
|
void BlendPalettesGradually(u32 selectedPalettes, s8 delay, u8 coeff, u8 coeffTarget, u16 color, u8 priority, u8 id)
|
||
|
{
|
||
|
u8 taskId;
|
||
|
|
||
|
taskId = CreateTask((void *)Task_BlendPalettesGradually, priority);
|
||
|
gTasks[taskId].tCoeff = coeff;
|
||
|
gTasks[taskId].tCoeffTarget = coeffTarget;
|
||
|
|
||
|
if (delay >= 0)
|
||
|
{
|
||
|
gTasks[taskId].tDelay = delay;
|
||
|
gTasks[taskId].tCoeffDelta = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gTasks[taskId].tDelay = 0;
|
||
|
gTasks[taskId].tCoeffDelta = -delay + 1;
|
||
|
}
|
||
|
|
||
|
if (coeffTarget < coeff)
|
||
|
gTasks[taskId].tCoeffDelta *= -1;
|
||
|
|
||
|
SetWordTaskArg(taskId, tPalettes, selectedPalettes);
|
||
|
gTasks[taskId].tColor = color;
|
||
|
gTasks[taskId].tId = id;
|
||
|
gTasks[taskId].func(taskId);
|
||
|
}
|
||
|
|
||
|
// Unused
|
||
|
static bool32 IsBlendPalettesGraduallyTaskActive(u8 id)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < NUM_TASKS; i++)
|
||
|
if ((gTasks[i].isActive == TRUE)
|
||
|
&& (gTasks[i].func == Task_BlendPalettesGradually)
|
||
|
&& (gTasks[i].tId == id))
|
||
|
return TRUE;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Unused
|
||
|
static void DestroyBlendPalettesGraduallyTask(void)
|
||
|
{
|
||
|
u8 taskId;
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
taskId = FindTaskIdByFunc(Task_BlendPalettesGradually);
|
||
|
if (taskId == TASK_NONE)
|
||
|
break;
|
||
|
DestroyTask(taskId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void Task_BlendPalettesGradually(u8 taskId)
|
||
|
{
|
||
|
u32 palettes;
|
||
|
s16 *data;
|
||
|
s16 target;
|
||
|
|
||
|
data = gTasks[taskId].data;
|
||
|
palettes = GetWordTaskArg(taskId, tPalettes);
|
||
|
|
||
|
if (++tDelayTimer > tDelay)
|
||
|
{
|
||
|
tDelayTimer = 0;
|
||
|
BlendPalettes(palettes, tCoeff, tColor);
|
||
|
target = tCoeffTarget;
|
||
|
if (tCoeff == target)
|
||
|
{
|
||
|
DestroyTask(taskId);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tCoeff += tCoeffDelta;
|
||
|
if (tCoeffDelta >= 0)
|
||
|
{
|
||
|
if (tCoeff < target)
|
||
|
return;
|
||
|
}
|
||
|
else if (tCoeff > target)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
tCoeff = target;
|
||
|
}
|
||
|
}
|
||
|
}
|