Fix some issues with sprite border fix for RECT primitives

This commit is contained in:
Henrik Rydgård
2026-06-10 15:29:18 +02:00
parent 63a51dc6c2
commit c9623374b1
2 changed files with 41 additions and 28 deletions
+37 -28
View File
@@ -1012,20 +1012,41 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
}
bool pixelMapped = g_Config.bSmart2DTexFiltering && !gstate_c.textureIsVideo;
if (pixelMapped) {
// Check for pixel mapping. If we find pixel mapping, abandon spriteBorderFix.
for (int i = 0; i < vertexCount; i += 2) {
const TransformedVertex &transVtxTL = transformed[indsIn[i + 0]];
const TransformedVertex &transVtxBR = transformed[indsIn[i + 1]];
if (pixelMapped) {
float dx = transVtxBR.x - transVtxTL.x;
float dy = transVtxBR.y - transVtxTL.y;
float du = transVtxBR.u - transVtxTL.u;
float dv = transVtxBR.v - transVtxTL.v;
// NOTE: We will accept it as pixel mapped if only one dimension is stretched. This fixes dialog frames in FFI.
// Though, there could be false positives in other games due to this. Let's see if it is a problem...
if (dx <= 0 || dy <= 0 || (dx != du && dy != dv)) {
pixelMapped = false;
break;
}
}
}
}
float spriteBorderFixL = 0.0f;
float spriteBorderFixR = 0.0f;
float spriteBorderFixT = 0.0f;
float spriteBorderFixB = 0.0f;
float spriteBorderFix = PSP_CoreParameter().compat.flags().SpriteBorderFix;
if (spriteBorderFix && !ShouldApplySpriteBorderFix(gstate)) {
spriteBorderFix = 0.0f;
const float spriteBorderFix = PSP_CoreParameter().compat.flags().SpriteBorderFix;
if (pixelMapped || (spriteBorderFix && !ShouldApplySpriteBorderFix(gstate))) {
// Don't apply spriteBorderFix if pixel mapped.
} else {
if (spriteBorderFix < 0.0f) {
spriteBorderFixL = (spriteBorderFix / uScale) / gstate_c.curTextureWidth;
spriteBorderFixT = (spriteBorderFix / vScale) / gstate_c.curTextureHeight;
spriteBorderFixR = (spriteBorderFix / uScale) / gstate_c.curTextureWidth;
spriteBorderFixB = (spriteBorderFix / vScale) / gstate_c.curTextureHeight;
spriteBorderFixL = (-spriteBorderFix / uScale) / gstate_c.curTextureWidth;
spriteBorderFixT = (-spriteBorderFix / vScale) / gstate_c.curTextureHeight;
spriteBorderFixR = (-spriteBorderFix / uScale) / gstate_c.curTextureWidth;
spriteBorderFixB = (-spriteBorderFix / vScale) / gstate_c.curTextureHeight;
} else if (spriteBorderFix > 0.0f) {
spriteBorderFixL = 0.0f;
spriteBorderFixR = (spriteBorderFix / uScale) / gstate_c.curTextureWidth;
@@ -1034,23 +1055,11 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
}
}
for (int i = 0; i < vertexCount; i += 2) {
const TransformedVertex &transVtxTL = transformed[indsIn[i + 0]];
const TransformedVertex &transVtxBR = transformed[indsIn[i + 1]];
if (pixelMapped) {
float dx = transVtxBR.x - transVtxTL.x;
float dy = transVtxBR.y - transVtxTL.y;
float du = transVtxBR.u - transVtxTL.u;
float dv = transVtxBR.v - transVtxTL.v;
// NOTE: We will accept it as pixel mapped if only one dimension is stretched. This fixes dialog frames in FFI.
// Though, there could be false positives in other games due to this. Let's see if it is a problem...
if (dx <= 0 || dy <= 0 || (dx != du && dy != dv)) {
pixelMapped = false;
}
}
float z = transVtxBR.z;
// Apply Z clamping. It appears clipping/culling does not affect rectangles, see #12058.
// TODO: We might want to make this 65536.999. Since those will pass, and if a game mixes through and non-through...
@@ -1065,30 +1074,30 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
// bottom right
trans[0] = transVtxBR;
trans[0].u = (transVtxBR.u + spriteBorderFixR) * uScale;
trans[0].v = (transVtxBR.v + spriteBorderFixB) * vScale;
trans[0].u = (transVtxBR.u - spriteBorderFixR) * uScale;
trans[0].v = (transVtxBR.v - spriteBorderFixB) * vScale;
trans[0].z = z;
// top right
trans[1] = transVtxBR;
trans[1].y = transVtxTL.y;
trans[1].u = (transVtxBR.u + spriteBorderFixR) * uScale;
trans[1].v = (transVtxTL.v - spriteBorderFixT) * vScale;
trans[1].u = (transVtxBR.u - spriteBorderFixR) * uScale;
trans[1].v = (transVtxTL.v + spriteBorderFixT) * vScale;
trans[1].z = z;
// top left
trans[2] = transVtxBR;
trans[2].x = transVtxTL.x;
trans[2].y = transVtxTL.y;
trans[2].u = (transVtxTL.u - spriteBorderFixL) * uScale;
trans[2].v = (transVtxTL.v - spriteBorderFixT) * vScale;
trans[2].u = (transVtxTL.u + spriteBorderFixL) * uScale;
trans[2].v = (transVtxTL.v + spriteBorderFixT) * vScale;
trans[2].z = z;
// bottom left
trans[3] = transVtxBR;
trans[3].x = transVtxTL.x;
trans[3].u = (transVtxTL.u - spriteBorderFixL) * uScale;
trans[3].v = (transVtxBR.v + spriteBorderFixB) * vScale;
trans[3].u = (transVtxTL.u + spriteBorderFixL) * uScale;
trans[3].v = (transVtxBR.v - spriteBorderFixB) * vScale;
trans[3].z = z;
// That's the four corners. Now process UV rotation.
+4
View File
@@ -2136,3 +2136,7 @@ ULJS00097 = -0.25
ULES00262 = 0.5
ULUS10064 = 0.5
ULKS46087 = 0.5
# Tokiden (issue #19422)
# This works in the provided dump, but needs more testing.
# NPJH50878 = -0.4