diff --git a/Core/Config.cpp b/Core/Config.cpp index a707a4e9e9..64ed3e27a2 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -444,6 +444,7 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("VSyncInterval", &g_Config.bVSync, false), ReportedConfigSetting("DisableStencilTest", &g_Config.bDisableStencilTest, false), ReportedConfigSetting("AlwaysDepthWrite", &g_Config.bAlwaysDepthWrite, false), + ReportedConfigSetting("DepthRangeHack", &g_Config.bDepthRangeHack, false), // Not really a graphics setting... ReportedConfigSetting("TimerHack", &g_Config.bTimerHack, &DefaultTimerHack), diff --git a/Core/Config.h b/Core/Config.h index f271bb5d51..f036ae37d2 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -165,6 +165,7 @@ public: bool bReloadCheats; bool bDisableStencilTest; bool bAlwaysDepthWrite; + bool bDepthRangeHack; bool bTimerHack; bool bAlphaMaskHack; bool bBlockTransferGPU; diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index a826854cc5..11313ae63c 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -805,9 +805,46 @@ void TransformDrawEngine::ApplyDrawState(int prim) { float zScale = getFloat24(gstate.viewportz1) / 65535.0f; float zOff = getFloat24(gstate.viewportz2) / 65535.0f; - float depthRangeMin = zOff - zScale; - float depthRangeMax = zOff + zScale; - glstate.depthRange.set(depthRangeMin, depthRangeMax); + + // 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) { + // if far depth range < 0 + if (zOff + zScale < 0.0f) { + // if perspective projection + if (gstate.projMatrix[11] < 0.0f) { + float depthMax = gstate.getDepthRangeMax() / 65535.0f; + float depthMin = gstate.getDepthRangeMin() / 65535.0f; + + float a = gstate.projMatrix[10]; + float b = gstate.projMatrix[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); + + gstate.projMatrix[10] = a; + gstate.projMatrix[14] = b; + + shaderManager_->DirtyUniform(DIRTY_PROJMATRIX); + + zOff = (zOff - zScale) / 2.0f; + zScale = -zOff; + + gstate.viewportz2 &= 0xFF000000; + gstate.viewportz2 |= toFloat24(zOff * 65535.0f); + + gstate.viewportz1 &= 0xFF000000; + gstate.viewportz1 |= toFloat24(zScale * 65535.0f); + } + } + } + + glstate.depthRange.set(zOff - zScale, zOff + zScale); } } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 2ed0afc049..a2c050c3f3 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -278,6 +278,9 @@ void GameSettingsScreen::CreateViews() { CheckBox *prescale = graphicsSettings->Add(new CheckBox(&g_Config.bPrescaleUV, gs->T("Texture Coord Speedhack"))); prescale->SetDisabledPtr(&g_Config.bSoftwareRendering); + CheckBox *depthRange = graphicsSettings->Add(new CheckBox(&g_Config.bDepthRangeHack, gs->T("Depth Range Hack (Phantasy Star Portable 2)"))); + depthRange->SetDisabledPtr(&g_Config.bSoftwareRendering); + graphicsSettings->Add(new ItemHeader(gs->T("Overlay Information"))); static const char *fpsChoices[] = { "None", "Speed", "FPS", "Both"