summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Dubé <159546+serprex@users.noreply.github.com>2026-08-09 22:01:31 +0000
committerGitHub <noreply@github.com>2026-08-09 22:01:31 +0000
commitf27ddede59d8134eccf8a106f62eaebeecc4ace5 (patch)
treeba9a8d77ce0158d8ce2df17d360c2d3274ab08c6
parent4e39d06accfa65fbed9e034c3cd7face91a6d80c (diff)
Fix mirror decal not rendering on some walls (#7052)
-rw-r--r--soh/soh/Enhancements/AlwaysOnFixes.cpp15
-rw-r--r--soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h8
-rw-r--r--soh/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c4
3 files changed, 26 insertions, 1 deletions
diff --git a/soh/soh/Enhancements/AlwaysOnFixes.cpp b/soh/soh/Enhancements/AlwaysOnFixes.cpp
index 639330f68..66c270c22 100644
--- a/soh/soh/Enhancements/AlwaysOnFixes.cpp
+++ b/soh/soh/Enhancements/AlwaysOnFixes.cpp
@@ -8,6 +8,7 @@ extern "C" {
#include "include/z64camera.h"
#include "src/overlays/actors/ovl_En_Test/z_en_test.h"
#include "src/overlays/actors/ovl_En_Horse/z_en_horse.h"
+#include "src/overlays/actors/ovl_Mir_Ray/z_mir_ray.h"
void UnregisterActorSkeletons(struct Actor* actor);
extern void Player_UseItem(PlayState*, Player*, s32);
extern PlayState* gPlayState;
@@ -110,6 +111,20 @@ void RegisterAlwaysOnFixes() {
}
});
+ // Mir_Ray draws the reflection image straight on the collision poly's plane, but CollisionPoly
+ // stores that plane quantized (s16 normal, integer dist), so for about half of all walls it
+ // lands a fraction of a unit inside the drawn surface. N64 RDP's decal mode handled that,
+ // but our graphics pipeline does not. Lift the image off the plane along the poly normal.
+ COND_VB_SHOULD(VB_MIRRAY_DRAW_REFLECTION, true, {
+ if (*should) {
+ MirRayShieldReflection* reflection = va_arg(args, MirRayShieldReflection*);
+ CollisionPoly* poly = reflection->reflectionPoly;
+ reflection->pos.x += COLPOLY_GET_NORMAL(poly->normal.x);
+ reflection->pos.y += COLPOLY_GET_NORMAL(poly->normal.y);
+ reflection->pos.z += COLPOLY_GET_NORMAL(poly->normal.z);
+ }
+ });
+
// Handle first person aiming camera settings
COND_VB_SHOULD(VB_CHANGE_AIMING_CAMERA, true, {
s8* heldItemAction = va_arg(args, s8*);
diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
index f0b91582c..e41669089 100644
--- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
+++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h
@@ -1642,6 +1642,14 @@ typedef enum {
// #### `result`
// ```c
+ // reflection[i].reflectionPoly != NULL
+ // ```
+ // #### `args`
+ // - `*MirRayShieldReflection`
+ VB_MIRRAY_DRAW_REFLECTION,
+
+ // #### `result`
+ // ```c
// false
// ```
// #### `args`
diff --git a/soh/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c b/soh/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c
index 334c1fdf6..ae1b130bd 100644
--- a/soh/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c
+++ b/soh/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c
@@ -7,6 +7,7 @@
#include "z_mir_ray.h"
#include "objects/object_mir_ray/object_mir_ray.h"
#include "soh/frame_interpolation.h"
+#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#define FLAGS (ACTOR_FLAG_UPDATE_CULLING_DISABLED | ACTOR_FLAG_DRAW_CULLING_DISABLED)
@@ -510,7 +511,8 @@ void MirRay_Draw(Actor* thisx, PlayState* play) {
}
}
for (i = 0; i < 6; i++) {
- if (reflection[i].reflectionPoly != NULL) {
+ if (GameInteractor_Should(VB_MIRRAY_DRAW_REFLECTION, reflection[i].reflectionPoly != NULL,
+ &reflection[i])) {
FrameInterpolation_RecordOpenChild(&reflection[i], i);
Matrix_Translate(reflection[i].pos.x, reflection[i].pos.y, reflection[i].pos.z, MTXMODE_NEW);
Matrix_Scale(0.01f, 0.01f, 0.01f, MTXMODE_APPLY);