diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 3282154550..fd38cf3c05 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -306,6 +306,38 @@ void ShaderManagerDX9::VSUpdateUniforms(int dirtyUniforms) { flippedMatrix[12] = -flippedMatrix[12]; } + // In Phantasy Star Portable 2, depth range sometimes goes negative and is clamped by glDepthRange to 0, + // causing graphics clipping glitch (issue #1788). This hack modifies the projection matrix to work around it. + if (g_Config.bDepthRangeHack) { + float zScale = getFloat24(gstate.viewportz1) / 65535.0f; + float zOff = getFloat24(gstate.viewportz2) / 65535.0f; + + // if far depth range < 0 + if (zOff + zScale < 0.0f) { + // if perspective projection + if (flippedMatrix[11] < 0.0f) { + float depthMax = gstate.getDepthRangeMax() / 65535.0f; + float depthMin = gstate.getDepthRangeMin() / 65535.0f; + + float a = flippedMatrix[10]; + float b = flippedMatrix[14]; + + float n = b / (a - 1.0f); + float f = b / (a + 1.0f); + + f = (n * f) / (n + ((zOff + zScale) * (n - f) / (depthMax - depthMin))); + + a = (n + f) / (n - f); + b = (2.0f * n * f) / (n - f); + + if (!my_isnan(a) && !my_isnan(b)) { + flippedMatrix[10] = a; + flippedMatrix[14] = b; + } + } + } + } + const bool invertedZ = gstate_c.vpDepth < 0; ConvertProjMatrixToD3D(flippedMatrix, invertedX, invertedY, invertedZ);