Rethink 2x src alpha->color doubling. Fixes #3379.

This commit is contained in:
Henrik Rydgard 2014-03-29 11:37:45 +01:00
parent 04bcbfb9a3
commit 47efded29f

View File

@ -234,33 +234,14 @@ static bool IsColorTestTriviallyTrue() {
}
}
static bool CanDoubleSrcBlendMode() {
static bool AlphaToColorDoubling() {
if (!gstate.isAlphaBlendEnabled()) {
return false;
}
int funcA = gstate.getBlendFuncA();
int funcB = gstate.getBlendFuncB();
if (funcA != GE_SRCBLEND_DOUBLESRCALPHA) {
funcB = funcA;
funcA = gstate.getBlendFuncB();
}
if (funcA != GE_SRCBLEND_DOUBLESRCALPHA) {
return false;
}
// One side should be doubled. Let's check the other side.
// LittleBigPlanet, for example, uses 2.0 * src, 1.0 - src, which can't double.
// Persona 2 uses the same function, which is the reason for its darkness. It only ever passes
// 1.0 as src alpha though, so in effect it's a color doubling.
switch (funcB) {
case GE_DSTBLEND_SRCALPHA:
case GE_DSTBLEND_INVSRCALPHA:
return false;
default:
return true;
}
// 2x alpha in the source function = source color doubling.
// We don't really need to care about the dest alpha function - sure we can't handle
// the doubling dest ones, but there's nothing we can do about that.
return (gstate.getBlendFuncA() == GE_SRCBLEND_DOUBLESRCALPHA);
}
// Here we must take all the bits of the gstate that determine what the fragment shader will
@ -275,9 +256,8 @@ void ComputeFragmentShaderID(FragmentShaderID *id) {
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough();
bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue() && !g_Config.bDisableAlphaTest;
bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue();
bool enableColorDoubling = gstate.isColorDoublingEnabled();
bool enableColorDoubling = gstate.isColorDoublingEnabled() || AlphaToColorDoubling();
// This isn't really correct, but it's a hack to get doubled blend modes to work more correctly.
bool enableAlphaDoubling = CanDoubleSrcBlendMode();
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
bool doTextureAlpha = gstate.isTextureAlphaUsed();
ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil();
@ -303,7 +283,6 @@ void ComputeFragmentShaderID(FragmentShaderID *id) {
id->d[0] |= (enableFog & 1) << 15;
id->d[0] |= (doTextureProjection & 1) << 16;
id->d[0] |= (enableColorDoubling & 1) << 17;
id->d[0] |= (enableAlphaDoubling & 1) << 18;
id->d[0] |= (stencilToAlpha) << 19;
if (stencilToAlpha != REPLACE_ALPHA_NO) {
@ -381,9 +360,12 @@ void GenerateFragmentShader(char *buffer) {
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue() && !gstate.isModeClear() && !g_Config.bDisableAlphaTest;
bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue() && !gstate.isModeClear();
bool enableColorDoubling = gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled();
// If alpha doubling is enabled, we double the color value instead. Otherwise alpha 255 doubled will have no effect.
// TODO: Why the texturemapenabled check?
bool enableColorDoubling = (gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled()) || AlphaToColorDoubling();
// This isn't really correct, but it's a hack to get doubled blend modes to work more correctly.
bool enableAlphaDoubling = CanDoubleSrcBlendMode();
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
bool doTextureAlpha = gstate.isTextureAlphaUsed();
ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil();
@ -547,12 +529,8 @@ void GenerateFragmentShader(char *buffer) {
}
// Color doubling happens after the color test.
if (enableColorDoubling && enableAlphaDoubling) {
WRITE(p, " v = v * 2.0;\n");
} else if (enableColorDoubling) {
if (enableColorDoubling) {
WRITE(p, " v.rgb = v.rgb * 2.0;\n");
} else if (enableAlphaDoubling) {
WRITE(p, " v.a = v.a * 2.0;\n");
}
if (enableFog) {