aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar dvonbeck <dvonbeck@google.com>2016-08-04 12:27:26 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-04 12:27:26 -0700
commit1b9e2fb49415d8dc41e449bee5f8ebec6f616d71 (patch)
treec274561302ff92df2970e4c207e52c9044d126f2
parentb8d1aac87a6e3821c7ed435a17a550e6e87d2044 (diff)
This CL's base is the CL that sets up the distance vector field req. exposure: https://codereview.chromium.org/2114993002/
-rw-r--r--src/core/SkNormalBevelSource.cpp190
1 files changed, 165 insertions, 25 deletions
diff --git a/src/core/SkNormalBevelSource.cpp b/src/core/SkNormalBevelSource.cpp
index a63e434c3f..04faa0006f 100644
--- a/src/core/SkNormalBevelSource.cpp
+++ b/src/core/SkNormalBevelSource.cpp
@@ -19,12 +19,20 @@
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "SkGr.h"
+/** \class NormalBevelFP
+ *
+ * Fragment processor for the SkNormalBevelSource.
+ *
+ * @param bevelType type of the bevel
+ * @param bevelWidth width of the bevel in device space
+ * @param bevelHeight height of the bevel in device space
+ */
class NormalBevelFP : public GrFragmentProcessor {
public:
- NormalBevelFP(SkNormalSource::BevelType type, SkScalar width, SkScalar height)
- : fType(type)
- , fWidth(width)
- , fHeight(height) {
+ NormalBevelFP(SkNormalSource::BevelType bevelType, SkScalar bevelWidth, SkScalar bevelHeight)
+ : fBevelType(bevelType)
+ , fBevelWidth(bevelWidth)
+ , fBevelHeight(bevelHeight) {
this->initClassID<NormalBevelFP>();
fUsesDistanceVectorField = true;
@@ -39,23 +47,68 @@ public:
void onEmitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+ const NormalBevelFP& fp = args.fFp.cast<NormalBevelFP>();
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
- const char* widthUniName = nullptr;
- fWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
- kDefault_GrSLPrecision, "Width", &widthUniName);
+ // Determining necessary uniforms and initializing them
+ bool needWidth = true;
+ bool needHeight = (fp.fBevelType == SkNormalSource::BevelType::kRoundedOut ||
+ fp.fBevelType == SkNormalSource::BevelType::kRoundedIn);
+ bool needNormalized = (fp.fBevelType == SkNormalSource::BevelType::kLinear);
+
+ const char *widthUniName = nullptr;
+ if (needWidth) {
+ fWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
+ kDefault_GrSLPrecision, "Width",
+ &widthUniName);
+ }
const char* heightUniName = nullptr;
- fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
- kDefault_GrSLPrecision, "Height", &heightUniName);
+ if (needHeight) {
+ fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
+ kDefault_GrSLPrecision, "Height",
+ &heightUniName);
+ }
- fragBuilder->codeAppendf("%s = vec4(0.0, 0.0, 1.0, 0.0);", args.fOutputColor);
+ const char* normalizedWidthUniName = nullptr;
+ const char* normalizedHeightUniName = nullptr;
+ if (needNormalized) {
+ fNormalizedWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
+ kFloat_GrSLType,
+ kDefault_GrSLPrecision,
+ "NormalizedWidth",
+ &normalizedWidthUniName);
+ fNormalizedHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
+ kFloat_GrSLType,
+ kDefault_GrSLPrecision,
+ "NormalizedHeight",
+ &normalizedHeightUniName);
+ }
+
+ // Here we are splitting the distance vector into length and normalized direction
+ // TODO: Output these values from the geometry processor frag code instead of the vector
+ fragBuilder->codeAppendf("float dv_length = length(%s);",
+ fragBuilder->distanceVectorName());
+ fragBuilder->codeAppendf("vec2 dv_norm = normalize(%s);",
+ fragBuilder->distanceVectorName());
+
+ // Asserting presence of necessary uniforms
+ SkASSERT(widthUniName);
+
+ fragBuilder->codeAppend( "vec3 normal;");
+ fragBuilder->codeAppendf("if (dv_length >= %s) {", widthUniName);
+ fragBuilder->codeAppend( " normal = vec3(0.0, 0.0, 1.0);");
+ fragBuilder->codeAppend( "} else {");
+ this->emitMath(fragBuilder, fp.fBevelType, widthUniName, heightUniName,
+ normalizedWidthUniName, normalizedHeightUniName);
+ fragBuilder->codeAppend( "}");
+ fragBuilder->codeAppendf("%s = vec4(normal, 0.0);", args.fOutputColor);
}
static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
GrProcessorKeyBuilder* b) {
const NormalBevelFP& fp = proc.cast<NormalBevelFP>();
- b->add32(static_cast<int>(fp.fType));
+ b->add32(static_cast<int>(fp.fBevelType));
}
protected:
@@ -63,13 +116,92 @@ public:
const GrProcessor& proc) override {
const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>();
- if (fPrevWidth != normalBevelFP.fWidth) {
- pdman.set1f(fWidthUni, normalBevelFP.fWidth);
- fPrevWidth = normalBevelFP.fWidth;
+ // Updating uniform if bevel type requires it and data has changed
+
+ bool needWidth = true;
+ bool needHeight = (normalBevelFP.fBevelType == SkNormalSource::BevelType::kRoundedOut ||
+ normalBevelFP.fBevelType == SkNormalSource::BevelType::kRoundedIn);
+ bool needNormalized = (normalBevelFP.fBevelType == SkNormalSource::BevelType::kLinear);
+
+ bool dirtyWidth = (fPrevWidth != normalBevelFP.fBevelWidth);
+ bool dirtyHeight = (fPrevHeight != normalBevelFP.fBevelHeight);
+ bool dirtyNormalized = (dirtyHeight || dirtyWidth);
+
+
+ if (needWidth && dirtyWidth) {
+ pdman.set1f(fWidthUni, normalBevelFP.fBevelWidth);
+ fPrevWidth = normalBevelFP.fBevelWidth;
}
- if (fPrevHeight != normalBevelFP.fHeight) {
- pdman.set1f(fHeightUni, normalBevelFP.fHeight);
- fPrevHeight = normalBevelFP.fHeight;
+ if (needHeight && dirtyHeight) {
+ pdman.set1f(fHeightUni, normalBevelFP.fBevelHeight);
+ fPrevHeight = normalBevelFP.fBevelHeight;
+ }
+ if (needNormalized && dirtyNormalized) {
+ SkScalar height = normalBevelFP.fBevelHeight;
+ SkScalar width = normalBevelFP.fBevelWidth;
+
+ SkScalar length = SkScalarSqrt(SkScalarSquare(height) + SkScalarSquare(width));
+ pdman.set1f(fNormalizedHeightUni, height/length);
+ pdman.set1f(fNormalizedWidthUni, width/length);
+ }
+ }
+
+ // This method emits the code that calculates the normal orthgonal to the simulated beveled
+ // surface. In the comments inside the function, the math involved is described. For this
+ // purpose, the d-axis is defined to be the axis co-linear to the distance vector, where the
+ // origin is the end of the bevel inside the shape.
+ void emitMath(GrGLSLFPFragmentBuilder* fb, SkNormalSource::BevelType type,
+ const char* width, const char* height, const char* normalizedWidth,
+ const char* normalizedHeight) {
+ switch (type) {
+ case SkNormalSource::BevelType::kLinear:
+ // Asserting presence of necessary uniforms
+ SkASSERT(normalizedHeight);
+ SkASSERT(normalizedWidth);
+
+ // Because the slope of the bevel is -height/width, the vector
+ // normalized(vec2(height, width)) is the d- and z-components of the normal
+ // vector that is orthogonal to the linear bevel. Multiplying the d-component
+ // to the normalized distance vector splits it into x- and y-components.
+ fb->codeAppendf("normal = vec3(%s * dv_norm, %s);",
+ normalizedHeight, normalizedWidth);
+ break;
+ case SkNormalSource::BevelType::kRoundedOut:
+ // Fall through
+ case SkNormalSource::BevelType::kRoundedIn:
+ // Asserting presence of necessary uniforms
+ SkASSERT(height);
+ SkASSERT(width);
+
+ // Setting the current position in the d-axis to the distance from the end of
+ // the bevel as opposed to the beginning if the bevel is rounded in, essentially
+ // flipping the bevel calculations.
+ if ( type == SkNormalSource::BevelType::kRoundedIn ) {
+ fb->codeAppendf("float currentPos_d = %s - dv_length;", width);
+ } else if (type == SkNormalSource::BevelType::kRoundedOut) {
+ fb->codeAppendf("float currentPos_d = dv_length;");
+ }
+
+ fb->codeAppendf("float rootDOverW = sqrt(currentPos_d/%s);", width);
+
+ // Calculating the d- and z-components of the normal, where 'd' is the axis
+ // co-linear to the distance vector. Equation was derived from the formula for
+ // a bezier curve by solving the parametric equation for d(t) and z(t), then
+ // with those, calculate d'(t), z'(t) and t(d), and from these, d'(d) and z'(d).
+ // z'(d)/d'(d) results in the slope of the bevel at d, so we construct an
+ // orthogonal vector of slope -d'(d)/z'(d) and length 1.
+ fb->codeAppendf("vec2 unnormalizedNormal_dz = vec2(%s*(1.0-rootDOverW), "
+ "%s*rootDOverW);",
+ height, width);
+ fb->codeAppendf("vec2 normal_dz = normalize(unnormalizedNormal_dz);");
+
+ // Multiplying the d-component to the normalized distance vector splits it into
+ // x- and y-components.
+ fb->codeAppendf("normal = vec3(normal_dz.x*dv_norm, normal_dz.y);");
+
+ break;
+ default:
+ SkDEBUGFAIL("Invalid bevel type passed to emitMath");
}
}
@@ -79,6 +211,11 @@ public:
SkScalar fPrevHeight;
GrGLSLProgramDataManager::UniformHandle fHeightUni;
+
+ // width / length(<width,height>)
+ GrGLSLProgramDataManager::UniformHandle fNormalizedWidthUni;
+ // height / length(<width,height>)
+ GrGLSLProgramDataManager::UniformHandle fNormalizedHeightUni;
};
void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
@@ -96,20 +233,23 @@ private:
bool onIsEqual(const GrFragmentProcessor& proc) const override {
const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>();
- return fType == normalBevelFP.fType &&
- fWidth == normalBevelFP.fWidth &&
- fHeight == normalBevelFP.fHeight;
+ return fBevelType == normalBevelFP.fBevelType &&
+ fBevelWidth == normalBevelFP.fBevelWidth &&
+ fBevelHeight == normalBevelFP.fBevelHeight;
}
- SkNormalSource::BevelType fType;
- SkScalar fWidth;
- SkScalar fHeight;
+ SkNormalSource::BevelType fBevelType;
+ SkScalar fBevelWidth;
+ SkScalar fBevelHeight;
};
sk_sp<GrFragmentProcessor> SkNormalBevelSourceImpl::asFragmentProcessor(
- const SkShader::AsFPArgs&) const {
+ const SkShader::AsFPArgs& args) const {
+
+ SkScalar maxScale = args.fViewMatrix->getMaxScale();
- return sk_make_sp<NormalBevelFP>(fType, fWidth, fHeight);
+ // Providing device-space width and height
+ return sk_make_sp<NormalBevelFP>(fType, maxScale * fWidth, maxScale * fHeight);
}
#endif // SK_SUPPORT_GPU