| Index: src/effects/SkRRectsGaussianEdgeShader.cpp
|
| diff --git a/src/effects/SkRRectsGaussianEdgeShader.cpp b/src/effects/SkRRectsGaussianEdgeShader.cpp
|
| index d3967dbb4434b55e41cce3367b75bd4d75967f30..02e46fb8746808f894b6235f84482dfbe044f234 100644
|
| --- a/src/effects/SkRRectsGaussianEdgeShader.cpp
|
| +++ b/src/effects/SkRRectsGaussianEdgeShader.cpp
|
| @@ -104,31 +104,34 @@ public:
|
| public:
|
| GLSLRRectsGaussianEdgeFP() { }
|
|
|
| + // This method emits code so that, for each shape, the distance from the edge is returned
|
| + // in 'outputName' clamped to 0..1 with positive distance being towards the center of the
|
| + // shape. The distance will have been normalized by the radius.
|
| void emitModeCode(Mode mode,
|
| GrGLSLFPFragmentBuilder* fragBuilder,
|
| const char* posName,
|
| const char* sizesName,
|
| const char* radiiName,
|
| + const char* padRadName,
|
| const char* outputName,
|
| const char indices[2]) { // how to access the params for the 2 rrects
|
|
|
| // positive distance is towards the center of the circle
|
| fragBuilder->codeAppendf("vec2 delta = %s.xy - %s.%s;",
|
| - fragBuilder->fragmentPosition(),
|
| - posName, indices);
|
| + fragBuilder->fragmentPosition(), posName, indices);
|
|
|
| switch (mode) {
|
| case kCircle_Mode:
|
| - fragBuilder->codeAppendf("%s = %s.%c - length(delta);",
|
| - outputName,
|
| - sizesName, indices[0]);
|
| + fragBuilder->codeAppendf("%s = clamp((%s.%c - length(delta))/%s.y, 0.0, 1.0);",
|
| + outputName, sizesName, indices[0], padRadName);
|
| break;
|
| case kRect_Mode:
|
| - fragBuilder->codeAppendf("float xDist = %s.%c - abs(delta.x);",
|
| - sizesName, indices[0]);
|
| - fragBuilder->codeAppendf("float yDist = %s.%c - abs(delta.y);",
|
| - sizesName, indices[1]);
|
| - fragBuilder->codeAppendf("%s = min(xDist, yDist);", outputName);
|
| + fragBuilder->codeAppendf(
|
| + "vec2 rectDist = vec2(1.0 - clamp((%s.%c - abs(delta.x))/%s.y, 0.0, 1.0),"
|
| + "1.0 - clamp((%s.%c - abs(delta.y))/%s.y, 0.0, 1.0));",
|
| + sizesName, indices[0], padRadName,
|
| + sizesName, indices[1], padRadName);
|
| + fragBuilder->codeAppendf("%s = 1.0 - length(rectDist);", outputName);
|
| break;
|
| case kSimpleCircular_Mode:
|
| // For the circular round rect we first compute the distance
|
| @@ -136,28 +139,28 @@ public:
|
| // point is in one of the circular corners. We then compute the
|
| // distance from the corner and then use the multiplier to mask
|
| // between the two distances.
|
| - fragBuilder->codeAppendf("float xDist = %s.%c - abs(delta.x);",
|
| - sizesName, indices[0]);
|
| - fragBuilder->codeAppendf("float yDist = %s.%c - abs(delta.y);",
|
| - sizesName, indices[1]);
|
| + fragBuilder->codeAppendf("float xDist = clamp((%s.%c - abs(delta.x))/%s.y,"
|
| + " 0.0, 1.0);",
|
| + sizesName, indices[0], padRadName);
|
| + fragBuilder->codeAppendf("float yDist = clamp((%s.%c - abs(delta.y))/%s.y,"
|
| + "0.0, 1.0);",
|
| + sizesName, indices[1], padRadName);
|
| fragBuilder->codeAppend("float rectDist = min(xDist, yDist);");
|
|
|
| fragBuilder->codeAppendf("vec2 cornerCenter = %s.%s - %s.%s;",
|
| - sizesName, indices,
|
| - radiiName, indices);
|
| + sizesName, indices, radiiName, indices);
|
| fragBuilder->codeAppend("delta = vec2(abs(delta.x) - cornerCenter.x,"
|
| "abs(delta.y) - cornerCenter.y);");
|
| - fragBuilder->codeAppendf("xDist = %s.%c - abs(delta.x);",
|
| - radiiName, indices[0]);
|
| - fragBuilder->codeAppendf("yDist = %s.%c - abs(delta.y);",
|
| - radiiName, indices[1]);
|
| + fragBuilder->codeAppendf("xDist = %s.%c - abs(delta.x);", radiiName, indices[0]);
|
| + fragBuilder->codeAppendf("yDist = %s.%c - abs(delta.y);", radiiName, indices[1]);
|
| fragBuilder->codeAppend("float cornerDist = min(xDist, yDist);");
|
| fragBuilder->codeAppend("float multiplier = step(0.0, cornerDist);");
|
|
|
| fragBuilder->codeAppendf("delta += %s.%s;", radiiName, indices);
|
|
|
| - fragBuilder->codeAppendf("cornerDist = 2.0 * %s.%c - length(delta);",
|
| - radiiName, indices[0]);
|
| + fragBuilder->codeAppendf("cornerDist = clamp((2.0 * %s.%c - length(delta))/%s.y,"
|
| + "0.0, 1.0);",
|
| + radiiName, indices[0], padRadName);
|
|
|
| fragBuilder->codeAppendf("%s = (multiplier * cornerDist) +"
|
| "((1.0-multiplier) * rectDist);",
|
| @@ -180,9 +183,11 @@ public:
|
| kVec4f_GrSLType, kDefault_GrSLPrecision,
|
| "Sizes", &sizesUniName);
|
| const char* radiiUniName = nullptr;
|
| - fRadiiUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
| - kVec4f_GrSLType, kDefault_GrSLPrecision,
|
| - "Radii", &radiiUniName);
|
| + if (fp.fFirstMode == kSimpleCircular_Mode || fp.fSecondMode == kSimpleCircular_Mode) {
|
| + fRadiiUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
| + kVec4f_GrSLType, kDefault_GrSLPrecision,
|
| + "Radii", &radiiUniName);
|
| + }
|
| const char* padRadUniName = nullptr;
|
| fPadRadUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
| kVec2f_GrSLType, kDefault_GrSLPrecision,
|
| @@ -191,25 +196,22 @@ public:
|
| fragBuilder->codeAppend("float firstDist;");
|
| fragBuilder->codeAppend("{");
|
| this->emitModeCode(fp.firstMode(), fragBuilder,
|
| - positionsUniName, sizesUniName, radiiUniName, "firstDist", "xy");
|
| + positionsUniName, sizesUniName, radiiUniName,
|
| + padRadUniName, "firstDist", "xy");
|
| fragBuilder->codeAppend("}");
|
|
|
| fragBuilder->codeAppend("float secondDist;");
|
| fragBuilder->codeAppend("{");
|
| this->emitModeCode(fp.secondMode(), fragBuilder,
|
| - positionsUniName, sizesUniName, radiiUniName, "secondDist", "zw");
|
| + positionsUniName, sizesUniName, radiiUniName,
|
| + padRadUniName, "secondDist", "zw");
|
| fragBuilder->codeAppend("}");
|
|
|
| - // Here use the sign of the distance to the two round rects to mask off the different
|
| - // cases.
|
| - fragBuilder->codeAppend("float in1 = step(0.0f, firstDist);");
|
| - fragBuilder->codeAppend("float in2 = step(0.0f, secondDist);");
|
| - fragBuilder->codeAppend("float dist = "
|
| - "in1*in2 * min(firstDist, secondDist);"
|
| - "in1*(1.0-in2) * firstDist +"
|
| - "(1.0-in1)*in2 * secondDist;");
|
| + fragBuilder->codeAppendf("float dist = %s.y * firstDist * secondDist;",
|
| + padRadUniName);
|
|
|
| // Finally use the distance to apply the Gaussian edge
|
| + // TODO: we undo the multiply by the radius here - we should just skip both
|
| fragBuilder->codeAppendf("float factor = 1.0 - clamp((dist - %s.x)/%s.y, 0.0, 1.0);",
|
| padRadUniName, padRadUniName);
|
| fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
|
| @@ -243,13 +245,16 @@ public:
|
| 0.5f * second.rect().width(),
|
| 0.5f * second.rect().height());
|
|
|
| - // This is a bit of overkill since fX should equal fY for both round rects but it
|
| - // makes the shader code simpler.
|
| - pdman.set4f(fRadiiUni,
|
| - 0.5f * first.getSimpleRadii().fX,
|
| - 0.5f * first.getSimpleRadii().fY,
|
| - 0.5f * second.getSimpleRadii().fX,
|
| - 0.5f * second.getSimpleRadii().fY);
|
| + if (edgeFP.firstMode() == kSimpleCircular_Mode ||
|
| + edgeFP.secondMode() == kSimpleCircular_Mode) {
|
| + // This is a bit of overkill since fX should equal fY for both round rects but it
|
| + // makes the shader code simpler.
|
| + pdman.set4f(fRadiiUni,
|
| + 0.5f * first.getSimpleRadii().fX,
|
| + 0.5f * first.getSimpleRadii().fY,
|
| + 0.5f * second.getSimpleRadii().fX,
|
| + 0.5f * second.getSimpleRadii().fY);
|
| + }
|
|
|
| pdman.set2f(fPadRadUni, edgeFP.pad(), edgeFP.radius());
|
| }
|
|
|