Implement some additional (still very WIP) OpenGL 1.1 rendering (#232)

* Render sprites with OpenGL directly (but graphics still get generated on-the-fly)

* Some Modelview mtx tests

* Some data documentation

* Very WIP changes

* Some more prep for tilemap rendering

* Draw back chunks

* Apply X/Y flips where needed

* Render 2nd chunk layer

* Document palette IDs in all uses of gObjPalette

* Some VRAM Heap documentation

* Use MetatileIndexType in Background::metatileMap

* Stretch Sonic Team logo on entire screen. Keep gBgScrollRegs in mind for positioning BGs

* Formatter. Fix realloc in win32. Fix crash in Zone 4

* Render 8BPP tilemaps

* Some crash fixes

* Minor priority documentation

* Address explicit gVramHeapState size in initialization

* Streamline most uses of gObjPalette

* Streamline most uses of gBgPalette
This commit is contained in:
JaceCear authored and GitHub committed 2026-02-17 02:27:21 +01:00
1 parent 91288fb33e
commit 2d42c0efae
40 files changed
+806 -300

No files matched your search

+10 -3
View File
@@ -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?
+3
View File
@@ -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))
+2
View File
@@ -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
+3 -2
View File
@@ -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)
+3
View File
@@ -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
+2
View File
@@ -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
+1 -1
View File
@@ -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 */
+10 -2
View File
@@ -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;
}
+4 -4
View File
@@ -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;
}
+1 -1
View File
@@ -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;
}
+3 -3
View File
@@ -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;
+9 -9
View File
@@ -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]);
}
}
+9 -9
View File
@@ -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]);
}
}
+5 -5
View File
@@ -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]);
}
}
+11 -10
View File
@@ -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;
}
}
+6 -6
View File
@@ -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)
+2 -2
View File
@@ -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]);
}
}
+7 -7
View File
@@ -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]);
}
}
+20 -22
View File
@@ -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]);
}
}
}
+3 -3
View File
@@ -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)
+2 -2
View File
@@ -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++;
+1 -1
View File
@@ -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));
}
}
@@ -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;
+8 -8
View File
@@ -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;
}
+3 -3
View File
@@ -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;
}
+1 -1
View File
@@ -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;
}
@@ -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);
+2 -2
View File
@@ -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);
+7
View File
@@ -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,
+37 -38
View File
@@ -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;
}
+9 -9
View File
@@ -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;
+1 -1
View File
@@ -849,4 +849,4 @@ static void sub_802C9B0(struct SuperSonic *sonic)
}
}
bool32 sub_802C9E0(void) { return FALSE; }
bool32 sub_802C9E0(void) { return FALSE; }
+3 -3
View File
@@ -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;
+23 -22
View File
@@ -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;
+6 -6
View File
@@ -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)
+1 -1
View File
@@ -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]
+39 -5
View File
@@ -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)
+494 -91
View File
@@ -1,8 +1,14 @@
#include <malloc.h> // realloc
//#include <malloc.h> // realloc
#include <stdio.h> // printf
#include <stdlib.h>
#include <GL/gl.h>
#include <math.h> // 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)));
}
sDynTextureBuffer.width = width;
sDynTextureBuffer.height = height;
}
u8 *texturePalette = TempConvertPLTTEntryToRGBA8(paletteId);
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;
}
glEnd();
if (sprite->frameFlags & SPRITE_FLAG_MASK_Y_FLIP) {
float temp = minY;
minY = maxY;
maxY = temp;
}
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
}
+33 -9
View File
@@ -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) { }
+11 -5
View File
@@ -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;
}