diff options
| author | Garrett Cox <garrettjcox@gmail.com> | 2024-10-02 22:44:36 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-02 23:44:36 -0400 |
| commit | c474a82a94db5ad2fb97dcc55db2b491906a653f (patch) | |
| tree | 04ece7d80243de4437b536a9b6bcf3bb866a2189 /mm/src/code | |
| parent | 71c2c94ece12c664fe54f9959cce40776ba36dcd (diff) | |
Mirror Mode (#535)
* Mirror mode initial version
* Update mm/src/code/z_actor.c
Co-authored-by: Archez <Archez@users.noreply.github.com>
* mirror mode support for minimaps and dungeon pause map
* mirror mode support overworld pause map and song of soaring
* mirror mode support for various remaining things
* mirror mode support pause warp enhancement
* Add searchable menu item
---------
Co-authored-by: Archez <Archez@users.noreply.github.com>
Co-authored-by: Archez <archez39@me.com>
Diffstat (limited to 'mm/src/code')
| -rw-r--r-- | mm/src/code/z_actor.c | 4 | ||||
| -rw-r--r-- | mm/src/code/z_kankyo.c | 3 | ||||
| -rw-r--r-- | mm/src/code/z_lib.c | 4 | ||||
| -rw-r--r-- | mm/src/code/z_map_disp.c | 60 | ||||
| -rw-r--r-- | mm/src/code/z_parameter.c | 8 | ||||
| -rw-r--r-- | mm/src/code/z_play.c | 17 | ||||
| -rw-r--r-- | mm/src/code/z_view.c | 41 |
7 files changed, 136 insertions, 1 deletions
diff --git a/mm/src/code/z_actor.c b/mm/src/code/z_actor.c index 65f9c9bac..ac9add966 100644 --- a/mm/src/code/z_actor.c +++ b/mm/src/code/z_actor.c @@ -1402,6 +1402,10 @@ void func_800B6F20(PlayState* play, Input* input, f32 magnitude, s16 baseYaw) { s16 relativeYaw = baseYaw - Camera_GetInputDirYaw(GET_ACTIVE_CAM(play)); input->cur.stick_x = -Math_SinS(relativeYaw) * magnitude; + // 2S2H [Enhancement] Allow inverting the X axis with GI, primarily for mirror mode, + // otherwise link moves in the opposite direction and likely get soft locked, and + // kafei turns the wrong direction as he paths. + input->cur.stick_x *= GameInteractor_InvertControl(GI_INVERT_MOVEMENT_X); input->rel.stick_x = input->cur.stick_x; input->cur.stick_y = Math_CosS(relativeYaw) * magnitude; input->rel.stick_y = input->cur.stick_y; diff --git a/mm/src/code/z_kankyo.c b/mm/src/code/z_kankyo.c index efeb6084f..f8c6a02a0 100644 --- a/mm/src/code/z_kankyo.c +++ b/mm/src/code/z_kankyo.c @@ -3326,6 +3326,9 @@ void Environment_DrawSkyboxStarsImpl(PlayState* play, Gfx** gfxP) { if ((scale >= 1.0f) && (imgX > -adjustedXBounds) && (imgX < adjustedXBounds) && (imgY > -1.0f) && (imgY < 1.0f)) { + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + imgX *= -1.0f; + } // #endregion imgX = (imgX * (SCREEN_WIDTH / 2)) + (SCREEN_WIDTH / 2); imgY = (imgY * -(SCREEN_HEIGHT / 2)) + (SCREEN_HEIGHT / 2); diff --git a/mm/src/code/z_lib.c b/mm/src/code/z_lib.c index b2ff2c086..5ca4d4f7a 100644 --- a/mm/src/code/z_lib.c +++ b/mm/src/code/z_lib.c @@ -1,5 +1,7 @@ #include "global.h" #include <libultraship/bridge.h> +#include "BenPort.h" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" f32 Math_CosS(s16 angle) { return coss(angle) * SHT_MINV; @@ -223,12 +225,14 @@ void Lib_GetControlStickData(f32* outMagnitude, s16* outAngle, Input* input) { f32 y = input->rel.stick_y; f32 magnitude; + x *= GameInteractor_InvertControl(GI_INVERT_MOVEMENT_X); magnitude = sqrtf(SQ(x) + SQ(y)); *outMagnitude = (60.0f < magnitude) ? 60.0f : magnitude; if (magnitude > 0.0f) { x = input->cur.stick_x; y = input->cur.stick_y; + x *= GameInteractor_InvertControl(GI_INVERT_MOVEMENT_X); *outAngle = Math_Atan2S_XY(y, -x); } else { *outAngle = 0; diff --git a/mm/src/code/z_map_disp.c b/mm/src/code/z_map_disp.c index e7a0197ae..6f2ce25fb 100644 --- a/mm/src/code/z_map_disp.c +++ b/mm/src/code/z_map_disp.c @@ -156,6 +156,31 @@ static const char* sMapGrandTextures[] = { map_grand_static_Blob_034BB0, map_grand_static_Blob_034F50, }; +static bool sMirrorWorldActive = false; +static u16 sOriginalMapDataRoomFlags[32] = { 0 }; + +s32 Ship_MapModifyPosMirrorMode(s32 pos, s32 offset) { + if (sMirrorWorldActive) { + pos -= offset; + pos *= -1; + pos += offset; + } + return pos; +} + +void Ship_MapDispUpdateMirrorMode() { + sMirrorWorldActive = CVarGetInteger("gModes.MirroredWorld.State", 0); + + for (s32 i = 0; i < sSceneNumRooms; i++) { + sMapDataRooms[i].flags = sOriginalMapDataRoomFlags[i]; + + if (sMirrorWorldActive) { + // Toggle the bit in case the scene already has this flag set, this way the map is still "flipped" visually + sMapDataRooms[i].flags ^= MAP_DATA_ROOM_FLIP_X; + } + } +} + // BENTODO, can we just set dest insetead of doing a memcpy? void MapDisp_GetMapITexture(void* dst, s32 mapCompactId) { s32 mapSize = MapDisp_GetSizeOfMapITex(mapCompactId); @@ -414,6 +439,9 @@ void MapDisp_Minimap_DrawActorIcon(PlayState* play, Actor* actor) { sMapDisp.minimapCurY - sMapDisp.minimapBaseY + texOffsetY; } + posX = Ship_MapModifyPosMirrorMode(posX, sMapDisp.minimapBaseX + sMapDisp.minimapCurX - sMapDisp.minimapBaseX + + texOffsetX); + // 2S2H [Cosmetic] Widescreen support if ((posX > OTRGetRectDimensionFromLeftEdge(0)) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) { // #region 2S2H [Cosmetic] Hud Editor override actor values and use them below @@ -449,6 +477,9 @@ void MapDisp_Minimap_DrawActorIcon(PlayState* play, Actor* actor) { if (MapDisp_IsDataRotated(play)) { compassRot += 0x7FFF; } + if (sMirrorWorldActive) { + compassRot *= -1; + } Matrix_RotateYF(compassRot / 10.0f, MTXMODE_APPLY); Matrix_Scale(0.4f, 0.4f, 0.4f, MTXMODE_APPLY); // #region 2S2H [Cosmetic] Hud Editor yellow compass matrix scale on x and z @@ -586,6 +617,9 @@ void MapDisp_Minimap_DrawDoorActor(PlayState* play, Actor* actor) { texOffsetY; } + posX = Ship_MapModifyPosMirrorMode(posX, sMapDisp.minimapBaseX + sMapDisp.minimapCurX - sMapDisp.minimapBaseX + + texOffsetX); + // 2S2H [Cosmetic] Widescreen support if ((posX > OTRGetRectDimensionFromLeftEdge(0)) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) { OPEN_DISPS(play->state.gfxCtx); @@ -893,6 +927,8 @@ void MapDisp_InitMapData(PlayState* play, void* segmentAddress) { for (i = 0; i < sSceneNumRooms; i++) { sMapDataRooms[i] = *mapDataRooms++; + // 2S2H [Enhancement] Track original flags to that we can make modifications mid-scene + sOriginalMapDataRoomFlags[i] = sMapDataRooms[i].flags; } sMapDataScene.rooms = sMapDataRooms; @@ -996,6 +1032,7 @@ void MapDisp_Update(PlayState* play) { s16 targetY; if ((sMapDisp.mapDataScene != NULL) && (sSceneNumRooms != 0)) { + Ship_MapDispUpdateMirrorMode(); // #region 2S2H [Cosmetic] Hud Editor minimap base position // This value is used to determine the relative positioning for all the other elements MapDataRoom* mapDataRoom = &sMapDisp.mapDataScene->rooms[sMapDisp.curRoom]; @@ -1161,6 +1198,8 @@ void MapDisp_SwapRooms(s16 nextRoom) { (f32)prevOffsetY); } + sMapDisp.minimapPrevX = Ship_MapModifyPosMirrorMode(sMapDisp.minimapPrevX, offsetX - prevOffsetX); + sMapDisp.minimapCurX = minimapBaseX - sMapDisp.minimapPrevX; sMapDisp.minimapCurY = minimapBaseY - sMapDisp.minimapPrevY; } @@ -1243,6 +1282,9 @@ void MapDisp_Minimap_DrawRedCompassIcon(PlayState* play, s32 x, s32 z, s32 rot) (sMapDisp.minimapCurY - sMapDisp.minimapBaseY) + texOffsetY; } + posX = Ship_MapModifyPosMirrorMode(posX, sMapDisp.minimapBaseX + sMapDisp.minimapCurX - sMapDisp.minimapBaseX + + texOffsetX); + // 2S2H [Cosmetic] Widescreen support if ((posX > OTRGetRectDimensionFromLeftEdge(0)) && (posX < 0x3FF) && (posY > 0) && (posY < 0x3FF)) { // 2S2H [Cosmetic] Hud Editor red compass position @@ -1264,6 +1306,9 @@ void MapDisp_Minimap_DrawRedCompassIcon(PlayState* play, s32 x, s32 z, s32 rot) if (MapDisp_IsDataRotated(play)) { rot += 0x7FFF; } + if (sMirrorWorldActive) { + rot *= -1; + } Matrix_RotateYF(rot / 10.0f, MTXMODE_APPLY); Matrix_Scale(0.4f, 0.4f, 0.4f, MTXMODE_APPLY); // #region 2S2H [Cosmetic] Hud Editor red compass scale the matrix in x and z @@ -1642,7 +1687,10 @@ void MapDisp_DrawRooms(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32 if (mapDataRoom->flags & MAP_DATA_ROOM_FLIP_X) { offsetX = ((texWidth / 2) - offsetX) + (texWidth / 2); - s = (texWidth - 1) << 5; + // 2S2H [Port] The width originally was subtracted by 1, but this caused the flipped texture to overflow on + // the edge. There are no vanilla scenes that leverage this, so its possibly an authentic bug. + // Removing it will allow the texture to display correctly for things like Mirror Mode. + s = (texWidth - 0) << 5; dsdx = 0xFC00; } else { s = 0; @@ -1665,6 +1713,8 @@ void MapDisp_DrawRooms(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s32 texPosY = ((mapDataRoom->centerZ - (f32)sMapDisp.sceneMidZ) * scaleFrac - offsetY) + ((viewHeight / two) + viewY); + texPosX = Ship_MapModifyPosMirrorMode(texPosX, -offsetX + ((viewWidth / two) + viewX)); + if (i == play->roomCtx.curRoom.num) { if (Map_IsInBossScene(play)) { gDPLoadTextureBlock_4b(POLY_OPA_DISP++, roomTexture, G_IM_FMT_CI, texWidth, texHeight, 1, @@ -1781,6 +1831,8 @@ void MapDisp_DrawChests(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, s3 texPosY = (s32)((((mapDataChests[i].z - (f32)sMapDisp.sceneMidZ) * scaleFrac) - offsetZ) + ((viewHeight / 2) + viewY)); + texPosX = Ship_MapModifyPosMirrorMode(texPosX, -offsetX + ((viewWidth / 2) + viewX)); + gSPTextureRectangle(POLY_OPA_DISP++, texPosX << 2, texPosY << 2, (texPosX + 8) << 2, (texPosY + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } @@ -1833,6 +1885,9 @@ void MapDisp_DrawRoomExits(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, ((viewWidth / 2) + viewX); texPosY = ((f32)sTransitionActors[i].pos.z - sMapDisp.sceneMidZ) * scaleFrac + ((viewHeight / 2) + viewY); + + texPosX = Ship_MapModifyPosMirrorMode(texPosX, ((viewWidth / 2) + viewX)); + gSPTextureRectangle(POLY_OPA_DISP++, ((texPosX - 1) << 2), ((texPosY - 1) << 2), ((texPosX + 1) << 2), ((texPosY + 1) << 2), G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); @@ -1894,6 +1949,9 @@ void MapDisp_DrawBossIcon(PlayState* play, s32 viewX, s32 viewY, s32 viewWidth, ((viewWidth / 2) + viewX); texPosY = ((((f32)sTransitionActors[i].pos.z - sMapDisp.sceneMidZ) * scaleFrac) - offsetZ) + ((viewHeight / 2) + viewY); + + texPosX = Ship_MapModifyPosMirrorMode(texPosX, -offsetX + ((viewWidth / 2) + viewX)); + gSPTextureRectangle(POLY_OPA_DISP++, texPosX << 2, texPosY << 2, (texPosX + 8) << 2, (texPosY + 8) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } diff --git a/mm/src/code/z_parameter.c b/mm/src/code/z_parameter.c index bf3faab58..da73d18fb 100644 --- a/mm/src/code/z_parameter.c +++ b/mm/src/code/z_parameter.c @@ -8610,7 +8610,15 @@ void Interface_Draw(PlayState* play) { Map_DrawMinimap(play); if ((R_PAUSE_BG_PRERENDER_STATE != 2) && (R_PAUSE_BG_PRERENDER_STATE != 3)) { + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + gSPMatrix(OVERLAY_DISP++, interfaceCtx->view.shipMirrorProjectionPtr, + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + } Target_Draw(&play->actorCtx.targetCtx, play); + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + gSPMatrix(OVERLAY_DISP++, interfaceCtx->view.projectionPtr, + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + } } Gfx_SetupDL39_Overlay(play->state.gfxCtx); diff --git a/mm/src/code/z_play.c b/mm/src/code/z_play.c index 024c0fe12..80492c22e 100644 --- a/mm/src/code/z_play.c +++ b/mm/src/code/z_play.c @@ -1248,6 +1248,18 @@ void Play_DrawMain(PlayState* this) { View_Apply(&this->view, 0xF); + // Setup mirror mode matrix handling when we are not drawing kaleido + if (R_PAUSE_BG_PRERENDER_STATE <= PAUSE_BG_PRERENDER_SETUP && CVarGetInteger("gModes.MirroredWorld.State", 0)) { + gSPSetExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING); + gSPSetExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING); + gSPMatrix(POLY_OPA_DISP++, this->view.shipMirrorProjectionPtr, + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + gSPMatrix(POLY_XLU_DISP++, this->view.shipMirrorProjectionPtr, + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + gSPMatrix(POLY_OPA_DISP++, this->view.viewingPtr, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + gSPMatrix(POLY_XLU_DISP++, this->view.viewingPtr, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + } + // The billboard matrix temporarily stores the viewing matrix Matrix_MtxToMtxF(&this->view.viewing, &this->billboardMtxF); Matrix_MtxToMtxF(&this->view.projection, &this->viewProjectionMtxF); @@ -1523,6 +1535,11 @@ void Play_DrawMain(PlayState* this) { Play_PostWorldDraw(this); } } + + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + gSPClearExtraGeometryMode(POLY_OPA_DISP++, G_EX_INVERT_CULLING); + gSPClearExtraGeometryMode(POLY_XLU_DISP++, G_EX_INVERT_CULLING); + } } SkipPostWorldDraw: diff --git a/mm/src/code/z_view.c b/mm/src/code/z_view.c index 8fedc585f..83801471b 100644 --- a/mm/src/code/z_view.c +++ b/mm/src/code/z_view.c @@ -325,6 +325,7 @@ s32 View_ApplyPerspective(View* view) { s32 height; Vp* vp; Mtx* projection; + Mtx* projectionFlipped; Mtx* viewing; GraphicsContext* gfxCtx = view->gfxCtx; @@ -342,13 +343,26 @@ s32 View_ApplyPerspective(View* view) { // Perspective projection projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); + projectionFlipped = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); view->projectionPtr = projection; + view->shipMirrorProjectionPtr = projectionFlipped; width = view->viewport.rightX - view->viewport.leftX; height = view->viewport.bottomY - view->viewport.topY; aspect = (f32)width / (f32)height; guPerspective(projection, &view->perspNorm, view->fovy, aspect, view->zNear, view->zFar, view->scale); + + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + MtxF flipF; + SkinMatrix_Clear(&flipF); + flipF.xx = -1.0; + MtxF projectionF; + Matrix_MtxToMtxF(projection, &projectionF); + SkinMatrix_MtxFMtxFMult(&projectionF, &flipF, &projectionF); + Matrix_MtxFToMtx(&projectionF, projectionFlipped); + } + view->projection = *projection; View_StepDistortion(view, projection); @@ -450,6 +464,7 @@ s32 View_ApplyPerspective(View* view) { s32 View_ApplyOrtho(View* view) { Vp* vp; Mtx* projection; + Mtx* projectionFlipped; GraphicsContext* gfxCtx = view->gfxCtx; OPEN_DISPS(gfxCtx); @@ -465,11 +480,23 @@ s32 View_ApplyOrtho(View* view) { gSPViewport(OVERLAY_DISP++, vp); projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); + projectionFlipped = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); view->projectionPtr = projection; + view->shipMirrorProjectionPtr = projectionFlipped; guOrtho(projection, gScreenWidth * -0.5f, gScreenWidth * 0.5f, gScreenHeight * -0.5f, gScreenHeight * 0.5f, view->zNear, view->zFar, view->scale); + // if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + // MtxF flipF; + // SkinMatrix_Clear(&flipF); + // flipF.xx = -1.0; + // MtxF projectionF; + // Matrix_MtxToMtxF(projection, &projectionF); + // SkinMatrix_MtxFMtxFMult(&projectionF, &flipF, &projectionF); + // Matrix_MtxFToMtx(&projectionF, projectionFlipped); + // } + view->projection = *projection; gSPMatrix(POLY_OPA_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); @@ -486,6 +513,7 @@ s32 View_ApplyOrtho(View* view) { s32 View_ApplyOrthoToOverlay(View* view) { Vp* vp; Mtx* projection; + Mtx* projectionFlipped; GraphicsContext* gfxCtx; gfxCtx = view->gfxCtx; @@ -509,10 +537,23 @@ s32 View_ApplyOrthoToOverlay(View* view) { gSPViewport(OVERLAY_DISP++, vp); projection = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); + projectionFlipped = GRAPH_ALLOC(gfxCtx, sizeof(Mtx)); view->projectionPtr = projection; + view->shipMirrorProjectionPtr = projectionFlipped; guOrtho(projection, gScreenWidth * -0.5f, gScreenWidth * 0.5f, gScreenHeight * -0.5f, gScreenHeight * 0.5f, view->zNear, view->zFar, view->scale); + + if (CVarGetInteger("gModes.MirroredWorld.State", 0)) { + MtxF flipF; + SkinMatrix_Clear(&flipF); + flipF.xx = -1.0; + MtxF projectionF; + Matrix_MtxToMtxF(projection, &projectionF); + SkinMatrix_MtxFMtxFMult(&projectionF, &flipF, &projectionF); + Matrix_MtxFToMtx(&projectionF, projectionFlipped); + } + view->projection = *projection; gSPMatrix(OVERLAY_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); |
