1- #include " utils/debug_draw.h"
21#include " cemu_hooks.h"
32#include " instance.h"
43#include " rendering/openxr.h"
4+ #include " utils/debug_draw.h"
55
66bool CemuHooks::UseMonoFrameBufferTemporarilyDuringMenusOrPictures () {
77 return IsScreenOpen (ScreenId::PauseMenuInfo_00) || VRManager::instance ().XR ->GetRenderer ()->IsGameCapturing3DFrameBuffer ();
@@ -27,6 +27,51 @@ static std::pair<glm::quat, glm::quat> swingTwistY(const glm::quat& q) {
2727 return { swing, twist };
2828}
2929
30+ // https://github.com/KhronosGroup/OpenXR-SDK/blob/858912260ca616f4c23f7fb61c89228c353eb124/src/common/xr_linear.h#L564C1-L632C2
31+ // https://github.com/aboood40091/sead/blob/45b629fb032d88b828600a1b787729f2d398f19d/engine/library/modules/src/gfx/seadProjection.cpp#L166
32+
33+ static data_VRProjectionMatrixOut calculateFOVAndOffset (XrFovf viewFOV) {
34+ float totalHorizontalFov = viewFOV.angleRight - viewFOV.angleLeft ;
35+ float totalVerticalFov = viewFOV.angleUp - viewFOV.angleDown ;
36+
37+ float aspectRatio = totalHorizontalFov / totalVerticalFov;
38+ float fovY = totalVerticalFov;
39+ float projectionCenter_offsetX = (viewFOV.angleRight + viewFOV.angleLeft ) / 2 .0f ;
40+ float projectionCenter_offsetY = (viewFOV.angleUp + viewFOV.angleDown ) / 2 .0f ;
41+
42+ data_VRProjectionMatrixOut ret = {};
43+ ret.aspectRatio = aspectRatio;
44+ ret.fovY = fovY;
45+ ret.offsetX = projectionCenter_offsetX;
46+ ret.offsetY = projectionCenter_offsetY;
47+
48+ return ret;
49+ }
50+
51+ static glm::mat4 calculateProjectionMatrix (float nearZ, float farZ, const XrFovf& fov) {
52+ float l = tanf (fov.angleLeft ) * nearZ;
53+ float r = tanf (fov.angleRight ) * nearZ;
54+ float b = tanf (fov.angleDown ) * nearZ;
55+ float t = tanf (fov.angleUp ) * nearZ;
56+
57+ float invW = 1 .0f / (r - l);
58+ float invH = 1 .0f / (t - b);
59+ float invD = 1 .0f / (farZ - nearZ);
60+
61+ glm::mat4 dst = {};
62+ dst[0 ][0 ] = 2 .0f * nearZ * invW;
63+ dst[1 ][1 ] = 2 .0f * nearZ * invH;
64+ dst[0 ][2 ] = (r + l) * invW;
65+ dst[1 ][2 ] = (t + b) * invH;
66+ dst[2 ][2 ] = -(farZ + nearZ) * invD;
67+ dst[2 ][3 ] = -(2 .0f * farZ * nearZ) * invD;
68+ dst[3 ][2 ] = -1 .0f ;
69+ dst[3 ][3 ] = 0 .0f ;
70+
71+ return dst;
72+ }
73+
74+
3075float hardcodedSwimOffset = 0 .0f ;
3176float hardcodedRidingOffset = 0 .65f ;
3277float hardcodedCrouchOffset = 0 .3f ;
@@ -88,7 +133,7 @@ void CemuHooks::hook_UpdateCameraForGameplay(PPCInterpreter_t* hCPU) {
88133
89134 PlayerMoveBitFlags moveBits = actor.moveBitFlags .getLE ();
90135 s_isSwimming = HAS_FLAG (moveBits, PlayerMoveBitFlags::IS_SWIMMING_OR_CLIMBING | PlayerMoveBitFlags::IS_SWIMMING);
91- s_isCrouching = HAS_FLAG (moveBits, PlayerMoveBitFlags::IS_CROUCHING);
136+ s_isCrouching = HAS_FLAG (moveBits, PlayerMoveBitFlags::IS_CROUCHING);
92137
93138 // Todo: move those and their hooks in controls.cpp ?
94139 auto gameState = VRManager::instance ().XR ->m_gameState .load ();
@@ -100,23 +145,19 @@ void CemuHooks::hook_UpdateCameraForGameplay(PPCInterpreter_t* hCPU) {
100145
101146 auto now = std::chrono::steady_clock::now ();
102147 std::chrono::milliseconds crouchLerpDuration{ 150 };
103- if (s_isCrouching != s_wasCrouching)
104- {
148+ if (s_isCrouching != s_wasCrouching) {
105149 crouch_state_change_time = now;
106150 }
107151 auto test = 0 .8f ;
108- if (now <= crouch_state_change_time + crouchLerpDuration)
109- {
152+ if (now <= crouch_state_change_time + crouchLerpDuration) {
110153 auto elapsed = std::chrono::duration<float >(now - crouch_state_change_time);
111154 auto duration = std::chrono::duration<float >(crouchLerpDuration);
112155 float t = elapsed.count () / duration.count ();
113156 t = glm::clamp (t, 0 .0f , 1 .0f );
114- if (s_isCrouching)
115- {
157+ if (s_isCrouching) {
116158 actualCrouchOffset = glm::mix (0 .0f , test, t);
117159 }
118- else
119- {
160+ else {
120161 actualCrouchOffset = glm::mix (test, 0 .0f , t);
121162 }
122163 }
@@ -267,7 +308,7 @@ void CemuHooks::hook_GetRenderCamera(PPCInterpreter_t* hCPU) {
267308 BEMatrix34 playerMtx = {};
268309 readMemory (s_playerMtxAddress, &playerMtx);
269310 glm::fvec3 playerPos = playerMtx.getPos ().getLE ();
270-
311+
271312 if (s_isRiding) {
272313 playerPos.y -= hardcodedRidingOffset;
273314 }
@@ -305,6 +346,20 @@ void CemuHooks::hook_GetRenderCamera(PPCInterpreter_t* hCPU) {
305346 glm::mat4 newWorldVR = glm::translate (glm::mat4 (1 .0f ), newPos) * glm::mat4_cast (newRot);
306347 glm::mat4 newViewVR = glm::inverse (newWorldVR);
307348
349+ if (side == EyeSide::RIGHT && GetSettings ().ShowDebugOverlay ()) {
350+ glm::mat4 proj = calculateProjectionMatrix (GetSettings ().GetZNear (), GetSettings ().GetZFar (), VRManager::instance ().XR ->GetRenderer ()->GetFOV (side).value ());
351+
352+ // transpose the sead-convention (row-major) projections to standard column-major
353+ glm::mat4 vrProj = glm::transpose (proj);
354+
355+ glm::mat4 vrVP = vrProj * newViewVR;
356+ // DebugDraw::instance().Frustum(vrVP, IM_COL32(0, 255, 0, 255));
357+
358+ // store the right-eye projection matrix to transform the debug lines with
359+ // use right-side due to that being the one shown in the 2D view
360+ DebugDraw::instance ().SetViewProjection (vrVP);
361+ }
362+
308363 camera.mtx .setLEMatrix (newViewVR);
309364
310365 camera.pos = newPos;
@@ -328,51 +383,6 @@ void CemuHooks::hook_GetRenderCamera(PPCInterpreter_t* hCPU) {
328383constexpr uint32_t seadOrthoProjection = 0x1027B5BC ;
329384constexpr uint32_t seadPerspectiveProjection = 0x1027B54C ;
330385
331-
332- // https://github.com/KhronosGroup/OpenXR-SDK/blob/858912260ca616f4c23f7fb61c89228c353eb124/src/common/xr_linear.h#L564C1-L632C2
333- // https://github.com/aboood40091/sead/blob/45b629fb032d88b828600a1b787729f2d398f19d/engine/library/modules/src/gfx/seadProjection.cpp#L166
334-
335- static data_VRProjectionMatrixOut calculateFOVAndOffset (XrFovf viewFOV) {
336- float totalHorizontalFov = viewFOV.angleRight - viewFOV.angleLeft ;
337- float totalVerticalFov = viewFOV.angleUp - viewFOV.angleDown ;
338-
339- float aspectRatio = totalHorizontalFov / totalVerticalFov;
340- float fovY = totalVerticalFov;
341- float projectionCenter_offsetX = (viewFOV.angleRight + viewFOV.angleLeft ) / 2 .0f ;
342- float projectionCenter_offsetY = (viewFOV.angleUp + viewFOV.angleDown ) / 2 .0f ;
343-
344- data_VRProjectionMatrixOut ret = {};
345- ret.aspectRatio = aspectRatio;
346- ret.fovY = fovY;
347- ret.offsetX = projectionCenter_offsetX;
348- ret.offsetY = projectionCenter_offsetY;
349-
350- return ret;
351- }
352-
353- static glm::mat4 calculateProjectionMatrix (float nearZ, float farZ, const XrFovf& fov) {
354- float l = tanf (fov.angleLeft ) * nearZ;
355- float r = tanf (fov.angleRight ) * nearZ;
356- float b = tanf (fov.angleDown ) * nearZ;
357- float t = tanf (fov.angleUp ) * nearZ;
358-
359- float invW = 1 .0f / (r - l);
360- float invH = 1 .0f / (t - b);
361- float invD = 1 .0f / (farZ - nearZ);
362-
363- glm::mat4 dst = {};
364- dst[0 ][0 ] = 2 .0f * nearZ * invW;
365- dst[1 ][1 ] = 2 .0f * nearZ * invH;
366- dst[0 ][2 ] = (r + l) * invW;
367- dst[1 ][2 ] = (t + b) * invH;
368- dst[2 ][2 ] = -(farZ + nearZ) * invD;
369- dst[2 ][3 ] = -(2 .0f * farZ * nearZ) * invD;
370- dst[3 ][2 ] = -1 .0f ;
371- dst[3 ][3 ] = 0 .0f ;
372-
373- return dst;
374- }
375-
376386void CemuHooks::hook_GetRenderProjection (PPCInterpreter_t* hCPU) {
377387 hCPU->instructionPointer = hCPU->sprNew .LR ;
378388
@@ -742,7 +752,6 @@ void CemuHooks::hook_CheckIfCameraCanSeePos(PPCInterpreter_t* hCPU) {
742752}
743753
744754
745-
746755void CemuHooks::hook_ModifyPixelUniformBlockData (PPCInterpreter_t* hCPU) {
747756 hCPU->instructionPointer = hCPU->sprNew .LR ;
748757
@@ -753,12 +762,12 @@ void CemuHooks::hook_ModifyPixelUniformBlockData(PPCInterpreter_t* hCPU) {
753762
754763 glm::fvec4 ubData = {};
755764 readMemory (hCPU->gpr [5 ], &ubData);
756-
765+
757766 XrFovf currFOV = currFovOpt.value ();
758767 auto newProjection = calculateFOVAndOffset (currFOV);
759768
760- ubData.x = 0 .5f + newProjection.offsetX .getLE ();
761- ubData.y = 0 .5f + newProjection.offsetY .getLE ();
769+ ubData.x = 0 .5f + newProjection.offsetX .getLE ();
770+ ubData.y = 0 .5f + newProjection.offsetY .getLE ();
762771
763772 writeMemory (hCPU->gpr [5 ], &ubData);
764773}
@@ -1035,7 +1044,7 @@ void CemuHooks::hook_OverwriteCameraParam(PPCInterpreter_t* hCPU) {
10351044 auto & paramList = storedCameraParameters[actionPtr];
10361045 // store parameter offset if not already stored
10371046 auto it = std::find_if (paramList.begin (), paramList.end (), [¶mNameStr](const CameraParamValueOffset& entry) {
1038- return entry.name == paramNameStr;
1047+ return entry.name == paramNameStr;
10391048 });
10401049 if (it == paramList.end ()) {
10411050 // get offset by calling original function first
@@ -1098,7 +1107,7 @@ void CemuHooks::hook_PlayerLadderFix(PPCInterpreter_t* hCPU) {
10981107void CemuHooks::hook_VisualizeRayCastHits (PPCInterpreter_t* hCPU) {
10991108 hCPU->instructionPointer = hCPU->sprNew .LR ;
11001109
1101- if (VRManager::instance ().XR ->GetRenderer () == nullptr ) {
1110+ if (VRManager::instance ().XR ->GetRenderer () == nullptr || ! GetSettings (). ShowDebugOverlay () ) {
11021111 return ;
11031112 }
11041113
0 commit comments