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 |