Skip to content

Commit 8c86b91

Browse files
committed
Waoooooh
1 parent 5cd173c commit 8c86b91

9 files changed

Lines changed: 233 additions & 2 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ file(GLOB_RECURSE ALL_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
231231
"src/port/Enhancements/game-interactor/*.cpp"
232232
"src/port/importer/*.cpp"
233233
"src/port/importer/types/*.cpp"
234+
"src/port/mods/mirror/*.h"
235+
"src/port/mods/mirror/*.cpp"
234236
"src/port/net/*.h"
235237
"src/port/net/*.cpp"
236238
"text/*.c"

src/game/game_init.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "port/ui/cvar_prefixes.h"
2323
#include "port/interpolation/FrameInterpolation.h"
2424

25+
extern void mirror_mode_invert_input(void);
26+
2527
// First 3 controller slots
2628
struct Controller gControllers[3];
2729

@@ -746,7 +748,8 @@ void thread5_iteration(void){
746748
select_gfx_pool();
747749
CALL_CANCELLABLE_EVENT(GameReadInput) {
748750
read_controller_inputs();
749-
};
751+
}
752+
mirror_mode_invert_input();
750753
if (CVarGetInteger("gFrameAdvance", 0) == 1) {
751754
bool shouldTick = CVarGetInteger("gFrameAdvanceTick", 0);
752755
if (shouldTick) {

src/game/rendering_graph_node.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,25 @@
66
#include "gfx_dimensions.h"
77
#include "main.h"
88
#include "memory.h"
9+
#include "model_ids.h"
910
#include "print.h"
1011
#include "rendering_graph_node.h"
1112
#include "shadow.h"
1213
#include "sm64.h"
1314
#include "port/interpolation/FrameInterpolation.h"
1415
#include "port/Matrix.h"
1516

17+
extern void mirror_mode_apply_projection(void);
18+
extern int mirror_mode_is_enabled(void);
19+
extern void mirror_mode_undo_projection(void);
20+
extern int mirror_mode_is_active(void);
21+
extern s16 gCurrLevelNum;
22+
extern s16 sCurrPlayMode;
23+
extern s32 gCurrCreditsEntry;
24+
extern struct MarioState *gMarioState;
25+
26+
#define PLAY_MODE_NORMAL 0
27+
1628
/**
1729
* This file contains the code that processes the scene graph for rendering.
1830
* The scene graph is responsible for drawing everything except the HUD / text boxes.
@@ -265,6 +277,12 @@ static void geo_process_perspective(struct GraphNodePerspective *node) {
265277

266278
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
267279

280+
// Apply mirror mode transform after perspective projection
281+
// Mirror during: normal gameplay, ending cutscenes, but NOT during credits text rendering
282+
if (sCurrPlayMode == PLAY_MODE_NORMAL && gMarioState != NULL && gMarioState->action != 0 && gCurrCreditsEntry == NULL) {
283+
mirror_mode_apply_projection();
284+
}
285+
268286
gCurGraphNodeCamFrustum = node;
269287
geo_process_node_and_siblings(node->fnNode.node.children);
270288
gCurGraphNodeCamFrustum = NULL;
@@ -917,6 +935,7 @@ static void geo_process_object(struct Object *node) {
917935

918936
mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex + 1],
919937
node->header.gfx.scale);
938+
920939
node->header.gfx.throwMatrix = &gMatStack[++gMatStackIndex];
921940
node->header.gfx.cameraToObject[0] = gMatStack[gMatStackIndex][3][0];
922941
node->header.gfx.cameraToObject[1] = gMatStack[gMatStackIndex][3][1];

src/game/skybox.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "assets/textures/skyboxes/water.h"
2222
#include "assets/textures/skyboxes/wdw.h"
2323
#include "port/interpolation/FrameInterpolation.h"
24+
#include "port/mods/mirror/MirrorMode.h"
2425

2526
/**
2627
* @file skybox.c
@@ -140,12 +141,22 @@ f32 calculate_skybox_scaled_x(s8 player, f32 fov) {
140141

141142
//! double literals are used instead of floats
142143
f32 yawScaled = SCREEN_WIDTH * 360.0 * yaw / (fov * 65536.0);
143-
// Round the scaled yaw. Since yaw is a u16, it doesn't need to check for < 0
144144
f32 scaledX = yawScaled;
145145

146146
if (scaledX > SKYBOX_WIDTH) {
147147
scaledX -= (s32) scaledX / SKYBOX_WIDTH * SKYBOX_WIDTH;
148148
}
149+
150+
// Apply mirror mode AFTER the wrap calculation
151+
scaledX = SKYBOX_WIDTH - scaledX;
152+
153+
if (mirror_mode_is_enabled()) {
154+
// In mirror mode, invert the skybox position
155+
scaledX = SKYBOX_WIDTH - scaledX;
156+
}
157+
158+
return scaledX;
159+
149160
return SKYBOX_WIDTH - scaledX;
150161
}
151162

src/menu/intro_geo.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "buffers/framebuffers.h"
1212
#include "game/game_init.h"
1313
#include "audio/external.h"
14+
#include "port/mods/mirror/MirrorMode.h"
1415
#include "gfx_dimensions.h"
1516
#include "game/rendering_graph_node.h"
1617
#include "assets/bin/title_screen_bg.h"

src/port/mods/PortEnhancements.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#include "PortEnhancements.h"
2+
#include "mirror/MirrorMode.h"
23

34
#define INIT_EVENT_IDS
45

56
#include "sm64.h"
67
#include "game/level_update.h"
8+
#include "game/game_init.h"
79
#include "port/events/Events.h"
810
#include "assets/bin/segment2.h"
911
#include "port/Rando/Rando.h"
@@ -52,6 +54,14 @@ void PortEnhancements_Init() {
5254
PortEnhancements_Register();
5355
PatchSetupDList();
5456

57+
// Initialize mirror mode
58+
mirror_mode_init();
59+
60+
// Register event listeners
61+
REGISTER_LISTENER(RenderHud, EVENT_PRIORITY_NORMAL, [](IEvent* event) {
62+
mirror_mode_undo_projection();
63+
});
64+
5565
// Register event listeners
5666
REGISTER_LISTENER(PlayerHealthChange, EVENT_PRIORITY_NORMAL, [](IEvent* event) {
5767
PlayerHealthChange* ev = (PlayerHealthChange*)event;
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#include "MirrorMode.h"
2+
3+
#include <libultraship.h>
4+
#include "../../ui/cvar_prefixes.h"
5+
#include "sm64.h"
6+
#include "game/game_init.h"
7+
8+
#define CVAR_MIRROR_MODE CVAR_ENHANCEMENT("Modes.MirroredWorld.Mode")
9+
10+
static int sMirrorEnabled = 0;
11+
static int sMirrorActive = 0;
12+
static int sCounterMirror = 0;
13+
static int sExcludeForFrame = 0;
14+
15+
int mirror_mode_is_enabled(void) {
16+
return CVarGetInteger(CVAR_MIRROR_MODE, 0);
17+
}
18+
19+
int mirror_mode_is_active(void) {
20+
return sMirrorActive;
21+
}
22+
23+
void mirror_mode_apply_projection(void) {
24+
if (!mirror_mode_is_enabled()) {
25+
return;
26+
}
27+
28+
// Check if we should exclude mirroring for this frame
29+
if (sExcludeForFrame) {
30+
sExcludeForFrame = 0;
31+
return;
32+
}
33+
34+
Mtx* mtx = (Mtx*)alloc_display_list(sizeof(Mtx));
35+
if (mtx == NULL) {
36+
return;
37+
}
38+
39+
// Apply horizontal scale flip
40+
guScale(mtx, -1.0f, 1.0f, 1.0f);
41+
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_MUL | G_MTX_NOPUSH);
42+
43+
// Set invert culling flag for proper face sorting
44+
gSPSetExtraGeometryMode(gDisplayListHead++, G_EX_INVERT_CULLING);
45+
46+
sMirrorActive = 1;
47+
}
48+
49+
void mirror_mode_undo_projection(void) {
50+
if (!sMirrorActive) {
51+
return;
52+
}
53+
54+
// Clear invert culling flag before HUD renders
55+
gSPClearExtraGeometryMode(gDisplayListHead++, G_EX_INVERT_CULLING);
56+
57+
sMirrorActive = 0;
58+
}
59+
60+
void mirror_mode_register(void) {
61+
// Events will be registered in mirror_mode_init via PortEnhancements
62+
}
63+
64+
void mirror_mode_init(void) {
65+
// Update enabled state from CVAR
66+
sMirrorEnabled = mirror_mode_is_enabled();
67+
}
68+
69+
void mirror_mode_set_counter_mirror(void) {
70+
sCounterMirror = 1;
71+
}
72+
73+
void mirror_mode_clear_counter_mirror(void) {
74+
sCounterMirror = 0;
75+
}
76+
77+
int mirror_mode_should_counter_mirror(void) {
78+
return sCounterMirror && sMirrorActive;
79+
}
80+
81+
// Exclude mirroring for the current frame (for file select, etc.)
82+
void mirror_mode_exclude_for_frame(void) {
83+
sExcludeForFrame = 1;
84+
}
85+
86+
// Apply counter-mirror scale to cancel projection mirror for text/numbers
87+
void mirror_mode_apply_counter_scale(void) {
88+
if (!mirror_mode_should_counter_mirror()) {
89+
return;
90+
}
91+
92+
Mtx* mtx = (Mtx*)alloc_display_list(sizeof(Mtx));
93+
if (mtx == NULL) {
94+
return;
95+
}
96+
97+
// Apply counter-scale to cancel the projection mirror
98+
guScale(mtx, -1.0f, 1.0f, 1.0f);
99+
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
100+
}
101+
102+
// Patch display lists to add counter-mirror for number sprites
103+
void mirror_mode_patch_number_dl(void) {
104+
// This function would patch the MODEL_NUMBER display list
105+
// to include a counter-mirror transform at the beginning
106+
// However, in the PC port, display lists are loaded dynamically
107+
// and the patching would need to happen at runtime
108+
//
109+
// The approach would be:
110+
// 1. Load the number_geo display list
111+
// 2. Inject a counter-mirror matrix at the beginning
112+
// 3. This would make all number sprites appear unmirrored
113+
//
114+
// This is currently a placeholder for future implementation
115+
// as it requires deeper integration with the display list system
116+
}
117+
118+
void mirror_mode_invert_input(void) {
119+
if (!mirror_mode_is_enabled()) {
120+
return;
121+
}
122+
123+
struct Controller* ctrl = gPlayer1Controller;
124+
if (ctrl == NULL) {
125+
return;
126+
}
127+
128+
// Invert BOTH rawStickX and processed stickX
129+
// rawStickX is used for some purposes, but stickX is what mario.c uses for movement
130+
ctrl->rawStickX = -ctrl->rawStickX;
131+
ctrl->stickX = -ctrl->stickX;
132+
133+
// Also need to update magnitude
134+
ctrl->stickMag = sqrtf(ctrl->stickX * ctrl->stickX + ctrl->stickY * ctrl->stickY);
135+
}

src/port/mods/mirror/MirrorMode.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#pragma once
2+
3+
#include <libultra/gbi.h>
4+
5+
#ifdef __cplusplus
6+
extern "C" {
7+
#endif
8+
9+
// Core state access
10+
int mirror_mode_is_enabled(void);
11+
int mirror_mode_is_active(void);
12+
13+
// Projection manipulation
14+
void mirror_mode_apply_projection(void);
15+
void mirror_mode_undo_projection(void);
16+
17+
// Counter-mirror for text-bearing elements (title, star doors, etc.)
18+
void mirror_mode_set_counter_mirror(void);
19+
void mirror_mode_clear_counter_mirror(void);
20+
int mirror_mode_should_counter_mirror(void);
21+
22+
// Apply counter-mirror scale to cancel projection mirror for text/numbers
23+
void mirror_mode_apply_counter_scale(void);
24+
25+
// Exclude mirroring for the current frame (for file select, etc.)
26+
void mirror_mode_exclude_for_frame(void);
27+
28+
// Patch display lists for number sprites and star doors
29+
void mirror_mode_patch_number_dl(void);
30+
31+
// Event registration
32+
void mirror_mode_register(void);
33+
void mirror_mode_init(void);
34+
35+
// Input inversion for mirror mode controls
36+
void mirror_mode_invert_input(void);
37+
38+
#ifdef __cplusplus
39+
}
40+
#endif

src/port/ui/GhostshipMenuEnhancements.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,16 @@ void GhostshipMenu::AddMenuEnhancements() {
223223
.RaceDisable(false)
224224
.Options(CheckboxOptions().Tooltip("Fixes the Koopa race music on Bob-omb Battlefield and Tiny-Huge Island."));
225225

226+
path = { "Enhancements", "Modes", SECTION_COLUMN_1 };
227+
AddSidebarEntry("Enhancements", path.sidebarName, 1);
228+
path.column = SECTION_COLUMN_1;
229+
230+
AddWidget(path, "Mirrored World", WIDGET_CVAR_CHECKBOX)
231+
.CVar(CVAR_ENHANCEMENT("Modes.MirroredWorld.Mode"))
232+
.RaceDisable(false)
233+
.Options(CheckboxOptions().Tooltip(
234+
"Mirrors the world horizontally. Inverts left/right controls to match."));
235+
226236
path = { "Enhancements", "Cheats", SECTION_COLUMN_1 };
227237
AddSidebarEntry("Enhancements", path.sidebarName, 1);
228238
path.column = SECTION_COLUMN_1;

0 commit comments

Comments
 (0)