diff --git a/include/core.h b/include/core.h index 1c08a5363..5a7c57ede 100644 --- a/include/core.h +++ b/include/core.h @@ -251,7 +251,7 @@ extern u8 gIwramHeap[TASK_HEAP_SIZE]; extern void *gVramHeapStartAddr; extern u16 gVramHeapMaxTileSlots; -extern u16 gVramHeapState[256]; +extern u16 gVramHeapState[OBJ_VRAM_TOTAL_SIZE / VRAM_HEAP_SEGMENT_SIZE]; extern bool8 gExecSoundMain; @@ -264,11 +264,18 @@ extern u16 gDispCnt; #define WINREG_WININ 4 #define WINREG_WINOUT 5 +#define PALETTE_LEN_4BPP 16u +#define GET_PALETTE_COLOR_OBJ(_paletteId, _colorId) gObjPalette[(_paletteId)*PALETTE_LEN_4BPP + (_colorId)] +#define GET_PALETTE_COLOR_BG(_paletteId, _colorId) gBgPalette[(_paletteId)*PALETTE_LEN_4BPP + (_colorId)] +#define SET_PALETTE_COLOR_OBJ(_paletteId, _colorId, _color) GET_PALETTE_COLOR_OBJ(_paletteId, _colorId) = (_color); +#define SET_PALETTE_COLOR_BG(_paletteId, _colorId, _color) GET_PALETTE_COLOR_BG(_paletteId, _colorId) = (_color); + extern winreg_t gWinRegs[6]; extern struct BlendRegs gBldRegs; extern BgAffineReg gBgAffineRegs[NUM_AFFINE_BACKGROUNDS]; -extern u16 gObjPalette[OBJ_PLTT_SIZE / sizeof(u16)]; -extern u16 gBgPalette[BG_PLTT_SIZE / sizeof(u16)]; +extern u16 gObjPalette[16 * PALETTE_LEN_4BPP]; +extern u16 gBgPalette[16 * PALETTE_LEN_4BPP]; + extern u16 gBgCntRegs[4]; // TODO: Turn this into a struct-array? diff --git a/include/gba/defines.h b/include/gba/defines.h index b904ee74d..d11003525 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -82,6 +82,7 @@ extern uint8_t OAM[OAM_SIZE]; #define OBJ_VRAM0 &VRAM[0x10000] #define OBJ_VRAM1 &VRAM[0x14000] +#define OBJ_VRAM_TOTAL_SIZE (VRAM_SIZE - BG_VRAM_SIZE) #else #define DISPLAY_WIDTH 240 #define DISPLAY_HEIGHT 160 @@ -118,8 +119,10 @@ extern uint8_t OAM[OAM_SIZE]; #define OAM 0x7000000 #define OAM_SIZE (OAM_ENTRY_COUNT*sizeof(OamData)) +#define OBJ_VRAM_TOTAL_SIZE (VRAM_SIZE - BG_VRAM_SIZE) #endif + #if WIDESCREEN_HACK #define WIN_REG_SIZE 4 #define WIN_RANGE(a, b) (((a) << 16) | (b)) diff --git a/include/global.h b/include/global.h index 946528d0d..8f186cacb 100644 --- a/include/global.h +++ b/include/global.h @@ -19,9 +19,11 @@ #if !PLATFORM_GBA #ifdef _WIN32 void *Platform_malloc(size_t numBytes); +void *Platform_realloc(void *ptr, size_t numBytes); void Platform_free(void *ptr); #define malloc(numBytes) Platform_malloc(numBytes) #define calloc(count, size) Platform_malloc(count *size) +#define realloc(ptr, size) Platform_realloc(ptr, size) #define free(numBytes) Platform_free(numBytes) #endif #endif diff --git a/include/malloc_vram.h b/include/malloc_vram.h index 5f69afce4..a50c328a2 100644 --- a/include/malloc_vram.h +++ b/include/malloc_vram.h @@ -3,8 +3,9 @@ #include "global.h" -#define VRAM_HEAP_SEGMENT_SIZE 0x80 -#define VRAM_TILE_SLOTS_PER_SEGMENT (VRAM_HEAP_SEGMENT_SIZE / TILE_SIZE_4BPP) +#define VRAM_HEAP_TILE_SIZE TILE_SIZE_4BPP +#define VRAM_HEAP_SEGMENT_SIZE (4 * VRAM_HEAP_TILE_SIZE) +#define VRAM_TILE_SLOTS_PER_SEGMENT (VRAM_HEAP_SEGMENT_SIZE / VRAM_HEAP_TILE_SIZE) // TODO: Find out where these numbers come from #if (ENGINE == ENGINE_1) diff --git a/include/platform/platform.h b/include/platform/platform.h index 0a44b8f1f..323b195c0 100644 --- a/include/platform/platform.h +++ b/include/platform/platform.h @@ -22,5 +22,8 @@ extern void Platform_LZDecompressUnsafe(unsigned char *src, unsigned char *dest) extern void Platform_RLDecompressUnsafe(unsigned char *src, unsigned char *dest); extern void Platform_QueueAudio(const void *data, u32 numBytes); +extern void Platform_ProcessBackgroundsCopyQueue(void); +// TODO: Re-enable once #include-ing global.h/core.h/sprite.h does not result in compilation errors. +// void Platform_TransformSprite(Sprite *s, SpriteTransform *transform); #endif // GUARD_SA2_PLATFORM_H diff --git a/include/platform/shared/opengl.h b/include/platform/shared/opengl.h index dc643c216..f3d6a5daf 100644 --- a/include/platform/shared/opengl.h +++ b/include/platform/shared/opengl.h @@ -4,7 +4,9 @@ #include "sprite.h" // for Sprite void OpenGL_OnInit(); +void OpenGL_ProcessBackgroundsCopyQueue(); void OpenGL_DisplaySprite(Sprite *sprite, u8 oamPaletteNum); +void OpenGL_TransformSprite(Sprite *sprite, SpriteTransform *transform); void OpenGL_Render(void *tempBufferPixels, int windowWidth, int windowHeight); #endif // GUARD_PLATFORM_SHARED_OPENGL_H diff --git a/include/sprite.h b/include/sprite.h index 255f3ef19..21464bca5 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -118,7 +118,7 @@ typedef struct { /* 0x36 */ u16 prevScrollY; /* Only used by stage maps (they are encoded as Tilemaps) */ - /* 0x38 */ const u16 *metatileMap; + /* 0x38 */ const MetatileIndexType *metatileMap; /* 0x3C */ u16 mapWidth; /* 0x3E */ u16 mapHeight; } Background; /* size = 0x40 */ diff --git a/src/background.c b/src/background.c index 7fba66626..aad7732c5 100644 --- a/src/background.c +++ b/src/background.c @@ -4,6 +4,7 @@ #include "sprite.h" #include "trig.h" #include "lib/m4a/m4a.h" +#include "platform/platform.h" #include "animation_commands.h" @@ -54,7 +55,7 @@ void DrawBackground(Background *background) background->paletteOffset = mapHeader->tileset.palOffset; if (!(background->flags & BACKGROUND_DISABLE_PALETTE_UPDATE)) { - DmaCopy16(3, pal, gBgPalette + background->paletteOffset, palSize * sizeof(*pal)); + DmaCopy16(3, pal, &GET_PALETTE_COLOR_BG(0, background->paletteOffset), palSize * sizeof(*pal)); gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; background->flags ^= BACKGROUND_DISABLE_PALETTE_UPDATE; } @@ -72,6 +73,7 @@ void DrawBackground(Background *background) // (85.37%) https://decomp.me/scratch/617Jb // (87.46%) https://decomp.me/scratch/1CFim +// TODO: ProcessBackgroundsCopyQueue might be a good name for this function? NONMATCH("asm/non_matching/engine/sub_8002B20.inc", bool32 sub_8002B20(void)) { u16 sp00; @@ -90,6 +92,7 @@ NONMATCH("asm/non_matching/engine/sub_8002B20.inc", bool32 sub_8002B20(void)) #if (RENDERER == RENDERER_OPENGL) // TEMP + Platform_ProcessBackgroundsCopyQueue(); return TRUE; #endif @@ -1289,7 +1292,12 @@ static AnimCmdResult animCmd_GetPalette_BG(void *cursor, Sprite *s) if (!(s->frameFlags & SPRITE_FLAG_MASK_18)) { s32 paletteIndex = cmd->palId; - DmaCopy32(3, &gRefSpriteTables->palettes[paletteIndex * 16], &gBgPalette[s->palId * 16 + cmd->insertOffset], cmd->numColors * 2); + // NOTE: + // For some reason, this only matches with a size of: + // (cmd->numColors * 2), not (cmd->numColors * sizeof(u16)) + // Same goes for sprite.c version called animCmd_GetPalette()... + DmaCopy32(3, &gRefSpriteTables->palettes[paletteIndex * 16], &GET_PALETTE_COLOR_BG(s->palId, cmd->insertOffset), + cmd->numColors * 2); gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; } diff --git a/src/core.c b/src/core.c index ea52547b7..fcbe84850 100644 --- a/src/core.c +++ b/src/core.c @@ -622,12 +622,12 @@ void UpdateScreenDma(void) DmaCopy32(3, gBgCntRegs, (void *)REG_ADDR_BG0CNT, sizeof(gBgCntRegs)); if (gFlags & FLAGS_UPDATE_BACKGROUND_PALETTES) { - DmaCopy32(3, gBgPalette, (void *)BG_PLTT, BG_PLTT_SIZE); + DmaCopy32(3, gBgPalette, (void *)BG_PLTT, sizeof(gBgPalette)); gFlags ^= FLAGS_UPDATE_BACKGROUND_PALETTES; } if (gFlags & FLAGS_UPDATE_SPRITE_PALETTES) { - DmaCopy32(3, gObjPalette, (void *)OBJ_PLTT, OBJ_PLTT_SIZE); + DmaCopy32(3, gObjPalette, (void *)OBJ_PLTT, sizeof(gObjPalette)); gFlags ^= FLAGS_UPDATE_SPRITE_PALETTES; } @@ -761,12 +761,12 @@ void UpdateScreenCpuSet(void) CpuCopy32(gBgCntRegs, (void *)REG_ADDR_BG0CNT, sizeof(gBgCntRegs)); if (gFlags & FLAGS_UPDATE_BACKGROUND_PALETTES) { - CpuFastCopy(gBgPalette, (void *)BG_PLTT, BG_PLTT_SIZE); + CpuFastCopy(gBgPalette, (void *)BG_PLTT, sizeof(gBgPalette)); gFlags ^= FLAGS_UPDATE_BACKGROUND_PALETTES; } if (gFlags & FLAGS_UPDATE_SPRITE_PALETTES) { - CpuFastCopy(gObjPalette, (void *)OBJ_PLTT, OBJ_PLTT_SIZE); + CpuFastCopy(gObjPalette, (void *)OBJ_PLTT, sizeof(gObjPalette)); gFlags ^= FLAGS_UPDATE_SPRITE_PALETTES; } diff --git a/src/game/boost_effect.c b/src/game/boost_effect.c index c05b69e91..313759914 100644 --- a/src/game/boost_effect.c +++ b/src/game/boost_effect.c @@ -173,7 +173,7 @@ static inline void sub_8015B64_inline(AnimId anim, u16 palId) #endif numColors = *pAnim % 256u; - DmaCopy32(3, &gRefSpriteTables->palettes[animPalId * 16], &gObjPalette[insertOffset], numColors * sizeof(u16)); + DmaCopy32(3, &gRefSpriteTables->palettes[animPalId * 16], &GET_PALETTE_COLOR_OBJ(0, insertOffset), numColors * sizeof(u16)); gFlags |= FLAGS_UPDATE_SPRITE_PALETTES; } diff --git a/src/game/bosses/boss_1.c b/src/game/bosses/boss_1.c index 964691300..d4c97977c 100644 --- a/src/game/bosses/boss_1.c +++ b/src/game/bosses/boss_1.c @@ -184,7 +184,7 @@ static const HammertankFunc sBossStateHandlers[] = { [EGG_HAMMER_TANK_II_STATE_DRAG] = StateHandler_HammerDrag, [EGG_HAMMER_TANK_II_STATE_RETRACT] = StateHandler_HammerRetract, }; -static const u16 gUnknown_080D7AD0[][16] = { +static const u16 gUnknown_080D7AD0[][PALETTE_LEN_4BPP] = { INCBIN_U16("graphics/80D7AD0.gbapal"), INCBIN_U16("graphics/80D7AF0.gbapal"), }; @@ -1613,8 +1613,8 @@ static void HandleBossHitPalette(EggHammerTankII *boss) if (boss->timerInvulnerability > 0) { u8 i; - for (i = 0; i < 16; i++) { - gObjPalette[8 * 16 + i] = gUnknown_080D7AD0[(boss->timerInvulnerability & 4) >> 2][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, i, gUnknown_080D7AD0[(boss->timerInvulnerability & 4) >> 2][i]); } gFlags |= FLAGS_UPDATE_SPRITE_PALETTES; diff --git a/src/game/bosses/boss_2.c b/src/game/bosses/boss_2.c index 807dca7cf..628e5de5f 100644 --- a/src/game/bosses/boss_2.c +++ b/src/game/bosses/boss_2.c @@ -152,7 +152,7 @@ static const u16 gUnknown_080D7B4E[][2] = { static const BossFunction sBossModeTasks[] = { HandleCannonBombTrigger, HandleCannonlessBombTrigger }; -static const u16 gUnknown_080D7B70[][16] = { +static const u16 gUnknown_080D7B70[][PALETTE_LEN_4BPP] = { INCBIN_U16("graphics/80D7B70.gbapal"), INCBIN_U16("graphics/80D7B90.gbapal"), }; @@ -575,23 +575,23 @@ static void UpdateBomberTankPalette(EggBomberTank *boss) { u8 i; if (boss->bossHitTimer != 0) { - for (i = 0; i < 16; i++) { - gObjPalette[i + 0x80] = gUnknown_080D7B70[(gStageTime & 2) >> 1][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, i, gUnknown_080D7B70[(gStageTime & 2) >> 1][i]); } } else { - for (i = 0; i < 16; i++) { - gObjPalette[i + 0x80] = gUnknown_080D7B70[1][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, i, gUnknown_080D7B70[1][i]); } } if (boss->cannonHitTimer != 0) { boss->cannonHitTimer--; - for (i = 0; i < 16; i++) { - gObjPalette[i + 0xD0] = gUnknown_080D7B70[(gStageTime & 2) >> 1][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(13, i, gUnknown_080D7B70[(gStageTime & 2) >> 1][i]); } } else { - for (i = 0; i < 16; i++) { - gObjPalette[i + 0xD0] = gUnknown_080D7B70[1][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(13, i, gUnknown_080D7B70[1][i]); } } diff --git a/src/game/bosses/boss_3.c b/src/game/bosses/boss_3.c index 333be2a0b..fd82fe68d 100644 --- a/src/game/bosses/boss_3.c +++ b/src/game/bosses/boss_3.c @@ -185,7 +185,7 @@ const u8 *const gUnknown_080D7ED4[] = { const s8 gUnknown_080D7F10[EGGTOTEM_NUM_PLATFORMS] = { 14, 14, 8 }; -const s16 gUnknown_080D7F14[2][16] = { +const s16 gUnknown_080D7F14[2][PALETTE_LEN_4BPP] = { INCBIN_U16("graphics/boss_3_a.gbapal"), INCBIN_U16("graphics/boss_3_b.gbapal"), }; @@ -1504,24 +1504,24 @@ void sub_8040F14(EggTotem *totem) u8 i; if (totem->unk35 != 0) { - for (i = 0; i < 16; i++) { - gObjPalette[128 + i] = gUnknown_080D7F14[((gStageTime & 0x2) / 2u)][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, i, gUnknown_080D7F14[((gStageTime & 0x2) / 2u)][i]); } } else { - for (i = 0; i < 16; i++) { - gObjPalette[128 + i] = gUnknown_080D7F14[1][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, i, gUnknown_080D7F14[1][i]); } } if (totem->unk36 > 0) { totem->unk36--; - for (i = 0; i < 16; i++) { - gObjPalette[176 + i] = gUnknown_080D7F14[((gStageTime & 0x2) / 2u)][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(11, i, gUnknown_080D7F14[((gStageTime & 0x2) / 2u)][i]); } } else { - for (i = 0; i < 16; i++) { - gObjPalette[176 + i] = gUnknown_080D7F14[1][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(11, i, gUnknown_080D7F14[1][i]); } } diff --git a/src/game/bosses/boss_4.c b/src/game/bosses/boss_4.c index 744d9d956..68b81366c 100644 --- a/src/game/bosses/boss_4.c +++ b/src/game/bosses/boss_4.c @@ -42,7 +42,7 @@ #define RESERVED_EXPLOSION_TILES_VRAM (void *)(OBJ_VRAM0 + 0x2980) -static const u16 sPalAeroEggHit[2][16] = { +static const u16 sPalAeroEggHit[2][PALETTE_LEN_4BPP] = { [PAL_BOSS_4_DEFAULT] = INCBIN_U16("graphics/boss_4_a.gbapal"), [PAL_BOSS_4_HIT] = INCBIN_U16("graphics/boss_4_b.gbapal"), }; @@ -761,12 +761,12 @@ static void sub_8042560(AeroEgg *boss) u8 i; if (boss->main.unk16 != 0) { - for (i = 0; i < ARRAY_COUNT(sPalAeroEggHit[PAL_BOSS_4_DEFAULT]); i++) { - gObjPalette[128 + i] = sPalAeroEggHit[((gStageTime & 0x2) >> 1)][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, i, sPalAeroEggHit[((gStageTime & 0x2) >> 1)][i]); } } else { - for (i = 0; i < ARRAY_COUNT(sPalAeroEggHit[PAL_BOSS_4_HIT]); i++) { - gObjPalette[128 + i] = sPalAeroEggHit[PAL_BOSS_4_HIT][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, i, sPalAeroEggHit[PAL_BOSS_4_HIT][i]); } } diff --git a/src/game/bosses/boss_5.c b/src/game/bosses/boss_5.c index 241296e11..0179f5cb8 100644 --- a/src/game/bosses/boss_5.c +++ b/src/game/bosses/boss_5.c @@ -149,7 +149,7 @@ static const TileInfo gUnknown_080D7FB0[] = { { 2, SA2_ANIM_EGG_SAUCER_SMACK_PARTICLE_UP, 0 }, { 4, SA2_ANIM_EGG_SAUCER_SMACK_PARTICLE_UP_RIGHT, 0 }, }; -static const u16 gUnknown_080D7FF0[][16] = { +static const u16 gUnknown_080D7FF0[][PALETTE_LEN_4BPP] = { INCBIN_U16("graphics/80D7FF0.gbapal"), INCBIN_U16("graphics/80D8010.gbapal"), }; @@ -1293,6 +1293,7 @@ static void sub_8044CBC(EggSaucer *boss) s->prevVariant = -1; } } + boss->unk36[0][boss->unkB6] = boss->unkB8; boss->unk36[1][boss->unkB6] = boss->unkBA; @@ -1756,27 +1757,27 @@ void sub_8045898(EggSaucer *boss) if (boss->unk15 == 0) { val = (gStageTime & 2) >> 1; if (boss->unk13 != 0) { - for (i = 0; i < 0x10; i++) { - gObjPalette[i + 0x80] = gUnknown_080D7FF0[val][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, i, gUnknown_080D7FF0[val][i]); } } else { - for (i = 0; i < 0x10; i++) { - gObjPalette[i + 0x80] = gUnknown_080D7FF0[1][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, i, gUnknown_080D7FF0[1][i]); } } if (boss->unk1F != 0) { boss->unk1F--; - for (i = 0; i < 0x10; i++) { - gObjPalette[i + 0x90] = gUnknown_080D7FF0[val][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(9, i, gUnknown_080D7FF0[val][i]); } } else { - for (i = 0; i < 0x10; i++) { - gObjPalette[i + 0x90] = gUnknown_080D7FF0[1][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(9, i, gUnknown_080D7FF0[1][i]); } } - gFlags |= 2; + gFlags |= FLAGS_UPDATE_SPRITE_PALETTES; } } diff --git a/src/game/bosses/boss_6.c b/src/game/bosses/boss_6.c index 9e31221ae..e34dafafc 100644 --- a/src/game/bosses/boss_6.c +++ b/src/game/bosses/boss_6.c @@ -168,7 +168,7 @@ static const u16 gUnknown_080D809E[][10] = { { 257, 257, 257, 257, 257, 256, 256, 256, 222, 222 }, }; -static const u16 sPalettes[][16] = { +static const u16 sPalettes[][PALETTE_LEN_4BPP] = { INCBIN_U16("graphics/80D80C6.gbapal"), // hit palette INCBIN_U16("graphics/80D80E6.gbapal"), // normal palette }; @@ -1164,16 +1164,16 @@ static void SetPalette(EggGoRound *boss) { u8 i; if (boss->invincibilityTimer > 0) { - for (i = 0; i < 16; i++) { - gObjPalette[128 + i] = sPalettes[(gStageTime & 2) / 2][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, i, sPalettes[(gStageTime & 2) / 2][i]); } } else { - for (i = 0; i < 16; i++) { - gObjPalette[128 + i] = sPalettes[1][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, i, sPalettes[1][i]); } } - gFlags |= 2; + gFlags |= FLAGS_UPDATE_SPRITE_PALETTES; } static void HandleCollisions(EggGoRound *boss) diff --git a/src/game/bosses/boss_7.c b/src/game/bosses/boss_7.c index 420e92fe8..3450261f4 100644 --- a/src/game/bosses/boss_7.c +++ b/src/game/bosses/boss_7.c @@ -1160,8 +1160,8 @@ static void sub_804931C(EggFrog *boss) if (boss->unk16 != 0) { u8 i; - for (i = 0; i < 16; i++) { - gBgPalette[i + 0xB0] = gUnknown_080D8796[(boss->unk16 & 2) >> 1][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_BG(11, i, gUnknown_080D8796[(boss->unk16 & 2) >> 1][i]); } } diff --git a/src/game/bosses/boss_8.c b/src/game/bosses/boss_8.c index f43700e4a..d714ec63e 100644 --- a/src/game/bosses/boss_8.c +++ b/src/game/bosses/boss_8.c @@ -173,7 +173,7 @@ const u16 gUnknown_080D8888[2][2] = { { Q(188), Q(110) }, { Q(162), Q(110) } }; static const EggRoboFn sArmFuncs[8] = { sub_804B43C, sub_804B594, sub_804B734, sub_804B984, sub_804BC44, sub_804BE6C, sub_804BAC0, sub_804C240 }; -const u16 sArmPalettes[2][16] = { +const u16 sArmPalettes[2][PALETTE_LEN_4BPP] = { INCBIN_U16("graphics/boss_8_a.gbapal"), INCBIN_U16("graphics/boss_8_b.gbapal"), }; @@ -2009,31 +2009,31 @@ static void sub_804CA70(SuperEggRoboZ *boss) if (boss->unkB != 0) { for (i = 0; i < ARRAY_COUNT(sArmPalettes[0]); i++) { - gObjPalette[8 * 16 + i] = sArmPalettes[pal][i]; + SET_PALETTE_COLOR_OBJ(8, i, sArmPalettes[pal][i]); } } else { for (i = 0; i < ARRAY_COUNT(sArmPalettes[0]); i++) { - gObjPalette[8 * 16 + i] = sArmPalettes[0][i]; + SET_PALETTE_COLOR_OBJ(8, i, sArmPalettes[0][i]); } } if (boss->unk3E[0] > 0) { for (i = 0; i < ARRAY_COUNT(sArmPalettes[0]); i++) { - gObjPalette[9 * 16 + i] = sArmPalettes[pal][i]; + SET_PALETTE_COLOR_OBJ(9, i, sArmPalettes[pal][i]); } } else { for (i = 0; i < ARRAY_COUNT(sArmPalettes[0]); i++) { - gObjPalette[9 * 16 + i] = sArmPalettes[0][i]; + SET_PALETTE_COLOR_OBJ(9, i, sArmPalettes[0][i]); } } if (boss->unk3E[1] > 0) { for (i = 0; i < ARRAY_COUNT(sArmPalettes[0]); i++) { - gObjPalette[12 * 16 + i] = sArmPalettes[pal][i]; + SET_PALETTE_COLOR_OBJ(12, i, sArmPalettes[pal][i]); } } else { for (i = 0; i < ARRAY_COUNT(sArmPalettes[0]); i++) { - gObjPalette[12 * 16 + i] = sArmPalettes[0][i]; + SET_PALETTE_COLOR_OBJ(12, i, sArmPalettes[0][i]); } } diff --git a/src/game/bosses/boss_9.c b/src/game/bosses/boss_9.c index b8b7d5687..c8baeff91 100644 --- a/src/game/bosses/boss_9.c +++ b/src/game/bosses/boss_9.c @@ -321,7 +321,7 @@ const TA53_Data1 gUnknown_080D8DCC[6] = { }; const TA53_Rocket_Callback gUnknown_080D8E14[3] = { sub_804E974, sub_804EB6C, sub_804EC6C }; -const u8 sRGB_080D8E20[4][16][3] = { +const u8 sRGB_080D8E20[4][PALETTE_LEN_4BPP][3] = { { { 0, 0, 0 }, { 2, 2, 28 }, @@ -1385,8 +1385,8 @@ void sub_804E4CC(struct TA53_unk48 *unk48) b = sRGB_080D8E20[3][c][2]; b = ((b * r6) >> 12) & 0x1F; - gObjPalette[c + 8 * 16] = RGB16_REV(r, g, b); - gBgPalette[c] = RGB16_REV(r, g, b); + SET_PALETTE_COLOR_OBJ(8, c, RGB16_REV(r, g, b)); + SET_PALETTE_COLOR_BG(0, c, RGB16_REV(r, g, b)); } gFlags |= FLAGS_UPDATE_SPRITE_PALETTES; @@ -1407,7 +1407,12 @@ void sub_804E4CC(struct TA53_unk48 *unk48) g = ((g * r6) >> 9) & 0x1F; b = sRGB_080D8E20[i][c][2]; b = ((b * r6) >> 9) & 0x1F; - gBgPalette[0x70 + c + (i * 16)] = RGB16_REV(r, g, b); +#ifndef NON_MATCHING + // TODO: This should work... + gBgPalette[7 * PALETTE_LEN_4BPP + c + (i * PALETTE_LEN_4BPP)] = RGB16_REV(r, g, b); +#else + SET_PALETTE_COLOR_BG(7, c + (i * PALETTE_LEN_4BPP), RGB16_REV(r, g, b)); +#endif } } @@ -2870,31 +2875,24 @@ void sub_8050958(TA53Boss *boss) if (boss->unkD > 0) { if (--boss->unkD == 0) { for (i = 0; i < 16; i++) { - gObjPalette[i + 8 * 16] = gUnknown_080D8EF0[1][i]; - gBgPalette[i + 0 * 16] = gObjPalette[i + 8 * 16]; + SET_PALETTE_COLOR_OBJ(8, i, gUnknown_080D8EF0[1][i]); + SET_PALETTE_COLOR_BG(0, i, gUnknown_080D8EF0[1][i]); } } else { // _080509B0 - u16 r6 = (gStageTime >> 1) % 16u; + u16 r6 = (gStageTime >> 1) % PALETTE_LEN_4BPP; if (boss->lives < 4) { - for (i = 0; i < 16; i++) { - gObjPalette[8 * 16 + ((i + r6) % 16u)] = gUnknown_080D8EF0[0][i] >> 5; - gBgPalette[0 * 16 + ((i + r6) % 16u)] = gObjPalette[8 * 16 + ((i + r6) % 16u)]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, ((i + r6) % PALETTE_LEN_4BPP), gUnknown_080D8EF0[0][i] >> 5); + SET_PALETTE_COLOR_BG(0, ((i + r6) % PALETTE_LEN_4BPP), gUnknown_080D8EF0[0][i] >> 5); } } else { - for (i = 0; i < 16; i++) { - u32 r0; - u32 r2; - u32 colId; - u16 *objPalTgt = &gObjPalette[0]; - u32 objPalId; - - colId = ((i + r6) % 16u); - objPalId = 8 * 16 + colId; - objPalTgt[objPalId] = ((gUnknown_080D8EF0[0][i] << 5) | (gUnknown_080D8EF0[0][i] >> 5)) | gUnknown_080D8EF0[0][i]; - gBgPalette[0 * 16 + colId] - = ((gUnknown_080D8EF0[0][i] << 5) | (gUnknown_080D8EF0[0][i] >> 5)) | gUnknown_080D8EF0[0][i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(8, ((i + r6) % PALETTE_LEN_4BPP), + ((gUnknown_080D8EF0[0][i] << 5) | (gUnknown_080D8EF0[0][i] >> 5)) | gUnknown_080D8EF0[0][i]); + SET_PALETTE_COLOR_BG(0, ((i + r6) % PALETTE_LEN_4BPP), + ((gUnknown_080D8EF0[0][i] << 5) | (gUnknown_080D8EF0[0][i] >> 5)) | gUnknown_080D8EF0[0][i]); } } } diff --git a/src/game/character_select.c b/src/game/character_select.c index 5257307d9..ad43c8762 100644 --- a/src/game/character_select.c +++ b/src/game/character_select.c @@ -515,11 +515,11 @@ void CreateCharacterSelectionScreen(u8 initialSelection, bool8 allUnlocked) s->frameFlags = 0; UpdateSpriteAnimation(s); - for (i = 0; i < 16; i++) { - gObjPalette[i + 240] = 0; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(15, i, 0); } - gFlags |= 0x2; + gFlags |= FLAGS_UPDATE_SPRITE_PALETTES; } static void Task_FadeInAndStartRollInAnim(void) diff --git a/src/game/cutscenes/extra_ending_fall.c b/src/game/cutscenes/extra_ending_fall.c index 7ce33dc55..2d3b53459 100644 --- a/src/game/cutscenes/extra_ending_fall.c +++ b/src/game/cutscenes/extra_ending_fall.c @@ -834,9 +834,9 @@ void sub_8090F6C(struct ExtraEndingCutScene *scene) if (scene->unk37F != 0) { scene->unk37F--; if (scene->unk37E <= 3) { - DmaCopy32(3, gUnknown_080E15C8[scene->unk37E], &gObjPalette[0x30], sizeof(gUnknown_080E15C8[0])); + DmaCopy32(3, gUnknown_080E15C8[scene->unk37E], &GET_PALETTE_COLOR_OBJ(3, 0), sizeof(gUnknown_080E15C8[0])); } else { - DmaCopy32(3, gUnknown_080E15C8[6 - scene->unk37E], &gObjPalette[0x30], sizeof(gUnknown_080E15C8[0])); + DmaCopy32(3, gUnknown_080E15C8[6 - scene->unk37E], &GET_PALETTE_COLOR_OBJ(3, 0), sizeof(gUnknown_080E15C8[0])); } } else { scene->unk37E++; diff --git a/src/game/cutscenes/final_ending_land.c b/src/game/cutscenes/final_ending_land.c index e82b4633c..8ee9b6ac2 100644 --- a/src/game/cutscenes/final_ending_land.c +++ b/src/game/cutscenes/final_ending_land.c @@ -504,7 +504,7 @@ void CreateFinalEndingLandingCutScene(void) if (!(gLoadedSaveGame->chaosEmeralds[gSelectedCharacter] & CHAOS_EMERALDS_COMPLETED)) { memcpy(unk1AF4, gUnknown_080E1AF4, sizeof(unk1AF4)); - DmaCopy32(3, unk1AF4, &gBgPalette[32], sizeof(unk1AF4)); + DmaCopy32(3, unk1AF4, &GET_PALETTE_COLOR_BG(2, 0), sizeof(unk1AF4)); } } diff --git a/src/game/multiboot/collect_rings/time_display.c b/src/game/multiboot/collect_rings/time_display.c index 85a06ba84..518073d96 100644 --- a/src/game/multiboot/collect_rings/time_display.c +++ b/src/game/multiboot/collect_rings/time_display.c @@ -23,7 +23,7 @@ const u8 gUnknown_080E0234[] = { 103, 104, 112, 114, 115, 117, 119, 120, 128, 130, 131, 133, 135, 136, 144, 146, 147, 149, 151, 152, }; -const u16 gUnknown_080E0270[] = INCBIN_U16("graphics/80E0270.gbapal"); +const u16 gUnknown_080E0270[PALETTE_LEN_4BPP] = INCBIN_U16("graphics/80E0270.gbapal"); #ifndef COLLECT_RINGS_ROM #define NUM_TILES 9 @@ -85,8 +85,8 @@ void CreateCollectRingsTimeDisplay(void) UpdateSpriteAnimation(s); } - for (i = 0; i < 16; i++) { - gObjPalette[i + 0x70] = gUnknown_080E0270[i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(7, i, gUnknown_080E0270[i]); } gFlags |= FLAGS_UPDATE_SPRITE_PALETTES; diff --git a/src/game/multiboot/connection.c b/src/game/multiboot/connection.c index cc29085dd..ad64bcb5d 100644 --- a/src/game/multiboot/connection.c +++ b/src/game/multiboot/connection.c @@ -602,22 +602,22 @@ void sub_8081AD4(struct SinglePakConnectScreen *connectScreen) background->flags = BACKGROUND_FLAGS_BG_ID(0); DrawBackground(background); - CpuFill16(0, &gBgPalette[17], 30); + CpuFill16(0, &GET_PALETTE_COLOR_BG(1, 1), RGB16_REV(30, 0, 0)); - gDispCnt |= 0x2200; - temp = 0x1f01; + gDispCnt |= (DISPCNT_BG1_ON | DISPCNT_WIN0_ON); + temp = BGCNT_SCREENBASE(31) | BGCNT_PRIORITY(1); gBgScrollRegs[1][0] = 0; gBgScrollRegs[1][1] = 0; - gWinRegs[0] = 0x2828; - gWinRegs[2] = 0x8890; - gWinRegs[4] = 2; - gWinRegs[5] = 1; + gWinRegs[WINREG_WIN0H] = WIN_RANGE(40, 40); + gWinRegs[WINREG_WIN0V] = WIN_RANGE(136, 144); + gWinRegs[WINREG_WININ] = 2; + gWinRegs[WINREG_WINOUT] = 1; gBgCntRegs[1] = temp; CpuFill16(0xF3FF, (void *)BG_SCREEN_ADDR(31), 2049); CpuFill16(0xFFFF, (void *)VRAM + 1023 * TILE_SIZE_4BPP, TILE_SIZE_4BPP); - gBgPalette[255] = RGB_RED; + SET_PALETTE_COLOR_BG(15, 15, RGB_RED); gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; } diff --git a/src/game/sa1_sa2_shared/pause_menu.c b/src/game/sa1_sa2_shared/pause_menu.c index 38ef95ccf..388e08e6a 100644 --- a/src/game/sa1_sa2_shared/pause_menu.c +++ b/src/game/sa1_sa2_shared/pause_menu.c @@ -182,8 +182,8 @@ void Task_PauseMenuInit(void) m4aSongNumStart(SE_PAUSE_SCREEN); gFlags |= FLAGS_PAUSE_GAME; - DmaCopy16(3, &gObjPalette[249], pm->pal64, sizeof(pm->pal64)); - DmaCopy16(3, &gObjPalette[252], pm->pal6A, sizeof(pm->pal6A)); + DmaCopy16(3, &GET_PALETTE_COLOR_OBJ(15, +9), pm->pal64, sizeof(pm->pal64)); + DmaCopy16(3, &GET_PALETTE_COLOR_OBJ(15, +12), pm->pal6A, sizeof(pm->pal6A)); gCurTask->main = Task_PauseMenuUpdate; } @@ -200,7 +200,7 @@ void sub_800AE58(void) { DmaCopy16(3, &Tileset_zone_1_act_1_fg[(4 * 16 * TILE_SIZE_4BPP) / sizeof(u16)], (void *)(OBJ_VRAM1 + 0x3EC0), 0x140); - gObjPalette[1] = RGB_WHITE; + GET_PALETTE_COLOR_OBJ(0, 1) = RGB_WHITE; gFlags |= FLAGS_UPDATE_SPRITE_PALETTES; gFlags &= ~FLAGS_PAUSE_GAME; } \ No newline at end of file diff --git a/src/game/sa1_sa2_shared/unused_flash_task.c b/src/game/sa1_sa2_shared/unused_flash_task.c index 5b90b77d2..2ae3ad48f 100644 --- a/src/game/sa1_sa2_shared/unused_flash_task.c +++ b/src/game/sa1_sa2_shared/unused_flash_task.c @@ -22,7 +22,7 @@ void CreateUnusedFlashTask(void) INIT_BG_SPRITES_LAYER_64(2); TaskCreate(Task_UnusedFlashTask, 0, 0x1000, 0, NULL); - gBgPalette[1] = RGB_WHITE; + SET_PALETTE_COLOR_BG(0, 1, RGB_WHITE); gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; } diff --git a/src/game/sa1_sa2_shared/unused_level_select.c b/src/game/sa1_sa2_shared/unused_level_select.c index aae79bbe8..f52ee0855 100644 --- a/src/game/sa1_sa2_shared/unused_level_select.c +++ b/src/game/sa1_sa2_shared/unused_level_select.c @@ -37,6 +37,13 @@ static void Task_LoadStage(void); void CreateUnusedLevelSelect(void) { +#ifdef BUG_FIX + // You can come into a situation where a backgorund gets put onto the queue, + // but the memory gets free'd. + // So we need to make sure the Background Copy Queue is clear. + PAUSE_BACKGROUNDS_QUEUE(); + PAUSE_GRAPHICS_QUEUE(); +#endif struct Task *t = TaskCreate(Task_UnusedLevelSelectInit, sizeof(LevelSelect), 0x2000, 0, NULL); gMultiplayerMissingHeartbeats[3] = 0; gMultiplayerMissingHeartbeats[2] = 0; @@ -140,7 +147,7 @@ static void Task_Poll(void) static void Task_UnusedLevelSelectInit(void) { LevelSelect *levelSelect = TASK_DATA(gCurTask); - gBgPalette[1] = RGB_WHITE; + SET_PALETTE_COLOR_BG(0, 1, RGB_WHITE); gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; levelSelect->vram += RenderText(levelSelect->vram, Tileset_DebugAscii, 6, 14, 0, "STAGE", 0); diff --git a/src/game/special_stage/ui.c b/src/game/special_stage/ui.c index d24cbc7f4..508e539d2 100644 --- a/src/game/special_stage/ui.c +++ b/src/game/special_stage/ui.c @@ -335,8 +335,8 @@ static void HandlePaused(struct SpecialStageUI *ui) sub_806CA88(s, 1, pauseMenuVariants[lang][0], pauseMenuVariants[lang][1], 0x1000, (DISPLAY_WIDTH / 2), (DISPLAY_HEIGHT / 2), 0, pauseMenuVariants[lang][2], 0); - DmaCopy16(3, &gObjPalette[249], ui->pauseMenuPalette1, sizeof(ui->pauseMenuPalette1)); - DmaCopy16(3, &gObjPalette[252], ui->pauseMenuPalette2, sizeof(ui->pauseMenuPalette2)); + DmaCopy16(3, &GET_PALETTE_COLOR_OBJ(15, 9), ui->pauseMenuPalette1, sizeof(ui->pauseMenuPalette1)); + DmaCopy16(3, &GET_PALETTE_COLOR_OBJ(15, 12), ui->pauseMenuPalette2, sizeof(ui->pauseMenuPalette2)); ui->wasPaused = TRUE; m4aMPlayAllStop(); m4aSongNumStart(SE_PAUSE_SCREEN); diff --git a/src/game/special_stage/utils.c b/src/game/special_stage/utils.c index 6f9adc369..323e5f298 100644 --- a/src/game/special_stage/utils.c +++ b/src/game/special_stage/utils.c @@ -201,6 +201,13 @@ void InitSpecialStageScreenVram(void) { gSpecialStageVramPointer = (void *)OBJ_VRAM0; gSpecialStageSubMenuVramPointer = NULL; +#ifdef BUG_FIX + // You can come into a situation where a backgorund gets put onto the queue, + // but the memory gets free'd. + // So we need to make sure the Background Copy Queue is clear. + PAUSE_BACKGROUNDS_QUEUE(); + PAUSE_GRAPHICS_QUEUE(); +#endif } void SpecialStageDrawBackground(Background *background, u32 a, u32 b, u8 tilemapId, u16 d, u16 e, u16 palOffset, u8 bg_id, u16 scrollX, diff --git a/src/game/stage/camera.c b/src/game/stage/camera.c index 541eee949..f79e15226 100644 --- a/src/game/stage/camera.c +++ b/src/game/stage/camera.c @@ -783,8 +783,8 @@ void RenderMetatileLayers(s32 x, s32 y) void CreateStageBg_Zone1(void) { Background *background = &gStageBackgroundsRam.unk0; - gDispCnt |= 0x100; - gBgCntRegs[0] = 0x1B0F; + gDispCnt |= DISPCNT_BG0_ON; + gBgCntRegs[0] = BGCNT_SCREENBASE(27) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); #ifndef COLLECT_RINGS_ROM if (gGameMode != GAME_MODE_MULTI_PLAYER_COLLECT_RINGS) { @@ -795,8 +795,8 @@ void CreateStageBg_Zone1(void) background->graphics.dest = (void *)BG_SCREEN_ADDR(24); background->layoutVram = (void *)BG_SCREEN_ADDR(27); - background->targetTilesX = 0x20; - background->targetTilesY = 0x20; + background->targetTilesX = 256 / TILE_WIDTH; + background->targetTilesY = 256 / TILE_WIDTH; } else #endif { @@ -807,8 +807,8 @@ void CreateStageBg_Zone1(void) background->graphics.dest = (void *)BG_SCREEN_ADDR(24); background->layoutVram = (void *)BG_SCREEN_ADDR(27); - background->targetTilesX = 0x20; - background->targetTilesY = 0x1E; + background->targetTilesX = 256 / TILE_WIDTH; + background->targetTilesY = 240 / TILE_WIDTH; } DrawBackground(background); @@ -999,10 +999,8 @@ const u8 gUnknown_080D5B20[16][3] = { { 255, 5, 6 }, // }; -// TODO: This data is unused in this module -// But the place that references this is -// further down in code than the .rodata after this. -const u8 gUnknown_080D5B50[DISPLAY_HEIGHT] = { // 0-105 +// NOTE: Only values > 105 appear to be used. +const u8 gUnknown_080D5B50[DISPLAY_HEIGHT] = { // 0-94 10, 10, 10, // 10, 10, 10, // 10, 10, 10, // @@ -1034,13 +1032,11 @@ const u8 gUnknown_080D5B50[DISPLAY_HEIGHT] = { // 0-105 10, 10, 10, // 10, 10, 10, // 10, 10, 10, // - 10, 10, 8, // - 8, 8, 8, // - 7, 7, 7, // - 7, 6, 6, // - - // 106-159 | This data appears to be unused - 6, 6, 6, // + 10, 10, 8, 8, 8, 8, // 95-98 + 7, 7, 7, 7, // 99-102 + 6, 6, 6, // 103-104 + /* 105-159 */ + 6, 6, // 6, 6, 6, // 5, 5, 5, // 5, 5, 5, // @@ -1070,8 +1066,8 @@ static s16 sUnknown_03000408; void CreateStageBg_Zone3(void) { Background *background = &gStageBackgroundsRam.unk0; - gDispCnt |= 0x100; - gBgCntRegs[0] = 0x1B0F; + gDispCnt |= DISPCNT_BG0_ON; + gBgCntRegs[0] = BGCNT_SCREENBASE(27) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); *background = gStageCameraBgTemplates[3]; @@ -1189,7 +1185,7 @@ void CreateStageBg_Zone4(void) { Background *background = &gStageBackgroundsRam.unk0; const Background *templates; - gBgCntRegs[0] = 0x1B0F; + gBgCntRegs[0] = BGCNT_SCREENBASE(27) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); *background = gStageCameraBgTemplates[CAMBG_BACK_B_LAYER]; @@ -1238,8 +1234,13 @@ void StageBgUpdate_Zone4Acts12(s32 cameraX, s32 cameraY) gBldRegs.bldAlpha = 0xc0c; } +#ifdef BUG_FIX + UpdateBgAnimationTiles(&gStageBackgroundsRam.unk0); + DrawBackground(&gStageBackgroundsRam.unk0); +#else DrawBackground(&gStageBackgroundsRam.unk0); UpdateBgAnimationTiles(&gStageBackgroundsRam.unk0); +#endif if ((gStageTime % 16u) == 0) { gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 1) & 0xff; @@ -1465,7 +1466,7 @@ const u8 gUnknown_080D5C02[2][16][3] = { void CreateStageBg_Zone6_Acts(void) { gDispCnt |= DISPCNT_BG0_ON; - gBgCntRegs[0] = 0x1a0f; + gBgCntRegs[0] = BGCNT_SCREENBASE(26) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); INIT_BG_SPRITES_LAYER_32(0); DmaFill32(3, 0, BG_SCREEN_ADDR(24), sizeof(Background)); gBgScrollRegs[0][0] = 0; @@ -1486,7 +1487,7 @@ void CreateStageBg_Zone6_Boss(void) { Background *background = &gStageBackgroundsRam.unk0; gDispCnt |= DISPCNT_BG0_ON; - gBgCntRegs[0] = 0x1a0f; + gBgCntRegs[0] = BGCNT_SCREENBASE(26) | BGCNT_CHARBASE(3) | BGCNT_PRIORITY(3); INIT_BG_SPRITES_LAYER_32(0); DmaFill32(3, 0, BG_SCREEN_ADDR(24), sizeof(Background)); gBgScrollRegs[0][0] = 0; @@ -1611,7 +1612,7 @@ NONMATCH("asm/non_matching/game/stage/background/sub_801D24C.inc", void sub_801D } // _0801D4A2 - for (i = 0; i < 16; i++) { + for (i = 0; i < PALETTE_LEN_4BPP; i++) { s32 b, g, r; r = (p0 * gUnknown_080D5C02[1][i][0]) >> 4; r &= 0x1F; @@ -1622,7 +1623,7 @@ NONMATCH("asm/non_matching/game/stage/background/sub_801D24C.inc", void sub_801D b = (p0 * gUnknown_080D5C02[1][i][2]) >> 4; b &= 0x1F; - gBgPalette[15 * 16 + i] = ((b << 10) + (g << 5) + (r << 0)); + SET_PALETTE_COLOR_BG(15, i, RGB16_REV(r, g, b)); } gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; @@ -1663,7 +1664,7 @@ NONMATCH("asm/non_matching/game/stage/background/StageBgUpdate_Zone6Acts12.inc", r5 = 5; } - gBgPalette[0] = RGB_BLACK; + SET_PALETTE_COLOR_BG(0, 0, RGB_BLACK); gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; switch (r5) { @@ -1722,7 +1723,7 @@ NONMATCH("asm/non_matching/game/stage/background/StageBgUpdate_Zone6Acts12.inc", gBgCntRegs[3] |= BGCNT_PRIORITY(2); for (i = 0; i < 16; i++) { - gBgPalette[(15 * 16) + i] = RGB_BLACK; + SET_PALETTE_COLOR_BG(15, i, RGB_BLACK); } // jumps to _0801D8EE for this @@ -1755,7 +1756,7 @@ NONMATCH("asm/non_matching/game/stage/background/StageBgUpdate_Zone6Acts12.inc", u32 green = ((gUnknown_080D5C02[0][i][1] * r6) >> 5) & 0x1F; u32 blue = ((gUnknown_080D5C02[0][i][2] * r6) >> 5) & 0x1F; - gBgPalette[(15 * 16) + i] = ((blue << 10) | (green << 5) | red); + SET_PALETTE_COLOR_BG(15, i, RGB16_REV(red, blue, green)); } // jumps to _0801D83C for this @@ -1773,7 +1774,7 @@ NONMATCH("asm/non_matching/game/stage/background/StageBgUpdate_Zone6Acts12.inc", u32 green = gUnknown_080D5C02[0][i][1]; u32 blue = gUnknown_080D5C02[0][i][2]; - gBgPalette[(15 * 16) + i] = ((blue << 10) | (green << 5) | red); + SET_PALETTE_COLOR_BG(15, i, RGB16_REV(red, blue, green)); } // _0801D83C @@ -1799,7 +1800,7 @@ NONMATCH("asm/non_matching/game/stage/background/StageBgUpdate_Zone6Acts12.inc", u32 green = ((gUnknown_080D5C02[0][i][1] * r6) >> 4) & 0x1F; u32 blue = ((gUnknown_080D5C02[0][i][2] * r6) >> 4) & 0x1F; - gBgPalette[(15 * 16) + i] = ((blue << 10) | (green << 5) | red); + SET_PALETTE_COLOR_BG(15, i, RGB16_REV(red, blue, green)); } gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; @@ -1808,7 +1809,7 @@ NONMATCH("asm/non_matching/game/stage/background/StageBgUpdate_Zone6Acts12.inc", case 7: { s8 i; for (i = 0; i < 16; i++) { - gBgPalette[(15 * 16) + i] = RGB_BLACK; + SET_PALETTE_COLOR_BG(15, i, RGB_BLACK); } gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; gDispCnt &= ~(DISPCNT_BG0_ON); @@ -2034,9 +2035,7 @@ NONMATCH("asm/non_matching/game/stage/background/Zone7BgUpdate_Inside.inc", void #else { // Draw the "ceiling" movement for (lineY = 0; lineY < 8; lineY++) { - dst = gBgPalette; - dst += 209; - dst[lineY] = sPalette_Zone7BgCeiling[((x >> 4) & 0x7) + 1]; + SET_PALETTE_COLOR_BG(13, lineY + 1, sPalette_Zone7BgCeiling[((x >> 4) & 0x7) + 1]); } } #endif @@ -2136,7 +2135,7 @@ const u16 sZone7BgTransitionRegions[2][NUM_ZONE7_BG_TRANSITION_POSITIONS] = { { 1344, 2616, 9432, 15192, 18552, 19892, 23158, 25848 }, // ACT 2 }; -const u16 gUnknown_080D5CC2[16] = INCBIN_U16("graphics/080D5CC2.gbapal"); +const u16 gUnknown_080D5CC2[PALETTE_LEN_4BPP] = INCBIN_U16("graphics/080D5CC2.gbapal"); void CreateStageBg_ZoneFinal_0(void) { @@ -2187,7 +2186,7 @@ void CreateStageBg_ZoneFinal_0(void) gBgScrollRegs[3][1] = 0; for (i = 0; i < ARRAY_COUNT(gUnknown_080D5CC2); i++) { - gBgPalette[i] = gUnknown_080D5CC2[i]; + SET_PALETTE_COLOR_BG(0, i, gUnknown_080D5CC2[i]); } gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; @@ -2316,9 +2315,9 @@ void StageBgUpdate_Zone5ActBoss(UNUSED s32 a, UNUSED s32 b) void StageBgUpdate_Zone6ActBoss(UNUSED s32 a, UNUSED s32 b) { - gBgCntRegs[0] |= 0x3; - gBgCntRegs[3] &= ~0x3; - gBgCntRegs[3] |= 0x2; + gBgCntRegs[0] |= BGCNT_PRIORITY(3); + gBgCntRegs[3] &= ~BGCNT_PRIORITY(3); + gBgCntRegs[3] |= BGCNT_PRIORITY(2); gBgScrollRegs[0][0] = (gBgScrollRegs[0][0] - 2) & 0xFF; gBgScrollRegs[0][1] = (gBgScrollRegs[0][1] + 1) & 0xFF; } diff --git a/src/game/stage/intro.c b/src/game/stage/intro.c index f18408765..fc671b99d 100644 --- a/src/game/stage/intro.c +++ b/src/game/stage/intro.c @@ -165,7 +165,7 @@ static const u8 sGettingReadyAnimationDuration[NUM_CHARACTERS] = { [CHARACTER_SONIC] = 40, [CHARACTER_CREAM] = 55, [CHARACTER_TAILS] = 52, [CHARACTER_KNUCKLES] = 40, [CHARACTER_AMY] = 40 }; // Each byte represents one RGB channel (0-31) -static const u8 gUnknown_080D6FF5[NUM_CHARACTERS + 1][16][3] = { +static const u8 gUnknown_080D6FF5[NUM_CHARACTERS + 1][PALETTE_LEN_4BPP][3] = { { { 0x00, 0x17, 0x06 }, { 0x16, 0x16, 0x16 }, @@ -731,13 +731,13 @@ static void Task_802F9F8(void) if (IS_SINGLE_PLAYER) { // _0802FA4C+8 - for (i = 0; i < 16; i++) { + for (i = 0; i < PALETTE_LEN_4BPP; i++) { r = gUnknown_080D6FF5[gSelectedCharacter][i][0]; r = (r * frameCounter) / 16u; g = ((gUnknown_080D6FF5[gSelectedCharacter][i][1] * frameCounter) / 16u); b = ((gUnknown_080D6FF5[gSelectedCharacter][i][2] * frameCounter) / 16u); - gObjPalette[i] = RGB16_REV(r, g, b); + SET_PALETTE_COLOR_OBJ(0, i, RGB16_REV(r, g, b)); if (gCheese != NULL) { r = gUnknown_080D6FF5[5][i][0]; @@ -745,7 +745,7 @@ static void Task_802F9F8(void) g = ((gUnknown_080D6FF5[5][i][1] * frameCounter) / 16u); b = ((gUnknown_080D6FF5[5][i][2] * frameCounter) / 16u); - gObjPalette[14 * 16 + i] = RGB16_REV(r, g, b); + SET_PALETTE_COLOR_OBJ(14, i, RGB16_REV(r, g, b)); } } } else { @@ -754,25 +754,25 @@ static void Task_802F9F8(void) for (sid = 0; sid < MULTI_SIO_PLAYERS_MAX; sid++) { if (GetBit(gMultiplayerConnections, sid)) { - for (i = 0; i < 16; i++) { + for (i = 0; i < PALETTE_LEN_4BPP; i++) { r = gUnknown_080D6FF5[(gMultiplayerCharacters)[sid]][i][0]; r = (r * frameCounter) / 16u; g = ((gUnknown_080D6FF5[(gMultiplayerCharacters)[sid]][i][1] * frameCounter) / 16u); b = ((gUnknown_080D6FF5[(gMultiplayerCharacters)[sid]][i][2] * frameCounter) / 16u); - gObjPalette[sid * 16 + i] = RGB16_REV(r, g, b); + SET_PALETTE_COLOR_OBJ(sid, i, RGB16_REV(r, g, b)); } } } if (gCheese != NULL) { - for (i = 0; i < 16; i++) { + for (i = 0; i < PALETTE_LEN_4BPP; i++) { r = gUnknown_080D6FF5[5][i][0]; r = (r * frameCounter) / 16u; g = ((gUnknown_080D6FF5[5][i][1] * frameCounter) / 16u); b = ((gUnknown_080D6FF5[5][i][2] * frameCounter) / 16u); - gObjPalette[14 * 16 + i] = RGB16_REV(r, g, b); + SET_PALETTE_COLOR_OBJ(14, i, RGB16_REV(r, g, b)); } } } @@ -1234,7 +1234,7 @@ static void Task_UpdateStageLoadingScreen(void) IntroBackgrounds *introBackgrounds = TASK_DATA(gCurTask); u32 counter = introBackgrounds->controller->counter; - gBgPalette[0] = sZoneLoadingCharacterColors[gSelectedCharacter]; + SET_PALETTE_COLOR_BG(0, 0, sZoneLoadingCharacterColors[gSelectedCharacter]); gFlags |= FLAGS_UPDATE_BACKGROUND_PALETTES; diff --git a/src/game/stage/player_super_sonic.c b/src/game/stage/player_super_sonic.c index d2880fe2a..ee22d3693 100644 --- a/src/game/stage/player_super_sonic.c +++ b/src/game/stage/player_super_sonic.c @@ -849,4 +849,4 @@ static void sub_802C9B0(struct SuperSonic *sonic) } } -bool32 sub_802C9E0(void) { return FALSE; } \ No newline at end of file +bool32 sub_802C9E0(void) { return FALSE; } diff --git a/src/game/stage/ui.c b/src/game/stage/ui.c index eac9d749b..a2b3f8b7c 100644 --- a/src/game/stage/ui.c +++ b/src/game/stage/ui.c @@ -43,7 +43,7 @@ const u16 sAnims1UpIcons[][3] [CHARACTER_KNUCKLES] = { ONE_UP_ICON_TILE_COUNT, SA2_ANIM_LIFE_COUNTER, SA2_ANIM_VARIANT_LIFE_COUNTER_KNUCKLES }, [CHARACTER_AMY] = { ONE_UP_ICON_TILE_COUNT, SA2_ANIM_LIFE_COUNTER, SA2_ANIM_VARIANT_LIFE_COUNTER_AMY } }; -const u16 sPalette1UpIcons[] = INCBIN_U16("graphics/ui_icon_1_up.gbapal"); +const u16 sPalette1UpIcons[PALETTE_LEN_4BPP] = INCBIN_U16("graphics/ui_icon_1_up.gbapal"); const u32 sOrdersOfMagnitude[6] = { 100000, 10000, 1000, 100, 10, 1, @@ -219,8 +219,8 @@ struct Task *CreateStageUI(void) s->frameFlags = 0; ui->ringCurrentFrame = 0; - for (i = 0; i < 16; i++) { - gObjPalette[0x70 + i] = sPalette1UpIcons[i]; + for (i = 0; i < PALETTE_LEN_4BPP; i++) { + SET_PALETTE_COLOR_OBJ(7, i, sPalette1UpIcons[i]); } gFlags |= FLAGS_UPDATE_SPRITE_PALETTES; diff --git a/src/game/title_screen.c b/src/game/title_screen.c index 436356017..1ca73ecdc 100644 --- a/src/game/title_screen.c +++ b/src/game/title_screen.c @@ -21,6 +21,7 @@ #include "game/stage/screen_fade.h" #include "game/time_attack/lobby.h" #include "game/time_attack/mode_select.h" +#include "game/sa1_sa2_shared/camera.h" // TILE_WIDTH #include "data/recordings.h" @@ -415,8 +416,8 @@ static void CreateTitleScreenWithoutIntro(TitleScreen *titleScreen) bg0->unk20 = 0; bg0->unk22 = 0; bg0->unk24 = 0; - bg0->targetTilesX = 26; - bg0->targetTilesY = 10; + bg0->targetTilesX = 208 / TILE_WIDTH; + bg0->targetTilesY = 80 / TILE_WIDTH; bg0->paletteOffset = 0; bg0->flags = BACKGROUND_FLAG_4 | BACKGROUND_FLAGS_BG_ID(2); @@ -441,8 +442,8 @@ static void CreateTitleScreenWithoutIntro(TitleScreen *titleScreen) config40->unk20 = 0; config40->unk22 = 0; config40->unk24 = 0; - config40->targetTilesX = 0x20; - config40->targetTilesY = 0x40; + config40->targetTilesX = 256 / TILE_WIDTH; + config40->targetTilesY = 512 / TILE_WIDTH; config40->paletteOffset = 0; config40->flags = BACKGROUND_FLAGS_BG_ID(1); @@ -461,9 +462,9 @@ static void InitTitleScreenBackgrounds(TitleScreen *titleScreen) gDispCnt = DISPCNT_MODE_1; gDispCnt |= DISPCNT_OBJ_1D_MAP | DISPCNT_BG2_ON | DISPCNT_OBJ_ON; - gBgCntRegs[0] = 0x1f04; - gBgCntRegs[1] = 0x9d0a; - gBgCntRegs[2] = 0x7a81; + gBgCntRegs[0] = BGCNT_16COLOR | BGCNT_TXT256x256 | BGCNT_SCREENBASE(31) | BGCNT_CHARBASE(1) | BGCNT_PRIORITY(0); + gBgCntRegs[1] = BGCNT_16COLOR | BGCNT_TXT256x512 | BGCNT_SCREENBASE(29) | BGCNT_CHARBASE(2) | BGCNT_PRIORITY(2); + gBgCntRegs[2] = BGCNT_256COLOR | BGCNT_AFF256x256 | BGCNT_WRAP | BGCNT_SCREENBASE(26) | BGCNT_CHARBASE(0) | BGCNT_PRIORITY(1); INIT_BG_SPRITES_LAYER_32(0); INIT_BG_SPRITES_LAYER_32(1); INIT_BG_SPRITES_LAYER_32(2); @@ -489,8 +490,8 @@ static void InitTitleScreenBackgrounds(TitleScreen *titleScreen) bg80->unk20 = 0; bg80->unk22 = 0; bg80->unk24 = 0; - bg80->targetTilesX = 30; - bg80->targetTilesY = 20; + bg80->targetTilesX = DISPLAY_WIDTH / TILE_WIDTH; + bg80->targetTilesY = DISPLAY_HEIGHT / TILE_WIDTH; bg80->paletteOffset = 0; bg80->flags = 0; @@ -508,8 +509,8 @@ static void InitTitleScreenBackgrounds(TitleScreen *titleScreen) bg0->unk20 = 0; bg0->unk22 = 0; bg0->unk24 = 0; - bg0->targetTilesX = 32; - bg0->targetTilesY = 32; + bg0->targetTilesX = 256 / TILE_WIDTH; + bg0->targetTilesY = 256 / TILE_WIDTH; bg0->paletteOffset = 0; bg0->flags = BACKGROUND_FLAG_4 | BACKGROUND_FLAGS_BG_ID(2); @@ -683,8 +684,8 @@ static void Task_IntroStartSonicTeamLogoAnim(void) bg->unk20 = 0; bg->unk22 = 0; bg->unk24 = 0; - bg->targetTilesX = 30; - bg->targetTilesY = 20; + bg->targetTilesX = DISPLAY_WIDTH / 8; + bg->targetTilesY = DISPLAY_HEIGHT / 8; bg->paletteOffset = 0; bg->flags = 0x10; DrawBackground(bg); @@ -795,13 +796,13 @@ static void Task_IntroPanSkyAnim(void) } gBgScrollRegs[1][1] -= titleScreen->introPanUpVelocity; - if (gBgScrollRegs[1][1] < 0xAF) { - gBgScrollRegs[1][1] = 0xAF; + if (gBgScrollRegs[1][1] < 175) { + gBgScrollRegs[1][1] = 175; } - if (gBgScrollRegs[1][1] < 0x15F) { - gDispCnt &= 0xFBFF; - gDispCnt &= 0xBFFF; + if (gBgScrollRegs[1][1] < 351) { + gDispCnt &= ~DISPCNT_BG2_ON; + gDispCnt &= ~DISPCNT_WIN1_ON; } else { titleScreen->wavesTopOffset += titleScreen->introPanUpVelocity; WavesBackgroundAnim(titleScreen); @@ -845,7 +846,7 @@ static void Task_IntroPanSkyAnim(void) bg0->flags = 0x10; DrawBackground(bg0); - gBgScrollRegs[0][1] = 0x4F; + gBgScrollRegs[0][1] = 79; gCurTask->main = Task_IntroSkyAnim; titleScreen->animFrame = 0; @@ -944,11 +945,11 @@ static void Task_IntroSkyAnim(void) DrawBackground(bg0); - gBgCntRegs[2] &= 0xDFFF; + gBgCntRegs[2] &= ~DISPCNT_WIN0_ON; gCurTask->main = Task_IntroFadeInTitleScreenAnim; - gDispCnt |= 0x400; - gDispCnt &= 0xFEFF; + gDispCnt |= DISPCNT_BG2_ON; + gDispCnt &= ~DISPCNT_BG0_ON; gBldRegs.bldAlpha = 0x1000; gBldRegs.bldCnt = 0x244; diff --git a/src/game/water_effects.c b/src/game/water_effects.c index f81fbc5f2..2ce366aa6 100644 --- a/src/game/water_effects.c +++ b/src/game/water_effects.c @@ -109,10 +109,10 @@ void InitWaterPalettes(void) #ifndef NON_MATCHING { const u16 *src = gSpritePalettes[pal]; - CopyPalette((u32 *)wd->pal[j], (u32 *)src, 16); + CopyPalette((u32 *)wd->pal[j], (u32 *)src, PALETTE_LEN_4BPP); }; #else - CopyPalette((u32 *)wd->pal[j], (u32 *)gSpritePalettes[pal], 16); + CopyPalette((u32 *)wd->pal[j], (u32 *)gSpritePalettes[pal], PALETTE_LEN_4BPP); #endif } } else { @@ -121,21 +121,21 @@ void InitWaterPalettes(void) animId = gUnknown_080D550C[character]; animation = gAnimations[animId]; pal = animation[0]->pal.palId; - CopyPalette((u32 *)wd->pal[0], (u32 *)gSpritePalettes[pal], 16); + CopyPalette((u32 *)wd->pal[0], (u32 *)gSpritePalettes[pal], PALETTE_LEN_4BPP); character = gPlayer.character; animId = sCharacterPalettesBoostEffect[character]; animation = gAnimations[animId]; pal = animation[0]->pal.palId; - CopyPalette((u32 *)wd->pal[1], (u32 *)gSpritePalettes[pal], 16); + CopyPalette((u32 *)wd->pal[1], (u32 *)gSpritePalettes[pal], PALETTE_LEN_4BPP); } animId = SA2_ANIM_PALETTE_554; animation = gAnimations[animId]; pal = (animation[0]->pal.palId + 4); - CopyPalette((u32 *)wd->pal[4], (u32 *)gSpritePalettes[pal], 12 * 16); + CopyPalette((u32 *)wd->pal[4], (u32 *)gSpritePalettes[pal], 12 * PALETTE_LEN_4BPP); - MaskPaletteWithUnderwaterColor_inline((u32 *)wd->pal[16], (u32 *)gBgPalette, water->mask, 16 * 16); + MaskPaletteWithUnderwaterColor_inline((u32 *)wd->pal[16], (u32 *)&GET_PALETTE_COLOR_BG(0, 0), water->mask, 16 * PALETTE_LEN_4BPP); } void CreateStageWaterTask(s32 waterLevel, u32 p1, u32 mask) diff --git a/src/lib/m4a/m4a0.s b/src/lib/m4a/m4a0.s index 7f000b7f0..d5bccca9a 100644 --- a/src/lib/m4a/m4a0.s +++ b/src/lib/m4a/m4a0.s @@ -25,7 +25,7 @@ SoundMain: ldr r3, [r0, o_SoundInfo_ident] cmp r2, r3 beq SoundMain_1 - bx lr @ Exit the function if ident doesn't match ID_NUMBER. + bx lr @ Exit the function if ident does not match ID_NUMBER. SoundMain_1: adds r3, 1 str r3, [r0, o_SoundInfo_ident] diff --git a/src/malloc_vram.c b/src/malloc_vram.c index 149c5940e..c20fec1d8 100644 --- a/src/malloc_vram.c +++ b/src/malloc_vram.c @@ -8,15 +8,48 @@ #define HEAP_END ewram_end #endif +/* --- HOW THIS WORKS --- + * + * gVramHeapState[] represents (or *can* represent) the entire Object Tiles memory range in VRAM (0x06010000 -> 0x06018000). + * Whereby each u16 word in gVramHeapState contains a reserved number of segments. + * Each segment in SA2: 4 tiles * size-per-tile = (4 * 0x20 | 0x80) [segment tile-count might vary per game] + * + * I say *can*, because in practice, there's a much smaller available heap. + * In practice it starts at: + * 0x06013200 in SA1 + * 0x06013A00 in SA2 + * 0x06012C50 in SA3 + * ( OBJ_VRAM1 - (VRAM_HEAP_TILE_COUNT * TILE_SIZE_4BPP) ) + * + * Take this representation for example: + * + * Imagine every digit being a u16 word. + * 0000000000000000 + * ^ + * This is basically an entirely empty VRAM heap, so starting with the first byte, some number of segments could be reserved. + * Note that VramResetHeapState() just clears the entire gVramHeapState[], so anything allocated before would be allocateable by a new + * VramMalloc() call. + * + * Below, each * is a word reserved by the segment-count preceding it, so those cannot be allocated. + * 6*****4***000000 + * ^ ^ + * | | + * +-----+--- 6 allocated segments (24 tiles) + * | + * 4 allocated segments (16 tiles) + * + * Note that the count itself is part of the number of allocated segments + */ + void *VramMalloc(u32 numTiles) { u16 i, j; - u32 count = numTiles; - count = (count + (VRAM_TILE_SLOTS_PER_SEGMENT - 1)) / VRAM_TILE_SLOTS_PER_SEGMENT; // round up + u32 segCount = numTiles; + segCount = (segCount + (VRAM_TILE_SLOTS_PER_SEGMENT - 1)) / VRAM_TILE_SLOTS_PER_SEGMENT; // round up for (i = 0; i < gVramHeapMaxTileSlots / VRAM_TILE_SLOTS_PER_SEGMENT; i++) { if (gVramHeapState[i] == 0) { - for (j = 0; j < count; j++) { + for (j = 0; j < segCount; j++) { if (i + j >= (gVramHeapMaxTileSlots / VRAM_TILE_SLOTS_PER_SEGMENT)) { return HEAP_END; } @@ -25,8 +58,8 @@ void *VramMalloc(u32 numTiles) } } - if (j == count) { - gVramHeapState[i] = count; + if (j == segCount) { + gVramHeapState[i] = segCount; return (void *)(gVramHeapStartAddr + i * VRAM_HEAP_SEGMENT_SIZE); } } else { @@ -36,6 +69,7 @@ void *VramMalloc(u32 numTiles) return HEAP_END; } +// Clear the entire gVramHeapState[], leading to zero tiles being allocated (even if OBJ_VRAM is populated) void VramResetHeapState(void) { DmaFill16(3, 0, gVramHeapState, sizeof(gVramHeapState)); } void VramFree(void *addr) diff --git a/src/platform/win32/opengl.c b/src/platform/win32/opengl.c index 5ff9897c4..b03815a14 100644 --- a/src/platform/win32/opengl.c +++ b/src/platform/win32/opengl.c @@ -1,8 +1,14 @@ -#include // realloc +//#include // realloc #include // printf +#include #include +#include // sinf/cosf #include "global.h" // TEMP for PLTT +#include "core.h" // temp? +#include "tilemap.h" // struct Tile #include "platform/shared/opengl.h" +#include "trig.h" // ONE_CYCLE +#include "game/sa1_sa2_shared/globals.h" // gCurrentLevel - TEMP: this shouldn't be exposed to the OpenGL backend... // NOTE: This is NOT final at all. EXPERIMENTAL!!!!! @@ -11,16 +17,40 @@ // TEMP static GLuint sTempTextureHandles[3] = { 0 }; -#define NUM_RGB_CHANNELS 4 -u8 tempRgbaPalette[16 * 32][NUM_RGB_CHANNELS] = {}; -u8 tempRgbaFrame[DISPLAY_WIDTH * DISPLAY_HEIGHT][NUM_RGB_CHANNELS] = {}; - +#define TILES_PER_CHUNK_AXIS 12 +#define TILES_PER_CHUNK (SQUARE(TILES_PER_CHUNK_AXIS)) +#define TILE_SIZE_PIXELS (8 * 8) +#define TILE_SIZE_RGBA (TILE_SIZE_PIXELS * sizeof(u32)) +#define CHUNK_SIZE_RGBA (TILES_PER_CHUNK * TILE_SIZE_RGBA) +#define CHUNK_SIZE_TEXCOORD (TILES_PER_CHUNK * sizeof(ChunkTileVertex)) +#define NUM_RGB_CHANNELS 4 +// u8 tempRgbaFrame[DISPLAY_WIDTH * DISPLAY_HEIGHT][NUM_RGB_CHANNELS] = {}; + +typedef struct ColorRGBA { + u8 r; + u8 g; + u8 b; + u8 a; +} ColorRGBA; typedef struct { u8 *data; int width, height; } TextureBuffer; static TextureBuffer sDynTextureBuffer = { 0 }; +ColorRGBA tempRgbaPalette[16 * 32] = {}; +static Background *sActiveBackgrounds[4] = { 0 }; + +void Debug_PrintMatrix(float *mtx) +{ + printf("%f %f %f %f\n" + "%f %f %f %f\n" + "%f %f %f %f\n" + "%f %f %f %f\n\n", + mtx[0], mtx[1], mtx[2], mtx[3], mtx[4], mtx[5], mtx[6], mtx[7], mtx[8], mtx[9], mtx[10], mtx[11], mtx[12], mtx[13], mtx[14], + mtx[15]); +} + static void TempConvertPLTTToRGBA8(void) { // Convert PLTT from ABGR1555 -> RGBA8 @@ -30,14 +60,14 @@ static void TempConvertPLTTToRGBA8(void) float g = (float)((color & 0x3E0) >> 5) / 31.0; float b = (float)((color & 0x7C00) >> 10) / 31.0; - tempRgbaPalette[i][0] = r * 255.0; - tempRgbaPalette[i][1] = g * 255.0; - tempRgbaPalette[i][2] = b * 255.0; - tempRgbaPalette[i][3] = 1 * 255.0; + tempRgbaPalette[i].r = r * 255.0; + tempRgbaPalette[i].g = g * 255.0; + tempRgbaPalette[i].b = b * 255.0; + tempRgbaPalette[i].a = 1 * 255.0; } } -static u8 *TempConvertPLTTEntryToRGBA8(u8 paletteId) +static ColorRGBA *TempConvertPLTTEntryToRGBA8(u8 paletteId) { // Convert PLTT from ABGR1555 -> RGBA8 u16 *pal4BPP = &PLTT[(paletteId + 16) * 16]; @@ -49,13 +79,13 @@ static u8 *TempConvertPLTTEntryToRGBA8(u8 paletteId) float g = (float)((color & 0x3E0) >> 5) / 31.0; float b = (float)((color & 0x7C00) >> 10) / 31.0; - tempRgbaPalette[paletteId * 16 + i][0] = r * 255.0; - tempRgbaPalette[paletteId * 16 + i][1] = g * 255.0; - tempRgbaPalette[paletteId * 16 + i][2] = b * 255.0; - tempRgbaPalette[paletteId * 16 + i][3] = 1 * 255.0; + tempRgbaPalette[paletteId * 16 + i].r = r * 255.0; + tempRgbaPalette[paletteId * 16 + i].g = g * 255.0; + tempRgbaPalette[paletteId * 16 + i].b = b * 255.0; + tempRgbaPalette[paletteId * 16 + i].a = 1 * 255.0; } - return tempRgbaPalette[paletteId * 16]; + return &tempRgbaPalette[paletteId * 16]; } // TODO: This should be done offline. @@ -71,28 +101,362 @@ static void TempConvert4bppToRGBA8_DynTextureBuffer(const u8 *bitmap4bpp, int wi } else { printf("realloc: w 0x%X, h 0x%X, full: 0x%X\n", width, height, (u32)(width * height * sizeof(u32))); } - } - u8 *texturePalette = TempConvertPLTTEntryToRGBA8(paletteId); + sDynTextureBuffer.width = width; + sDynTextureBuffer.height = height; + } - sDynTextureBuffer.width = width; - sDynTextureBuffer.height = height; + ColorRGBA *texturePalette = TempConvertPLTTEntryToRGBA8(paletteId); u16 widthInTiles = width >> 3; int numSourcePixels = width * height; for (int frameY = 0; frameY < height; frameY++) { for (int frameX = 0; frameX < width; frameX++) { - u8 colorIndex = ((frameY & 0x7) * 8 + (frameX & 0x7)); + int tileIndex = (frameY >> 3) * widthInTiles + (frameX >> 3); + int tileColorIndex = ((frameY & 0x7) * 8 + (frameX & 0x7)) + (tileIndex * (8 * 8)); + int targetColorIndex = ((frameY * width) + frameX); - bool8 doShift = (colorIndex & 1); - u8 textureColorId = bitmap4bpp[colorIndex >> 1] & (0xF << (doShift * 4)); + bool8 doShift = (targetColorIndex & 1); + int textureColorId = bitmap4bpp[tileColorIndex >> 1] & (0xF << (doShift * 4)); textureColorId >>= doShift * 4; - sDynTextureBuffer.data[colorIndex * 4 + 0] = tempRgbaPalette[textureColorId][0]; - sDynTextureBuffer.data[colorIndex * 4 + 1] = tempRgbaPalette[textureColorId][1]; - sDynTextureBuffer.data[colorIndex * 4 + 2] = tempRgbaPalette[textureColorId][2]; - sDynTextureBuffer.data[colorIndex * 4 + 3] = 0xFF; + sDynTextureBuffer.data[targetColorIndex * 4 + 0] = texturePalette[textureColorId].r; + sDynTextureBuffer.data[targetColorIndex * 4 + 1] = texturePalette[textureColorId].g; + sDynTextureBuffer.data[targetColorIndex * 4 + 2] = texturePalette[textureColorId].b; + sDynTextureBuffer.data[targetColorIndex * 4 + 3] = (textureColorId == 0) ? 0x00 : 0xFF; + } + } +} + +typedef struct ChunkTileVertex { + u8 x, y; +} ChunkTileVertex; + +typedef struct ChunkGfx { + ChunkTileVertex *tileVerts; + u8 *rgbaChunks; + u16 count; + u16 capacity; +} ChunkGfx; + +static ChunkGfx sChunkGfx = { 0 }; +#define RENDERED_CHUNKS_W ((DISPLAY_WIDTH / 96) + 2) +#define RENDERED_CHUNKS_H ((DISPLAY_HEIGHT / 96) + 2) +#define RENDERED_CHUNKS (RENDERED_CHUNKS_W * RENDERED_CHUNKS_H) + +// Set of chunks that have to be drawn this frame +typedef struct ChunkSet { + u16 *items; + u16 count, capacity; +} ChunkSet; +static ChunkSet sChunkSet = { 0 }; + +// TODO: minY should be from upper-left corner, not bottom-left! +void OpenGL_RenderRGBABuffer(u8 *buffer, u16 bufferWidth, u16 bufferHeight, float minX, float minY, float maxX, float maxY) +{ + glBindTexture(GL_TEXTURE_2D, sTempTextureHandles[2]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bufferWidth, bufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // downscale filtering + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // upscale filtering + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glBegin(GL_TRIANGLES); + { + glTexCoord2f(0.0, 0.0); + glVertex2f(minX, maxY); + glTexCoord2f(1.0, 1.0); + glVertex2f(maxX, minY); + glTexCoord2f(0.0, 1.0); + glVertex2f(minX, minY); + + glTexCoord2f(0.0, 0.0); + glVertex2f(minX, maxY); + glTexCoord2f(1.0, 0.0); + glVertex2f(maxX, maxY); + glTexCoord2f(1.0, 1.0); + glVertex2f(maxX, minY); + } + glEnd(); +} + +void CreateChunkSet(void) +{ + const int defaultCap = 16; + void *mem = malloc(defaultCap * sizeof(*sChunkSet.items)); + sChunkSet.items = mem; + sChunkSet.items[0] = 0; + sChunkSet.count = 1; // initialize to 1, to skip zero-filled chunk (which always exists) + sChunkSet.capacity = defaultCap; +} + +void FindUniqueChunks(ChunkSet *set, Background *bg, u16 mapChunkX, u16 mapChunkY, u8 screenChunkWidth, u8 screenChunkHeight) +{ + for (int y = 0; y < screenChunkHeight; y++) { + for (int x = 0; x < screenChunkWidth; x++) { + u32 screenChunkIndex = (mapChunkY + y) * bg->mapWidth + (mapChunkX + x); + const u16 *chunk = &bg->metatileMap[screenChunkIndex]; + const u16 chunkId = *chunk; + bool8 isInSet = FALSE; + + // Find chunk ID in set + for (int setI = 0; setI < set->count; setI++) { + if (set->items[setI] == chunkId) { + isInSet = TRUE; + break; + } + } + + // Add if not inside + if (!isInSet) { + while (set->count + 1 >= set->capacity) { + set->items = realloc(set->items, set->capacity * 2 * sizeof(*set->items)); + set->capacity *= 2; + } + + set->items[set->count] = chunkId; + set->count++; + } + } + } +} + +void RenderTilemap(ColorRGBA *dstBuffer, Background *bg, int chunkIndex) +{ + const u8 *tileset = bg->graphics.src; + int chunkTileCount = bg->xTiles * bg->yTiles; + u8 bgId = bg->flags & BACKGROUND_FLAGS_MASK_BG_ID; + bool8 mapIs4BPP = (gBgCntRegs[bgId] & BGCNT_256COLOR) ? FALSE : TRUE; + + if (!(bg->flags & BACKGROUND_FLAG_IS_LEVEL_MAP)) { + // NOTE(Jace): Non-stage maps do not have any "chunks", + // but chunks themselves get rendered like all other tilemaps + chunkIndex = 0; + } + + for (int tileIdY = 0; tileIdY < bg->yTiles; tileIdY++) { + for (int tileIdX = 0; tileIdX < bg->xTiles; tileIdX++) { + // int tileId = tileIdY * bg->xTiles + tileIdX; + ColorRGBA *dstTileRGBA = &dstBuffer[tileIdY * 8 * (bg->xTiles * 8) + tileIdX * 8]; + + if (mapIs4BPP) { + int tileInChunkIndex = (chunkIndex * chunkTileCount) + tileIdY * bg->xTiles + tileIdX; + Tile tile = *(const Tile *)&bg->layout[tileInChunkIndex]; + const u8 *srcTile4BPP = &tileset[(tile.index * TILE_SIZE_PIXELS) >> 1]; + + for (int tileLoopY = 0; tileLoopY < 8; tileLoopY++) { + int tileY = (tile.yFlip) ? (7 - tileLoopY) : tileLoopY; + for (int tileLoopX = 0; tileLoopX < 8; tileLoopX++) { + int tileX = (tile.xFlip) ? (7 - tileLoopX) : tileLoopX; + + int targetColorIndex = ((tileY * 8) + tileX); + bool8 doShift = (targetColorIndex & 1); + int colorId = srcTile4BPP[targetColorIndex >> 1] & (0xF << (doShift * 4)); + colorId >>= doShift * 4; + + ColorRGBA *tilePalette = (ColorRGBA *)(&tempRgbaPalette[tile.pal * 16 + colorId]); + int dstTileIndex = tileLoopY * (bg->xTiles * 8) + tileLoopX; + dstTileRGBA[dstTileIndex].r = tilePalette->r; + dstTileRGBA[dstTileIndex].g = tilePalette->g; + dstTileRGBA[dstTileIndex].b = tilePalette->b; + dstTileRGBA[dstTileIndex].a = (colorId == 0) ? 0x00 : 0xFF; + } + } + } else { + // 8BPP + u8 tile = ((const u8 *)bg->layout)[tileIdY * bg->xTiles + tileIdX]; + const u8 *srcTile8BPP = &tileset[tile * TILE_SIZE_PIXELS]; + + for (int tileLoopY = 0; tileLoopY < 8; tileLoopY++) { + int tileY = tileLoopY; + for (int tileLoopX = 0; tileLoopX < 8; tileLoopX++) { + int tileX = tileLoopX; + + int targetColorIndex = ((tileY * 8) + tileX); + int colorId = srcTile8BPP[targetColorIndex]; + + ColorRGBA *tilePalette = (ColorRGBA *)(&tempRgbaPalette[colorId]); + int dstTileIndex = tileLoopY * (bg->xTiles * 8) + tileLoopX; + dstTileRGBA[dstTileIndex].r = tilePalette->r; + dstTileRGBA[dstTileIndex].g = tilePalette->g; + dstTileRGBA[dstTileIndex].b = tilePalette->b; + dstTileRGBA[dstTileIndex].a = (colorId == 0) ? 0x00 : 0xFF; + } + } + } + } + } +} + +void CacheUncachedUniqueChunks(Background *bg, ChunkSet *set, ChunkGfx *gfx) +{ + // if (!(bg->flags & (BACKGROUND_DISABLE_TILESET_UPDATE | BACKGROUND_DISABLE_PALETTE_UPDATE))) + { + for (int chunkSetItemIndex = 0; chunkSetItemIndex < sChunkSet.count; chunkSetItemIndex++) { + int chunkIndex = sChunkSet.items[chunkSetItemIndex]; + if (chunkIndex == 0) + continue; + + ColorRGBA *chunkRGBA = (ColorRGBA *)(&gfx->rgbaChunks[chunkSetItemIndex * CHUNK_SIZE_RGBA]); + const u8 *tileset4BPP = &((const u8 *)bg->graphics.src)[0]; + RenderTilemap(chunkRGBA, bg, chunkIndex); + } + } +} + +u16 GetChunkSetIndexFromChunkId(ChunkSet *set, u16 chunkId) +{ + for (int i = 0; i < set->count; i++) { + if (set->items[i] == chunkId) { + return i; + } + } + + return 0; +} + +void RenderScreenChunks(ChunkSet *set, ChunkGfx *gfx, Background *bg, s16 mapChunkX, s16 mapChunkY, s16 screenX, s16 screenY, + u8 screenChunkWidth, u8 screenChunkHeight) +{ + for (int chunkY = 0; chunkY < screenChunkHeight; chunkY++) { + int chunkPosIndexY = (mapChunkY + chunkY); + if (chunkPosIndexY >= bg->mapHeight) { + break; + } + + for (int chunkX = 0; chunkX < screenChunkWidth; chunkX++) { + int chunkPosIndexX = (mapChunkX + chunkX); + if (chunkPosIndexX >= bg->mapWidth) { + break; + } + int chunkPosIndex = chunkPosIndexY * bg->mapWidth + chunkPosIndexX; + int chunkSetIndex = GetChunkSetIndexFromChunkId(set, bg->metatileMap[chunkPosIndex]); + int chunkStartIndex = chunkSetIndex * CHUNK_SIZE_RGBA; + int chunkScreenX = (screenX + (chunkX * 96)); + int chunkScreenY = DISPLAY_HEIGHT - (screenY + (chunkY * 96)); + OpenGL_RenderRGBABuffer(&gfx->rgbaChunks[chunkStartIndex], 96, 96, chunkScreenX, chunkScreenY, chunkScreenX + 96, + chunkScreenY + 96); + } + } +} + +void UpdateChunkGfx(ChunkGfx *gfx, Background *bg) +{ + u32 mapWidthPixels = bg->mapWidth * 96; + u32 mapHeightPixels = bg->mapHeight * 96; + u16 mapChunkX = bg->scrollX / 96; + u16 mapChunkY = bg->scrollY / 96; + s16 screenX = -(bg->scrollX % 96u); + s16 screenY = 96 - (bg->scrollY % 96u); + u8 screenChunkWidth = MIN(bg->mapWidth - mapChunkX, RENDERED_CHUNKS_W); + u8 screenChunkHeight = MIN(bg->mapHeight - mapChunkY, RENDERED_CHUNKS_H); + // bool8 updateAll = TRUE; + + if (sChunkGfx.tileVerts == NULL || sChunkGfx.rgbaChunks == NULL) { + const int DEFAULT_CAP = 16; + gfx->tileVerts = calloc(RENDERED_CHUNKS, CHUNK_SIZE_TEXCOORD * DEFAULT_CAP); + gfx->rgbaChunks = calloc(RENDERED_CHUNKS, 96 * 96 * NUM_RGB_CHANNELS * DEFAULT_CAP); + gfx->count = 1; // initialize to 1, to skip zero-filled chunk (which always exists) + gfx->capacity = DEFAULT_CAP; + } + + // TODO/PERFORMANCE: + // This should probably be two sets, like a "Double Buffer", + // with the previous set not getting reset and chunks from it getting copied over if needed. + // Both would somehow have to be reset on a stage transition + // (more accurately: when the tileset/tilemap changes), though! + sChunkSet.count = 1; // initialize to 1, to skip zero-filled chunk (which always exists) + FindUniqueChunks(&sChunkSet, bg, mapChunkX, mapChunkY, screenChunkWidth, screenChunkHeight); + + TempConvertPLTTToRGBA8(); + CacheUncachedUniqueChunks(bg, &sChunkSet, &sChunkGfx); + + // Draw metatile RGBA graphics + RenderScreenChunks(&sChunkSet, gfx, bg, mapChunkX, mapChunkY, screenX, screenY, screenChunkWidth, screenChunkHeight); + +#if 0 + // NOTE: Need to call glEnableClientState(GL_TEXTURE_COORD_ARRAY) first! + // + // Call using this: + void glTexCoordPointer(2, // coordinates per vertex + GL_BYTE, // data type of each vertex coordinate + 0, // stride (0 = tightly packed) + chunkIndex*CHUNK_SIZE_TEXCOORD); +#endif +} + +Background *SwitchActiveBackground(Background *bg) +{ + u8 bgId = bg->flags & BACKGROUND_FLAGS_MASK_BG_ID; + + Background *prev = sActiveBackgrounds[bgId]; + sActiveBackgrounds[bgId] = bg; + return prev; +} + +// TODO/TEMP: The VRAM memory mimmicking the GBA, used by the software-renderer, shall not be part "hardware renderers". +// We need to initialize all sprites and tilemaps without hardcoded values (as happens in the base games). +#define IN_VRAM(ptr) (((ptr) >= (void *)&VRAM[0]) && ((ptr) < (void *)&VRAM[VRAM_SIZE])) + +void OpenGL_ProcessBackgroundsCopyQueue(void) +{ + // 'renderOrder' contains one background ID in each slot. + u8 renderOrder[4] = { 0 }; + u8 orderIndex = 0; + bool8 needsUpdate[4] = { 0 }; + + while (gBackgroundsCopyQueueCursor != gBackgroundsCopyQueueIndex) { + Background *bg = gBackgroundsCopyQueue[gBackgroundsCopyQueueCursor]; + INC_BACKGROUNDS_QUEUE_CURSOR(gBackgroundsCopyQueueCursor); + + if ((bg->flags & BACKGROUND_FLAG_20) && (bg->scrollX == bg->prevScrollX) && bg->scrollY == bg->prevScrollY) + continue; + + Background *prev = SwitchActiveBackground(bg); + u8 bgId = bg->flags & BACKGROUND_FLAGS_MASK_BG_ID; + needsUpdate[bgId] = (prev != bg); + } + + for (int prioIndex = 3; prioIndex >= 0; prioIndex--) { + for (int bgId = 3; bgId >= 0; bgId--) { + u8 bgPrio = gBgCntRegs[bgId] & BGCNT_PRIORITY(0x3); + if (bgPrio == prioIndex) { + renderOrder[orderIndex] = bgId; + + if (++orderIndex == 4) { + goto loopBreak; + } + } + } + } +loopBreak: + + for (orderIndex = 0; orderIndex < 4; orderIndex++) { + u8 bgId = renderOrder[orderIndex]; + Background *bg = sActiveBackgrounds[bgId]; + s16 bgScrollX = gBgScrollRegs[bgId][0]; + s16 bgScrollY = gBgScrollRegs[bgId][1]; + + if (gDispCnt & (DISPCNT_BG0_ON << bgId)) { + if (bg->flags & BACKGROUND_FLAG_IS_LEVEL_MAP) { + UpdateChunkGfx(&sChunkGfx, bg); + } else { + // TEMP!!! + // DON'T MALLOC AND FREE TILEMAPS ALL THE TIME!!! + // (Also currently it's possible to get corrupted Background pointers, leading to crashes) + if (needsUpdate[bgId]) { + if (bg->graphics.dest && !IN_VRAM(bg->graphics.dest)) { + free(bg->graphics.dest); + } + bg->graphics.dest = malloc((bg->xTiles * 8) * (bg->yTiles * 8) * TILE_SIZE_RGBA); + } + TempConvertPLTTToRGBA8(); + RenderTilemap(bg->graphics.dest, bg, 0); + OpenGL_RenderRGBABuffer(bg->graphics.dest, bg->xTiles * 8, bg->yTiles * 8, bgScrollX, bgScrollY, + bgScrollX + bg->targetTilesX * 8, bgScrollY + bg->targetTilesY * 8); + } } } } @@ -102,6 +466,11 @@ void OpenGL_OnInit() // Enable texturing glEnable(GL_TEXTURE_2D); + // Enable blending via Alpha Test + // TODO: Maybe only do this for sprites? + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_EQUAL, 1.0); + glMatrixMode(GL_TEXTURE); glLoadIdentity(); @@ -109,14 +478,78 @@ void OpenGL_OnInit() glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - glGenTextures(2, &sTempTextureHandles[0]); + glGenTextures(3, &sTempTextureHandles[0]); + + // TODO: Maybe this shuld be done in the platform layers? + CreateChunkSet(); +} + +void OpenGL_TransformSprite(Sprite *sprite, SpriteTransform *transform) +{ + glMatrixMode(GL_MODELVIEW); + s16 rotation = (transform->rotation & ONE_CYCLE); + float rotNormalized = (((float)rotation) / 1024.0f); + float theta = -(2.0f * M_PI * rotNormalized); + float sinTheta = sinf(theta); + float cosTheta = cosf(theta); + float modelViewMatrix[] = { +#if 01 + 1, + 0, + 0, + 0, // + 0, + 1, + 0, + 0, // + 0, + 0, + 1, + 0, // + 0, + 0, + 0, + 1, // +#else + +cosTheta, + +sinTheta, + 0, + 0, + -sinTheta, + +cosTheta, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, +#endif + }; + + // glLoadMatrixf(modelViewMatrix); + // glTranslatef(transform->x, transform->y, 0); + + // Debug_PrintMatrix(modelViewMatrix); + + // TODO: This doesn't happen in the original TransformSprite() procedure! + SPRITE_FLAG_SET(sprite, ROT_SCALE_ENABLE); } void OpenGL_DisplaySprite(Sprite *sprite, u8 oamPaletteNum) { const SpriteOffset *dims = sprite->dimensions; + int x = sprite->x; + int y = sprite->y; if (dims != (void *)-1) { + if (!(sprite->oamFlags & SPRITE_FLAG_MASK_ROT_SCALE_ENABLE)) { + // glMatrixMode(GL_MODELVIEW); + // glLoadIdentity(); + } // Convert vertices screenspace -> unit space glMatrixMode(GL_PROJECTION); #if 0 @@ -124,57 +557,55 @@ void OpenGL_DisplaySprite(Sprite *sprite, u8 oamPaletteNum) #else float a = 2.0f / DISPLAY_WIDTH; float b = 2.0f / DISPLAY_HEIGHT; - float projMtx[] = { a, 0, 0, 0, 0, b, 0, 0, 0, 0, 1, 0, -1, -1, 0, 1 }; + float projMtx[] = { +a, 0, 0, 0, // + 0, +b, 0, 0, // + 0, 0, 0, 0, // + -1, -1, 0, +1 }; // glLoadMatrixf(projMtx); #endif TempConvert4bppToRGBA8_DynTextureBuffer(sprite->graphics.src, dims->width, dims->height, sprite->palId + oamPaletteNum); - // glGenTextures(1, &sTempTextureHandles[2]); - glBindTexture(GL_TEXTURE_2D, sTempTextureHandles[2]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dims->width, dims->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, sDynTextureBuffer.data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // downscale filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // upscale filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - // glClearColor((float)tempRgbaPalette[1][0] / 255., - // (float)tempRgbaPalette[1][1] / 255., - // (float)tempRgbaPalette[1][2] / 255., - // 1.0); - // glClear(GL_COLOR_BUFFER_BIT); - - float minX = sprite->x - (dims->width >> 1); +#if 0 + x -= (sprite->frameFlags & SPRITE_FLAG_MASK_X_FLIP) ? dims->width - dims->offsetX : dims->offsetX; + y -= (sprite->frameFlags & SPRITE_FLAG_MASK_Y_FLIP) ? dims->height - dims->offsetY : dims->offsetY; +#else + x -= dims->offsetX; + y -= dims->offsetY; +#endif + x += (dims->width >> 1); + y += (dims->height >> 1); + float minX = x - (dims->width >> 1); float maxX = minX + dims->width; - float minY = sprite->y - (dims->height >> 1); + float minY = (DISPLAY_HEIGHT - y) - (dims->height >> 1); float maxY = minY + dims->height; - glBegin(GL_TRIANGLES); - { - glTexCoord2f(0.0, 0.0); - glVertex2f(minX, maxY); - glTexCoord2f(1.0, 1.0); - glVertex2f(maxX, minY); - glTexCoord2f(0.0, 1.0); - glVertex2f(minX, minY); - - glTexCoord2f(0.0, 0.0); - glVertex2f(minX, maxY); - glTexCoord2f(1.0, 0.0); - glVertex2f(maxX, maxY); - glTexCoord2f(1.0, 1.0); - glVertex2f(maxX, minY); + if (sprite->frameFlags & SPRITE_FLAG_MASK_X_FLIP) { + float temp = minX; + minX = maxX; + maxX = temp; + } + + if (sprite->frameFlags & SPRITE_FLAG_MASK_Y_FLIP) { + float temp = minY; + minY = maxY; + maxY = temp; } - glEnd(); + + OpenGL_RenderRGBABuffer(sDynTextureBuffer.data, dims->width, dims->height, minX, minY, maxX, maxY); } + + // TODO: This doesn't happen in the original DisplaySprite() procedure! + SPRITE_FLAG_CLEAR(sprite, ROT_SCALE_ENABLE); } void OpenGL_Render(void *tempBufferPixels, int viewportWidth, int viewportHeight) { glViewport(0, 0, viewportWidth, viewportHeight); + Background **bgQueue = &gBackgroundsCopyQueue[0]; +// __debugbreak(); #if 0 // Don't convert input-vertices glMatrixMode(GL_PROJECTION); @@ -195,6 +626,7 @@ void OpenGL_Render(void *tempBufferPixels, int viewportWidth, int viewportHeight // TempConvertPLTTToRGBA8(); +#if 0 // Convert the "software-rendered" image from ABGR1555 -> RGBA8 for (int i = 0; i < ARRAY_COUNT(tempRgbaFrame); i++) { u16 color = ((u16 *)tempBufferPixels)[i]; @@ -208,6 +640,7 @@ void OpenGL_Render(void *tempBufferPixels, int viewportWidth, int viewportHeight tempRgbaFrame[i][3] = 1 * 255.0; } + // Update palette glBindTexture(GL_TEXTURE_2D, sTempTextureHandles[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempRgbaPalette); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // downscale filtering @@ -215,35 +648,5 @@ void OpenGL_Render(void *tempBufferPixels, int viewportWidth, int viewportHeight glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - glBindTexture(GL_TEXTURE_2D, sTempTextureHandles[1]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, tempRgbaFrame); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // downscale filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // upscale filtering - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - glClearColor(1.0, 1.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - - glBindTexture(GL_TEXTURE_2D, sTempTextureHandles[1]); - glBegin(GL_TRIANGLES); - { - glTexCoord2f(0.0, 0.0); - glVertex2f(0.0, +DISPLAY_HEIGHT); - glTexCoord2f(1.0, 1.0); - glVertex2f(+DISPLAY_WIDTH, 0); - glTexCoord2f(0.0, 1.0); - glVertex2f(0, 0); - - glTexCoord2f(0.0, 0.0); - glVertex2f(0, DISPLAY_HEIGHT); - glTexCoord2f(1.0, 0.0); - glVertex2f(DISPLAY_WIDTH, DISPLAY_HEIGHT); - glTexCoord2f(1.0, 1.0); - glVertex2f(DISPLAY_WIDTH, 0); - } - glEnd(); +#endif } \ No newline at end of file diff --git a/src/platform/win32/win32.c b/src/platform/win32/win32.c index 261a18e60..21d27dbf9 100644 --- a/src/platform/win32/win32.c +++ b/src/platform/win32/win32.c @@ -123,7 +123,7 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR lpCmdLine, DWORD threadId; #if 01 - REG_KEYINPUT &= ~START_BUTTON; + // REG_KEYINPUT &= ~START_BUTTON; while (sRunning) { memset(sImageBuffer, 0, sizeof(sImageBuffer)); @@ -320,16 +320,26 @@ static void Win32_ProcessPendingMessages(HWND window) // Converts GBA -> Win32 RGB value #define RGB_SHIFT(value) (((value >> 10) & 0x1F) | (value & 0x3E0) | (((value & 0x1F) << 10))) +void Platform_ProcessBackgroundsCopyQueue(void) +{ +#if (RENDERER == RENDERER_OPENGL) + OpenGL_ProcessBackgroundsCopyQueue(); +#endif +} + +void Platform_TransformSprite(Sprite *s, SpriteTransform *transform) { OpenGL_TransformSprite(s, transform); } + void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum) { - if (sprite->graphics.src == NULL) + if (sprite->graphics.src == NULL) { return; + } #if (RENDERER == RENDERER_OPENGL) - // TEMP - Currently the display buffer gets drawn in software, but we should load the assets as a textures and let OpenGL render - // everything - // OpenGL_DisplaySprite(sprite, oamPaletteNum); - // return; + // TEMP - Currently the display buffer gets drawn in software, but we should load the assets as a textures and let OpenGL render + // everything + OpenGL_DisplaySprite(sprite, oamPaletteNum); + return; #endif const SpriteOffset *dims = sprite->dimensions; @@ -344,6 +354,12 @@ void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum) x = sprite->x; y = sprite->y; + // Effectively unused, but here for accuracy's sake + if (sprite->frameFlags & SPRITE_FLAG_GLOBAL_OFFSET) { + x -= gSpriteOffset.x; + y -= gSpriteOffset.y; + } + { // TEMP - from sprite.c sprWidth = dims->width; @@ -376,7 +392,7 @@ void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum) u16 widthInTiles = dims->width >> 3; for (int frameY = 0; frameY < dims->height; frameY++) { - s32 finalY = (tempY + frameY); + s32 finalY = (sprite->frameFlags & SPRITE_FLAG_MASK_Y_FLIP) ? (tempY + dims->height - 1 - frameY) : (tempY + frameY); if (finalY < 0) continue; @@ -386,7 +402,7 @@ void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum) for (int frameX = 0; frameX < dims->width; frameX++) { - s32 finalX = (tempX + frameX); + s32 finalX = (sprite->frameFlags & SPRITE_FLAG_MASK_X_FLIP) ? (tempX + dims->width - 1 - frameX) : (tempX + frameX); if (finalX < 0) continue; @@ -446,7 +462,15 @@ void VBlankIntrWait() } void *Platform_malloc(size_t numBytes) { return HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, numBytes); } - +void *Platform_realloc(void *ptr, size_t numBytes) +{ + if (ptr == NULL) { + // HeapReAlloc returns NULL when called with NULL, unlike C std realloc(). + return HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, numBytes); + } else { + return HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, ptr, numBytes); + } +} void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } void Platform_QueueAudio(const u8 *data, u32 numBytes) { } diff --git a/src/sprite.c b/src/sprite.c index 94f677da0..f4a7bbdea 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -11,6 +11,7 @@ #if !PLATFORM_GBA && !PLATFORM_SDL extern void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum); +extern void Platform_TransformSprite(Sprite *sprite, SpriteTransform *transform); #endif #define ReadInstruction(script, cursor) ((void *)(script) + (cursor * sizeof(s32))) @@ -325,10 +326,11 @@ static AnimCmdResult animCmd_GetPalette(void *cursor, Sprite *s) s32 paletteIndex = cmd->palId; if (gFlags & FLAGS_20000) { - CopyPalette(&gRefSpriteTables->palettes[paletteIndex * 16], s->palId * 16 + cmd->insertOffset, cmd->numColors); + CopyPalette(&gRefSpriteTables->palettes[paletteIndex * PALETTE_LEN_4BPP], s->palId * PALETTE_LEN_4BPP + cmd->insertOffset, + cmd->numColors); } else { - DmaCopy16(3, &gRefSpriteTables->palettes[paletteIndex * 16], &gObjPalette[s->palId * 16 + cmd->insertOffset], - cmd->numColors * 2); + DmaCopy16(3, &gRefSpriteTables->palettes[paletteIndex * PALETTE_LEN_4BPP], &GET_PALETTE_COLOR_OBJ(s->palId, cmd->insertOffset), + cmd->numColors * sizeof(u16)); gFlags |= FLAGS_UPDATE_SPRITE_PALETTES; } @@ -393,7 +395,10 @@ NONMATCH("asm/non_matching/engine/TransformSprite.inc", void TransformSprite(Spr // sp24 = s UnkSpriteStruct big; const SpriteOffset *dimensions = s->dimensions; - +#if PORTABLE && (RENDERER != RENDERER_SOFTWARE) + Platform_TransformSprite(s, transform); + return; +#endif if (dimensions != (SpriteOffset *)-1) { s16 res; s16 x16, y16; @@ -1059,7 +1064,8 @@ static AnimCmdResult animCmd_GetPalette(void *cursor, Sprite *s) if (!(s->frameFlags & SPRITE_FLAG_MASK_18)) { s32 paletteIndex = cmd->palId; - DmaCopy32(3, &gRefSpriteTables->palettes[paletteIndex * 16], &gObjPalette[s->palId * 16 + cmd->insertOffset], cmd->numColors * 2); + DmaCopy32(3, &gRefSpriteTables->palettes[paletteIndex * PALETTE_LEN_4BPP], &GET_PALETTE_COLOR_OBJ(s->palId, cmd->insertOffset), + cmd->numColors * 2); gFlags |= FLAGS_UPDATE_SPRITE_PALETTES; }