Added inter-time-of-day blending.

This commit is contained in:
Ariel Antonitis 2021-04-19 00:07:42 -04:00
parent 3bd46b5b7a
commit 22c429d0d6
4 changed files with 181 additions and 52 deletions

View file

@ -44,6 +44,12 @@ struct LinkPlayerObjectEvent
u8 movementMode;
};
struct __attribute__((packed)) TimeBlendSettings {
u16 weight:9;
u16 time1:3;
u16 time0:3;
};
// Exported RAM declarations
extern struct WarpData gLastUsedWarp;
extern struct LinkPlayerObjectEvent gLinkPlayerObjectEvents[4];

View file

@ -77,9 +77,9 @@ void BlendPalettes(u32 selectedPalettes, u8 coeff, u16 color);
void BlendPalettesUnfaded(u32, u8, u16);
void BlendPalettesGradually(u32 selectedPalettes, s8 delay, u8 coeff, u8 coeffTarget, u16 color, u8 priority, u8 id);
void AveragePalettes(u16 *palette0, u16* palette1, u16* dest, u16 weight);
void TimeBlendPalette(u16 palOffset, u16 numEntries, u8 coeff, u16 blendColor);
void TimeBlendPalette(u16 palOffset, u32 coeff, u32 blendColor);
void TintPalette_RGB_Copy(u16 palOffset, u16 numEntries, u8 coeff, u16 blendColor);
void TimeBlendPalettes(u32 palettes, u8 coeff, u16 color);
void TimeBlendPalettes(u32 palettes, u32 coeff, u32 blendColor);
void TintPalette_GrayScale(u16 *palette, u16 count);
void TintPalette_GrayScale2(u16 *palette, u16 count);
void TintPalette_SepiaTone(u16 *palette, u16 count);

View file

@ -186,7 +186,9 @@ static u16 (*sPlayerKeyInterceptCallback)(u32);
static bool8 sReceivingFromLink;
static u8 sRfuKeepAliveTimer;
u8 static gTimeOfDayState;
static u8 gTimeOfDayState;
static u8 timeCounter;
static struct TimeBlendSettings currentTimeBlend;
// IWRAM common
u16 *gBGTilemapBuffers1;
@ -1472,12 +1474,39 @@ static const struct TimeOfDayBlend sTimeOfDayBlendVars[] =
};
u8 UpdateTimeOfDay(void) {
s8 hours, minutes;
RtcCalcLocalTime();
if (gLocalTime.hours >= 20 || gLocalTime.hours < 4)
return gTimeOfDay = TIME_OF_DAY_NIGHT;
else if (gLocalTime.hours >= 10 && gLocalTime.hours < 20)
hours = gLocalTime.hours;
minutes = gLocalTime.minutes;
if (hours >= 22 || hours < 4) {
currentTimeBlend.weight = 256;
return gTimeOfDay = currentTimeBlend.time0 = currentTimeBlend.time1 = TIME_OF_DAY_NIGHT;
} else if (hours >= 4 && hours < 7) { // night->twilight
currentTimeBlend.time0 = TIME_OF_DAY_NIGHT;
currentTimeBlend.time1 = TIME_OF_DAY_TWILIGHT;
currentTimeBlend.weight = 256 - 256 * ((hours - 4) * 60 + minutes) / ((7-4)*60);
return gTimeOfDay = TIME_OF_DAY_DAY;
return gTimeOfDay = TIME_OF_DAY_TWILIGHT;
} else if (hours >= 7 && hours < 10) { // twilight->day
currentTimeBlend.time0 = TIME_OF_DAY_TWILIGHT;
currentTimeBlend.time1 = TIME_OF_DAY_DAY;
currentTimeBlend.weight = 256 - 256 * ((hours - 7) * 60 + minutes) / ((10-7)*60);
return gTimeOfDay = TIME_OF_DAY_DAY;
} else if (hours >= 10 && hours < 18) { // day
currentTimeBlend.weight = 256;
return gTimeOfDay = currentTimeBlend.time0 = currentTimeBlend.time1 = TIME_OF_DAY_DAY;
} else if (hours >= 18 && hours < 20) { // day->twilight
currentTimeBlend.time0 = TIME_OF_DAY_DAY;
currentTimeBlend.time1 = TIME_OF_DAY_TWILIGHT;
currentTimeBlend.weight = 256 - 256 * ((hours - 18) * 60 + minutes) / ((20-18)*60);
return gTimeOfDay = TIME_OF_DAY_TWILIGHT;
} else if (hours >= 20 && hours < 22) { // twilight->night
currentTimeBlend.time0 = TIME_OF_DAY_TWILIGHT;
currentTimeBlend.time1 = TIME_OF_DAY_NIGHT;
currentTimeBlend.weight = 256 - 256 * ((hours - 20) * 60 + minutes) / ((22-20)*60);
return gTimeOfDay = TIME_OF_DAY_NIGHT;
} else { // This should never occur
return TIME_OF_DAY_MAX;
}
}
static bool8 MapHasNaturalLight(u8 mapType) { // Weather a map type is naturally lit/outside
@ -1485,7 +1514,7 @@ static bool8 MapHasNaturalLight(u8 mapType) { // Weather a map type is naturally
|| mapType == MAP_TYPE_OCEAN_ROUTE;
}
static bool8 FadePalettesWithTime(void) {
static bool8 FadePalettesWithTime(void) { // Only used to fade back in
gTimeOfDayState = 0;
gTimeOfDay = UpdateTimeOfDay();
if (MapHasNaturalLight(gMapHeader.mapType)) {
@ -1495,8 +1524,7 @@ static bool8 FadePalettesWithTime(void) {
}
void UpdatePalettesWithTime(u32 palettes) {
// Only blend if not transitioning between times and the map type allows
if (gTimeOfDayState == 0 && MapHasNaturalLight(gMapHeader.mapType)) {
if (MapHasNaturalLight(gMapHeader.mapType)) {
u8 i, j;
u16 tempPaletteBuffer[16];
for (i = 0; i < 16; i++) {
@ -1509,10 +1537,14 @@ void UpdatePalettesWithTime(u32 palettes) {
return;
for (i = 0; palettes; i++) {
if (palettes & 1) {
TimeBlendPalette(i*16, 16, sTimeOfDayBlendVars[gTimeOfDay].coeff, sTimeOfDayBlendVars[gTimeOfDay].blendColor);
TimeBlendPalette(i*16, sTimeOfDayBlendVars[currentTimeBlend.time0].coeff, sTimeOfDayBlendVars[currentTimeBlend.time0].blendColor);
if (currentTimeBlend.weight == 256) {
palettes >>= 1;
continue;
}
CpuFastCopy(&gPlttBufferFaded[i*16], tempPaletteBuffer, 32);
TimeBlendPalette(i*16, 16, sTimeOfDayBlendVars[TIME_OF_DAY_TWILIGHT].coeff, sTimeOfDayBlendVars[TIME_OF_DAY_TWILIGHT].blendColor);
AveragePalettes(tempPaletteBuffer, &gPlttBufferFaded[i*16], &gPlttBufferFaded[i*16], 256);
TimeBlendPalette(i*16, sTimeOfDayBlendVars[currentTimeBlend.time1].coeff, sTimeOfDayBlendVars[currentTimeBlend.time1].blendColor);
AveragePalettes(tempPaletteBuffer, &gPlttBufferFaded[i*16], &gPlttBufferFaded[i*16], currentTimeBlend.weight);
}
palettes >>= 1;
}
@ -1535,6 +1567,19 @@ static void OverworldBasic(void)
UpdatePaletteFade();
UpdateTilesetAnimations();
DoScheduledBgTilemapCopiesToVram();
if (!(gPaletteFade.active || (timeCounter++ % 60))) {
struct TimeBlendSettings cachedBlend = {
.time0 = currentTimeBlend.time0,
.time1 = currentTimeBlend.time1,
.weight = currentTimeBlend.weight,
};
timeCounter = 0;
UpdateTimeOfDay();
if (cachedBlend.time0 != currentTimeBlend.time0
|| cachedBlend.time1 != currentTimeBlend.time1
|| cachedBlend.weight != currentTimeBlend.weight)
UpdatePalettesWithTime(0xFFFFFFFF);
}
}
// This CB2 is used when starting
@ -1545,9 +1590,7 @@ void CB2_OverworldBasic(void)
void CB2_Overworld(void)
{
u32 *debugPtr = (u32*) 0x0203de00;
bool32 fading = (gPaletteFade.active != 0);
*debugPtr = (u32) &gTimeOfDay;
if (fading)
SetVBlankCallback(NULL);
OverworldBasic();

View file

@ -496,13 +496,13 @@ static u8 UpdateTimeOfDayPaletteFade(void)
if (gPaletteFade.yDec) {
if (gPaletteFade.objPaletteToggle) { // sprite palettes
if (gPaletteFade.y >= gPaletteFade.targetY || GetSpritePaletteTagByPaletteNum(paletteNum) & 0x8000)
TimeBlendPalette(paletteOffset, 16, gPaletteFade.y, gPaletteFade.blendColor);
TimeBlendPalette(paletteOffset, gPaletteFade.y, gPaletteFade.blendColor);
// tile palettes
} else if (gPaletteFade.y >= gPaletteFade.targetY || (paletteNum >= 13 && paletteNum <= 15)) {
TimeBlendPalette(paletteOffset, 16, gPaletteFade.y, gPaletteFade.blendColor);
TimeBlendPalette(paletteOffset, gPaletteFade.y, gPaletteFade.blendColor);
}
} else {
TimeBlendPalette(paletteOffset, 16, gPaletteFade.y, gPaletteFade.blendColor);
TimeBlendPalette(paletteOffset, gPaletteFade.y, gPaletteFade.blendColor);
}
}
}
@ -1010,45 +1010,125 @@ void AveragePalettes(u16 *palette0, u16* palette1, u16* dest, u16 weight) {
#define DEFAULT_LIGHT_COLOR 0x3f9f
// Like BlendPalette, but ignores blendColor if the transparency high bit is set
void TimeBlendPalette(u16 palOffset, u16 numEntries, u8 coeff, u16 blendColor) {
u16 i;
u16 defaultBlendColor = DEFAULT_LIGHT_COLOR;
s8 r, g, b;
struct PlttData *data2 = (struct PlttData *)&blendColor;
struct PlttData *data3;
struct PlttData *blendData;
u16 altBlendIndices = 0;
for (i = 0; i < numEntries; i++) {
u16 index = i + palOffset;
struct PlttData *data1 = (struct PlttData *)&gPlttBufferUnfaded[index];
if (i == 0) {
if (data1->unused_15) { // Color 0 is a bitmask for which colors to blend; color 15 is the alt blend color
gPlttBufferFaded[index] = gPlttBufferUnfaded[index];
altBlendIndices = gPlttBufferUnfaded[index] << 1; // bit 0 specifies color 1, etc.
data3 = (struct PlttData *)&gPlttBufferUnfaded[index+15];
if (!data3->unused_15) // use default blend color instead
data3 = (struct PlttData *)&defaultBlendColor;
}
continue;
// Optimization help by lucktyphlosion
void TimeBlendPalette(u16 palOffset, u32 coeff, u32 blendColor) {
s32 newR, newG, newB, defR, defG, defB;
u16 * palDataSrc = gPlttBufferUnfaded + palOffset;
u16 * palDataDst = gPlttBufferFaded + palOffset;
u32 defaultBlendColor = DEFAULT_LIGHT_COLOR;
u16 *palDataSrcEnd = palDataSrc + 16;
u16 altBlendIndices = *palDataDst++ = *palDataSrc++; // color 0 is copied through unchanged
u32 altBlendColor;
coeff *= 2;
newR = (blendColor << 27) >> 27;
newG = (blendColor << 22) >> 27;
newB = (blendColor << 17) >> 27;
if (altBlendIndices >> 15) { // High bit set; bitmask of which colors to alt-blend
// Note that bit 0 of altBlendIndices specifies color 1
altBlendColor = palDataSrc[14]; // color 15
if (altBlendColor >> 15) { // Set alternate blend color
defR = (altBlendColor << 27) >> 27;
defG = (altBlendColor << 22) >> 27;
defB = (altBlendColor << 17) >> 27;
} else { // Set default blend color
defR = (defaultBlendColor << 27) >> 27;
defG = (defaultBlendColor << 22) >> 27;
defB = (defaultBlendColor << 17) >> 27;
}
r = data1->r;
g = data1->g;
b = data1->b;
blendData = (altBlendIndices && altBlendIndices & (1 << i)) ? data3 : data2;
gPlttBufferFaded[index] = RGB(r + (((blendData->r - r) * coeff) >> 4),
g + (((blendData->g - g) * coeff) >> 4),
b + (((blendData->b - b) * coeff) >> 4));
} else {
altBlendIndices = 0;
}
while (palDataSrc != palDataSrcEnd) {
u32 palDataSrcColor = *palDataSrc;
s32 r = (palDataSrcColor << 27) >> 27;
s32 g = (palDataSrcColor << 22) >> 27;
s32 b = (palDataSrcColor << 17) >> 27;
if (altBlendIndices & 1) {
*palDataDst = ((r + (((defR - r) * coeff) >> 5)) << 0)
| ((g + (((defG - g) * coeff) >> 5)) << 5)
| ((b + (((defB - b) * coeff) >> 5)) << 10);
} else { // Use provided blend color
*palDataDst = ((r + (((newR - r) * coeff) >> 5)) << 0)
| ((g + (((newG - g) * coeff) >> 5)) << 5)
| ((b + (((newB - b) * coeff) >> 5)) << 10);
}
palDataSrc++;
palDataDst++;
altBlendIndices >>= 1;
}
}
// Apply time effect to a series of palettes
void TimeBlendPalettes(u32 palettes, u8 coeff, u16 color) {
u16 paletteOffset;
for (paletteOffset = 0; palettes; paletteOffset += 16) {
if (palettes & 1)
TimeBlendPalette(paletteOffset, 16, coeff, color);
void TimeBlendPalettes(u32 palettes, u32 coeff, u32 blendColor) {
s32 newR, newG, newB, defR, defG, defB, altR, altG, altB;
u16 * palDataSrc;
u16 * palDataDst;
u32 defaultBlendColor = DEFAULT_LIGHT_COLOR;
if (!palettes)
return;
coeff *= 2;
newR = (blendColor << 27) >> 27;
newG = (blendColor << 22) >> 27;
newB = (blendColor << 17) >> 27;
defR = (defaultBlendColor << 27) >> 27;
defG = (defaultBlendColor << 22) >> 27;
defB = (defaultBlendColor << 17) >> 27;
palDataSrc = gPlttBufferUnfaded;
palDataDst = gPlttBufferFaded;
do {
if (palettes & 1) {
u16 *palDataSrcEnd = palDataSrc + 16;
u16 altBlendIndices = *palDataDst++ = *palDataSrc++; // color 0 is copied through
u32 altBlendColor;
if (altBlendIndices >> 15) { // High bit set; bitmask of which colors to alt-blend
// Note that bit 0 of altBlendIndices specifies color 1
altBlendColor = palDataSrc[14]; // color 15
if (altBlendColor >> 15) { // Set alternate blend color
altR = (altBlendColor << 27) >> 27;
altG = (altBlendColor << 22) >> 27;
altB = (altBlendColor << 17) >> 27;
} else {
altBlendColor = 0;
}
} else {
altBlendIndices = 0;
}
while (palDataSrc != palDataSrcEnd) {
u32 palDataSrcColor = *palDataSrc;
s32 r = (palDataSrcColor << 27) >> 27;
s32 g = (palDataSrcColor << 22) >> 27;
s32 b = (palDataSrcColor << 17) >> 27;
if (altBlendIndices & 1) {
if (altBlendColor) { // Use alternate blend color
*palDataDst = ((r + (((altR - r) * coeff) >> 5)) << 0)
| ((g + (((altG - g) * coeff) >> 5)) << 5)
| ((b + (((altB - b) * coeff) >> 5)) << 10);
} else { // Use default blend color
*palDataDst = ((r + (((defR - r) * coeff) >> 5)) << 0)
| ((g + (((defG - g) * coeff) >> 5)) << 5)
| ((b + (((defB - b) * coeff) >> 5)) << 10);
}
} else { // Use provided blend color
*palDataDst = ((r + (((newR - r) * coeff) >> 5)) << 0)
| ((g + (((newG - g) * coeff) >> 5)) << 5)
| ((b + (((newB - b) * coeff) >> 5)) << 10);
}
palDataSrc++;
palDataDst++;
altBlendIndices >>= 1;
}
} else {
palDataSrc += 16;
palDataDst += 16;
}
palettes >>= 1;
}
} while (palettes);
}
void BlendPalettesUnfaded(u32 selectedPalettes, u8 coeff, u16 color)