Chromium Code Reviews| Index: src/core/SkNormalBevelSource.cpp |
| diff --git a/src/core/SkNormalBevelSource.cpp b/src/core/SkNormalBevelSource.cpp |
| index a63e434c3fb1fe7f01162735d8ac7ebbd11dc330..75c5bf6c4a1de7c9af251098c79e11b7253022a5 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,6 +47,7 @@ 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; |
| @@ -49,13 +58,26 @@ public: |
| 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); |
| + // 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()); |
| + |
| + 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); |
| + 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 +85,53 @@ public: |
| const GrProcessor& proc) override { |
| const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>(); |
| - if (fPrevWidth != normalBevelFP.fWidth) { |
| - pdman.set1f(fWidthUni, normalBevelFP.fWidth); |
| - fPrevWidth = normalBevelFP.fWidth; |
| + if (fPrevWidth != normalBevelFP.fBevelWidth) { |
| + pdman.set1f(fWidthUni, normalBevelFP.fBevelWidth); |
| + fPrevWidth = normalBevelFP.fBevelWidth; |
| + } |
| + if (fPrevHeight != normalBevelFP.fBevelHeight) { |
| + pdman.set1f(fHeightUni, normalBevelFP.fBevelHeight); |
| + fPrevHeight = normalBevelFP.fBevelHeight; |
| + } |
| + } |
| + |
| + void emitMath(GrGLSLFPFragmentBuilder* fb, SkNormalSource::BevelType type, |
| + const char* width, const char* height) { |
| + const char* distanceVector = fb->distanceVectorName(); |
| + |
| + // Setting t to the distance from the end of the bevel as opposed to the beginning if |
| + // the bevel is rounded in. |
| + if ( type == SkNormalSource::BevelType::kRoundedIn ) { |
|
egdaniel
2016/08/04 03:08:17
this should be inside roundOut/In section right?
dvonbeck
2016/08/04 17:57:25
I guess it makes more sense over there. Done.
|
| + fb->codeAppendf("float t = %s - dv_length;", width); |
| + } else if (type == SkNormalSource::BevelType::kRoundedOut) { |
| + fb->codeAppendf("float t = dv_length;"); |
| } |
| - if (fPrevHeight != normalBevelFP.fHeight) { |
| - pdman.set1f(fHeightUni, normalBevelFP.fHeight); |
| - fPrevHeight = normalBevelFP.fHeight; |
| + |
| + switch (type) { |
| + case SkNormalSource::BevelType::kLinear: |
| + fb->codeAppendf("normal = normalize(%s*vec3(%s, 0.0) + vec3(0.0, 0.0, %s));", |
|
egdaniel
2016/08/04 03:08:17
I don't think this is correct. Without going into
dvonbeck
2016/08/04 17:57:25
Done.
|
| + height, distanceVector, width); |
| + break; |
| + case SkNormalSource::BevelType::kRoundedOut: |
| + // Fall through |
| + case SkNormalSource::BevelType::kRoundedIn: |
| + fb->codeAppendf("float rootTOverW = sqrt(t/%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. |
| + fb->codeAppendf("vec2 unnormalizedNormal_dz = vec2(%s*(1.0-rootTOverW), " |
|
egdaniel
2016/08/04 03:08:17
just trying to confirm in my head, since we multip
dvonbeck
2016/08/04 17:57:25
Yes. I think it's more that my math explicitly bui
|
| + "%s*rootTOverW);", |
| + height, width); |
| + fb->codeAppendf("vec2 normal_dz = normalize(unnormalizedNormal_dz);"); |
| + |
| + // Multiplying the d-component of the normal with the normalized distance vector |
| + // splitting it in 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"); |
| } |
| } |
| @@ -96,20 +158,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 |