Re-implement Pause menu Dungeon map texture effects (#3496)

* first pass implement dungeon maps

* wrap up map dungeon implementation

* add comments and enums, rename vars

* bump lus
This commit is contained in:
Adam Bird 2023-12-17 15:42:34 -05:00 committed by GitHub
parent e6fc34e4c2
commit f655ab592d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 138 additions and 12 deletions

View File

@ -343,7 +343,7 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
// Offset the U value of each vertex to be in the mirror boundary for the map textures
if (mirroredWorld) {
for (size_t i = 0; i < 8; i++) {
pauseCtx->mapPageVtx[60 + i].v.tc[0] += 48 << 5;
pauseCtx->mapPageVtx[60 + i].v.tc[0] += MAP_48x85_TEX_WIDTH << 5;
}
}
@ -353,8 +353,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[0]);
gSPInvalidateTexCache(POLY_KAL_DISP++, interfaceCtx->mapSegment[1]);
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_CI, 48, 85, 0, G_TX_WRAP | mirrorMode,
G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_CI, MAP_48x85_TEX_WIDTH,
MAP_48x85_TEX_HEIGHT, 0, G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK,
G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
// Swap vertices to render left half on the right and vice-versa
if (mirroredWorld) {
@ -363,9 +364,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);
}
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[1], G_IM_FMT_CI, 48, 85, 0,
G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
gDPLoadTextureBlock_4b(POLY_KAL_DISP++, interfaceCtx->mapSegmentName[1], G_IM_FMT_CI, MAP_48x85_TEX_WIDTH,
MAP_48x85_TEX_HEIGHT, 0, G_TX_WRAP | mirrorMode, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK,
G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD);
if (mirroredWorld) {
gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0);

View File

@ -13,6 +13,10 @@ extern u8 gItemAgeReqs[];
extern u8 gAreaGsFlags[];
extern bool gSelectingMask;
#define MAP_48x85_TEX_WIDTH 48
#define MAP_48x85_TEX_HEIGHT 85
#define MAP_48x85_TEX_SIZE ((MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT) / 2) // 48x85 CI4 texture
#define AGE_REQ_ADULT LINK_AGE_ADULT
#define AGE_REQ_CHILD LINK_AGE_CHILD
#define AGE_REQ_NONE 9

View File

@ -1205,6 +1205,8 @@ Gfx* KaleidoScope_DrawPageSections(Gfx* gfx, Vtx* vertices, void** textures) {
return gfx;
}
static uint8_t mapBlendMask[MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT];
void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) {
static Color_RGB8 D_8082ACF4[12] = {
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 255, 255, 0 }, { 0, 0, 0 },
@ -1373,6 +1375,10 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) {
}
}
// Need to invalidate the blend mask every frame. Ideally this would be done in KaleidoScope_DrawDungeonMap
// but the reference is not shared between files
gSPInvalidateTexCache(POLY_KAL_DISP++, mapBlendMask);
if (pauseCtx->pageIndex) { // pageIndex != PAUSE_ITEM
gDPPipeSync(OVERLAY_DISP++);
gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA, G_CC_MODULATEIA);
@ -3315,13 +3321,118 @@ void KaleidoScope_UpdateCursorSize(PauseContext* pauseCtx) {
pauseCtx->cursorVtx[14].v.ob[1] = pauseCtx->cursorVtx[15].v.ob[1] = pauseCtx->cursorVtx[12].v.ob[1] - 16;
}
// Modifed map texture buffers for registered blend effects and the room indicator color
static uint8_t mapLeftTexModified[MAP_48x85_TEX_SIZE];
static uint8_t mapRightTexModified[MAP_48x85_TEX_SIZE];
static uint8_t* mapLeftTexModifiedRaw = NULL;
static uint8_t* mapRightTexModifiedRaw = NULL;
// Load dungeon maps into the interface context
// SoH [General] - Modified to account for our resource system and HD textures
void KaleidoScope_LoadDungeonMap(PlayState* play) {
InterfaceContext* interfaceCtx = &play->interfaceCtx;
// Free old textures
if (mapLeftTexModifiedRaw != NULL) {
free(mapLeftTexModifiedRaw);
mapLeftTexModifiedRaw = NULL;
}
if (mapRightTexModifiedRaw != NULL) {
free(mapRightTexModifiedRaw);
mapRightTexModifiedRaw = NULL;
}
// Unload original textures to bypass cache result for lookups
ResourceMgr_UnloadOriginalWhenAltExists(sDungeonMapTexs[R_MAP_TEX_INDEX]);
ResourceMgr_UnloadOriginalWhenAltExists(sDungeonMapTexs[R_MAP_TEX_INDEX + 1]);
interfaceCtx->mapSegmentName[0] = sDungeonMapTexs[R_MAP_TEX_INDEX];
interfaceCtx->mapSegmentName[1] = sDungeonMapTexs[R_MAP_TEX_INDEX + 1];
interfaceCtx->mapSegment[0] = ResourceGetDataByName(sDungeonMapTexs[R_MAP_TEX_INDEX]);
interfaceCtx->mapSegment[1] = ResourceGetDataByName(sDungeonMapTexs[R_MAP_TEX_INDEX + 1]);
// When the texture is HD (raw) we need to copy a dynamic amount of data
// Otherwise the original asset has a static size
if (ResourceMgr_TexIsRaw(interfaceCtx->mapSegmentName[0])) {
u32 width = ResourceGetTexWidthByName(interfaceCtx->mapSegmentName[0]);
u32 height = ResourceGetTexHeightByName(interfaceCtx->mapSegmentName[0]);
size_t size = (width * height) / 2; // account for CI4 size
// Resource size being larger than the calculated CI size means it is most likely not a CI4 texture
// Abort early end undo the blended effect by clearing the mask to avoid crashing
if (size < ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0])) {
if (mapBlendMask[0] != 0) {
for (size_t i = 0; i < ARRAY_COUNT(mapBlendMask); i++) {
mapBlendMask[i] = 0;
}
}
interfaceCtx->mapSegment[0] = NULL;
interfaceCtx->mapSegment[1] = NULL;
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[0], mapBlendMask, NULL);
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[1], mapBlendMask, NULL);
return;
}
u8* map1TexRaw = ResourceGetDataByName(interfaceCtx->mapSegmentName[0]);
u8* map2TexRaw = ResourceGetDataByName(interfaceCtx->mapSegmentName[1]);
mapLeftTexModifiedRaw = malloc(size);
mapRightTexModifiedRaw = malloc(size);
memcpy(mapLeftTexModifiedRaw, map1TexRaw, size);
memcpy(mapRightTexModifiedRaw, map2TexRaw, size);
interfaceCtx->mapSegment[0] = mapLeftTexModifiedRaw;
interfaceCtx->mapSegment[1] = mapRightTexModifiedRaw;
} else {
u8* map1Tex = ResourceGetDataByName(interfaceCtx->mapSegmentName[0]);
u8* map2Tex = ResourceGetDataByName(interfaceCtx->mapSegmentName[1]);
memcpy(mapLeftTexModified, map1Tex, MAP_48x85_TEX_SIZE);
memcpy(mapRightTexModified, map2Tex, MAP_48x85_TEX_SIZE);
interfaceCtx->mapSegment[0] = mapLeftTexModified;
interfaceCtx->mapSegment[1] = mapRightTexModified;
}
// Mark and register the blend mask for the copied textures
if (mapBlendMask[0] != 1) {
for (size_t i = 0; i < ARRAY_COUNT(mapBlendMask); i++) {
mapBlendMask[i] = 1;
}
}
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[0], mapBlendMask, interfaceCtx->mapSegment[0]);
Gfx_RegisterBlendedTexture(interfaceCtx->mapSegmentName[1], mapBlendMask, interfaceCtx->mapSegment[1]);
}
static uint8_t registeredDungeonMapTextureHook = false;
void KaleidoScope_RegisterUpdatedDungeonMapTexture() {
if (gPlayState == NULL) {
return;
}
PauseContext* pauseCtx = &gPlayState->pauseCtx;
// Kaleido is not open in a dungeon so there is nothing to do
if (R_PAUSE_MENU_MODE < 3 || pauseCtx->state < 4 || pauseCtx->state > 7 || !sInDungeonScene) {
return;
}
KaleidoScope_UpdateDungeonMap(gPlayState);
// KaleidoScope_UpdateDungeonMap will update the palette index for the current floor if the cursor is on the floor
// If the player toggles alt assets while the cursor is not in the floor level, then we handle the palette index here
if (gPlayState->sceneNum >= SCENE_DEKU_TREE && gPlayState->sceneNum <= SCENE_TREASURE_BOX_SHOP &&
(VREG(30) + 3) == pauseCtx->dungeonMapSlot && (VREG(30) + 3) != pauseCtx->cursorPoint[PAUSE_MAP]) {
InterfaceContext* interfaceCtx = &gPlayState->interfaceCtx;
int32_t size = ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0]);
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], size, interfaceCtx->mapPaletteIndex, 14);
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], size, interfaceCtx->mapPaletteIndex, 14);
}
}
void KaleidoScope_UpdateDungeonMap(PlayState* play) {
@ -3333,19 +3444,29 @@ void KaleidoScope_UpdateDungeonMap(PlayState* play) {
KaleidoScope_LoadDungeonMap(play);
Map_SetFloorPalettesData(play, pauseCtx->dungeonMapSlot - 3);
s32 size = MAP_48x85_TEX_SIZE;
if (ResourceMgr_TexIsRaw(interfaceCtx->mapSegmentName[0])) {
size = ResourceGetTexSizeByName(interfaceCtx->mapSegmentName[0]);
}
if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) {
if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) {
// HDTODO: Handle Runtime Modified Textures (HD)
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], 2040, interfaceCtx->mapPaletteIndex, 14);
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[0], size, interfaceCtx->mapPaletteIndex, 14);
}
}
if ((play->sceneNum >= SCENE_DEKU_TREE) && (play->sceneNum <= SCENE_TREASURE_BOX_SHOP)) {
if ((VREG(30) + 3) == pauseCtx->cursorPoint[PAUSE_MAP]) {
// HDTODO: Handle Runtime Modified Textures (HD)
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], 2040, interfaceCtx->mapPaletteIndex, 14);
KaleidoScope_OverridePalIndexCI4(interfaceCtx->mapSegment[1], size, interfaceCtx->mapPaletteIndex, 14);
}
}
// Register alt listener to update the blended dungeon map textures on alt toggle
if (!registeredDungeonMapTextureHook) {
registeredDungeonMapTextureHook = true;
GameInteractor_RegisterOnAssetAltChange(KaleidoScope_RegisterUpdatedDungeonMapTexture);
}
}
void KaleidoScope_Update(PlayState* play)