mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Improve the sprite border fix to work with RECTs, add some conditions
This commit is contained in:
@@ -78,6 +78,10 @@ static void RotateUV(TransformedVertex v[4]) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool ShouldApplySpriteBorderFix(const GPUgstate &gstate) {
|
||||
return gstate.isAlphaBlendEnabled() && gstate.getBlendFuncA() != GE_SRCBLEND_FIXA;
|
||||
}
|
||||
|
||||
// Clears on the PSP are best done by drawing a series of vertical strips
|
||||
// in clear mode. This tries to detect that.
|
||||
static bool IsReallyAClear(const TransformedVertex *transformed, int numVerts, float x2, float y2) {
|
||||
@@ -595,9 +599,6 @@ static void ClipTrianglesAgainstNearPlane(
|
||||
|
||||
// Note: This modifies the U/V coordinates of transformed.
|
||||
static void ApplySpriteBorderFixTriangles(TransformedVertex *transformed, const u16 *quad, float uScale, float vScale, float spriteBorderFix) {
|
||||
const float invUScale = 1.0f / uScale;
|
||||
const float invVScale = 1.0f / vScale;
|
||||
|
||||
// We have two triangles, but the vertex order can really be anything. We just need to find the shared edge, and then check the opposite vertices.
|
||||
|
||||
// sharedA and sharedB are indices into transformed, picked from the quad array.
|
||||
@@ -677,9 +678,14 @@ static void ApplySpriteBorderFixTriangles(TransformedVertex *transformed, const
|
||||
}
|
||||
}
|
||||
|
||||
const float invUScale = 1.0f / uScale;
|
||||
const float invVScale = 1.0f / vScale;
|
||||
if (validSprite) {
|
||||
// We have a valid sprite! Apply the border fix if needed.
|
||||
if (spriteBorderFix != 0.0f) {
|
||||
const bool topleft = spriteBorderFix < 0.0f;
|
||||
spriteBorderFix = fabsf(spriteBorderFix);
|
||||
|
||||
//spriteBorderFix *= 10.0f;
|
||||
const float uBorderFix = spriteBorderFix * invUScale;
|
||||
const float vBorderFix = spriteBorderFix * invVScale;
|
||||
@@ -693,24 +699,22 @@ static void ApplySpriteBorderFixTriangles(TransformedVertex *transformed, const
|
||||
if (du != 0.0f && fabsf(dx) != 480.0f) {
|
||||
const float uSign = (du > 0.0f ? 1.0f : -1.0f);
|
||||
const float uAmount = uBorderFix * uSign;
|
||||
const float xAmount = spriteBorderFix * uSign;
|
||||
// vSharedA.u += uAmount;
|
||||
// vCornerB.u += uAmount;
|
||||
if (topleft) {
|
||||
vSharedA.u += uAmount;
|
||||
vCornerB.u += uAmount;
|
||||
}
|
||||
vCornerA.u -= uAmount;
|
||||
vSharedB.u -= uAmount;
|
||||
vCornerA.x -= xAmount;
|
||||
vSharedB.x -= xAmount;
|
||||
}
|
||||
if (dv != 0.0f && fabsf(dy) != 272.0f) {
|
||||
const float vSign = (dv > 0.0f ? 1.0f : -1.0f);
|
||||
const float vAmount = vBorderFix * vSign;
|
||||
const float yAmount = spriteBorderFix * vSign;
|
||||
// vSharedA.v += vAmount;
|
||||
// vCornerA.v += vAmount;
|
||||
if (topleft) {
|
||||
vSharedA.v += vAmount;
|
||||
vCornerA.v += vAmount;
|
||||
}
|
||||
vCornerB.v -= vAmount;
|
||||
vSharedB.v -= vAmount;
|
||||
vCornerB.y -= yAmount;
|
||||
vSharedB.y -= yAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -835,15 +839,17 @@ static SoftwareTransformAction ProjectClipAndExpand(SoftwareTransformParams &par
|
||||
}
|
||||
|
||||
// Apply the sprite border fix, but only if pixel mapping was not detected!
|
||||
const float spriteBorderFix = PSP_CoreParameter().compat.flags().SpriteBorderFix; // if != 0.0, apply border fix.
|
||||
if (spriteBorderFix != 0.0f && flat) {
|
||||
// This assumes that we have a list of two-triangle sprites. If not the position checks will fail anyway.
|
||||
const u16 *indsIn = (const u16 *)inds;
|
||||
for (int t = 0; t < vertexCount - 5; t += 6) {
|
||||
// The previous triangle started three vertices ago. Now, let's do some disgustingly hacky checks,
|
||||
// to identify the type of sprite (if any) and move the UV coordinates inwards a bit.
|
||||
const u16 *quad = indsIn + t;
|
||||
ApplySpriteBorderFixTriangles(transformed, quad, uScale, vScale, spriteBorderFix);
|
||||
if (flat) {
|
||||
const float spriteBorderFix = ShouldApplySpriteBorderFix(gstate) ? PSP_CoreParameter().compat.flags().SpriteBorderFix : 0.0f; // if != 0.0, apply border fix.
|
||||
if (spriteBorderFix != 0.0f) {
|
||||
// This assumes that we have a list of two-triangle sprites. If not the position checks will fail anyway.
|
||||
const u16 *indsIn = (const u16 *)inds;
|
||||
for (int t = 0; t < vertexCount - 5; t += 6) {
|
||||
// The previous triangle started three vertices ago. Now, let's do some disgustingly hacky checks,
|
||||
// to identify the type of sprite (if any) and move the UV coordinates inwards a bit.
|
||||
const u16 *quad = indsIn + t;
|
||||
ApplySpriteBorderFixTriangles(transformed, quad, uScale, vScale, spriteBorderFix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1000,15 +1006,36 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
|
||||
|
||||
numDecodedVerts = 4 * (vertexCount / 2);
|
||||
|
||||
float uscale = 1.0f;
|
||||
float vscale = 1.0f;
|
||||
float uScale = 1.0f;
|
||||
float vScale = 1.0f;
|
||||
if (throughmode) {
|
||||
uscale /= gstate_c.curTextureWidth;
|
||||
vscale /= gstate_c.curTextureHeight;
|
||||
uScale /= gstate_c.curTextureWidth;
|
||||
vScale /= gstate_c.curTextureHeight;
|
||||
}
|
||||
|
||||
bool pixelMapped = g_Config.bSmart2DTexFiltering && !gstate_c.textureIsVideo;
|
||||
|
||||
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;
|
||||
} 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;
|
||||
} else if (spriteBorderFix > 0.0f) {
|
||||
spriteBorderFixL = 0.0f;
|
||||
spriteBorderFixR = (spriteBorderFix / uScale) / gstate_c.curTextureWidth;
|
||||
spriteBorderFixT = 0.0f;
|
||||
spriteBorderFixB = (spriteBorderFix / vScale) / gstate_c.curTextureHeight;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < vertexCount; i += 2) {
|
||||
const TransformedVertex &transVtxTL = transformed[indsIn[i + 0]];
|
||||
const TransformedVertex &transVtxBR = transformed[indsIn[i + 1]];
|
||||
@@ -1028,6 +1055,7 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
|
||||
|
||||
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...
|
||||
if (z > 65535.0f) {
|
||||
z = 65535.0f;
|
||||
} else if (z < 0.0f) {
|
||||
@@ -1039,33 +1067,34 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz
|
||||
|
||||
// bottom right
|
||||
trans[0] = transVtxBR;
|
||||
trans[0].u = transVtxBR.u * uscale;
|
||||
trans[0].v = transVtxBR.v * 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 * uscale;
|
||||
trans[1].v = transVtxTL.v * 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 * uscale;
|
||||
trans[2].v = transVtxTL.v * 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 * uscale;
|
||||
trans[3].v = transVtxBR.v * 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.
|
||||
// TODO: Should we apply the sprite border fix before or after rotation? Likely after, right?
|
||||
RotateUV(trans);
|
||||
|
||||
// Triangle: BR-TR-TL
|
||||
|
||||
@@ -695,7 +695,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() {
|
||||
|
||||
gstate_c.curTextureWidth = w;
|
||||
gstate_c.curTextureHeight = h;
|
||||
gstate_c.SetTextureIsVideo(false);
|
||||
gstate_c.SetTextureIsVideo((entry->status & TexCacheEntry::STATUS_VIDEO) != 0);
|
||||
gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0);
|
||||
gstate_c.SetTextureIsArray(false); // Ordinary 2D textures still aren't used by array view in VK. We probably might as well, though, at this point..
|
||||
gstate_c.SetTextureIsFramebuffer(false);
|
||||
|
||||
@@ -2090,6 +2090,9 @@ ULES00969 = true
|
||||
# NOTE: This is currently tuned only for GTA, but may work with some other games too with filtering
|
||||
# problems. 0.5 is half a texel, which seems to be enough to smooth everything out.
|
||||
|
||||
# NOTE: Negative values are interpreted as applying from both top, left, bottom and right,
|
||||
# while positive values only apply to bottom and right. Different games need different measures.
|
||||
|
||||
# Grand Theft Auto: Vice City Stories
|
||||
ULUS10160 = 0.5
|
||||
ULES00502 = 0.5
|
||||
@@ -2114,3 +2117,7 @@ ULUX80146 = 0.5
|
||||
ULUS01826 = 0.5
|
||||
# Seen in Liberty City (GTA LCS romhack)
|
||||
ULUS11826 = 0.5
|
||||
|
||||
# Tales of Destiny 2
|
||||
# Unfortunately, this affects game backgrounds negatively, although fixes lines in the menus.
|
||||
ULJS00097 = -0.25
|
||||
|
||||
Reference in New Issue
Block a user