Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ file(GLOB_RECURSE ALL_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
"src/port/Enhancements/game-interactor/*.cpp"
"src/port/importer/*.cpp"
"src/port/importer/types/*.cpp"
"src/port/mods/mirror/*.h"
"src/port/mods/mirror/*.cpp"
"src/port/net/*.h"
"src/port/net/*.cpp"
"text/*.c"
Expand Down
5 changes: 4 additions & 1 deletion src/game/game_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include "port/ui/cvar_prefixes.h"
#include "port/interpolation/FrameInterpolation.h"

extern void mirror_mode_invert_input(void);

// First 3 controller slots
struct Controller gControllers[3];

Expand Down Expand Up @@ -746,7 +748,8 @@ void thread5_iteration(void){
select_gfx_pool();
CALL_CANCELLABLE_EVENT(GameReadInput) {
read_controller_inputs();
};
}
mirror_mode_invert_input();
if (CVarGetInteger("gFrameAdvance", 0) == 1) {
bool shouldTick = CVarGetInteger("gFrameAdvanceTick", 0);
if (shouldTick) {
Expand Down
19 changes: 19 additions & 0 deletions src/game/rendering_graph_node.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,25 @@
#include "gfx_dimensions.h"
#include "main.h"
#include "memory.h"
#include "model_ids.h"
#include "print.h"
#include "rendering_graph_node.h"
#include "shadow.h"
#include "sm64.h"
#include "port/interpolation/FrameInterpolation.h"
#include "port/Matrix.h"

extern void mirror_mode_apply_projection(void);
extern int mirror_mode_is_enabled(void);
extern void mirror_mode_undo_projection(void);
extern int mirror_mode_is_active(void);
extern s16 gCurrLevelNum;
extern s16 sCurrPlayMode;
extern s32 gCurrCreditsEntry;
extern struct MarioState *gMarioState;

#define PLAY_MODE_NORMAL 0

/**
* This file contains the code that processes the scene graph for rendering.
* The scene graph is responsible for drawing everything except the HUD / text boxes.
Expand Down Expand Up @@ -265,6 +277,12 @@ static void geo_process_perspective(struct GraphNodePerspective *node) {

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

// Apply mirror mode transform after perspective projection
// Mirror during: normal gameplay, ending cutscenes, but NOT during credits text rendering
if (sCurrPlayMode == PLAY_MODE_NORMAL && gMarioState != NULL && gMarioState->action != 0 && gCurrCreditsEntry == NULL) {
mirror_mode_apply_projection();
}

gCurGraphNodeCamFrustum = node;
geo_process_node_and_siblings(node->fnNode.node.children);
gCurGraphNodeCamFrustum = NULL;
Expand Down Expand Up @@ -917,6 +935,7 @@ static void geo_process_object(struct Object *node) {

mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex + 1],
node->header.gfx.scale);

node->header.gfx.throwMatrix = &gMatStack[++gMatStackIndex];
node->header.gfx.cameraToObject[0] = gMatStack[gMatStackIndex][3][0];
node->header.gfx.cameraToObject[1] = gMatStack[gMatStackIndex][3][1];
Expand Down
12 changes: 12 additions & 0 deletions src/game/skybox.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "assets/textures/skyboxes/water.h"
#include "assets/textures/skyboxes/wdw.h"
#include "port/interpolation/FrameInterpolation.h"
#include "port/mods/mirror/MirrorMode.h"

/**
* @file skybox.c
Expand Down Expand Up @@ -146,6 +147,17 @@ f32 calculate_skybox_scaled_x(s8 player, f32 fov) {
if (scaledX > SKYBOX_WIDTH) {
scaledX -= (s32) scaledX / SKYBOX_WIDTH * SKYBOX_WIDTH;
}

// Apply mirror mode AFTER the wrap calculation
scaledX = SKYBOX_WIDTH - scaledX;

if (mirror_mode_is_enabled()) {
// In mirror mode, invert the skybox position
scaledX = SKYBOX_WIDTH - scaledX;
}

return scaledX;

return SKYBOX_WIDTH - scaledX;
}

Expand Down
1 change: 1 addition & 0 deletions src/menu/intro_geo.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "buffers/framebuffers.h"
#include "game/game_init.h"
#include "audio/external.h"
#include "port/mods/mirror/MirrorMode.h"
#include "gfx_dimensions.h"
#include "game/rendering_graph_node.h"
#include "assets/bin/title_screen_bg.h"
Expand Down
8 changes: 8 additions & 0 deletions src/port/mods/PortEnhancements.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include "PortEnhancements.h"
#include "mirror/MirrorMode.h"

#define INIT_EVENT_IDS

#include "sm64.h"
#include "game/level_update.h"
#include "game/game_init.h"
#include "port/events/Events.h"
#include "assets/bin/segment2.h"
#include "port/Rando/Rando.h"
Expand Down Expand Up @@ -52,6 +54,12 @@ void PortEnhancements_Init() {
PortEnhancements_Register();
PatchSetupDList();

// Initialize mirror mode
mirror_mode_init();

// Register event listeners
REGISTER_LISTENER(RenderHud, EVENT_PRIORITY_NORMAL, [](IEvent* event) { mirror_mode_undo_projection(); });

// Register event listeners
REGISTER_LISTENER(PlayerHealthChange, EVENT_PRIORITY_NORMAL, [](IEvent* event) {
PlayerHealthChange* ev = (PlayerHealthChange*)event;
Expand Down
135 changes: 135 additions & 0 deletions src/port/mods/mirror/MirrorMode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include "MirrorMode.h"

#include <libultraship.h>
#include "../../ui/cvar_prefixes.h"
#include "sm64.h"
#include "game/game_init.h"

#define CVAR_MIRROR_MODE CVAR_ENHANCEMENT("Modes.MirroredWorld.Mode")

static int sMirrorEnabled = 0;
static int sMirrorActive = 0;
static int sCounterMirror = 0;
static int sExcludeForFrame = 0;

int mirror_mode_is_enabled(void) {
return CVarGetInteger(CVAR_MIRROR_MODE, 0);
}

int mirror_mode_is_active(void) {
return sMirrorActive;
}

void mirror_mode_apply_projection(void) {
if (!mirror_mode_is_enabled()) {
return;
}

// Check if we should exclude mirroring for this frame
if (sExcludeForFrame) {
sExcludeForFrame = 0;
return;
}

Mtx* mtx = (Mtx*)alloc_display_list(sizeof(Mtx));
if (mtx == NULL) {
return;
}

// Apply horizontal scale flip
guScale(mtx, -1.0f, 1.0f, 1.0f);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_MUL | G_MTX_NOPUSH);

// Set invert culling flag for proper face sorting
gSPSetExtraGeometryMode(gDisplayListHead++, G_EX_INVERT_CULLING);

sMirrorActive = 1;
}

void mirror_mode_undo_projection(void) {
if (!sMirrorActive) {
return;
}

// Clear invert culling flag before HUD renders
gSPClearExtraGeometryMode(gDisplayListHead++, G_EX_INVERT_CULLING);

sMirrorActive = 0;
}

void mirror_mode_register(void) {
// Events will be registered in mirror_mode_init via PortEnhancements
}

void mirror_mode_init(void) {
// Update enabled state from CVAR
sMirrorEnabled = mirror_mode_is_enabled();
}

void mirror_mode_set_counter_mirror(void) {
sCounterMirror = 1;
}

void mirror_mode_clear_counter_mirror(void) {
sCounterMirror = 0;
}

int mirror_mode_should_counter_mirror(void) {
return sCounterMirror && sMirrorActive;
}

// Exclude mirroring for the current frame (for file select, etc.)
void mirror_mode_exclude_for_frame(void) {
sExcludeForFrame = 1;
}

// Apply counter-mirror scale to cancel projection mirror for text/numbers
void mirror_mode_apply_counter_scale(void) {
if (!mirror_mode_should_counter_mirror()) {
return;
}

Mtx* mtx = (Mtx*)alloc_display_list(sizeof(Mtx));
if (mtx == NULL) {
return;
}

// Apply counter-scale to cancel the projection mirror
guScale(mtx, -1.0f, 1.0f, 1.0f);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
}

// Patch display lists to add counter-mirror for number sprites
void mirror_mode_patch_number_dl(void) {
// This function would patch the MODEL_NUMBER display list
// to include a counter-mirror transform at the beginning
// However, in the PC port, display lists are loaded dynamically
// and the patching would need to happen at runtime
//
// The approach would be:
// 1. Load the number_geo display list
// 2. Inject a counter-mirror matrix at the beginning
// 3. This would make all number sprites appear unmirrored
//
// This is currently a placeholder for future implementation
// as it requires deeper integration with the display list system
}

void mirror_mode_invert_input(void) {
if (!mirror_mode_is_enabled()) {
return;
}

struct Controller* ctrl = gPlayer1Controller;
if (ctrl == NULL) {
return;
}

// Invert BOTH rawStickX and processed stickX
// rawStickX is used for some purposes, but stickX is what mario.c uses for movement
ctrl->rawStickX = -ctrl->rawStickX;
ctrl->stickX = -ctrl->stickX;

// Also need to update magnitude
ctrl->stickMag = sqrtf(ctrl->stickX * ctrl->stickX + ctrl->stickY * ctrl->stickY);
}
40 changes: 40 additions & 0 deletions src/port/mods/mirror/MirrorMode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#include <libultra/gbi.h>

#ifdef __cplusplus
extern "C" {
#endif

// Core state access
int mirror_mode_is_enabled(void);
int mirror_mode_is_active(void);

// Projection manipulation
void mirror_mode_apply_projection(void);
void mirror_mode_undo_projection(void);

// Counter-mirror for text-bearing elements (title, star doors, etc.)
void mirror_mode_set_counter_mirror(void);
void mirror_mode_clear_counter_mirror(void);
int mirror_mode_should_counter_mirror(void);

// Apply counter-mirror scale to cancel projection mirror for text/numbers
void mirror_mode_apply_counter_scale(void);

// Exclude mirroring for the current frame (for file select, etc.)
void mirror_mode_exclude_for_frame(void);

// Patch display lists for number sprites and star doors
void mirror_mode_patch_number_dl(void);

// Event registration
void mirror_mode_register(void);
void mirror_mode_init(void);

// Input inversion for mirror mode controls
void mirror_mode_invert_input(void);

#ifdef __cplusplus
}
#endif
9 changes: 9 additions & 0 deletions src/port/ui/GhostshipMenuEnhancements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,15 @@ void GhostshipMenu::AddMenuEnhancements() {
.RaceDisable(false)
.Options(CheckboxOptions().Tooltip("Fixes the Koopa race music on Bob-omb Battlefield and Tiny-Huge Island."));

path = { "Enhancements", "Modes", SECTION_COLUMN_1 };
AddSidebarEntry("Enhancements", path.sidebarName, 1);
path.column = SECTION_COLUMN_1;

AddWidget(path, "Mirrored World", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("Modes.MirroredWorld.Mode"))
.RaceDisable(false)
.Options(CheckboxOptions().Tooltip("Mirrors the world horizontally. Inverts left/right controls to match."));

path = { "Enhancements", "Cheats", SECTION_COLUMN_1 };
AddSidebarEntry("Enhancements", path.sidebarName, 1);
path.column = SECTION_COLUMN_1;
Expand Down
Loading