From e44f1f6790da70d776cce32a392395e29d480ce9 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Thu, 21 Aug 2025 01:45:35 +0200 Subject: [PATCH 01/19] Try new attempt at EXTENDED_OAM --- include/gba/defines.h | 4 + include/gba/types.h | 118 +++++++--- include/global.h | 2 +- src/game/interactables_1/platform_crumbling.c | 68 +++--- src/game/sa1_sa2_shared/rings_manager.c | 10 + src/game/special_stage/utils.c | 2 +- src/game/stage/rings_scatter.c | 59 +---- src/game/stage/ui.c | 94 ++++---- src/sprite.c | 205 +++++++++++++++--- 9 files changed, 373 insertions(+), 189 deletions(-) diff --git a/include/gba/defines.h b/include/gba/defines.h index 1857a1e7d2..a627e31cd3 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -42,9 +42,13 @@ #define DISPLAY_WIDTH 426 #define DISPLAY_HEIGHT 240 +#if !EXTENDED_OAM //#include "gba/types.h" // TODO: Fix #define OAM_SIZE (OAM_ENTRY_COUNT*sizeof(OamData)) #define OAM_SIZE (OAM_ENTRY_COUNT*8) +#else // EXTENDED_OAM +#define OAM_SIZE (OAM_ENTRY_COUNT*0xC) +#endif extern struct SoundMixerState *SOUND_INFO_PTR; extern uint16_t INTR_CHECK; extern void (*INTR_VECTOR)(void); diff --git a/include/gba/types.h b/include/gba/types.h index f5a19dc696..a843563f22 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -95,18 +95,18 @@ struct PlttData // as well using this to determine the size for some DMAs to gOamBuffer. // TODO: Somehow this does not work by #include-ing main.h and using PACKED(); // TODO: EXTENDED_OAM is not yet functional -#define EXTENDED_OAM FALSE +#define EXTENDED_OAM TRUE #if !EXTENDED_OAM PACKED(OamDataShort, { /*0x00*/ u32 y : 8; /*0x01*/ - u32 affineMode : 2; // 0x1, 0x2 -> 0x4 - u32 objMode : 2; // 0x4, 0x8 -> 0xC - u32 mosaic : 1; // 0x10 - u32 bpp : 1; // 0x20 - u32 shape : 2; // 0x40, 0x80 -> 0xC0 + u32 affineMode : 2; // 0x100, 0x200 -> 0x300 + u32 objMode : 2; // 0x400, 0x800 -> 0xC00 + u32 mosaic : 1; // 0x1000 + u32 bpp : 1; // 0x2000 + u32 shape : 2; // 0x4000, 0x8000 -> 0xC000 /*0x02*/ u32 x : 9; @@ -118,36 +118,15 @@ PACKED(OamDataShort, { u16 priority : 2; // 0x400, 0x800 -> 0xC00 u16 paletteNum : 4; }); /* size: 0x6 (important to not be 0x8, see comment above struct!) */ -#else -PACKED(OamDataShort, { - /* 0x00 */ s16 x; - /* 0x02 */ s16 y; - - /* 0x04 */ u32 affineMode:2; // 0x1, 0x2 -> 0x4 - u32 objMode:2; // 0x4, 0x8 -> 0xC - u32 mosaic:1; // 0x10 - u32 bpp:1; // 0x20 - u32 shape:2; // 0x40, 0x80 -> 0xC0 - - /* 0x06 */ u32 padding:9; - u32 matrixNum:5; // bits 3/4 are h-flip/v-flip if not in affine mode - u32 size:2; // 0x4000, 0x8000 -> 0xC000 - - /* 0x08 */ u16 tileNum:10; // 0x3FF - u16 priority:2; // 0x400, 0x800 -> 0xC00 - u16 paletteNum:4; -}); /* size: 0x6 (important to not be 0x8, see comment above struct!) */ -#endif -#if !EXTENDED_OAM typedef union { struct { /*0x00*/ u32 y:8; - /*0x01*/ u32 affineMode:2; // 0x1, 0x2 -> 0x4 - u32 objMode:2; // 0x4, 0x8 -> 0xC - u32 mosaic:1; // 0x10 - u32 bpp:1; // 0x20 - u32 shape:2; // 0x40, 0x80 -> 0xC0 + /*0x01*/ u32 affineMode:2; // 0x100, 0x200 -> 0x400 + u32 objMode:2; // 0x400, 0x800 -> 0xC00 + u32 mosaic:1; // 0x1000 + u32 bpp:1; // 0x2000 + u32 shape:2; // 0x4000, 0x8000 -> 0xC000 /*0x02*/ u32 x:9; u32 matrixNum:5; // bits 3/4 are h-flip/v-flip if not in affine mode @@ -171,7 +150,55 @@ typedef union { u16 raw[4]; } OamData; + +#define OAM_GET_X(oamEntry) ((oamEntry)->all.attr1 & 0x1FF) +#define OAM_INIT_X(oamEntry, value, flip) (oamEntry)->all.attr1 = (((value) & 0x1FF) | ((flip) ? 0x1000 : 0)); +#define OAM_SET_X(oamEntry, value) { \ + u32 v; \ + (oamEntry)->all.attr1 &= ~0x1FF; \ + v = (value); \ + (oamEntry)->all.attr1 += v & 0x1FF; \ +} + +#define OAM_GET_Y(oamEntry) (oamEntry)->all.attr0 & 0xFF +#define OAM_INIT_Y(oamEntry, value) (oamEntry)->all.attr0 = (value) & 0xFF +#define OAM_SET_Y(oamEntry, value) { \ + u32 v; \ + (oamEntry)->all.attr0 &= ~0xFF; \ + v = (value); \ + (oamEntry)->all.attr0 += v & 0xFF; \ +} +#define OAM_SET_AFFINE_MODE(oamEntry, value) { \ + u32 v; \ + (oamEntry)->all.attr0 &= ~0x3; \ + v = (value); \ + (oamEntry)->all.attr0 |= v; \ +} + +#define OAM_DATA_SIZE_AFFINE ARRAY_COUNT(((OamData *)0)->raw) +#define OAM_DATA_SIZE_NO_AFFINE (OAM_DATA_SIZE_AFFINE-1) + #else +PACKED(OamDataShort, { + /* 0x00 */ s16 x; + /* 0x02 */ s16 y; + + /* 0x04 */ u32 affineMode:2; // 0x1, 0x2 -> 0x4 + u32 objMode:2; // 0x4, 0x8 -> 0xC + u32 mosaic:1; // 0x10 + u32 bpp:1; // 0x20 + u32 shape:2; // 0x40, 0x80 -> 0xC0 + + /* 0x05 */ u32 padding:9; + u32 matrixNum:5; // bits 3/4 are h-flip/v-flip if not in affine mode + u32 size:2; // 0x4000, 0x8000 -> 0xC000 + + /* 0x07 */ u16 tileNum:10; // 0x3FF + u16 priority:2; // 0x400, 0x800 -> 0xC00 + u16 paletteNum:4; + +}); /* size: 0x6 (important to not be 0x8, see comment above struct!) */ + typedef union { struct { /* 0x00 */ s16 x; @@ -183,15 +210,15 @@ typedef union { u32 bpp:1; // 0x20 u32 shape:2; // 0x40, 0x80 -> 0xC0 - /* 0x06 */ u32 padding:9; + /* 0x05 */ u32 padding:9; u32 matrixNum:5; // bits 3/4 are h-flip/v-flip if not in affine mode u32 size:2; // 0x4000, 0x8000 -> 0xC000 - /* 0x08 */ u16 tileNum:10; // 0x3FF + /* 0x07 */ u16 tileNum:10; // 0x3FF u16 priority:2; // 0x400, 0x800 -> 0xC00 u16 paletteNum:4; - /* 0x0A */ u16 fractional:8; + /* 0x09 */ u16 fractional:8; u16 integer:7; u16 sign:1; } split; @@ -205,8 +232,27 @@ typedef union { u16 affineParam; } all; - u16 raw[4]; + u16 raw[6]; } OamData; + +#define OAM_GET_X(oamEntry) (oamEntry)->x +#define OAM_INIT_X(oamEntry, value, flip) \ + (oamEntry)->split.x = (value); \ + (oamEntry)->split.matrixNum = ((flip) ? 0x08 : 0); +#define OAM_SET_X(oamEntry, value) { \ + (oamEntry)->split.x = (value); \ +} + +#define OAM_GET_Y(oamEntry) (oamEntry)->split.y +#define OAM_INIT_Y(oamEntry, value) (oamEntry)->split.y = (value); +#define OAM_SET_Y(oamEntry, value) (oamEntry)->split.y = (value); +#define OAM_SET_AFFINE_MODE(oamEntry, value) { \ + (oamEntry)->split.affineMode = (value); \ +} + +#define OAM_DATA_SIZE_AFFINE ARRAY_COUNT(((OamData *)0)->raw) +#define OAM_DATA_SIZE_NO_AFFINE (OAM_DATA_SIZE_AFFINE-1) + #endif #define ST_OAM_HFLIP 0x08 diff --git a/include/global.h b/include/global.h index 78912d488c..a8e046ff4e 100644 --- a/include/global.h +++ b/include/global.h @@ -8,7 +8,7 @@ #define ENABLE_AUDIO TRUE #else #define ENABLE_AUDIO TRUE -#define ENABLE_VRAM_VIEW !TRUE +#define ENABLE_VRAM_VIEW TRUE #endif #define CONST_DATA __attribute__((section(".data"))) diff --git a/src/game/interactables_1/platform_crumbling.c b/src/game/interactables_1/platform_crumbling.c index 947e64dd54..d16659b849 100644 --- a/src/game/interactables_1/platform_crumbling.c +++ b/src/game/interactables_1/platform_crumbling.c @@ -186,13 +186,13 @@ void Task_805E480(void) } oam_ptr = gRefSpriteTables->oamData[s->graphics.anim]; - oam = &oam_ptr[s->dimensions->oamIndex * 3]; + oam = &oam_ptr[s->dimensions->oamIndex * OAM_DATA_SIZE_NO_AFFINE]; r6 = 0; for (y = 0; y < 4; y++) { for (x = 0; x < 8; r6++, x++) { s16 r4; - OamData *pointer; + OamData *oamAllocated; s16 value = -31; value = r6 + value + platform->unk3C; @@ -216,36 +216,40 @@ void Task_805E480(void) r4 = 0; } - pointer = OamMalloc(GET_SPRITE_OAM_ORDER(s)); - if (iwram_end == pointer) + oamAllocated = OamMalloc(GET_SPRITE_OAM_ORDER(s)); + if (iwram_end == oamAllocated) return; #if !EXTENDED_OAM - pointer->all.attr0 = ((s16)(r4 + ((y * TILE_WIDTH) + s->y))) & 0xFF; + oamAllocated->all.attr0 = ((s16)(r4 + ((y * TILE_WIDTH) + s->y))) & 0xFF; if (s->frameFlags & SPRITE_FLAG_MASK_X_FLIP) { - pointer->all.attr1 = ((s->x - x * TILE_WIDTH - 8) & 0x1FF) | 0x1000; + oamAllocated->all.attr1 = ((s->x - x * TILE_WIDTH - 8) & 0x1FF) | 0x1000; } else { - pointer->all.attr1 = (s->x + x * TILE_WIDTH) & 0x1FF; + oamAllocated->all.attr1 = (s->x + x * TILE_WIDTH) & 0x1FF; } + + oamAllocated->all.attr2 + = (((oam[2] + s->palId) & ~0xFFF) | (SPRITE_FLAG_GET(s, PRIORITY) << 10) | (u16)(GET_TILE_NUM(s->graphics.dest) + r6)); #else - pointer->split.y = (r4 + ((y * TILE_WIDTH) + s->y)); - pointer->split.affineMode = 0; - pointer->split.objMode = 0; - pointer->split.mosaic = 0; - pointer->split.bpp = 0; - pointer->split.shape = 0; + oamAllocated->split.y = (r4 + ((y * TILE_WIDTH) + s->y)); + oamAllocated->split.affineMode = 0; + oamAllocated->split.objMode = 0; + oamAllocated->split.mosaic = 0; + oamAllocated->split.bpp = 0; + oamAllocated->split.shape = 0; if (s->frameFlags & SPRITE_FLAG_MASK_X_FLIP) { - pointer->split.x = (s->x - x * TILE_WIDTH - 8); - pointer->split.matrixNum = 0x8; // x-flip, actually + oamAllocated->split.x = (s->x - x * TILE_WIDTH - 8); + oamAllocated->split.matrixNum = 0x8; // x-flip, actually } else { - pointer->split.x = (s->x + x * TILE_WIDTH); + oamAllocated->split.x = (s->x + x * TILE_WIDTH); } -#endif - pointer->all.attr2 - = (((oam[2] + s->palId) & ~0xFFF) | (SPRITE_FLAG_GET(s, PRIORITY) << 10) | (u16)(GET_TILE_NUM(s->graphics.dest) + r6)); + oamAllocated->split.tileNum = GET_TILE_NUM(s->graphics.dest) + r6; + oamAllocated->split.priority = SPRITE_FLAG_GET(s, PRIORITY); + oamAllocated->split.paletteNum = ((oam[2] + s->palId) & 0xF000) >> 12; +#endif } } } @@ -286,11 +290,11 @@ void Task_805E6A4(void) for (y = 0; y < 4; y++) { for (x = 0; x < 8; r6++, x++) { s16 r4; - OamData *pointer; + OamData *oamAllocated; s16 value = -31; value = r6 + value + platform->unk3C; - r4 = (((((s16)value * 42) * (s16)value) << 8) >> 16); + r4 = I((value * 42) * value); if (r4 > otherPos) { if (r6 == 0) { @@ -300,21 +304,27 @@ void Task_805E6A4(void) return; } - pointer = OamMalloc(GET_SPRITE_OAM_ORDER(s)); - if (iwram_end == pointer) { + oamAllocated = OamMalloc(GET_SPRITE_OAM_ORDER(s)); + if (iwram_end == oamAllocated) { return; } - pointer->all.attr0 = ((s16)(r4 + ((y * TILE_WIDTH) + s->y))) & 0xFF; + OAM_INIT_Y(oamAllocated, (r4 + ((y * TILE_WIDTH) + s->y))); - if (s->frameFlags & 0x400) { - pointer->all.attr1 = ((s->x - x * TILE_WIDTH - 8) & 0x1FF) | 0x1000; + if (s->frameFlags & SPRITE_FLAG(X_FLIP, 1)) { + OAM_INIT_X(oamAllocated, (s->x - x * TILE_WIDTH - 8), TRUE); } else { - pointer->all.attr1 = (s->x + x * TILE_WIDTH) & 0x1FF; + OAM_INIT_X(oamAllocated, (s->x + x * TILE_WIDTH + 0), FALSE); } - pointer->all.attr2 - = (((oam[2] + s->palId) & ~0xFFF) | ((s->frameFlags & 0x3000) >> 2) | (u16)(GET_TILE_NUM(s->graphics.dest) + r6)); +#if !EXTENDED_OAM + oamAllocated->all.attr2 + = (((oam[2] + s->palId) & 0xF000) | (SPRITE_FLAG_GET(s, PRIORITY) << 10) | ((GET_TILE_NUM(s->graphics.dest) + r6))); +#else + oamAllocated->split.paletteNum = (oam[2] + s->palId) >> 12; + oamAllocated->split.priority = SPRITE_FLAG_GET(s, PRIORITY); + oamAllocated->split.tileNum = (GET_TILE_NUM(s->graphics.dest) + r6); +#endif } } } diff --git a/src/game/sa1_sa2_shared/rings_manager.c b/src/game/sa1_sa2_shared/rings_manager.c index 4897c76231..0fdbc67367 100644 --- a/src/game/sa1_sa2_shared/rings_manager.c +++ b/src/game/sa1_sa2_shared/rings_manager.c @@ -377,10 +377,15 @@ NONMATCH("asm/non_matching/game/sa1_sa2_shared/Task_RingsMgrMain_collect_rings.i DmaCopy16(3, oamDat, oamAllocated, sizeof(OamDataShort)); // TODO: Can these be done more explicitly? +#if !EXTENDED_OAM oamAllocated->all.attr1 &= 0xFE00; oamAllocated->all.attr0 &= 0xFF00; oamAllocated->all.attr0 += ((ry - gCamera.y) - dimensions->offsetY) & 0xFF; oamAllocated->all.attr1 += ((rx - gCamera.x) - dimensions->offsetX) & 0x1FF; +#else + oamAllocated->split.x = ((rx - gCamera.x) - dimensions->offsetX); + oamAllocated->split.y = ((ry - gCamera.y) - dimensions->offsetY); +#endif } drawCount++; @@ -433,10 +438,15 @@ NONMATCH("asm/non_matching/game/sa1_sa2_shared/Task_RingsMgrMain_collect_rings.i DmaCopy16(3, oamDat, oamAllocated, sizeof(OamDataShort)); // TODO: Can these be done more explicitly? +#if !EXTENDED_OAM oamAllocated->all.attr1 &= 0xFE00; oamAllocated->all.attr0 &= 0xFF00; oamAllocated->all.attr0 += ((ry - gCamera.y) - dimensions->offsetY) & 0xFF; oamAllocated->all.attr1 += ((rx - gCamera.x) - dimensions->offsetX) & 0x1FF; +#else + oamAllocated->split.x = ((rx - gCamera.x) - dimensions->offsetX); + oamAllocated->split.y = ((ry - gCamera.y) - dimensions->offsetY); +#endif } drawCount++; diff --git a/src/game/special_stage/utils.c b/src/game/special_stage/utils.c index 1282c7ec0c..d41148c5dd 100644 --- a/src/game/special_stage/utils.c +++ b/src/game/special_stage/utils.c @@ -173,7 +173,7 @@ void sub_806CD68(Sprite *s) s->oamBaseIndex = gOamFreeIndex - 1; } - DmaCopy16(3, &reference[(sprDims->oamIndex + i) * 3], oam, sizeof(u16) * 3); + DmaCopy16(3, &reference[(sprDims->oamIndex + i) * OAM_DATA_SIZE_NO_AFFINE], oam, sizeof(u16) * 3); attr1_2 = oam->all.attr1 & 0x1FF; oam->all.attr0 = (unk18 + (oam->all.attr0 & 0xff)) & 0xff; oam->all.attr0 |= 0x300; diff --git a/src/game/stage/rings_scatter.c b/src/game/stage/rings_scatter.c index 4b5c53cad5..76770a2167 100644 --- a/src/game/stage/rings_scatter.c +++ b/src/game/stage/rings_scatter.c @@ -453,18 +453,10 @@ void RingsScatterSingleplayer_FlippedGravity(void) OamData *oamAlloced = OamMalloc(GET_SPRITE_OAM_ORDER(s)); if (iwram_end != oamAlloced) { - // NOTE: This will not work out for widescreen resolutions - u32 dimOffX, dimOffY; DmaCopy16(3, oam, oamAlloced, sizeof(OamDataShort)); - oamAlloced->all.attr0 &= 0xFF00; - dimOffY = screenY - (u16)s->dimensions->offsetY; - oamAlloced->all.attr0 += dimOffY & 0xFF; - - oamAlloced->all.attr1 &= 0xFE00; - - dimOffX = screenX - (u16)s->dimensions->offsetX; - oamAlloced->all.attr1 += dimOffX & 0x1FF; + OAM_SET_Y(oamAlloced, screenY - (u16)s->dimensions->offsetY); + OAM_SET_X(oamAlloced, screenX - (u16)s->dimensions->offsetX); } } } @@ -581,18 +573,10 @@ void RingsScatterSingleplayer_NormalGravity(void) OamData *oamAlloced = OamMalloc(GET_SPRITE_OAM_ORDER(s)); if (iwram_end != oamAlloced) { - // NOTE: This will not work out for widescreen resolutions - u32 dimOffX, dimOffY; DmaCopy16(3, oam, oamAlloced, sizeof(OamDataShort)); - oamAlloced->all.attr0 &= 0xFF00; - - dimOffY = screenY - (u16)s->dimensions->offsetY; - oamAlloced->all.attr0 += dimOffY & 0xFF; - oamAlloced->all.attr1 &= 0xFE00; - - dimOffX = screenX - (u16)s->dimensions->offsetX; - oamAlloced->all.attr1 += dimOffX & 0x1FF; + OAM_SET_Y(oamAlloced, screenY - (u16)s->dimensions->offsetY); + OAM_SET_X(oamAlloced, screenX - (u16)s->dimensions->offsetX); } } } @@ -709,18 +693,10 @@ NONMATCH("asm/non_matching/game/stage/rings_scatter/RingsScatterMultipak_Flipped OamData *oamAlloced = OamMalloc(GET_SPRITE_OAM_ORDER(s)); if (iwram_end != oamAlloced) { - // NOTE: This will not work out for widescreen resolutions - u32 dimOffX, dimOffY; DmaCopy16(3, oam, oamAlloced, sizeof(OamDataShort)); - oamAlloced->all.attr0 &= 0xFF00; - - dimOffY = screenY - (u16)s->dimensions->offsetY; - oamAlloced->all.attr0 += dimOffY & 0xFF; - oamAlloced->all.attr1 &= 0xFE00; - - dimOffX = screenX - (u16)s->dimensions->offsetX; - oamAlloced->all.attr1 += dimOffX & 0x1FF; + OAM_SET_Y(oamAlloced, screenY - (u16)s->dimensions->offsetY); + OAM_SET_X(oamAlloced, screenX - (u16)s->dimensions->offsetX); } } } @@ -836,18 +812,11 @@ NONMATCH("asm/non_matching/game/stage/rings_scatter/RingsScatterMultipak_NormalG OamData *oamAlloced = OamMalloc(GET_SPRITE_OAM_ORDER(s)); if (iwram_end != oamAlloced) { - // NOTE: This will not work out for widescreen resolutions u32 dimOffX, dimOffY; DmaCopy16(3, oam, oamAlloced, sizeof(OamDataShort)); - oamAlloced->all.attr0 &= 0xFF00; - - dimOffY = screenY - (u16)s->dimensions->offsetY; - oamAlloced->all.attr0 += dimOffY & 0xFF; - - oamAlloced->all.attr1 &= 0xFE00; - dimOffX = screenX - (u16)s->dimensions->offsetX; - oamAlloced->all.attr1 += dimOffX & 0x1FF; + OAM_SET_Y(oamAlloced, screenY - (u16)s->dimensions->offsetY); + OAM_SET_X(oamAlloced, screenX - (u16)s->dimensions->offsetX); } } } @@ -970,18 +939,10 @@ NONMATCH("asm/non_matching/game/stage/rings_scatter/RingsScatterSinglepakMain_Co OamData *oamAlloced = OamMalloc(GET_SPRITE_OAM_ORDER(s)); if (iwram_end != oamAlloced) { - // NOTE: This will not work out for widescreen resolutions - u32 dimOffX, dimOffY; DmaCopy16(3, oam, oamAlloced, sizeof(OamDataShort)); - oamAlloced->all.attr0 &= 0xFF00; - - dimOffY = screenY - (u16)s->dimensions->offsetY; - oamAlloced->all.attr0 += dimOffY & 0xFF; - - oamAlloced->all.attr1 &= 0xFE00; - dimOffX = screenX - (u16)s->dimensions->offsetX; - oamAlloced->all.attr1 += dimOffX & 0x1FF; + OAM_SET_Y(oamAlloced, screenY - (u16)s->dimensions->offsetY); + OAM_SET_X(oamAlloced, screenX - (u16)s->dimensions->offsetX); } } } diff --git a/src/game/stage/ui.c b/src/game/stage/ui.c index 0f5feafe65..0e8a0ff713 100644 --- a/src/game/stage/ui.c +++ b/src/game/stage/ui.c @@ -220,12 +220,36 @@ struct Task *CreateStageUI(void) return gStageUITask; } +#if !EXTENDED_OAM +#define UI_OAM_SETUP(_oam, _x, _y, _shape, _size, _tileNumPlus) \ + { \ + (_oam)->all.attr0 = ((_shape) << 14) | ((_y)); \ + (_oam)->all.attr1 = ((_size) << 14) | ((_x)); \ + (_oam)->all.attr2 = (_tileNumPlus); \ + } +#else +#define UI_OAM_SETUP(_oam, _x, _y, _shape, _size, _tileNumPlus) \ + { \ + (_oam)->split.x = (_x); \ + (_oam)->split.y = (_y); \ + (_oam)->split.shape = (_shape); \ + (_oam)->split.size = (_size); \ + (_oam)->split.tileNum = ((_tileNumPlus)&0x3FF); \ + (_oam)->split.paletteNum = (((_tileNumPlus)&0xF000) >> 12); \ + (_oam)->split.objMode = 0; \ + (_oam)->split.mosaic = 0; \ + (_oam)->split.bpp = 0; \ + (_oam)->split.priority = 0; \ + (_oam)->split.matrixNum = 0; \ + } +#endif + void Task_StageUIMain(void) { if (!(gStageFlags & STAGE_FLAG__TURN_OFF_HUD)) { u32 time; s32 score; - u32 sl; + u32 palId; u16 i; OamData *oam; u32 courseTime; @@ -246,9 +270,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - oam->all.attr0 = 31; - oam->all.attr1 = i * 8 + 4; - oam->all.attr2 = ui->digitsTileData[UI_ASCII_SP_RING]; + UI_OAM_SETUP(oam, i * 8 + 4, 31, SPRITE_SHAPE(8x8), SPRITE_SIZE(8x8), ui->digitsTileData[UI_ASCII_SP_RING]); } } } @@ -273,9 +295,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - oam->all.attr0 = (0x8000 | 14); - oam->all.attr1 = i * 8 + 28; - oam->all.attr2 = ui->digitsTileData[digit]; + UI_OAM_SETUP(oam, i * 8 + 28, 14, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[digit]); } score -= digit * m; @@ -288,9 +308,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - oam->all.attr0 = DISPLAY_HEIGHT - 18; - oam->all.attr1 = (0x4000 | 6); - oam->all.attr2 = ui->playerIconTileData; + UI_OAM_SETUP(oam, 6, DISPLAY_HEIGHT - 18, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->playerIconTileData); } if (gNumLives > 0) @@ -308,9 +326,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - oam->all.attr0 = (0x8000 | (DISPLAY_HEIGHT - 20)); - oam->all.attr1 = 30; - oam->all.attr2 = ui->digitsTileData[i]; + UI_OAM_SETUP(oam, 30, (DISPLAY_HEIGHT - 20), SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[i]); } } @@ -321,9 +337,11 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - oam->all.attr0 = (0x4000 | 0); - oam->all.attr1 = (0xC000 | ((u32)-3 & 0x1FF)); - oam->all.attr2 = ui->ringContainerTileData; +#if !EXTENDED_OAM + UI_OAM_SETUP(oam, ((u32)-3 & 0x1FF), 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ui->ringContainerTileData); +#else + UI_OAM_SETUP(oam, -3, 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ui->ringContainerTileData); +#endif } /* Ring */ @@ -339,9 +357,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - oam->all.attr0 = 8; - oam->all.attr1 = (0x4000 | 7); - oam->all.attr2 = ui->ringTileData; + UI_OAM_SETUP(oam, 7, 8, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->ringTileData); } if (gRingCount > 999) { @@ -360,7 +376,7 @@ void Task_StageUIMain(void) } else { u32 processed2; u16 processed; - sl = (gRingCount == 0) && gStageTime & 0x10 ? 0x7000 : 0; + palId = (gRingCount == 0) && gStageTime & 0x10 ? 0x7000 : 0; { /* 100s */ u16 hundreds; @@ -371,9 +387,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - oam->all.attr0 = (0x8000 | 0); - oam->all.attr1 = (28 + 0 * 8); - oam->all.attr2 = (ui->digitsTileData[hundreds] | sl); + UI_OAM_SETUP(oam, 28 + 0 * 8, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[hundreds] | palId)); } processed = hundreds * 100; } @@ -387,9 +401,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - oam->all.attr0 = (0x8000 | 0); - oam->all.attr1 = (28 + 1 * 8); - oam->all.attr2 = (ui->digitsTileData[tens] | sl); + UI_OAM_SETUP(oam, (28 + 1 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[tens] | palId)); } processed2 = processed + tens * 10; @@ -404,9 +416,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - oam->all.attr0 = (0x8000 | 0); - oam->all.attr1 = (28 + 2 * 8); - oam->all.attr2 = (ui->digitsTileData[ones] | sl); + UI_OAM_SETUP(oam, (28 + 2 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[ones] | palId)); } } } @@ -419,7 +429,7 @@ void Task_StageUIMain(void) u32 r1, r5; u32 tempTime, tempB; - sl = 0x6000; + palId = 0x6000; oam = OamMalloc(3); @@ -427,9 +437,8 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - oam->all.attr0 = (0x8000 | 0); - oam->all.attr1 = (DISPLAY_WIDTH / 2) - 21; - oam->all.attr2 = (ui->digitsTileData[UI_ASCII_COLON] | sl); + UI_OAM_SETUP(oam, (DISPLAY_WIDTH / 2) - 21, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), + (ui->digitsTileData[UI_ASCII_COLON] | palId)); } oam = OamMalloc(3); @@ -438,9 +447,8 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - oam->all.attr0 = (0x8000 | 0); - oam->all.attr1 = (DISPLAY_WIDTH / 2) + 3; - oam->all.attr2 = (ui->digitsTileData[UI_ASCII_COLON] | sl); + UI_OAM_SETUP(oam, (DISPLAY_WIDTH / 2) + 3, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), + (ui->digitsTileData[UI_ASCII_COLON] | palId)); } seconds = Div(time, GBA_FRAMES_PER_SECOND); @@ -452,44 +460,44 @@ void Task_StageUIMain(void) tempTime = gCourseTime; tempB = ZONE_TIME_TO_INT(9, 0); - sl = 0; + palId = 0; if (tempTime > tempB) { - sl = (-(gStageTime & 0x10)) >> 31; + palId = (-(gStageTime & 0x10)) >> 31; } // Milliseconds-L sd = &digits[gMillisUnpackTable[r5][0]]; sd->x = ((DISPLAY_WIDTH / 2) + 16) + 0 * 8; sd->y = 16; - sd->palId = sl; + sd->palId = palId; DisplaySprite(sd); // Milliseconds-R sd = &digits[gMillisUnpackTable[r5][1]]; sd->x = ((DISPLAY_WIDTH / 2) + 16) + 1 * 8; sd->y = 16; - sd->palId = sl; + sd->palId = palId; DisplaySprite(sd); // Seconds-L sd = &digits[gSecondsTable[seconds][0]]; sd->x = ((DISPLAY_WIDTH / 2) - 8) + 0 * 8; sd->y = 16; - sd->palId = sl; + sd->palId = palId; DisplaySprite(sd); // Seconds-R sd = &digits[gSecondsTable[seconds][1]]; sd->x = ((DISPLAY_WIDTH / 2) - 8) + 1 * 8; sd->y = 16; - sd->palId = sl; + sd->palId = palId; DisplaySprite(sd); // Minutes sd = &digits[minutes]; sd->x = (DISPLAY_WIDTH / 2) - 24; sd->y = 16; - sd->palId = sl; + sd->palId = palId; DisplaySprite(sd); } } diff --git a/src/sprite.c b/src/sprite.c index 2e6170b30c..171080e514 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -269,6 +269,7 @@ static AnimCmdResult animCmd_AddHitbox(void *cursor, Sprite *s) void sub_80047A0(u16 angle, s16 p1, s16 p2, u16 affineIndex) { +#if !EXTENDED_OAM u16 *affine = &gOamBuffer[affineIndex * 4].all.affineParam; s16 res; @@ -283,6 +284,25 @@ void sub_80047A0(u16 angle, s16 p1, s16 p2, u16 affineIndex) res = Div(0x10000, p2); affine[12] = I(COS_24_8(angle) * res); +#else + OamData *oam = &gOamBuffer[affineIndex * 4]; + s16 res; + + res = Div(0x10000, p1); + oam->all.affineParam = I(COS_24_8(angle) * res); + oam++; + + res = Div(0x10000, p1); + oam->all.affineParam = I(SIN_24_8(angle) * res); + oam++; + + res = Div(0x10000, p2); + oam->all.affineParam = I((-(SIN(angle)) >> 6) * res); + oam++; + + res = Div(0x10000, p2); + oam->all.affineParam = I(COS_24_8(angle) * res); +#endif } // Similar to sub_8004ABC and sub_8004E14 @@ -297,37 +317,71 @@ NONMATCH("asm/non_matching/engine/TransformSprite.inc", void TransformSprite(Spr if (dimensions != (SpriteOffset *)-1) { s16 res; s16 x16, y16; - s16 *affine; big.affineIndex = s->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE; - affine = (void *)&gOamBuffer[big.affineIndex * 4].all.affineParam; + + { +#if !EXTENDED_OAM + s16 *affine = (void *)&gOamBuffer[big.affineIndex * 4].all.affineParam; #if 0 - sub_80047A0(transform->rotation & ONE_CYCLE, transform->qScaleX, transform->qScaleY, + sub_80047A0(transform->rotation & ONE_CYCLE, transform->qScaleX, transform->qScaleY, big.affineIndex); #else - big.qDirX = COS_24_8(transform->rotation & ONE_CYCLE); - big.qDirY = SIN_24_8(transform->rotation & ONE_CYCLE); + big.qDirX = COS_24_8(transform->rotation & ONE_CYCLE); + big.qDirY = SIN_24_8(transform->rotation & ONE_CYCLE); - big.unkC[0] = transform->qScaleX; - big.unkC[1] = transform->qScaleY; - // __set_UnkC + big.unkC[0] = transform->qScaleX; + big.unkC[1] = transform->qScaleY; + // __set_UnkC - res = Div(0x10000, big.unkC[0]); - x16 = big.qDirX; - affine[0] = (x16 * res) >> 8; + res = Div(0x10000, big.unkC[0]); + x16 = big.qDirX; + affine[0] = (x16 * res) >> 8; - res = Div(0x10000, big.unkC[0]); - y16 = big.qDirY; - affine[4] = (y16 * res) >> 8; + res = Div(0x10000, big.unkC[0]); + y16 = big.qDirY; + affine[4] = (y16 * res) >> 8; - res = Div(0x10000, big.unkC[1]); - y16 = big.qDirY; - affine[8] = (-y16 * res) >> 8; + res = Div(0x10000, big.unkC[1]); + y16 = big.qDirY; + affine[8] = (-y16 * res) >> 8; - res = Div(0x10000, big.unkC[1]); - x16 = big.qDirX; - affine[12] = (x16 * res) >> 8; + res = Div(0x10000, big.unkC[1]); + x16 = big.qDirX; + affine[12] = (x16 * res) >> 8; +#endif +#else // EXTENDED_OAM + OamData *oam = &gOamBuffer[big.affineIndex * 4]; + + big.qDirX = COS_24_8(transform->rotation & ONE_CYCLE); + big.qDirY = SIN_24_8(transform->rotation & ONE_CYCLE); + + big.unkC[0] = transform->qScaleX; + big.unkC[1] = transform->qScaleY; + // __set_UnkC + + res = Div(0x10000, big.unkC[0]); + x16 = big.qDirX; + oam->all.affineParam = (x16 * res) >> 8; + oam++; + + res = Div(0x10000, big.unkC[0]); + y16 = big.qDirY; + oam->all.affineParam = (y16 * res) >> 8; + oam++; + + res = Div(0x10000, big.unkC[1]); + y16 = big.qDirY; + oam->all.affineParam = (-y16 * res) >> 8; + oam++; + + res = Div(0x10000, big.unkC[1]); + x16 = big.qDirX; + oam->all.affineParam = (x16 * res) >> 8; + oam++; #endif + } + // __post_Divs if (transform->qScaleX < 0) @@ -417,10 +471,11 @@ NONMATCH("asm/non_matching/engine/sub_8004E14.inc", void sub_8004E14(Sprite *spr UnkSpriteStruct us; if (sprite->dimensions != (void *)-1) { const SpriteOffset *sprDims = sprite->dimensions; +#if !EXTENDED_OAM u16 *affine; us.affineIndex = sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE; - affine = (u16 *)&gOamBuffer[us.affineIndex * 4 + 3]; + affine = (u16 *)&gOamBuffer[us.affineIndex * 4].all.affineParam; us.qDirX = COS_24_8((transform->rotation + gUnknown_03001944) & ONE_CYCLE); us.qDirY = SIN_24_8((transform->rotation + gUnknown_03001944) & ONE_CYCLE); @@ -431,6 +486,28 @@ NONMATCH("asm/non_matching/engine/sub_8004E14.inc", void sub_8004E14(Sprite *spr affine[4] = I(Div(Q(256), us.unkC[0]) * us.qDirY); affine[8] = I(Div(Q(256), us.unkC[1]) * -us.qDirY); affine[12] = I(Div(Q(256), us.unkC[1]) * us.qDirX); +#else + { + OamData *oam; + + us.affineIndex = sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE; + oam = &gOamBuffer[us.affineIndex * 4]; + + us.qDirX = COS_24_8((transform->rotation + gUnknown_03001944) & ONE_CYCLE); + us.qDirY = SIN_24_8((transform->rotation + gUnknown_03001944) & ONE_CYCLE); + us.unkC[0] = I(transform->qScaleX * gUnknown_030017F0); + us.unkC[1] = I(transform->qScaleY * gUnknown_03005394); + + oam->all.affineParam = I(Div(Q(256), us.unkC[0]) * us.qDirX); + oam++; + oam->all.affineParam = I(Div(Q(256), us.unkC[0]) * us.qDirY); + oam++; + oam->all.affineParam = I(Div(Q(256), us.unkC[1]) * -us.qDirY); + oam++; + oam->all.affineParam = I(Div(Q(256), us.unkC[1]) * us.qDirX); + oam++; + } +#endif if (transform->qScaleX < 0) { us.unkC[0] = I(-transform->qScaleX * gUnknown_030017F0); @@ -530,7 +607,7 @@ void DisplaySprite(Sprite *sprite) OamData *oam; s32 x, y, sprWidth, sprHeight; u8 i; - u32 r5, r7; + u32 sprX, sprY; const u16 *oamData; if (sprite->dimensions != (void *)-1) { @@ -586,10 +663,13 @@ void DisplaySprite(Sprite *sprite) sprite->oamBaseIndex = gOamFreeIndex - 1; } +#if !EXTENDED_OAM // oamIndex is a byte, why are they ANDing with 0x3FFF? - DmaCopy16(3, &oamData[3 * ((sprDims->oamIndex & 0x3FFF) + i)], oam, sizeof(OamDataShort)); - r7 = oam->all.attr1 & 0x1FF; - r5 = oam->all.attr0 & 0xFF; + DmaCopy16(3, &oamData[(sizeof(OamDataShort) / sizeof(u16)) * ((sprDims->oamIndex & 0x3FFF) + i)], oam, + sizeof(OamDataShort)); + + sprX = oam->all.attr1 & 0x1FF; + sprY = oam->all.attr0 & 0xFF; oam->all.attr1 &= 0xFE00; oam->all.attr0 &= 0xFE00; @@ -621,13 +701,13 @@ void DisplaySprite(Sprite *sprite) // y-flip if ((((sprDims->flip >> 1) ^ flipY) & r6) != 0) { oam->all.attr1 ^= 0x2000; - r5 = sprHeight - gOamShapesSizes[shapeAndSize][1] - r5; + sprY = sprHeight - gOamShapesSizes[shapeAndSize][1] - sprY; } // x-flip if (((sprite->frameFlags >> SPRITE_FLAG_SHIFT_X_FLIP) & r6) != (sprDims->flip & 1)) { oam->all.attr1 ^= 0x1000; - r7 = sprWidth - gOamShapesSizes[shapeAndSize][0] - r7; + sprX = sprWidth - gOamShapesSizes[shapeAndSize][0] - sprX; } } @@ -638,13 +718,76 @@ void DisplaySprite(Sprite *sprite) oam->all.attr0 |= (sprite->frameFlags & SPRITE_FLAG_MASK_OBJ_MODE) * 8; oam->all.attr2 |= (sprite->frameFlags & SPRITE_FLAG_MASK_PRIORITY) >> 2; - oam->all.attr0 += ((y + r5) & 0xFF); - oam->all.attr1 += ((x + r7) & 0x1FF); + oam->all.attr0 += ((y + sprY) & 0xFF); + oam->all.attr1 += ((x + sprX) & 0x1FF); if (oam->all.attr0 & (ST_OAM_8BPP << 13)) { oam->all.attr2 += oam->all.attr2 & 0x3FF; } oam->all.attr2 += GET_TILE_NUM(sprite->graphics.dest); +#else /* EXTENDED_OAM */ + // oamIndex is a byte, why are they ANDing with 0x3FFF? + s32 sub_index = ((sprDims->oamIndex & 0x3FFF) + i); + s32 full_index = sub_index * (sizeof(OamDataShort) / sizeof(u16)); + DmaCopy16(3, &oamData[full_index], oam, sizeof(OamDataShort)); + + sprX = oam->split.x; + sprY = oam->split.y; + + oam->split.affineMode &= ~0x1; + oam->split.paletteNum += sprite->palId; + +#if !PLATFORM_GBA && !PLATFORM_SDL + // TEMP + // Quick hack for getting output in OpenGL test + // The whole function call should be replaced by this! + Platform_DisplaySprite(sprite, oam->split.paletteNum); + return; +#endif + + if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_ENABLE) { + oam->split.affineMode |= 1; + if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_DOUBLE_SIZE) { + oam->split.affineMode |= 2; + } + oam->split.matrixNum = (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE); + } else { + u32 shapeAndSize = oam->split.shape << 2; + u32 flipY; + u32 r6; + + shapeAndSize |= oam->split.size; + flipY = sprite->frameFlags >> SPRITE_FLAG_SHIFT_Y_FLIP; + r6 = 1; + + // y-flip + if ((((sprDims->flip >> 1) ^ flipY) & r6) != 0) { + oam->split.matrixNum ^= (1 << 4); + sprY = sprHeight - gOamShapesSizes[shapeAndSize][1] - sprY; + } + + // x-flip + if (((sprite->frameFlags >> SPRITE_FLAG_SHIFT_X_FLIP) & r6) != (sprDims->flip & 1)) { + oam->split.matrixNum ^= (1 << 3); + sprX = sprWidth - gOamShapesSizes[shapeAndSize][0] - sprX; + } + } + + if (mosaicHVSizes != 0 && (sprite->frameFlags & SPRITE_FLAG_MASK_MOSAIC) != 0) { + // Enable mosaic bit + oam->split.mosaic = 1; + } + + oam->split.objMode = (sprite->frameFlags & SPRITE_FLAG_MASK_OBJ_MODE) >> SPRITE_FLAG_SHIFT_OBJ_MODE; + oam->split.priority = (sprite->frameFlags & SPRITE_FLAG_MASK_PRIORITY) >> SPRITE_FLAG_SHIFT_PRIORITY; + oam->split.x = x + sprX; + oam->split.y = y + sprY; + + if (oam->split.bpp) { + oam->split.tileNum += oam->split.tileNum & 0x3FF; + } + oam->split.tileNum += GET_TILE_NUM(sprite->graphics.dest); +#endif } } } @@ -704,13 +847,15 @@ void DisplaySprites(Sprite *sprite, Vec2_16 *positions, u8 numPositions) } // copy excluding affine params - DmaCopy16(3, &oamData[3 * ((sprDims->oamIndex & 0x3FFF) + subframe)], oam, sizeof(OamDataShort)); + DmaCopy16(3, &oamData[(sizeof(OamDataShort) / sizeof(u16)) * ((sprDims->oamIndex & 0x3FFF) + subframe)], oam, + sizeof(OamDataShort)); x1 = oam->all.attr1 & 0x1FF; y1 = oam->all.attr0 & 0xFF; oam->all.attr1 &= 0xFE00; oam->all.attr0 &= 0xFE00; oam->all.attr2 += sprite->palId << 12; + if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_ENABLE) { oam->all.attr0 |= 0x100; if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_DOUBLE_SIZE) { From 4990ede721f8de6c5688b886313412fd3a720114 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Thu, 21 Aug 2025 23:04:29 +0200 Subject: [PATCH 02/19] More EXTENDED_OAM documentation --- include/gba/types.h | 14 +++++--- src/game/interactables_1/platform_crumbling.c | 4 +-- src/game/special_stage/utils.c | 36 ++++++++++++------- src/platform/pret_sdl/sdl2.c | 19 +++------- src/sprite.c | 7 ++-- 5 files changed, 44 insertions(+), 36 deletions(-) diff --git a/include/gba/types.h b/include/gba/types.h index a843563f22..ebfb88933c 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -175,8 +175,11 @@ typedef union { (oamEntry)->all.attr0 |= v; \ } -#define OAM_DATA_SIZE_AFFINE ARRAY_COUNT(((OamData *)0)->raw) -#define OAM_DATA_SIZE_NO_AFFINE (OAM_DATA_SIZE_AFFINE-1) +#define OAM_DATA_SIZE_AFFINE 8 +#define OAM_DATA_SIZE_NO_AFFINE 6 + +#define OAM_DATA_COUNT_AFFINE (OAM_DATA_SIZE_AFFINE / sizeof(short)) +#define OAM_DATA_COUNT_NO_AFFINE (OAM_DATA_SIZE_NO_AFFINE / sizeof(short)) #else PACKED(OamDataShort, { @@ -250,8 +253,11 @@ typedef union { (oamEntry)->split.affineMode = (value); \ } -#define OAM_DATA_SIZE_AFFINE ARRAY_COUNT(((OamData *)0)->raw) -#define OAM_DATA_SIZE_NO_AFFINE (OAM_DATA_SIZE_AFFINE-1) +#define OAM_DATA_SIZE_AFFINE 12 +#define OAM_DATA_SIZE_NO_AFFINE 10 + +#define OAM_DATA_COUNT_AFFINE (OAM_DATA_SIZE_AFFINE / sizeof(short)) +#define OAM_DATA_COUNT_NO_AFFINE (OAM_DATA_SIZE_NO_AFFINE / sizeof(short)) #endif diff --git a/src/game/interactables_1/platform_crumbling.c b/src/game/interactables_1/platform_crumbling.c index d16659b849..f2af272af4 100644 --- a/src/game/interactables_1/platform_crumbling.c +++ b/src/game/interactables_1/platform_crumbling.c @@ -186,7 +186,7 @@ void Task_805E480(void) } oam_ptr = gRefSpriteTables->oamData[s->graphics.anim]; - oam = &oam_ptr[s->dimensions->oamIndex * OAM_DATA_SIZE_NO_AFFINE]; + oam = &oam_ptr[s->dimensions->oamIndex * OAM_DATA_COUNT_NO_AFFINE]; r6 = 0; for (y = 0; y < 4; y++) { @@ -284,7 +284,7 @@ void Task_805E6A4(void) } oam_ptr = gRefSpriteTables->oamData[s->graphics.anim]; - oam = &oam_ptr[s->dimensions->oamIndex * 3]; + oam = &oam_ptr[s->dimensions->oamIndex * OAM_DATA_COUNT_NO_AFFINE]; r6 = 0; for (y = 0; y < 4; y++) { diff --git a/src/game/special_stage/utils.c b/src/game/special_stage/utils.c index d41148c5dd..7ad9e0de7d 100644 --- a/src/game/special_stage/utils.c +++ b/src/game/special_stage/utils.c @@ -143,9 +143,9 @@ bool16 SpecialStageCalcEntityScreenPosition(struct UNK_806CB84 *a, struct Specia void sub_806CD68(Sprite *s) { - const u16 *reference; + const u16 *oamTemplate; OamData *oam; - u32 unk16, unk18; + u32 sx, sy; u16 sprHeight; u16 sprWidth; s16 numSubframes; @@ -156,13 +156,13 @@ void sub_806CD68(Sprite *s) s->numSubFrames = sprDims->numSubframes; sprWidth = sprDims->width; sprHeight = sprDims->height; - unk16 = (s16)s->x - (sprWidth / 2); - unk18 = (s16)s->y - (sprHeight / 2); + sx = (s16)s->x - (sprWidth / 2); + sy = (s16)s->y - (sprHeight / 2); numSubframes = sprDims->numSubframes; for (i = 0; i < numSubframes; i++) { - u32 attr1_2; - reference = gRefSpriteTables->oamData[s->graphics.anim]; + u32 x; + oamTemplate = gRefSpriteTables->oamData[s->graphics.anim]; oam = OamMalloc(GET_SPRITE_OAM_ORDER(s)); if (oam == iwram_end) { @@ -173,16 +173,28 @@ void sub_806CD68(Sprite *s) s->oamBaseIndex = gOamFreeIndex - 1; } - DmaCopy16(3, &reference[(sprDims->oamIndex + i) * OAM_DATA_SIZE_NO_AFFINE], oam, sizeof(u16) * 3); - attr1_2 = oam->all.attr1 & 0x1FF; - oam->all.attr0 = (unk18 + (oam->all.attr0 & 0xff)) & 0xff; + DmaCopy16(3, &oamTemplate[(sprDims->oamIndex + i) * OAM_DATA_COUNT_NO_AFFINE], oam, OAM_DATA_SIZE_NO_AFFINE); +#if !EXTENDED_OAM + x = oam->all.attr1 & 0x1FF; + oam->all.attr0 = (sy + (oam->all.attr0 & 0xff)) & 0xff; oam->all.attr0 |= 0x300; oam->all.attr1 &= 0xfe00; - oam->all.attr1 |= ((s->frameFlags & 0x1f) << 9); - oam->all.attr1 |= ((unk16 + attr1_2) & 0x1ff); + oam->all.attr1 |= (SPRITE_FLAG_GET(s, ROT_SCALE) << 9); + oam->all.attr1 |= ((sx + x) & 0x1ff); oam->all.attr2 += s->palId << 12; - oam->all.attr2 |= ((s->frameFlags & 0x3000) >> 2); + oam->all.attr2 |= (SPRITE_FLAG_GET(s, PRIORITY) << 10); oam->all.attr2 += GET_TILE_NUM(s->graphics.dest); +#else + x = oam->split.x; + oam->split.y += sy; + oam->split.mosaic = 1; + oam->split.bpp = 1; + oam->split.matrixNum = SPRITE_FLAG_GET(s, ROT_SCALE); + oam->split.x = sx + x; + oam->split.paletteNum += s->palId; + oam->split.priority = SPRITE_FLAG_GET(s, PRIORITY); + oam->split.tileNum += GET_TILE_NUM(s->graphics.dest); +#endif } } diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 400d96d2ea..065072e470 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -1359,6 +1359,8 @@ static bool winCheckHorizontalBounds(u16 left, u16 right, u16 xpos) return (xpos >= left && xpos < right); } +extern const u8 gOamShapesSizes[12][2]; + // Parts of this code heavily borrowed from NanoboyAdvance. static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool windowsEnabled) { @@ -1391,20 +1393,9 @@ static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool continue; } - if (oam->split.shape == 0) { - width = (1 << oam->split.size) * 8; - height = (1 << oam->split.size) * 8; - } else if (oam->split.shape == 1) // wide - { - width = spriteSizes[oam->split.size][1]; - height = spriteSizes[oam->split.size][0]; - } else if (oam->split.shape == 2) // tall - { - width = spriteSizes[oam->split.size][0]; - height = spriteSizes[oam->split.size][1]; - } else { - continue; // prohibited, do not draw - } + s32 index = (oam->split.shape << 2) | oam->split.size; + width = gOamShapesSizes[index][0]; + height = gOamShapesSizes[index][1]; int rect_width = width; int rect_height = height; diff --git a/src/sprite.c b/src/sprite.c index 171080e514..5265508cae 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -665,8 +665,7 @@ void DisplaySprite(Sprite *sprite) #if !EXTENDED_OAM // oamIndex is a byte, why are they ANDing with 0x3FFF? - DmaCopy16(3, &oamData[(sizeof(OamDataShort) / sizeof(u16)) * ((sprDims->oamIndex & 0x3FFF) + i)], oam, - sizeof(OamDataShort)); + DmaCopy16(3, &oamData[((sprDims->oamIndex & 0x3FFF) + i) * OAM_DATA_COUNT_NO_AFFINE], oam, sizeof(OamDataShort)); sprX = oam->all.attr1 & 0x1FF; sprY = oam->all.attr0 & 0xFF; @@ -728,7 +727,7 @@ void DisplaySprite(Sprite *sprite) #else /* EXTENDED_OAM */ // oamIndex is a byte, why are they ANDing with 0x3FFF? s32 sub_index = ((sprDims->oamIndex & 0x3FFF) + i); - s32 full_index = sub_index * (sizeof(OamDataShort) / sizeof(u16)); + s32 full_index = sub_index * OAM_DATA_COUNT_NO_AFFINE; DmaCopy16(3, &oamData[full_index], oam, sizeof(OamDataShort)); sprX = oam->split.x; @@ -784,7 +783,7 @@ void DisplaySprite(Sprite *sprite) oam->split.y = y + sprY; if (oam->split.bpp) { - oam->split.tileNum += oam->split.tileNum & 0x3FF; + oam->split.tileNum += oam->split.tileNum; } oam->split.tileNum += GET_TILE_NUM(sprite->graphics.dest); #endif From 0fe3b9bf0cb21d7ef6cc5d4eee4b80b532353ab9 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Thu, 21 Aug 2025 23:27:41 +0200 Subject: [PATCH 03/19] Fix erroneous OamBuffer copy --- src/core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/core.c b/src/core.c index e669f44f63..d9aa708f8c 100644 --- a/src/core.c +++ b/src/core.c @@ -490,10 +490,14 @@ static void UpdateScreenDma(void) if (sLastCalledVblankFuncId == VBLANK_FUNC_ID_NONE) { CopyOamBufferToOam(); +#if !EXTENDED_OAM DmaCopy16(3, gOamBuffer + 0x00, (void *)OAM + 0x000, 0x100); DmaCopy16(3, gOamBuffer + 0x20, (void *)OAM + 0x100, 0x100); DmaCopy16(3, gOamBuffer + 0x40, (void *)OAM + 0x200, 0x100); DmaCopy16(3, gOamBuffer + 0x60, (void *)OAM + 0x300, 0x100); +#else + DmaCopy16(3, gOamBuffer, (void *)OAM, OAM_SIZE); +#endif } for (i = 0; i < gNumVBlankIntrs; i++) { @@ -569,10 +573,14 @@ static void ClearOamBufferDma(void) #endif } gFlags &= ~FLAGS_EXECUTE_HBLANK_COPY; +#if !EXTENDED_OAM DmaFill16(3, 0x200, gOamBuffer + 0x00, 0x100); DmaFill16(3, 0x200, gOamBuffer + 0x20, 0x100); DmaFill16(3, 0x200, gOamBuffer + 0x40, 0x100); DmaFill16(3, 0x200, gOamBuffer + 0x60, 0x100); +#else + DmaFill16(3, 0x200, gOamBuffer, OAM_SIZE); +#endif gNumVBlankCallbacks = 0; gFlags &= ~FLAGS_10; From 8cc12e725fd48a27cfa6ea3be9a06908f7e51040 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Thu, 21 Aug 2025 23:49:40 +0200 Subject: [PATCH 04/19] Fix extended sprite wrapping behaviour --- src/platform/pret_sdl/sdl2.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 065072e470..d3a4232e6d 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -1408,10 +1408,17 @@ static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool int32_t x = oam->split.x; int32_t y = oam->split.y; +#if !EXTENDED_OAM + // The regular, unextended values are 9 and 8 unsigned bits for x and y respectively. + // Once they have exceeded the screen's right or bottom, they get treated as signed values on origina hardware. + // This is done so that, for example, a sprite at 0 on either axis that moves left or up will no suddenly disappear. + // + // With EXTENDED_OAM we are using signed 16 bit values, so we don't want to change the raw value. if (x >= DISPLAY_WIDTH) x -= 512; if (y >= DISPLAY_HEIGHT) y -= 256; +#endif if (isAffine) { // TODO: there is probably a better way to do this From 1386d1a5907e816bf548655776e233ae48afd832 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Fri, 22 Aug 2025 00:35:57 +0200 Subject: [PATCH 05/19] Define EXTENDED_OAM depending on resolution --- include/gba/defines.h | 24 +++++++++++++----------- include/gba/types.h | 1 - 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/gba/defines.h b/include/gba/defines.h index a627e31cd3..86ef6cf073 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -42,6 +42,19 @@ #define DISPLAY_WIDTH 426 #define DISPLAY_HEIGHT 240 +// NOTE: We shouldn't consider WIDESCREEN_HACK a permanent thing. +// This hack should best be removed once there's a "native" platform layer. +#if ((DISPLAY_WIDTH >= 256) || (DISPLAY_HEIGHT >= 256)) +#undef VRAM_SIZE +#define VRAM_SIZE (0x18000 + (0x800 * (12))) +#define WIDESCREEN_HACK TRUE +#define EXTENDED_OAM 1 +#else +#define WIDESCREEN_HACK FALSE +#define EXTENDED_OAM 0 +#endif +extern uint8_t VRAM[VRAM_SIZE]; + #if !EXTENDED_OAM //#include "gba/types.h" // TODO: Fix #define OAM_SIZE (OAM_ENTRY_COUNT*sizeof(OamData)) @@ -60,17 +73,6 @@ extern uint16_t PLTT[PLTT_SIZE/sizeof(uint16_t)]; #define OBJ_PLTT (u8*)&PLTT[BG_PLTT_SIZE/sizeof(uint16_t)] extern uint8_t OAM[OAM_SIZE]; -// NOTE: We shouldn't consider WIDESCREEN_HACK a permanent thing. -// This hack should best be removed once there's a "native" platform layer. -#if ((DISPLAY_WIDTH >= 256) || (DISPLAY_HEIGHT >= 256)) -#undef VRAM_SIZE -#define VRAM_SIZE (0x18000 + (0x800 * (12))) -#define WIDESCREEN_HACK TRUE -#else -#define WIDESCREEN_HACK FALSE -#endif -extern uint8_t VRAM[VRAM_SIZE]; - #define BG_VRAM &VRAM[0] #define BG_CHAR_ADDR(n) (((u8*)BG_VRAM) + (0x4000 * (n))) #define BG_CHAR_ADDR_FROM_BGCNT(bg) (BG_VRAM + ((gBgCntRegs[bg] & BGCNT_CHARBASE(0x3)) << 12)) diff --git a/include/gba/types.h b/include/gba/types.h index ebfb88933c..c4050409b8 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -95,7 +95,6 @@ struct PlttData // as well using this to determine the size for some DMAs to gOamBuffer. // TODO: Somehow this does not work by #include-ing main.h and using PACKED(); // TODO: EXTENDED_OAM is not yet functional -#define EXTENDED_OAM TRUE #if !EXTENDED_OAM PACKED(OamDataShort, { /*0x00*/ From ad8c582e77012bfaa7d21eda5ca8667cf8236dd9 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Fri, 22 Aug 2025 01:04:05 +0200 Subject: [PATCH 06/19] Add padding to align struct between different OS behaviors --- include/gba/types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/gba/types.h b/include/gba/types.h index c4050409b8..d2aae3853e 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -130,6 +130,7 @@ typedef union { /*0x02*/ u32 x:9; u32 matrixNum:5; // bits 3/4 are h-flip/v-flip if not in affine mode u32 size:2; // 0x4000, 0x8000 -> 0xC000 + u32 padding : 8; /*0x04*/ u16 tileNum:10; // 0x3FF u16 priority:2; // 0x400, 0x800 -> 0xC00 From 9564dc1a0a2f80abcab535e048b1d704ffbe06fe Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Fri, 22 Aug 2025 01:50:07 +0200 Subject: [PATCH 07/19] Unify paddings to one struct member --- include/bg_triangles.h | 11 +++++++++++ include/gba/types.h | 9 ++++----- src/sprite.c | 5 +++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/include/bg_triangles.h b/include/bg_triangles.h index 625464165d..d66538d943 100644 --- a/include/bg_triangles.h +++ b/include/bg_triangles.h @@ -2,6 +2,7 @@ #define GUARD_SPRITE_4_H typedef struct { +#if !WIDESCREEN_HACK u8 unk0; u8 unk1; u8 unk2; @@ -10,6 +11,16 @@ typedef struct { u8 unk5; u8 unk6; u8 unk7; +#else + u16 unk0; + u16 unk1; + u16 unk2; + u16 unk3; + u16 unk4; + u16 unk5; + u16 unk6; + u16 unk7; +#endif } TriParam1; extern void sub_800724C(u8 bg, TriParam1 *param1); diff --git a/include/gba/types.h b/include/gba/types.h index d2aae3853e..4524428a44 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -130,7 +130,6 @@ typedef union { /*0x02*/ u32 x:9; u32 matrixNum:5; // bits 3/4 are h-flip/v-flip if not in affine mode u32 size:2; // 0x4000, 0x8000 -> 0xC000 - u32 padding : 8; /*0x04*/ u16 tileNum:10; // 0x3FF u16 priority:2; // 0x400, 0x800 -> 0xC00 @@ -192,9 +191,9 @@ PACKED(OamDataShort, { u32 bpp:1; // 0x20 u32 shape:2; // 0x40, 0x80 -> 0xC0 - /* 0x05 */ u32 padding:9; - u32 matrixNum:5; // bits 3/4 are h-flip/v-flip if not in affine mode - u32 size:2; // 0x4000, 0x8000 -> 0xC000 + /* 0x05 */ u32 matrixNum:5; // bits 3/4 are h-flip/v-flip if not in affine mode + u32 size:2; // 0x4000, 0x8000 -> 0xC000u32 + u32 padding:17; // NOTE: Padding MUST be here for some platforms not to break /* 0x07 */ u16 tileNum:10; // 0x3FF u16 priority:2; // 0x400, 0x800 -> 0xC00 @@ -213,9 +212,9 @@ typedef union { u32 bpp:1; // 0x20 u32 shape:2; // 0x40, 0x80 -> 0xC0 - /* 0x05 */ u32 padding:9; u32 matrixNum:5; // bits 3/4 are h-flip/v-flip if not in affine mode u32 size:2; // 0x4000, 0x8000 -> 0xC000 + /* 0x05 */ u32 padding:17; // NOTE: Padding MUST be here for some platforms not to break /* 0x07 */ u16 tileNum:10; // 0x3FF u16 priority:2; // 0x400, 0x800 -> 0xC00 diff --git a/src/sprite.c b/src/sprite.c index 5265508cae..32dfceaa37 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -792,6 +792,10 @@ void DisplaySprite(Sprite *sprite) } } +#ifndef NON_MATCHING +// TODO: Make this compatible with EXTENDED_OAM, maybe? +// It's unused though, anyway. +// Technically this could just be a loop that calls DisplaySprite()... void DisplaySprites(Sprite *sprite, Vec2_16 *positions, u8 numPositions) { vs32 x, y; @@ -908,6 +912,7 @@ void DisplaySprites(Sprite *sprite, Vec2_16 *positions, u8 numPositions) } } } +#endif // The parameter to this determines the order this sprite is expected to be drawn at. // From fa117d89c715e9103d6f03e4989268cd99b80902 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Fri, 22 Aug 2025 01:51:56 +0200 Subject: [PATCH 08/19] Put offset-comment back to the right place --- include/gba/types.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/gba/types.h b/include/gba/types.h index 4524428a44..f7d74c65fc 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -212,9 +212,9 @@ typedef union { u32 bpp:1; // 0x20 u32 shape:2; // 0x40, 0x80 -> 0xC0 - u32 matrixNum:5; // bits 3/4 are h-flip/v-flip if not in affine mode - u32 size:2; // 0x4000, 0x8000 -> 0xC000 - /* 0x05 */ u32 padding:17; // NOTE: Padding MUST be here for some platforms not to break + /* 0x05 */ u32 matrixNum:5; // bits 3/4 are h-flip/v-flip if not in affine mode + u32 size:2; // 0x4000, 0x8000 -> 0xC000 + u32 padding:17; // NOTE: Padding MUST be here for some platforms not to break /* 0x07 */ u16 tileNum:10; // 0x3FF u16 priority:2; // 0x400, 0x800 -> 0xC00 From b30f3baadbdb898e104c735cc3f2830cda8578bc Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Fri, 22 Aug 2025 01:56:05 +0200 Subject: [PATCH 09/19] Adjust the lower offsets correctly --- include/gba/types.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/gba/types.h b/include/gba/types.h index f7d74c65fc..dbc5a752d0 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -195,7 +195,7 @@ PACKED(OamDataShort, { u32 size:2; // 0x4000, 0x8000 -> 0xC000u32 u32 padding:17; // NOTE: Padding MUST be here for some platforms not to break - /* 0x07 */ u16 tileNum:10; // 0x3FF + /* 0x08 */ u16 tileNum:10; // 0x3FF u16 priority:2; // 0x400, 0x800 -> 0xC00 u16 paletteNum:4; @@ -216,11 +216,11 @@ typedef union { u32 size:2; // 0x4000, 0x8000 -> 0xC000 u32 padding:17; // NOTE: Padding MUST be here for some platforms not to break - /* 0x07 */ u16 tileNum:10; // 0x3FF + /* 0x08 */ u16 tileNum:10; // 0x3FF u16 priority:2; // 0x400, 0x800 -> 0xC00 u16 paletteNum:4; - /* 0x09 */ u16 fractional:8; + /* 0x0A */ u16 fractional:8; u16 integer:7; u16 sign:1; } split; From c63e9978939dbe9b34b18031b3d38aca9776f040 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Fri, 22 Aug 2025 14:09:09 +0200 Subject: [PATCH 10/19] Reintroduce speedup to controller code --- include/platform/shared/input.h | 9 ++++++-- src/platform/pret_sdl/sdl2.c | 15 ++++++++++-- src/platform/shared/input.c | 41 +++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/include/platform/shared/input.h b/include/platform/shared/input.h index 5b6045212b..7d1866e551 100644 --- a/include/platform/shared/input.h +++ b/include/platform/shared/input.h @@ -1,8 +1,13 @@ #ifndef GUARD_PLATFORM_SHARED_INPUT_H #define GUARD_PLATFORM_SHARED_INPUT_H -#include "sprite.h" // for Sprite +typedef u32 SharedKeys; -u16 GetXInputKeys(); +#define KEY_SPEEDUP (1 << 16) +#define SPEEDUP_SCALE 5.0f + +#ifdef _WIN32 +SharedKeys GetXInputKeys(); +#endif // _WIN32 #endif // GUARD_PLATFORM_SHARED_INPUT_H diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index d3a4232e6d..5c5938505c 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -513,7 +513,7 @@ void ProcessSDLEvents(void) case SDLK_SPACE: if (!speedUp) { speedUp = true; - timeScale = 5.0; + timeScale = SPEEDUP_SCALE; SDL_PauseAudio(1); } break; @@ -546,7 +546,18 @@ void ProcessSDLEvents(void) u16 Platform_GetKeyInput(void) { #ifdef _WIN32 - u16 gamepadKeys = GetXInputKeys(); + SharedKeys gamepadKeys = GetXInputKeys(); + + speedUp = (gamepadKeys & KEY_SPEEDUP) ? true : false; + + if (speedUp) { + timeScale = SPEEDUP_SCALE; + SDL_PauseAudio(1); + } else { + timeScale = 1.0f; + SDL_PauseAudio(0); + } + return (gamepadKeys != 0) ? gamepadKeys : keys; #endif diff --git a/src/platform/shared/input.c b/src/platform/shared/input.c index d4b3a38785..e8250ed040 100644 --- a/src/platform/shared/input.c +++ b/src/platform/shared/input.c @@ -1,44 +1,51 @@ #ifdef _WIN32 +#include +#include #include #include #include "gba/io_reg.h" #include "gba/types.h" +#include "platform/shared/input.h" #define STICK_THRESHOLD 0.5f -u16 GetXInputKeys() +SharedKeys GetXInputKeys() { XINPUT_STATE state; ZeroMemory(&state, sizeof(XINPUT_STATE)); DWORD dwResult = XInputGetState(0, &state); - u16 xinputKeys = 0; + SharedKeys keys = 0; if (dwResult == ERROR_SUCCESS) { - /* A */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) >> 12; - /* B */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) >> 13; - /* Start */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) >> 1; - /* Select */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) >> 3; - /* L */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) << 1; - /* R */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) >> 1; - /* Up */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) << 6; - /* Down */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) << 6; - /* Left */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) << 3; - /* Right */ xinputKeys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) << 1; + /* A */ keys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) >> 12; + /* B */ keys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) >> 13; + /* Start */ keys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) >> 1; + /* Select */ keys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) >> 3; + /* L */ keys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) << 1; + /* R */ keys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) >> 1; + /* Up */ keys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) << 6; + /* Down */ keys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) << 6; + /* Left */ keys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) << 3; + /* Right */ keys |= (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) << 1; /* Control Stick */ float xAxis = (float)state.Gamepad.sThumbLX / (float)SHRT_MAX; float yAxis = (float)state.Gamepad.sThumbLY / (float)SHRT_MAX; if (xAxis < -STICK_THRESHOLD) - xinputKeys |= DPAD_LEFT; + keys |= DPAD_LEFT; else if (xAxis > STICK_THRESHOLD) - xinputKeys |= DPAD_RIGHT; + keys |= DPAD_RIGHT; if (yAxis < -STICK_THRESHOLD) - xinputKeys |= DPAD_DOWN; + keys |= DPAD_DOWN; else if (yAxis > STICK_THRESHOLD) - xinputKeys |= DPAD_UP; + keys |= DPAD_UP; } - return xinputKeys; + if (state.Gamepad.bRightTrigger > 170) { + keys |= KEY_SPEEDUP; + } + + return keys; } #endif // _WIN32 From e4c7376c3144c3b1b4c3dac90d53a3ff3fae5d8e Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:10:39 +0200 Subject: [PATCH 11/19] Fix incorrect tile indices in EXTENDED_OAM Special Stages --- include/global.h | 2 +- src/game/special_stage/collectables.c | 16 +++++++-------- src/game/special_stage/guard_robo.c | 12 ++++++------ src/game/special_stage/player.c | 28 +++++++++++++-------------- src/game/special_stage/utils.c | 5 ++--- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/include/global.h b/include/global.h index a8e046ff4e..78912d488c 100644 --- a/include/global.h +++ b/include/global.h @@ -8,7 +8,7 @@ #define ENABLE_AUDIO TRUE #else #define ENABLE_AUDIO TRUE -#define ENABLE_VRAM_VIEW TRUE +#define ENABLE_VRAM_VIEW !TRUE #endif #define CONST_DATA __attribute__((section(".data"))) diff --git a/src/game/special_stage/collectables.c b/src/game/special_stage/collectables.c index e85b53313f..aca7ea0866 100644 --- a/src/game/special_stage/collectables.c +++ b/src/game/special_stage/collectables.c @@ -422,13 +422,13 @@ void sub_806E1AC(s16 index, struct UNK_806DEA4 *unkDEA4) } sub_806CD68(element1); - affine = &gOamBuffer[index * 4].all.affineParam; + affine = &gOamBuffer[index * OAM_DATA_COUNT_AFFINE].all.affineParam; *affine = unkDEA4->unkC; - affine += 4; + affine += OAM_DATA_COUNT_AFFINE; *affine = unkDEA4->unkE; - affine += 4; + affine += OAM_DATA_COUNT_AFFINE; *affine = unkDEA4->unk10; - affine += 4; + affine += OAM_DATA_COUNT_AFFINE; *affine = unkDEA4->unk12; } @@ -544,13 +544,13 @@ void sub_806E584(s16 index, struct SpecialStageCollectables_UNK874 *unk874) unk7B4->oamFlags = (new_unkCB84.screenY < (stage->cameraHeight - 15)) ? SPRITE_OAM_ORDER(13) : SPRITE_OAM_ORDER(6); sub_806CD68(unk7B4); - affine = &gOamBuffer[(index + 16) * 4].all.affineParam; + affine = &gOamBuffer[(index + 16) * OAM_DATA_COUNT_AFFINE].all.affineParam; *affine = new_unkCB84.unkC; - affine += 4; + affine += OAM_DATA_COUNT_AFFINE; *affine = new_unkCB84.unkE; - affine += 4; + affine += OAM_DATA_COUNT_AFFINE; *affine = new_unkCB84.unk10; - affine += 4; + affine += OAM_DATA_COUNT_AFFINE; *affine = new_unkCB84.unk12; } } diff --git a/src/game/special_stage/guard_robo.c b/src/game/special_stage/guard_robo.c index 1eb406ef44..2d66bd6958 100644 --- a/src/game/special_stage/guard_robo.c +++ b/src/game/special_stage/guard_robo.c @@ -90,11 +90,11 @@ void Task_GuardRoboMain(void) u16 angle; *oam = unkCBB4.unkC; - oam += 4; + oam += OAM_DATA_COUNT_AFFINE; *oam = unkCBB4.unkE; - oam += 4; + oam += OAM_DATA_COUNT_AFFINE; *oam = unkCBB4.unk10; - oam += 4; + oam += OAM_DATA_COUNT_AFFINE; *oam = unkCBB4.unk12; angle = ((guardRobo->bearing - stage->cameraRotX) + 64) & ONE_CYCLE; @@ -252,11 +252,11 @@ void sub_8071380(Sprite *s, void *vram, s16 x, s16 y, u8 b, const struct UNK_80D UpdateSpriteAnimation(s); *oam = 0x100; - oam += 4; + oam += OAM_DATA_COUNT_AFFINE; *oam = 0; - oam += 4; + oam += OAM_DATA_COUNT_AFFINE; *oam = 0; - oam += 4; + oam += OAM_DATA_COUNT_AFFINE; *oam = 0x100; } diff --git a/src/game/special_stage/player.c b/src/game/special_stage/player.c index 84473f103e..ae82c8491f 100644 --- a/src/game/special_stage/player.c +++ b/src/game/special_stage/player.c @@ -125,11 +125,11 @@ struct Task *CreateSpecialStagePlayer(struct SpecialStage *stage) } *affine = 0x100; - affine += 4; + affine += OAM_DATA_COUNT_AFFINE; *affine = 0; - affine += 4; + affine += OAM_DATA_COUNT_AFFINE; *affine = 0; - affine += 4; + affine += OAM_DATA_COUNT_AFFINE; *affine = 0x100; } @@ -392,39 +392,39 @@ void sub_806D788(void) void sub_806D7D0(Sprite *s, s16 animSpeed, s16 spriteY, const struct UNK_80DF670 *anim) { - u32 unk10 = 0x1000; + u32 frameFlags = SPRITE_FLAG(PRIORITY, 1) | SPRITE_FLAG(OBJ_MODE, ST_OAM_OBJ_NORMAL); if (anim->unk7 & 1) { - unk10 |= 0x400; + frameFlags |= SPRITE_FLAG(X_FLIP, 1); } if (anim->unk7 & 2) { - unk10 |= 0x800; + frameFlags |= SPRITE_FLAG(Y_FLIP, 1); } s->graphics.anim = anim->anim; - s->frameFlags = unk10; + s->frameFlags = frameFlags; s->y = spriteY; s->variant = anim->variant; - s->animSpeed = animSpeed != -1 ? animSpeed : 0x10; + s->animSpeed = animSpeed != -1 ? animSpeed : SPRITE_ANIM_SPEED(1.0); UpdateSpriteAnimation(s); } -void sub_806D830(Sprite *s, s16 a, s16 spriteY, const struct UNK_80DF670 *anim) +void sub_806D830(Sprite *s, s16 animSpeed, s16 spriteY, const struct UNK_80DF670 *anim) { u8 unk22; - u32 unk10 = 0x1100; + u32 frameFlags = SPRITE_FLAG(PRIORITY, 1) | SPRITE_FLAG(OBJ_MODE, ST_OAM_OBJ_WINDOW); if (anim->unk7 & 1) { - unk10 |= 0x400; + frameFlags |= SPRITE_FLAG(X_FLIP, 1); } if (anim->unk7 & 2) { - unk10 |= 0x800; + frameFlags |= SPRITE_FLAG(Y_FLIP, 1); } s->graphics.anim = anim->anim; - s->frameFlags = unk10; + s->frameFlags = frameFlags; s->y = spriteY; s->variant = anim->variant; - s->animSpeed = a != -1 ? a : 0x10; + s->animSpeed = animSpeed != -1 ? animSpeed : SPRITE_ANIM_SPEED(1.0); UpdateSpriteAnimation(s); } diff --git a/src/game/special_stage/utils.c b/src/game/special_stage/utils.c index 7ad9e0de7d..0af7d8c508 100644 --- a/src/game/special_stage/utils.c +++ b/src/game/special_stage/utils.c @@ -177,7 +177,7 @@ void sub_806CD68(Sprite *s) #if !EXTENDED_OAM x = oam->all.attr1 & 0x1FF; oam->all.attr0 = (sy + (oam->all.attr0 & 0xff)) & 0xff; - oam->all.attr0 |= 0x300; + oam->all.attr0 |= (ST_OAM_AFFINE_DOUBLE << 8); oam->all.attr1 &= 0xfe00; oam->all.attr1 |= (SPRITE_FLAG_GET(s, ROT_SCALE) << 9); oam->all.attr1 |= ((sx + x) & 0x1ff); @@ -187,8 +187,7 @@ void sub_806CD68(Sprite *s) #else x = oam->split.x; oam->split.y += sy; - oam->split.mosaic = 1; - oam->split.bpp = 1; + oam->split.affineMode = ST_OAM_AFFINE_DOUBLE; oam->split.matrixNum = SPRITE_FLAG_GET(s, ROT_SCALE); oam->split.x = sx + x; oam->split.paletteNum += s->palId; From 8b70a4d9b19d298e6b446e6095b344be39b90d82 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:16:48 +0200 Subject: [PATCH 12/19] Fix crash when closing Special Stages using the Pause Menu --- include/gba/defines.h | 4 +-- src/game/special_stage/main.c | 65 ++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/include/gba/defines.h b/include/gba/defines.h index 86ef6cf073..eaca8e62fe 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -48,10 +48,10 @@ #undef VRAM_SIZE #define VRAM_SIZE (0x18000 + (0x800 * (12))) #define WIDESCREEN_HACK TRUE -#define EXTENDED_OAM 1 +#define EXTENDED_OAM !TRUE #else #define WIDESCREEN_HACK FALSE -#define EXTENDED_OAM 0 +#define EXTENDED_OAM !TRUE #endif extern uint8_t VRAM[VRAM_SIZE]; diff --git a/src/game/special_stage/main.c b/src/game/special_stage/main.c index 02518df536..fb03b6d379 100644 --- a/src/game/special_stage/main.c +++ b/src/game/special_stage/main.c @@ -22,10 +22,22 @@ #define MAX_POINTS 99900 +// TODO(Jace): Should this be in global.h? +// To me it seems like a very localized case, but maybe we could use it in other places? +#ifndef BUG_FIX +#define BUG_FIX_RETURN(_value) return; +#else +#define BUG_FIX_RETURN(_value) return (_value); +#endif + static void Task_ShowIntroScreen(void); static void SpecialStageOnDestroy(struct Task *); static void Task_InitComponents(void); +#ifndef BUG_FIX static void SpecialStagePauseMenuMain(void); +#else +static bool32 SpecialStagePauseMenuMain(void); +#endif static void TickStageTimer(void); void Task_SpecialStageMain(void); void sub_806BFD0(void); @@ -212,7 +224,15 @@ void Task_InitComponents(void) void Task_SpecialStageStartDelay(void) { struct SpecialStage *stage = TASK_DATA(gCurTask); +#ifndef BUG_FIX SpecialStagePauseMenuMain(); +#else + bool32 closed = SpecialStagePauseMenuMain(); + + // Without this, we would access free'd task memory. + if (closed) + return; +#endif if (!stage->paused) { TickStageTimer(); @@ -233,13 +253,13 @@ void Task_SpecialStageMain(void) if (stage->state == 6) { #ifndef NON_MATCHING - do + do { #endif if (player->state != 14 && player->state != 15) { player->state = 11; } #ifndef NON_MATCHING - while (0); + } while (0); #endif stage->state = 7; } @@ -251,19 +271,30 @@ void Task_SpecialStageMain(void) } switch (player->state) { - case 13: + case 13: { stage->state = 8; gCurTask->main = sub_806BFD0; + } return; - case 15: + + case 15: { stage->state = 8; gCurTask->main = sub_806BFD0; + } return; - case 14: - break; - default: + + case 14: { + } break; + + default: { +#ifndef BUG_FIX SpecialStagePauseMenuMain(); - break; +#else + bool32 closed = SpecialStagePauseMenuMain(); + if (closed) + return; +#endif + } break; } if (stage->paused == FALSE) { @@ -649,7 +680,11 @@ static void TickStageTimer(void) stage->timeTicks = GBA_FRAMES_PER_SECOND - 1; } +#ifndef BUG_FIX void SpecialStagePauseMenuMain(void) +#else +bool32 SpecialStagePauseMenuMain(void) +#endif { struct SpecialStage *stage = TASK_DATA(gCurTask); @@ -668,22 +703,24 @@ void SpecialStagePauseMenuMain(void) if (prevCursorPosition != stage->pauseMenuCursor) { m4aSongNumStart(SE_MENU_CURSOR_MOVE); } - return; - } - if (gPressedKeys & A_BUTTON) { + BUG_FIX_RETURN(FALSE); + } else if (gPressedKeys & A_BUTTON) { if (stage->pauseMenuCursor == 0) { stage->paused = FALSE; // Don't jump when exiting menu gPressedKeys &= ~A_BUTTON; - return; + + BUG_FIX_RETURN(FALSE); } TasksDestroyAll(); PAUSE_BACKGROUNDS_QUEUE(); gUnknown_03005390 = 0; PAUSE_GRAPHICS_QUEUE(); CreateTitleScreenAndSkipIntro(); - return; + + // Signal to calling functions that the task was destroyed. + BUG_FIX_RETURN(TRUE); } } @@ -691,6 +728,8 @@ void SpecialStagePauseMenuMain(void) stage->paused = !stage->paused ? TRUE : FALSE; stage->pauseMenuCursor = 0; } + + BUG_FIX_RETURN(FALSE); } static void SpecialStageOnDestroy(UNUSED struct Task *t) From 1979b4ae1cc0d2706f10a002a0563e4d398c94a5 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:18:29 +0200 Subject: [PATCH 13/19] Don't disbale EXTENDED_OAM in widescreen --- include/gba/defines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gba/defines.h b/include/gba/defines.h index eaca8e62fe..1e15e191f5 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -48,7 +48,7 @@ #undef VRAM_SIZE #define VRAM_SIZE (0x18000 + (0x800 * (12))) #define WIDESCREEN_HACK TRUE -#define EXTENDED_OAM !TRUE +#define EXTENDED_OAM TRUE #else #define WIDESCREEN_HACK FALSE #define EXTENDED_OAM !TRUE From 0e8a2cb0f55530f6e3fd874cd90cccc79953d855 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:34:44 +0200 Subject: [PATCH 14/19] Use more descriptive var name --- src/game/special_stage/main.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/game/special_stage/main.c b/src/game/special_stage/main.c index fb03b6d379..ac7530661c 100644 --- a/src/game/special_stage/main.c +++ b/src/game/special_stage/main.c @@ -227,10 +227,9 @@ void Task_SpecialStageStartDelay(void) #ifndef BUG_FIX SpecialStagePauseMenuMain(); #else - bool32 closed = SpecialStagePauseMenuMain(); - - // Without this, we would access free'd task memory. - if (closed) + // BUG: Without this, we would access free'd task memory. + bool32 taskDestroyed = SpecialStagePauseMenuMain(); + if (taskDestroyed) return; #endif @@ -290,8 +289,8 @@ void Task_SpecialStageMain(void) #ifndef BUG_FIX SpecialStagePauseMenuMain(); #else - bool32 closed = SpecialStagePauseMenuMain(); - if (closed) + bool32 taskDestroyed = SpecialStagePauseMenuMain(); + if (taskDestroyed) return; #endif } break; From beb84ada2604e9e1518fb5cf10a0bcd729bb1da6 Mon Sep 17 00:00:00 2001 From: JaceCear <11230293+JaceCear@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:52:10 +0200 Subject: [PATCH 15/19] Fix typos --- src/platform/pret_sdl/sdl2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 5c5938505c..e88e001d38 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -1421,8 +1421,8 @@ static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool #if !EXTENDED_OAM // The regular, unextended values are 9 and 8 unsigned bits for x and y respectively. - // Once they have exceeded the screen's right or bottom, they get treated as signed values on origina hardware. - // This is done so that, for example, a sprite at 0 on either axis that moves left or up will no suddenly disappear. + // Once they have exceeded the screen's right or bottom, they get treated as signed values on original hardware. + // This is done so that, for example, a sprite at 0 on either axis that moves left or up will not suddenly disappear. // // With EXTENDED_OAM we are using signed 16 bit values, so we don't want to change the raw value. if (x >= DISPLAY_WIDTH) From caa80c265de7d99e29253daf9c2aef4cca8aa213 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 31 Aug 2025 13:33:58 +0100 Subject: [PATCH 16/19] fix special stage rings --- src/game/special_stage/collectables.c | 4 ++-- src/game/stage/ui.c | 32 +++++++++++++-------------- src/sprite.c | 8 +++---- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/game/special_stage/collectables.c b/src/game/special_stage/collectables.c index aca7ea0866..19aaf95a0a 100644 --- a/src/game/special_stage/collectables.c +++ b/src/game/special_stage/collectables.c @@ -422,7 +422,7 @@ void sub_806E1AC(s16 index, struct UNK_806DEA4 *unkDEA4) } sub_806CD68(element1); - affine = &gOamBuffer[index * OAM_DATA_COUNT_AFFINE].all.affineParam; + affine = &gOamBuffer[index * 4].all.affineParam; *affine = unkDEA4->unkC; affine += OAM_DATA_COUNT_AFFINE; *affine = unkDEA4->unkE; @@ -544,7 +544,7 @@ void sub_806E584(s16 index, struct SpecialStageCollectables_UNK874 *unk874) unk7B4->oamFlags = (new_unkCB84.screenY < (stage->cameraHeight - 15)) ? SPRITE_OAM_ORDER(13) : SPRITE_OAM_ORDER(6); sub_806CD68(unk7B4); - affine = &gOamBuffer[(index + 16) * OAM_DATA_COUNT_AFFINE].all.affineParam; + affine = &gOamBuffer[(index + 16) * 4].all.affineParam; *affine = new_unkCB84.unkC; affine += OAM_DATA_COUNT_AFFINE; *affine = new_unkCB84.unkE; diff --git a/src/game/stage/ui.c b/src/game/stage/ui.c index 0e8a0ff713..b590c0bdd8 100644 --- a/src/game/stage/ui.c +++ b/src/game/stage/ui.c @@ -221,14 +221,14 @@ struct Task *CreateStageUI(void) } #if !EXTENDED_OAM -#define UI_OAM_SETUP(_oam, _x, _y, _shape, _size, _tileNumPlus) \ +#define UI_OAM_INIT(_oam, _x, _y, _shape, _size, _tileNumPlus) \ { \ (_oam)->all.attr0 = ((_shape) << 14) | ((_y)); \ (_oam)->all.attr1 = ((_size) << 14) | ((_x)); \ (_oam)->all.attr2 = (_tileNumPlus); \ } #else -#define UI_OAM_SETUP(_oam, _x, _y, _shape, _size, _tileNumPlus) \ +#define UI_OAM_INIT(_oam, _x, _y, _shape, _size, _tileNumPlus) \ { \ (_oam)->split.x = (_x); \ (_oam)->split.y = (_y); \ @@ -270,7 +270,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_SETUP(oam, i * 8 + 4, 31, SPRITE_SHAPE(8x8), SPRITE_SIZE(8x8), ui->digitsTileData[UI_ASCII_SP_RING]); + UI_OAM_INIT(oam, i * 8 + 4, 31, SPRITE_SHAPE(8x8), SPRITE_SIZE(8x8), ui->digitsTileData[UI_ASCII_SP_RING]); } } } @@ -295,7 +295,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_SETUP(oam, i * 8 + 28, 14, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[digit]); + UI_OAM_INIT(oam, i * 8 + 28, 14, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[digit]); } score -= digit * m; @@ -308,7 +308,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_SETUP(oam, 6, DISPLAY_HEIGHT - 18, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->playerIconTileData); + UI_OAM_INIT(oam, 6, DISPLAY_HEIGHT - 18, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->playerIconTileData); } if (gNumLives > 0) @@ -326,7 +326,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_SETUP(oam, 30, (DISPLAY_HEIGHT - 20), SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[i]); + UI_OAM_INIT(oam, 30, (DISPLAY_HEIGHT - 20), SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[i]); } } @@ -338,9 +338,9 @@ void Task_StageUIMain(void) #endif { #if !EXTENDED_OAM - UI_OAM_SETUP(oam, ((u32)-3 & 0x1FF), 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ui->ringContainerTileData); + UI_OAM_INIT(oam, ((u32)-3 & 0x1FF), 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ui->ringContainerTileData); #else - UI_OAM_SETUP(oam, -3, 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ui->ringContainerTileData); + UI_OAM_INIT(oam, -3, 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ui->ringContainerTileData); #endif } @@ -357,7 +357,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_SETUP(oam, 7, 8, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->ringTileData); + UI_OAM_INIT(oam, 7, 8, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->ringTileData); } if (gRingCount > 999) { @@ -387,7 +387,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_SETUP(oam, 28 + 0 * 8, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[hundreds] | palId)); + UI_OAM_INIT(oam, 28 + 0 * 8, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[hundreds] | palId)); } processed = hundreds * 100; } @@ -401,7 +401,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_SETUP(oam, (28 + 1 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[tens] | palId)); + UI_OAM_INIT(oam, (28 + 1 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[tens] | palId)); } processed2 = processed + tens * 10; @@ -416,7 +416,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_SETUP(oam, (28 + 2 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[ones] | palId)); + UI_OAM_INIT(oam, (28 + 2 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[ones] | palId)); } } } @@ -437,8 +437,8 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_SETUP(oam, (DISPLAY_WIDTH / 2) - 21, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), - (ui->digitsTileData[UI_ASCII_COLON] | palId)); + UI_OAM_INIT(oam, (DISPLAY_WIDTH / 2) - 21, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), + (ui->digitsTileData[UI_ASCII_COLON] | palId)); } oam = OamMalloc(3); @@ -447,8 +447,8 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_SETUP(oam, (DISPLAY_WIDTH / 2) + 3, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), - (ui->digitsTileData[UI_ASCII_COLON] | palId)); + UI_OAM_INIT(oam, (DISPLAY_WIDTH / 2) + 3, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), + (ui->digitsTileData[UI_ASCII_COLON] | palId)); } seconds = Div(time, GBA_FRAMES_PER_SECOND); diff --git a/src/sprite.c b/src/sprite.c index 32dfceaa37..7cdefbea4d 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -733,7 +733,7 @@ void DisplaySprite(Sprite *sprite) sprX = oam->split.x; sprY = oam->split.y; - oam->split.affineMode &= ~0x1; + oam->split.affineMode &= ~ST_OAM_AFFINE_ON_MASK; oam->split.paletteNum += sprite->palId; #if !PLATFORM_GBA && !PLATFORM_SDL @@ -745,9 +745,9 @@ void DisplaySprite(Sprite *sprite) #endif if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_ENABLE) { - oam->split.affineMode |= 1; + oam->split.affineMode |= ST_OAM_AFFINE_ON_MASK; if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_DOUBLE_SIZE) { - oam->split.affineMode |= 2; + oam->split.affineMode |= ST_OAM_AFFINE_DOUBLE_MASK; } oam->split.matrixNum = (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE); } else { @@ -792,7 +792,6 @@ void DisplaySprite(Sprite *sprite) } } -#ifndef NON_MATCHING // TODO: Make this compatible with EXTENDED_OAM, maybe? // It's unused though, anyway. // Technically this could just be a loop that calls DisplaySprite()... @@ -912,7 +911,6 @@ void DisplaySprites(Sprite *sprite, Vec2_16 *positions, u8 numPositions) } } } -#endif // The parameter to this determines the order this sprite is expected to be drawn at. // From ff4050ed80fbbe644057c8085727b774d534e142 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 31 Aug 2025 14:32:51 +0100 Subject: [PATCH 17/19] clean up --- src/core.c | 16 +++---- src/sprite.c | 130 +++++++++++---------------------------------------- 2 files changed, 35 insertions(+), 111 deletions(-) diff --git a/src/core.c b/src/core.c index d9aa708f8c..979bc2ce30 100644 --- a/src/core.c +++ b/src/core.c @@ -490,14 +490,14 @@ static void UpdateScreenDma(void) if (sLastCalledVblankFuncId == VBLANK_FUNC_ID_NONE) { CopyOamBufferToOam(); -#if !EXTENDED_OAM - DmaCopy16(3, gOamBuffer + 0x00, (void *)OAM + 0x000, 0x100); - DmaCopy16(3, gOamBuffer + 0x20, (void *)OAM + 0x100, 0x100); - DmaCopy16(3, gOamBuffer + 0x40, (void *)OAM + 0x200, 0x100); - DmaCopy16(3, gOamBuffer + 0x60, (void *)OAM + 0x300, 0x100); -#else - DmaCopy16(3, gOamBuffer, (void *)OAM, OAM_SIZE); -#endif + DmaCopy16(3, gOamBuffer + (OAM_ENTRY_COUNT / 4) * 0, (void *)OAM + (OAM_ENTRY_COUNT * (OAM_DATA_SIZE_AFFINE / 4) * 0), + OAM_SIZE / 4); + DmaCopy16(3, gOamBuffer + (OAM_ENTRY_COUNT / 4) * 1, (void *)OAM + (OAM_ENTRY_COUNT * (OAM_DATA_SIZE_AFFINE / 4) * 1), + OAM_SIZE / 4); + DmaCopy16(3, gOamBuffer + (OAM_ENTRY_COUNT / 4) * 2, (void *)OAM + (OAM_ENTRY_COUNT * (OAM_DATA_SIZE_AFFINE / 4) * 2), + OAM_SIZE / 4); + DmaCopy16(3, gOamBuffer + (OAM_ENTRY_COUNT / 4) * 3, (void *)OAM + (OAM_ENTRY_COUNT * (OAM_DATA_SIZE_AFFINE / 4) * 3), + OAM_SIZE / 4); } for (i = 0; i < gNumVBlankIntrs; i++) { diff --git a/src/sprite.c b/src/sprite.c index 7cdefbea4d..af45689734 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -269,40 +269,20 @@ static AnimCmdResult animCmd_AddHitbox(void *cursor, Sprite *s) void sub_80047A0(u16 angle, s16 p1, s16 p2, u16 affineIndex) { -#if !EXTENDED_OAM u16 *affine = &gOamBuffer[affineIndex * 4].all.affineParam; s16 res; res = Div(0x10000, p1); - affine[0] = I(COS_24_8(angle) * res); + affine[0 * OAM_DATA_COUNT_AFFINE] = I(COS_24_8(angle) * res); res = Div(0x10000, p1); - affine[4] = I(SIN_24_8(angle) * res); + affine[1 * OAM_DATA_COUNT_AFFINE] = I(SIN_24_8(angle) * res); res = Div(0x10000, p2); - affine[8] = I((-(SIN(angle)) >> 6) * res); + affine[2 * OAM_DATA_COUNT_AFFINE] = I((-(SIN(angle)) >> 6) * res); res = Div(0x10000, p2); - affine[12] = I(COS_24_8(angle) * res); -#else - OamData *oam = &gOamBuffer[affineIndex * 4]; - s16 res; - - res = Div(0x10000, p1); - oam->all.affineParam = I(COS_24_8(angle) * res); - oam++; - - res = Div(0x10000, p1); - oam->all.affineParam = I(SIN_24_8(angle) * res); - oam++; - - res = Div(0x10000, p2); - oam->all.affineParam = I((-(SIN(angle)) >> 6) * res); - oam++; - - res = Div(0x10000, p2); - oam->all.affineParam = I(COS_24_8(angle) * res); -#endif + affine[3 * OAM_DATA_COUNT_AFFINE] = I(COS_24_8(angle) * res); } // Similar to sub_8004ABC and sub_8004E14 @@ -317,70 +297,37 @@ NONMATCH("asm/non_matching/engine/TransformSprite.inc", void TransformSprite(Spr if (dimensions != (SpriteOffset *)-1) { s16 res; s16 x16, y16; + s16 *affine; big.affineIndex = s->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE; - { -#if !EXTENDED_OAM - s16 *affine = (void *)&gOamBuffer[big.affineIndex * 4].all.affineParam; - + affine = (void *)&gOamBuffer[big.affineIndex * 4].all.affineParam; #if 0 sub_80047A0(transform->rotation & ONE_CYCLE, transform->qScaleX, transform->qScaleY, big.affineIndex); #else - big.qDirX = COS_24_8(transform->rotation & ONE_CYCLE); - big.qDirY = SIN_24_8(transform->rotation & ONE_CYCLE); + big.qDirX = COS_24_8(transform->rotation & ONE_CYCLE); + big.qDirY = SIN_24_8(transform->rotation & ONE_CYCLE); - big.unkC[0] = transform->qScaleX; - big.unkC[1] = transform->qScaleY; - // __set_UnkC + big.unkC[0] = transform->qScaleX; + big.unkC[1] = transform->qScaleY; + // __set_UnkC - res = Div(0x10000, big.unkC[0]); - x16 = big.qDirX; - affine[0] = (x16 * res) >> 8; + res = Div(0x10000, big.unkC[0]); + x16 = big.qDirX; + affine[0 * OAM_DATA_COUNT_AFFINE] = (x16 * res) >> 8; - res = Div(0x10000, big.unkC[0]); - y16 = big.qDirY; - affine[4] = (y16 * res) >> 8; + res = Div(0x10000, big.unkC[0]); + y16 = big.qDirY; + affine[1 * OAM_DATA_COUNT_AFFINE] = (y16 * res) >> 8; - res = Div(0x10000, big.unkC[1]); - y16 = big.qDirY; - affine[8] = (-y16 * res) >> 8; + res = Div(0x10000, big.unkC[1]); + y16 = big.qDirY; + affine[2 * OAM_DATA_COUNT_AFFINE] = (-y16 * res) >> 8; - res = Div(0x10000, big.unkC[1]); - x16 = big.qDirX; - affine[12] = (x16 * res) >> 8; -#endif -#else // EXTENDED_OAM - OamData *oam = &gOamBuffer[big.affineIndex * 4]; - - big.qDirX = COS_24_8(transform->rotation & ONE_CYCLE); - big.qDirY = SIN_24_8(transform->rotation & ONE_CYCLE); - - big.unkC[0] = transform->qScaleX; - big.unkC[1] = transform->qScaleY; - // __set_UnkC - - res = Div(0x10000, big.unkC[0]); - x16 = big.qDirX; - oam->all.affineParam = (x16 * res) >> 8; - oam++; - - res = Div(0x10000, big.unkC[0]); - y16 = big.qDirY; - oam->all.affineParam = (y16 * res) >> 8; - oam++; - - res = Div(0x10000, big.unkC[1]); - y16 = big.qDirY; - oam->all.affineParam = (-y16 * res) >> 8; - oam++; - - res = Div(0x10000, big.unkC[1]); - x16 = big.qDirX; - oam->all.affineParam = (x16 * res) >> 8; - oam++; + res = Div(0x10000, big.unkC[1]); + x16 = big.qDirX; + affine[3 * OAM_DATA_COUNT_AFFINE] = (x16 * res) >> 8; #endif - } // __post_Divs @@ -471,7 +418,6 @@ NONMATCH("asm/non_matching/engine/sub_8004E14.inc", void sub_8004E14(Sprite *spr UnkSpriteStruct us; if (sprite->dimensions != (void *)-1) { const SpriteOffset *sprDims = sprite->dimensions; -#if !EXTENDED_OAM u16 *affine; us.affineIndex = sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE; @@ -482,32 +428,10 @@ NONMATCH("asm/non_matching/engine/sub_8004E14.inc", void sub_8004E14(Sprite *spr us.unkC[0] = I(transform->qScaleX * gUnknown_030017F0); us.unkC[1] = I(transform->qScaleY * gUnknown_03005394); - affine[0] = I(Div(Q(256), us.unkC[0]) * us.qDirX); - affine[4] = I(Div(Q(256), us.unkC[0]) * us.qDirY); - affine[8] = I(Div(Q(256), us.unkC[1]) * -us.qDirY); - affine[12] = I(Div(Q(256), us.unkC[1]) * us.qDirX); -#else - { - OamData *oam; - - us.affineIndex = sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE; - oam = &gOamBuffer[us.affineIndex * 4]; - - us.qDirX = COS_24_8((transform->rotation + gUnknown_03001944) & ONE_CYCLE); - us.qDirY = SIN_24_8((transform->rotation + gUnknown_03001944) & ONE_CYCLE); - us.unkC[0] = I(transform->qScaleX * gUnknown_030017F0); - us.unkC[1] = I(transform->qScaleY * gUnknown_03005394); - - oam->all.affineParam = I(Div(Q(256), us.unkC[0]) * us.qDirX); - oam++; - oam->all.affineParam = I(Div(Q(256), us.unkC[0]) * us.qDirY); - oam++; - oam->all.affineParam = I(Div(Q(256), us.unkC[1]) * -us.qDirY); - oam++; - oam->all.affineParam = I(Div(Q(256), us.unkC[1]) * us.qDirX); - oam++; - } -#endif + affine[0 * OAM_DATA_COUNT_AFFINE] = I(Div(Q(256), us.unkC[0]) * us.qDirX); + affine[1 * OAM_DATA_COUNT_AFFINE] = I(Div(Q(256), us.unkC[0]) * us.qDirY); + affine[2 * OAM_DATA_COUNT_AFFINE] = I(Div(Q(256), us.unkC[1]) * -us.qDirY); + affine[3 * OAM_DATA_COUNT_AFFINE] = I(Div(Q(256), us.unkC[1]) * us.qDirX); if (transform->qScaleX < 0) { us.unkC[0] = I(-transform->qScaleX * gUnknown_030017F0); From deed5ad7e77046eb80a03e4fffdad403171e3b54 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 31 Aug 2025 22:10:57 +0100 Subject: [PATCH 18/19] clean up --- src/core.c | 13 ++----- src/sprite.c | 104 +++++++++++++++++++++------------------------------ 2 files changed, 46 insertions(+), 71 deletions(-) diff --git a/src/core.c b/src/core.c index 979bc2ce30..b576d71f63 100644 --- a/src/core.c +++ b/src/core.c @@ -573,15 +573,10 @@ static void ClearOamBufferDma(void) #endif } gFlags &= ~FLAGS_EXECUTE_HBLANK_COPY; -#if !EXTENDED_OAM - DmaFill16(3, 0x200, gOamBuffer + 0x00, 0x100); - DmaFill16(3, 0x200, gOamBuffer + 0x20, 0x100); - DmaFill16(3, 0x200, gOamBuffer + 0x40, 0x100); - DmaFill16(3, 0x200, gOamBuffer + 0x60, 0x100); -#else - DmaFill16(3, 0x200, gOamBuffer, OAM_SIZE); -#endif - + DmaFill16(3, 0x200, gOamBuffer + (OAM_ENTRY_COUNT / 4) * 0, OAM_SIZE / 4); + DmaFill16(3, 0x200, gOamBuffer + (OAM_ENTRY_COUNT / 4) * 1, OAM_SIZE / 4); + DmaFill16(3, 0x200, gOamBuffer + (OAM_ENTRY_COUNT / 4) * 2, OAM_SIZE / 4); + DmaFill16(3, 0x200, gOamBuffer + (OAM_ENTRY_COUNT / 4) * 3, OAM_SIZE / 4); gNumVBlankCallbacks = 0; gFlags &= ~FLAGS_10; } diff --git a/src/sprite.c b/src/sprite.c index af45689734..6e11f9170f 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -587,16 +587,20 @@ void DisplaySprite(Sprite *sprite) sprite->oamBaseIndex = gOamFreeIndex - 1; } -#if !EXTENDED_OAM // oamIndex is a byte, why are they ANDing with 0x3FFF? DmaCopy16(3, &oamData[((sprDims->oamIndex & 0x3FFF) + i) * OAM_DATA_COUNT_NO_AFFINE], oam, sizeof(OamDataShort)); - +#if !EXTENDED_OAM sprX = oam->all.attr1 & 0x1FF; sprY = oam->all.attr0 & 0xFF; oam->all.attr1 &= 0xFE00; oam->all.attr0 &= 0xFE00; - oam->all.attr2 += sprite->palId << 12; +#else + sprX = oam->split.x; + sprY = oam->split.y; + oam->split.affineMode &= ~ST_OAM_AFFINE_ON_MASK; + oam->split.paletteNum += sprite->palId; +#endif #if !PLATFORM_GBA && !PLATFORM_SDL // TEMP @@ -605,40 +609,68 @@ void DisplaySprite(Sprite *sprite) Platform_DisplaySprite(sprite, oam->split.paletteNum); return; #endif - if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_ENABLE) { +#if !EXTENDED_OAM oam->all.attr0 |= 0x100; +#else + oam->split.affineMode |= ST_OAM_AFFINE_NORMAL; +#endif if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_DOUBLE_SIZE) { +#if !EXTENDED_OAM oam->all.attr0 |= 0x200; +#else + oam->split.affineMode |= ST_OAM_AFFINE_DOUBLE; +#endif } +#if !EXTENDED_OAM oam->all.attr1 |= (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE) << 9; +#else + oam->split.matrixNum = (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE); +#endif } else { - u32 shapeAndSize = ((oam->all.attr0 & 0xC000) >> 12); - u32 flipY; - u32 r6; - + u32 flipY, r6, shapeAndSize; +#if !EXTENDED_OAM + shapeAndSize = ((oam->all.attr0 & 0xC000) >> 12); shapeAndSize |= ((oam->all.attr1 & 0xC000) >> 14); flipY = sprite->frameFlags >> SPRITE_FLAG_SHIFT_Y_FLIP; +#else + shapeAndSize = oam->split.shape << 2; + shapeAndSize |= oam->split.size; + flipY = sprite->frameFlags >> SPRITE_FLAG_SHIFT_Y_FLIP; +#endif r6 = 1; // y-flip if ((((sprDims->flip >> 1) ^ flipY) & r6) != 0) { +#if !EXTENDED_OAM oam->all.attr1 ^= 0x2000; +#else + oam->split.matrixNum ^= (1 << 4); +#endif sprY = sprHeight - gOamShapesSizes[shapeAndSize][1] - sprY; } // x-flip if (((sprite->frameFlags >> SPRITE_FLAG_SHIFT_X_FLIP) & r6) != (sprDims->flip & 1)) { +#if !EXTENDED_OAM oam->all.attr1 ^= 0x1000; +#else + oam->split.matrixNum ^= (1 << 3); +#endif sprX = sprWidth - gOamShapesSizes[shapeAndSize][0] - sprX; } } if (mosaicHVSizes != 0 && (sprite->frameFlags & SPRITE_FLAG_MASK_MOSAIC) != 0) { +#if !EXTENDED_OAM // Enable mosaic bit oam->all.attr0 |= 0x1000; +#else + oam->split.mosaic = 1; +#endif } +#if !EXTENDED_OAM oam->all.attr0 |= (sprite->frameFlags & SPRITE_FLAG_MASK_OBJ_MODE) * 8; oam->all.attr2 |= (sprite->frameFlags & SPRITE_FLAG_MASK_PRIORITY) >> 2; oam->all.attr0 += ((y + sprY) & 0xFF); @@ -648,59 +680,7 @@ void DisplaySprite(Sprite *sprite) oam->all.attr2 += oam->all.attr2 & 0x3FF; } oam->all.attr2 += GET_TILE_NUM(sprite->graphics.dest); -#else /* EXTENDED_OAM */ - // oamIndex is a byte, why are they ANDing with 0x3FFF? - s32 sub_index = ((sprDims->oamIndex & 0x3FFF) + i); - s32 full_index = sub_index * OAM_DATA_COUNT_NO_AFFINE; - DmaCopy16(3, &oamData[full_index], oam, sizeof(OamDataShort)); - - sprX = oam->split.x; - sprY = oam->split.y; - - oam->split.affineMode &= ~ST_OAM_AFFINE_ON_MASK; - oam->split.paletteNum += sprite->palId; - -#if !PLATFORM_GBA && !PLATFORM_SDL - // TEMP - // Quick hack for getting output in OpenGL test - // The whole function call should be replaced by this! - Platform_DisplaySprite(sprite, oam->split.paletteNum); - return; -#endif - - if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_ENABLE) { - oam->split.affineMode |= ST_OAM_AFFINE_ON_MASK; - if (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE_DOUBLE_SIZE) { - oam->split.affineMode |= ST_OAM_AFFINE_DOUBLE_MASK; - } - oam->split.matrixNum = (sprite->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE); - } else { - u32 shapeAndSize = oam->split.shape << 2; - u32 flipY; - u32 r6; - - shapeAndSize |= oam->split.size; - flipY = sprite->frameFlags >> SPRITE_FLAG_SHIFT_Y_FLIP; - r6 = 1; - - // y-flip - if ((((sprDims->flip >> 1) ^ flipY) & r6) != 0) { - oam->split.matrixNum ^= (1 << 4); - sprY = sprHeight - gOamShapesSizes[shapeAndSize][1] - sprY; - } - - // x-flip - if (((sprite->frameFlags >> SPRITE_FLAG_SHIFT_X_FLIP) & r6) != (sprDims->flip & 1)) { - oam->split.matrixNum ^= (1 << 3); - sprX = sprWidth - gOamShapesSizes[shapeAndSize][0] - sprX; - } - } - - if (mosaicHVSizes != 0 && (sprite->frameFlags & SPRITE_FLAG_MASK_MOSAIC) != 0) { - // Enable mosaic bit - oam->split.mosaic = 1; - } - +#else oam->split.objMode = (sprite->frameFlags & SPRITE_FLAG_MASK_OBJ_MODE) >> SPRITE_FLAG_SHIFT_OBJ_MODE; oam->split.priority = (sprite->frameFlags & SPRITE_FLAG_MASK_PRIORITY) >> SPRITE_FLAG_SHIFT_PRIORITY; oam->split.x = x + sprX; @@ -719,7 +699,7 @@ void DisplaySprite(Sprite *sprite) // TODO: Make this compatible with EXTENDED_OAM, maybe? // It's unused though, anyway. // Technically this could just be a loop that calls DisplaySprite()... -void DisplaySprites(Sprite *sprite, Vec2_16 *positions, u8 numPositions) +UNUSED void DisplaySprites(Sprite *sprite, Vec2_16 *positions, u8 numPositions) { vs32 x, y; s32 sprWidth, sprHeight; From 2335bbb172dd988e516a455da2fe32b69c4a720b Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Mon, 1 Sep 2025 00:23:24 +0100 Subject: [PATCH 19/19] fix UI issues --- src/game/stage/ui.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/game/stage/ui.c b/src/game/stage/ui.c index b590c0bdd8..eac9d749be 100644 --- a/src/game/stage/ui.c +++ b/src/game/stage/ui.c @@ -20,6 +20,13 @@ #define UI_POS_RING_COUNT_X 32 #define UI_POS_RING_COUNT_Y 16 +#if !EXTENDED_OAM +#define RINGS_CONTAINER_X ((u32)-3) & 0x1FF +#else +#define RINGS_CONTAINER_X -3 +#endif +#define RINGS_CONTAINER_Y 0 + struct Task *gStageUITask = NULL; const u16 sAnimsAsciiDigits[12][2] = { @@ -125,7 +132,7 @@ struct Task *CreateStageUI(void) s->graphics.dest = ui->digits[0].graphics.dest + (i * (2 * TILE_SIZE_4BPP)); } - ui->digitsTileData[i] = (GET_TILE_NUM(s->graphics.dest) & ONE_CYCLE) | 0x6000; + ui->digitsTileData[i] = (GET_TILE_NUM(s->graphics.dest) & 0x3FF) | 0x6000; s->oamFlags = SPRITE_OAM_ORDER(0); s->graphics.size = 0; @@ -221,14 +228,14 @@ struct Task *CreateStageUI(void) } #if !EXTENDED_OAM -#define UI_OAM_INIT(_oam, _x, _y, _shape, _size, _tileNumPlus) \ +#define UI_OAM_SET(_oam, _x, _y, _shape, _size, _tileNumPlus) \ { \ (_oam)->all.attr0 = ((_shape) << 14) | ((_y)); \ (_oam)->all.attr1 = ((_size) << 14) | ((_x)); \ (_oam)->all.attr2 = (_tileNumPlus); \ } #else -#define UI_OAM_INIT(_oam, _x, _y, _shape, _size, _tileNumPlus) \ +#define UI_OAM_SET(_oam, _x, _y, _shape, _size, _tileNumPlus) \ { \ (_oam)->split.x = (_x); \ (_oam)->split.y = (_y); \ @@ -236,6 +243,7 @@ struct Task *CreateStageUI(void) (_oam)->split.size = (_size); \ (_oam)->split.tileNum = ((_tileNumPlus)&0x3FF); \ (_oam)->split.paletteNum = (((_tileNumPlus)&0xF000) >> 12); \ + (_oam)->split.affineMode = 0; \ (_oam)->split.objMode = 0; \ (_oam)->split.mosaic = 0; \ (_oam)->split.bpp = 0; \ @@ -270,7 +278,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_INIT(oam, i * 8 + 4, 31, SPRITE_SHAPE(8x8), SPRITE_SIZE(8x8), ui->digitsTileData[UI_ASCII_SP_RING]); + UI_OAM_SET(oam, i * 8 + 4, 31, SPRITE_SHAPE(8x8), SPRITE_SIZE(8x8), ui->digitsTileData[UI_ASCII_SP_RING]); } } } @@ -295,7 +303,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_INIT(oam, i * 8 + 28, 14, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[digit]); + UI_OAM_SET(oam, i * 8 + 28, 14, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[digit]); } score -= digit * m; @@ -308,7 +316,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_INIT(oam, 6, DISPLAY_HEIGHT - 18, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->playerIconTileData); + UI_OAM_SET(oam, 6, DISPLAY_HEIGHT - 18, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->playerIconTileData); } if (gNumLives > 0) @@ -326,7 +334,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_INIT(oam, 30, (DISPLAY_HEIGHT - 20), SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[i]); + UI_OAM_SET(oam, 30, (DISPLAY_HEIGHT - 20), SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[i]); } } @@ -337,11 +345,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { -#if !EXTENDED_OAM - UI_OAM_INIT(oam, ((u32)-3 & 0x1FF), 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ui->ringContainerTileData); -#else - UI_OAM_INIT(oam, -3, 0, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ui->ringContainerTileData); -#endif + UI_OAM_SET(oam, RINGS_CONTAINER_X, RINGS_CONTAINER_Y, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ui->ringContainerTileData); } /* Ring */ @@ -357,7 +361,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_INIT(oam, 7, 8, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->ringTileData); + UI_OAM_SET(oam, 7, 8, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->ringTileData); } if (gRingCount > 999) { @@ -387,7 +391,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_INIT(oam, 28 + 0 * 8, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[hundreds] | palId)); + UI_OAM_SET(oam, 28 + 0 * 8, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[hundreds] | palId)); } processed = hundreds * 100; } @@ -401,7 +405,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_INIT(oam, (28 + 1 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[tens] | palId)); + UI_OAM_SET(oam, (28 + 1 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[tens] | palId)); } processed2 = processed + tens * 10; @@ -416,7 +420,7 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_INIT(oam, (28 + 2 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[ones] | palId)); + UI_OAM_SET(oam, (28 + 2 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[ones] | palId)); } } } @@ -437,8 +441,8 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_INIT(oam, (DISPLAY_WIDTH / 2) - 21, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), - (ui->digitsTileData[UI_ASCII_COLON] | palId)); + UI_OAM_SET(oam, (DISPLAY_WIDTH / 2) - 21, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), + (ui->digitsTileData[UI_ASCII_COLON] | palId)); } oam = OamMalloc(3); @@ -447,8 +451,8 @@ void Task_StageUIMain(void) if (oam != (OamData *)iwram_end) #endif { - UI_OAM_INIT(oam, (DISPLAY_WIDTH / 2) + 3, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), - (ui->digitsTileData[UI_ASCII_COLON] | palId)); + UI_OAM_SET(oam, (DISPLAY_WIDTH / 2) + 3, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), + (ui->digitsTileData[UI_ASCII_COLON] | palId)); } seconds = Div(time, GBA_FRAMES_PER_SECOND);