Index: src/core/SkXfermode.cpp |
=================================================================== |
--- src/core/SkXfermode.cpp (revision 8796) |
+++ src/core/SkXfermode.cpp (working copy) |
@@ -955,7 +955,7 @@ |
class XferEffect : public GrEffect { |
public: |
static bool IsSupportedMode(SkXfermode::Mode mode) { |
- return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastSeparableMode; |
+ return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode; |
} |
static GrEffectRef* Create(SkXfermode::Mode mode) { |
@@ -1000,11 +1000,14 @@ |
inputColor = "ones"; |
} |
+ SkXfermode::Mode mode = drawEffect.castEffect<XferEffect>().mode(); |
+ builder->fsCodeAppendf("\t\t// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode)); |
+ |
// These all perform src-over on the alpha channel. |
builder->fsCodeAppendf("\t\t%s.a = %s.a + (1.0 - %s.a) * %s.a;\n", |
outputColor, inputColor, inputColor, dstColor); |
- switch (drawEffect.castEffect<XferEffect>().mode()) { |
+ switch (mode) { |
case SkXfermode::kOverlay_Mode: |
// Overlay is Hard-Light with the src and dst reversed |
HardLight(builder, outputColor, dstColor, inputColor); |
@@ -1063,12 +1066,52 @@ |
outputColor, inputColor, dstColor, dstColor, inputColor, |
inputColor, dstColor); |
break; |
- case SkXfermode::kHue_Mode: |
- case SkXfermode::kSaturation_Mode: |
- case SkXfermode::kColor_Mode: |
- case SkXfermode::kLuminosity_Mode: |
- GrCrash("Unimplemented XferEffect mode."); |
+ case SkXfermode::kHue_Mode: { |
+ // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S |
+ SkString setSat, setLum; |
+ AddSatFunction(builder, &setSat); |
+ AddLumFunction(builder, &setLum); |
robertphillips
2013/04/22 15:46:31
\n before dstColor?
bsalomon
2013/04/22 17:36:17
Done.
|
+ builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n", dstColor, inputColor); |
+ builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb), dstSrcAlpha.a, dstSrcAlpha.rgb);\n", |
robertphillips
2013/04/22 15:46:31
\n before inputColor?
bsalomon
2013/04/22 17:36:17
Done.
|
+ outputColor, setLum.c_str(), setSat.c_str(), inputColor, dstColor); |
+ builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n", |
+ outputColor, inputColor, dstColor, dstColor, inputColor); |
break; |
+ } |
+ case SkXfermode::kSaturation_Mode: { |
+ // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S |
+ SkString setSat, setLum; |
+ AddSatFunction(builder, &setSat); |
+ AddLumFunction(builder, &setLum); |
robertphillips
2013/04/22 15:46:31
\n
bsalomon
2013/04/22 17:36:17
Done.
|
+ builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n", dstColor, inputColor); |
+ builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a), dstSrcAlpha.a, dstSrcAlpha.rgb);\n", |
robertphillips
2013/04/22 15:46:31
/n
bsalomon
2013/04/22 17:36:17
Done.
|
+ outputColor, setLum.c_str(), setSat.c_str(), inputColor, dstColor); |
+ builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n", |
+ outputColor, inputColor, dstColor, dstColor, inputColor); |
+ break; |
+ } |
+ case SkXfermode::kColor_Mode: { |
+ // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S |
+ SkString setLum; |
+ AddLumFunction(builder, &setLum); |
robertphillips
2013/04/22 15:46:31
\n
bsalomon
2013/04/22 17:36:17
Done.
|
+ builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n", inputColor, dstColor); |
+ builder->fsCodeAppendf("\t\t%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);\n", |
+ outputColor, setLum.c_str(), dstColor, inputColor); |
+ builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n", |
+ outputColor, inputColor, dstColor, dstColor, inputColor); |
+ break; |
+ } |
+ case SkXfermode::kLuminosity_Mode: { |
+ // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S |
+ SkString setLum; |
+ AddLumFunction(builder, &setLum); |
robertphillips
2013/04/22 15:46:31
\n
bsalomon
2013/04/22 17:36:17
Done.
|
+ builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n", inputColor, dstColor); |
+ builder->fsCodeAppendf("\t\t%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);\n", |
+ outputColor, setLum.c_str(), dstColor, inputColor); |
+ builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n", |
+ outputColor, inputColor, dstColor, dstColor, inputColor); |
+ break; |
+ } |
default: |
GrCrash("Unknown XferEffect mode."); |
break; |
@@ -1178,6 +1221,132 @@ |
builder->fsCodeAppendf("\t\t\t}\n"); |
} |
robertphillips
2013/04/22 15:46:31
It also emits "luminance" method
bsalomon
2013/04/22 17:36:17
But it doesn't return the name of it, so it isn't
|
+ // Adds a function that takes two colors and an alpha as input. It produces a color with the |
+ // hue and saturation of the first color, the luminosity of the second color, and the input |
+ // alpha. It has this signature: |
+ // vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor). |
+ static void AddLumFunction(GrGLShaderBuilder* builder, SkString* setLumFunction) { |
+ SkString getFunction; |
robertphillips
2013/04/22 15:46:31
Is the indent right after this {?
bsalomon
2013/04/22 17:36:17
I removed the blocks.
|
+ { |
robertphillips
2013/04/22 15:46:31
one line?
bsalomon
2013/04/22 17:36:17
Done.
|
+ GrGLShaderVar args[] = { |
+ GrGLShaderVar("color", kVec3f_GrSLType), |
+ }; |
+ SkString body("\treturn dot(vec3(0.3, 0.59, 0.11), color);\n"); |
+ builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, |
+ kFloat_GrSLType, |
+ "luminance", |
+ SK_ARRAY_COUNT(args), args, |
+ body.c_str(), |
+ &getFunction); |
+ } |
+ |
+ { |
+ GrGLShaderVar args[] = { |
+ GrGLShaderVar("hueSat", kVec3f_GrSLType), |
+ GrGLShaderVar("alpha", kFloat_GrSLType), |
+ GrGLShaderVar("lumColor", kVec3f_GrSLType), |
+ }; |
+ SkString body; |
+ body.printf("\tfloat diff = %s(lumColor - hueSat);\n", getFunction.c_str()); |
+ body.append("\tvec3 outColor = hueSat + diff;\n"); |
+ body.appendf("\tfloat outLum = %s(outColor);\n", getFunction.c_str()); |
robertphillips
2013/04/22 15:46:31
Is this code happy with black?
bsalomon
2013/04/22 17:36:17
yup
|
+ body.append("\tfloat minComp = min(min(outColor.r, outColor.g), outColor.b);\n" |
+ "\tfloat maxComp = max(max(outColor.r, outColor.g), outColor.b);\n" |
+ "\tif (minComp < 0.0) {\n" |
+ "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) / (outLum - minComp);\n" |
+ "\t}\n" |
+ "\tif (maxComp > alpha) {\n" |
+ "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) / (maxComp - outLum);\n" |
+ "\t}\n" |
+ "\treturn outColor;\n"); |
+ builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, |
+ kVec3f_GrSLType, |
+ "set_luminance", |
+ SK_ARRAY_COUNT(args), args, |
+ body.c_str(), |
+ setLumFunction); |
+ } |
+ } |
+ |
robertphillips
2013/04/22 15:46:31
functions that create?
bsalomon
2013/04/22 17:36:17
Changed to "Adds a function that creates"
|
+ // Adds functions that creates a color with the hue and luminosity of one input color and |
+ // the saturation of another color. It will have this signature: |
+ // float set_saturation(vec3 hueLumColor, vec3 satColor) |
+ static void AddSatFunction(GrGLShaderBuilder* builder, SkString* setSatFunction) { |
+ SkString getFunction; |
robertphillips
2013/04/22 15:46:31
// emit 'saturation' function?
bsalomon
2013/04/22 17:36:17
Done.
|
+ { |
+ GrGLShaderVar args[] = { |
+ GrGLShaderVar("color", kVec3f_GrSLType), |
+ }; |
+ SkString body; |
+ body.appendf("\treturn max(max(color.r, color.g), color.b) - " |
+ "min(min(color.r, color.g), color.b);\n"); |
+ builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, |
+ kFloat_GrSLType, |
+ "saturation", |
+ SK_ARRAY_COUNT(args), args, |
+ body.c_str(), |
+ &getFunction); |
+ } |
+ |
+ SkString helper; |
robertphillips
2013/04/22 15:46:31
emit "set_saturation_helper" method?
bsalomon
2013/04/22 17:36:17
Done.
|
+ { |
+ GrGLShaderVar args[] = { |
+ GrGLShaderVar("minComp", kFloat_GrSLType), |
+ GrGLShaderVar("midComp", kFloat_GrSLType), |
+ GrGLShaderVar("maxComp", kFloat_GrSLType), |
+ GrGLShaderVar("sat", kFloat_GrSLType), |
+ }; |
+ args[0].setTypeModifier(GrGLShaderVar::kInOut_TypeModifier); |
+ args[1].setTypeModifier(GrGLShaderVar::kInOut_TypeModifier); |
+ args[2].setTypeModifier(GrGLShaderVar::kInOut_TypeModifier); |
+ SkString body; |
+ body.append("\tif (minComp < maxComp) {\n" |
+ "\t\tmidComp = sat * (midComp - minComp) / (maxComp - minComp);\n" |
+ "\t\tmaxComp = sat;\n" |
+ "\t} else {\n" |
+ "\t\tmidComp = midComp = 0.0;\n" |
+ "\t}\n" |
+ "\tminComp = 0.0;\n"); |
+ builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, |
+ kVoid_GrSLType, |
+ "set_saturation_helper", |
+ SK_ARRAY_COUNT(args), args, |
+ body.c_str(), |
+ &helper); |
+ } |
+ { |
+ GrGLShaderVar args[] = { |
+ GrGLShaderVar("hueLumColor", kVec3f_GrSLType), |
+ GrGLShaderVar("satColor", kVec3f_GrSLType), |
+ }; |
+ SkString body; |
+ const char* helpFunc = helper.c_str(); |
+ body.appendf("\tfloat sat = %s(satColor);\n" |
+ "\tif (hueLumColor.r <= hueLumColor.g) {\n" |
+ "\t\tif (hueLumColor.g <= hueLumColor.b) {\n" |
+ "\t\t\t%s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);\n" |
+ "\t\t} else {\n" |
+ "\t\t\t%s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);\n" |
+ "\t\t}\n" |
+ "\t} else if (hueLumColor.r <= hueLumColor.b) {\n" |
+ "\t\t%s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);\n" |
+ "\t} else if (hueLumColor.g <= hueLumColor.b) {\n" |
+ "\t\t%s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);\n" |
+ "\t} else {\n" |
+ "\t\t%s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);\n" |
+ "\t}\n" |
+ "\treturn hueLumColor;", |
+ getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc, helpFunc); |
+ builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType, |
+ kVec3f_GrSLType, |
+ "set_saturation", |
+ SK_ARRAY_COUNT(args), args, |
+ body.c_str(), |
+ setSatFunction); |
+ } |
+ |
+ } |
+ |
typedef GrGLEffect INHERITED; |
}; |