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/defines.h b/include/gba/defines.h index 1857a1e7d2..1e15e191f5 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -42,9 +42,26 @@ #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 TRUE +#else +#define WIDESCREEN_HACK FALSE +#define EXTENDED_OAM !TRUE +#endif +extern uint8_t VRAM[VRAM_SIZE]; + +#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); @@ -56,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 f5a19dc696..dbc5a752d0 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -95,18 +95,17 @@ 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 #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 +117,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 +149,58 @@ 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 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, { + /* 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 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 + + /* 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!) */ + typedef union { struct { /* 0x00 */ s16 x; @@ -183,9 +212,9 @@ typedef union { 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 + /* 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 /* 0x08 */ u16 tileNum:10; // 0x3FF u16 priority:2; // 0x400, 0x800 -> 0xC00 @@ -205,8 +234,30 @@ 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 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 #define ST_OAM_HFLIP 0x08 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/core.c b/src/core.c index e669f44f63..b576d71f63 100644 --- a/src/core.c +++ b/src/core.c @@ -490,10 +490,14 @@ static void UpdateScreenDma(void) if (sLastCalledVblankFuncId == VBLANK_FUNC_ID_NONE) { CopyOamBufferToOam(); - 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); + 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++) { @@ -569,11 +573,10 @@ static void ClearOamBufferDma(void) #endif } gFlags &= ~FLAGS_EXECUTE_HBLANK_COPY; - DmaFill16(3, 0x200, gOamBuffer + 0x00, 0x100); - DmaFill16(3, 0x200, gOamBuffer + 0x20, 0x100); - DmaFill16(3, 0x200, gOamBuffer + 0x40, 0x100); - DmaFill16(3, 0x200, gOamBuffer + 0x60, 0x100); - + 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/game/interactables_1/platform_crumbling.c b/src/game/interactables_1/platform_crumbling.c index 947e64dd54..f2af272af4 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_COUNT_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 } } } @@ -280,17 +284,17 @@ 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++) { 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/collectables.c b/src/game/special_stage/collectables.c index e85b53313f..19aaf95a0a 100644 --- a/src/game/special_stage/collectables.c +++ b/src/game/special_stage/collectables.c @@ -424,11 +424,11 @@ void sub_806E1AC(s16 index, struct UNK_806DEA4 *unkDEA4) sub_806CD68(element1); affine = &gOamBuffer[index * 4].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; } @@ -546,11 +546,11 @@ void sub_806E584(s16 index, struct SpecialStageCollectables_UNK874 *unk874) affine = &gOamBuffer[(index + 16) * 4].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/main.c b/src/game/special_stage/main.c index 02518df536..ac7530661c 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,14 @@ void Task_InitComponents(void) void Task_SpecialStageStartDelay(void) { struct SpecialStage *stage = TASK_DATA(gCurTask); +#ifndef BUG_FIX SpecialStagePauseMenuMain(); +#else + // BUG: Without this, we would access free'd task memory. + bool32 taskDestroyed = SpecialStagePauseMenuMain(); + if (taskDestroyed) + return; +#endif if (!stage->paused) { TickStageTimer(); @@ -233,13 +252,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 +270,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 taskDestroyed = SpecialStagePauseMenuMain(); + if (taskDestroyed) + return; +#endif + } break; } if (stage->paused == FALSE) { @@ -649,7 +679,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 +702,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 +727,8 @@ void SpecialStagePauseMenuMain(void) stage->paused = !stage->paused ? TRUE : FALSE; stage->pauseMenuCursor = 0; } + + BUG_FIX_RETURN(FALSE); } static void SpecialStageOnDestroy(UNUSED struct Task *t) 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 1282c7ec0c..0af7d8c508 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,27 @@ void sub_806CD68(Sprite *s) s->oamBaseIndex = gOamFreeIndex - 1; } - DmaCopy16(3, &reference[(sprDims->oamIndex + i) * 3], oam, sizeof(u16) * 3); - attr1_2 = oam->all.attr1 & 0x1FF; - oam->all.attr0 = (unk18 + (oam->all.attr0 & 0xff)) & 0xff; - oam->all.attr0 |= 0x300; + 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 |= (ST_OAM_AFFINE_DOUBLE << 8); 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.affineMode = ST_OAM_AFFINE_DOUBLE; + 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/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..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; @@ -220,12 +227,37 @@ struct Task *CreateStageUI(void) return gStageUITask; } +#if !EXTENDED_OAM +#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_SET(_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.affineMode = 0; \ + (_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 +278,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_SET(oam, i * 8 + 4, 31, SPRITE_SHAPE(8x8), SPRITE_SIZE(8x8), ui->digitsTileData[UI_ASCII_SP_RING]); } } } @@ -273,9 +303,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_SET(oam, i * 8 + 28, 14, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[digit]); } score -= digit * m; @@ -288,9 +316,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_SET(oam, 6, DISPLAY_HEIGHT - 18, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->playerIconTileData); } if (gNumLives > 0) @@ -308,9 +334,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_SET(oam, 30, (DISPLAY_HEIGHT - 20), SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), ui->digitsTileData[i]); } } @@ -321,9 +345,7 @@ 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; + UI_OAM_SET(oam, RINGS_CONTAINER_X, RINGS_CONTAINER_Y, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ui->ringContainerTileData); } /* Ring */ @@ -339,9 +361,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_SET(oam, 7, 8, SPRITE_SHAPE(16x16), SPRITE_SIZE(16x16), ui->ringTileData); } if (gRingCount > 999) { @@ -360,7 +380,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 +391,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_SET(oam, 28 + 0 * 8, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[hundreds] | palId)); } processed = hundreds * 100; } @@ -387,9 +405,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_SET(oam, (28 + 1 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[tens] | palId)); } processed2 = processed + tens * 10; @@ -404,9 +420,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_SET(oam, (28 + 2 * 8), 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), (ui->digitsTileData[ones] | palId)); } } } @@ -419,7 +433,7 @@ void Task_StageUIMain(void) u32 r1, r5; u32 tempTime, tempB; - sl = 0x6000; + palId = 0x6000; oam = OamMalloc(3); @@ -427,9 +441,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_SET(oam, (DISPLAY_WIDTH / 2) - 21, 0, SPRITE_SHAPE(8x16), SPRITE_SIZE(8x16), + (ui->digitsTileData[UI_ASCII_COLON] | palId)); } oam = OamMalloc(3); @@ -438,9 +451,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_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); @@ -452,44 +464,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/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 400d96d2ea..e88e001d38 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 @@ -1359,6 +1370,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 +1404,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; @@ -1417,10 +1419,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 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) x -= 512; if (y >= DISPLAY_HEIGHT) y -= 256; +#endif if (isAffine) { // TODO: there is probably a better way to do this 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 diff --git a/src/sprite.c b/src/sprite.c index 2e6170b30c..6e11f9170f 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -273,16 +273,16 @@ void sub_80047A0(u16 angle, s16 p1, s16 p2, u16 affineIndex) 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); + affine[3 * OAM_DATA_COUNT_AFFINE] = I(COS_24_8(angle) * res); } // Similar to sub_8004ABC and sub_8004E14 @@ -299,10 +299,10 @@ NONMATCH("asm/non_matching/engine/TransformSprite.inc", void TransformSprite(Spr s16 x16, y16; s16 *affine; big.affineIndex = s->frameFlags & SPRITE_FLAG_MASK_ROT_SCALE; - 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, + sub_80047A0(transform->rotation & ONE_CYCLE, transform->qScaleX, transform->qScaleY, big.affineIndex); #else big.qDirX = COS_24_8(transform->rotation & ONE_CYCLE); @@ -314,20 +314,21 @@ NONMATCH("asm/non_matching/engine/TransformSprite.inc", void TransformSprite(Spr res = Div(0x10000, big.unkC[0]); x16 = big.qDirX; - affine[0] = (x16 * res) >> 8; + affine[0 * OAM_DATA_COUNT_AFFINE] = (x16 * res) >> 8; res = Div(0x10000, big.unkC[0]); y16 = big.qDirY; - affine[4] = (y16 * res) >> 8; + affine[1 * OAM_DATA_COUNT_AFFINE] = (y16 * res) >> 8; res = Div(0x10000, big.unkC[1]); y16 = big.qDirY; - affine[8] = (-y16 * res) >> 8; + affine[2 * OAM_DATA_COUNT_AFFINE] = (-y16 * res) >> 8; res = Div(0x10000, big.unkC[1]); x16 = big.qDirX; - affine[12] = (x16 * res) >> 8; + affine[3 * OAM_DATA_COUNT_AFFINE] = (x16 * res) >> 8; #endif + // __post_Divs if (transform->qScaleX < 0) @@ -420,17 +421,17 @@ NONMATCH("asm/non_matching/engine/sub_8004E14.inc", void sub_8004E14(Sprite *spr 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); 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); + 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); @@ -530,7 +531,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) { @@ -587,13 +588,19 @@ void DisplaySprite(Sprite *sprite) } // 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[((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 @@ -602,55 +609,97 @@ 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; - r5 = sprHeight - gOamShapesSizes[shapeAndSize][1] - r5; +#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; - r7 = sprWidth - gOamShapesSizes[shapeAndSize][0] - r7; +#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 + 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 + 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; + } + oam->split.tileNum += GET_TILE_NUM(sprite->graphics.dest); +#endif } } } } -void DisplaySprites(Sprite *sprite, Vec2_16 *positions, u8 numPositions) +// TODO: Make this compatible with EXTENDED_OAM, maybe? +// It's unused though, anyway. +// Technically this could just be a loop that calls DisplaySprite()... +UNUSED void DisplaySprites(Sprite *sprite, Vec2_16 *positions, u8 numPositions) { vs32 x, y; s32 sprWidth, sprHeight; @@ -704,13 +753,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) {