blob: 75b1cf7090a791580738a6baf096b755a0381bf9 [file] [log] [blame]
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00007
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00008
9#include "SkTwoPointConicalGradient.h"
10
commit-bot@chromium.orgef93d292014-04-10 15:37:52 +000011#if SK_SUPPORT_GPU
egdaniel7ea439b2015-12-03 09:20:44 -080012#include "GrCoordTransform.h"
13#include "GrInvariantOutput.h"
joshualitt8ca93e72015-07-08 06:51:43 -070014#include "GrPaint.h"
egdaniel2d721d32015-11-11 13:06:05 -080015#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070016#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080017#include "glsl/GrGLSLUniformHandler.h"
brianosman9557c272016-09-15 06:59:15 -070018#include "SkTwoPointConicalGradient_gpu.h"
19
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000020// For brevity
egdaniel018fb622015-10-28 07:26:40 -070021typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000022
commit-bot@chromium.org80894672014-04-22 21:24:22 +000023static const SkScalar kErrorTol = 0.00001f;
egdaniel8405ef92014-06-09 11:57:28 -070024static const SkScalar kEdgeErrorTol = 5.f * kErrorTol;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000025
26/**
27 * We have three general cases for 2pt conical gradients. First we always assume that
28 * the start radius <= end radius. Our first case (kInside_) is when the start circle
29 * is completely enclosed by the end circle. The second case (kOutside_) is the case
30 * when the start circle is either completely outside the end circle or the circles
31 * overlap. The final case (kEdge_) is when the start circle is inside the end one,
32 * but the two are just barely touching at 1 point along their edges.
33 */
34enum ConicalType {
35 kInside_ConicalType,
36 kOutside_ConicalType,
37 kEdge_ConicalType,
38};
39
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000040//////////////////////////////////////////////////////////////////////////////
41
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000042static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader,
43 SkMatrix* invLMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000044 // Inverse of the current local matrix is passed in then,
45 // translate to center1, rotate so center2 is on x axis.
46 const SkPoint& center1 = shader.getStartCenter();
47 const SkPoint& center2 = shader.getEndCenter();
48
49 invLMatrix->postTranslate(-center1.fX, -center1.fY);
50
51 SkPoint diff = center2 - center1;
52 SkScalar diffLen = diff.length();
53 if (0 != diffLen) {
54 SkScalar invDiffLen = SkScalarInvert(diffLen);
55 SkMatrix rot;
56 rot.setSinCos(-SkScalarMul(invDiffLen, diff.fY),
57 SkScalarMul(invDiffLen, diff.fX));
58 invLMatrix->postConcat(rot);
59 }
60}
61
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000062class Edge2PtConicalEffect : public GrGradientEffect {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000063public:
fmenozzi55d318d2016-08-09 08:05:57 -070064 class GLSLEdge2PtConicalProcessor;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000065
brianosman9557c272016-09-15 06:59:15 -070066 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
67 return sk_sp<GrFragmentProcessor>(new Edge2PtConicalEffect(args));
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000068 }
69
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000070 virtual ~Edge2PtConicalEffect() {}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000071
mtklein36352bf2015-03-25 18:17:31 -070072 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -080073 return "Two-Point Conical Gradient Edge Touching";
74 }
75
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000076 // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000077 SkScalar center() const { return fCenterX1; }
78 SkScalar diffRadius() const { return fDiffRadius; }
79 SkScalar radius() const { return fRadius0; }
80
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000081private:
egdaniel57d3b032015-11-13 11:57:27 -080082 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -070083
Brian Salomon94efbf52016-11-29 13:43:05 -050084 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -070085
mtklein36352bf2015-03-25 18:17:31 -070086 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -070087 const Edge2PtConicalEffect& s = sBase.cast<Edge2PtConicalEffect>();
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000088 return (INHERITED::onIsEqual(sBase) &&
89 this->fCenterX1 == s.fCenterX1 &&
90 this->fRadius0 == s.fRadius0 &&
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000091 this->fDiffRadius == s.fDiffRadius);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000092 }
93
brianosman9557c272016-09-15 06:59:15 -070094 Edge2PtConicalEffect(const CreateArgs& args)
Brian Salomon587e08f2017-01-27 10:59:27 -050095 : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */) {
brianosman9557c272016-09-15 06:59:15 -070096 const SkTwoPointConicalGradient& shader =
97 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
98 fCenterX1 = shader.getCenterX1();
99 fRadius0 = shader.getStartRadius();
100 fDiffRadius = shader.getDiffRadius();
joshualitteb2a6762014-12-04 11:35:33 -0800101 this->initClassID<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000102 // We should only be calling this shader if we are degenerate case with touching circles
egdaniel8405ef92014-06-09 11:57:28 -0700103 // When deciding if we are in edge case, we scaled by the end radius for cases when the
joshualitt01258472014-09-22 10:29:30 -0700104 // start radius was close to zero, otherwise we scaled by the start radius. In addition
105 // Our test for the edge case in set_matrix_circle_conical has a higher tolerance so we
106 // need the sqrt value below
107 SkASSERT(SkScalarAbs(SkScalarAbs(fDiffRadius) - fCenterX1) <
108 (fRadius0 < kErrorTol ? shader.getEndRadius() * kEdgeErrorTol :
109 fRadius0 * sqrt(kEdgeErrorTol)));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000110
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000111 // We pass the linear part of the quadratic as a varying.
112 // float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
113 fBTransform = this->getCoordTransform();
114 SkMatrix& bMatrix = *fBTransform.accessMatrix();
115 SkScalar r0dr = SkScalarMul(fRadius0, fDiffRadius);
116 bMatrix[SkMatrix::kMScaleX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMScaleX]) +
117 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp0]));
118 bMatrix[SkMatrix::kMSkewX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMSkewX]) +
119 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp1]));
120 bMatrix[SkMatrix::kMTransX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMTransX]) +
121 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp2]));
122 this->addCoordTransform(&fBTransform);
123 }
124
joshualittb0a8a372014-09-23 09:50:21 -0700125 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000126
127 // @{
128 // Cache of values - these can change arbitrarily, EXCEPT
129 // we shouldn't change between degenerate and non-degenerate?!
130
131 GrCoordTransform fBTransform;
132 SkScalar fCenterX1;
133 SkScalar fRadius0;
134 SkScalar fDiffRadius;
135
136 // @}
137
138 typedef GrGradientEffect INHERITED;
139};
140
fmenozzi55d318d2016-08-09 08:05:57 -0700141class Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000142public:
fmenozzi55d318d2016-08-09 08:05:57 -0700143 GLSLEdge2PtConicalProcessor(const GrProcessor&);
144 virtual ~GLSLEdge2PtConicalProcessor() { }
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000145
wangyix7c157a92015-07-22 15:08:53 -0700146 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000147
Brian Salomon94efbf52016-11-29 13:43:05 -0500148 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000149
150protected:
egdaniel018fb622015-10-28 07:26:40 -0700151 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700152
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000153 UniformHandle fParamUni;
154
155 const char* fVSVaryingName;
156 const char* fFSVaryingName;
157
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000158 // @{
159 /// Values last uploaded as uniforms
160
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000161 SkScalar fCachedRadius;
162 SkScalar fCachedDiffRadius;
163
164 // @}
165
166private:
fmenozzi55d318d2016-08-09 08:05:57 -0700167 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000168
169};
170
Brian Salomon94efbf52016-11-29 13:43:05 -0500171void Edge2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800172 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700173 Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800174}
175
egdaniel57d3b032015-11-13 11:57:27 -0800176GrGLSLFragmentProcessor* Edge2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700177 return new Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor(*this);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000178}
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000179
joshualittb0a8a372014-09-23 09:50:21 -0700180GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Edge2PtConicalEffect);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000181
joshualitt01258472014-09-22 10:29:30 -0700182/*
183 * All Two point conical gradient test create functions may occasionally create edge case shaders
184 */
bungeman06ca8ec2016-06-09 08:01:03 -0700185sk_sp<GrFragmentProcessor> Edge2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700186 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
187 SkScalar radius1 = d->fRandom->nextUScalar1();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000188 SkPoint center2;
189 SkScalar radius2;
190 do {
joshualitt0067ff52015-07-08 14:26:19 -0700191 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000192 // If the circles are identical the factory will give us an empty shader.
193 // This will happen if we pick identical centers
194 } while (center1 == center2);
195
196 // Below makes sure that circle one is contained within circle two
197 // and both circles are touching on an edge
198 SkPoint diff = center2 - center1;
199 SkScalar diffLen = diff.length();
200 radius2 = radius1 + diffLen;
201
Brian Osman3f748602016-10-03 18:29:03 -0400202 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400203 auto shader = params.fUseColors4f ?
204 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
205 params.fColors4f, params.fColorSpace, params.fStops,
206 params.fColorCount, params.fTileMode) :
207 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
208 params.fColors, params.fStops,
209 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400210 GrTest::TestAsFPArgs asFPArgs(d);
211 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -0700212 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700213 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000214}
215
fmenozzi55d318d2016-08-09 08:05:57 -0700216Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GLSLEdge2PtConicalProcessor(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700217 : fVSVaryingName(nullptr)
218 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000219 , fCachedRadius(-SK_ScalarMax)
220 , fCachedDiffRadius(-SK_ScalarMax) {}
221
fmenozzi55d318d2016-08-09 08:05:57 -0700222void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700223 const Edge2PtConicalEffect& ge = args.fFp.cast<Edge2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800224 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
225 this->emitUniforms(uniformHandler, ge);
jvanverthde11ee42016-02-26 13:58:40 -0800226 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
227 kVec3f_GrSLType, kDefault_GrSLPrecision,
228 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000229
230 SkString cName("c");
231 SkString tName("t");
232 SkString p0; // start radius
233 SkString p1; // start radius squared
234 SkString p2; // difference in radii (r1 - r0)
235
jvanverthde11ee42016-02-26 13:58:40 -0800236
237 p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
238 p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
239 p2.appendf("%s.z", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000240
241 // We interpolate the linear component in coords[1].
bsalomon1a1aa932016-09-12 09:30:36 -0700242 SkASSERT(args.fTransformedCoords[0].getType() == args.fTransformedCoords[1].getType());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000243 const char* coords2D;
244 SkString bVar;
cdalton85285412016-02-18 12:37:07 -0800245 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700246 if (kVec3f_GrSLType == args.fTransformedCoords[0].getType()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800247 fragBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
bsalomon1a1aa932016-09-12 09:30:36 -0700248 args.fTransformedCoords[0].c_str(),
249 args.fTransformedCoords[0].c_str(),
250 args.fTransformedCoords[1].c_str(),
251 args.fTransformedCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000252 coords2D = "interpolants.xy";
253 bVar = "interpolants.z";
254 } else {
bsalomon1a1aa932016-09-12 09:30:36 -0700255 coords2D = args.fTransformedCoords[0].c_str();
256 bVar.printf("%s.x", args.fTransformedCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000257 }
258
259 // output will default to transparent black (we simply won't write anything
260 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -0800261 fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000262
263 // c = (x^2)+(y^2) - params[1]
egdaniel4ca2e602015-11-18 08:01:26 -0800264 fragBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000265 cName.c_str(), coords2D, coords2D, p1.c_str());
266
267 // linear case: t = -c/b
egdaniel4ca2e602015-11-18 08:01:26 -0800268 fragBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000269 cName.c_str(), bVar.c_str());
270
271 // if r(t) > 0, then t will be the x coordinate
egdaniel4ca2e602015-11-18 08:01:26 -0800272 fragBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000273 p2.c_str(), p0.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -0800274 fragBuilder->codeAppend("\t");
egdaniel7ea439b2015-12-03 09:20:44 -0800275 this->emitColor(fragBuilder,
276 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500277 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800278 ge,
279 tName.c_str(),
280 args.fOutputColor,
281 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700282 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -0800283 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000284}
285
fmenozzi55d318d2016-08-09 08:05:57 -0700286void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::onSetData(
287 const GrGLSLProgramDataManager& pdman,
288 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700289 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700290 const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000291 SkScalar radius0 = data.radius();
292 SkScalar diffRadius = data.diffRadius();
293
294 if (fCachedRadius != radius0 ||
295 fCachedDiffRadius != diffRadius) {
296
halcanary9d524f22016-03-29 09:03:52 -0700297 pdman.set3f(fParamUni, SkScalarToFloat(radius0),
jvanverthde11ee42016-02-26 13:58:40 -0800298 SkScalarToFloat(SkScalarMul(radius0, radius0)), SkScalarToFloat(diffRadius));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000299 fCachedRadius = radius0;
300 fCachedDiffRadius = diffRadius;
301 }
302}
303
fmenozzi55d318d2016-08-09 08:05:57 -0700304void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -0500305 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700306 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000307}
308
309//////////////////////////////////////////////////////////////////////////////
310// Focal Conical Gradients
311//////////////////////////////////////////////////////////////////////////////
312
313static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
314 SkMatrix* invLMatrix, SkScalar* focalX) {
315 // Inverse of the current local matrix is passed in then,
316 // translate, scale, and rotate such that endCircle is unit circle on x-axis,
317 // and focal point is at the origin.
318 ConicalType conicalType;
319 const SkPoint& focal = shader.getStartCenter();
320 const SkPoint& centerEnd = shader.getEndCenter();
321 SkScalar radius = shader.getEndRadius();
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000322 SkScalar invRadius = 1.f / radius;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000323
324 SkMatrix matrix;
325
326 matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
327 matrix.postScale(invRadius, invRadius);
328
329 SkPoint focalTrans;
330 matrix.mapPoints(&focalTrans, &focal, 1);
331 *focalX = focalTrans.length();
332
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000333 if (0.f != *focalX) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000334 SkScalar invFocalX = SkScalarInvert(*focalX);
335 SkMatrix rot;
336 rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY),
337 SkScalarMul(invFocalX, focalTrans.fX));
338 matrix.postConcat(rot);
339 }
340
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000341 matrix.postTranslate(-(*focalX), 0.f);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000342
343 // If the focal point is touching the edge of the circle it will
344 // cause a degenerate case that must be handled separately
egdaniel8405ef92014-06-09 11:57:28 -0700345 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
346 // stability trade off versus the linear approx used in the Edge Shader
347 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000348 return kEdge_ConicalType;
349 }
350
351 // Scale factor 1 / (1 - focalX * focalX)
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000352 SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX);
reed80ea19c2015-05-12 10:37:34 -0700353 SkScalar s = SkScalarInvert(oneMinusF2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000354
355
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000356 if (s >= 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000357 conicalType = kInside_ConicalType;
358 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
359 } else {
360 conicalType = kOutside_ConicalType;
361 matrix.postScale(s, s);
362 }
363
364 invLMatrix->postConcat(matrix);
365
366 return conicalType;
367}
368
369//////////////////////////////////////////////////////////////////////////////
370
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000371class FocalOutside2PtConicalEffect : public GrGradientEffect {
372public:
fmenozzi55d318d2016-08-09 08:05:57 -0700373 class GLSLFocalOutside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000374
brianosman9557c272016-09-15 06:59:15 -0700375 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
bungeman06ca8ec2016-06-09 08:01:03 -0700376 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700377 new FocalOutside2PtConicalEffect(args, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000378 }
379
380 virtual ~FocalOutside2PtConicalEffect() { }
381
mtklein36352bf2015-03-25 18:17:31 -0700382 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800383 return "Two-Point Conical Gradient Focal Outside";
384 }
385
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000386 bool isFlipped() const { return fIsFlipped; }
387 SkScalar focal() const { return fFocalX; }
388
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000389private:
egdaniel57d3b032015-11-13 11:57:27 -0800390 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700391
Brian Salomon94efbf52016-11-29 13:43:05 -0500392 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700393
mtklein36352bf2015-03-25 18:17:31 -0700394 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700395 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000396 return (INHERITED::onIsEqual(sBase) &&
397 this->fFocalX == s.fFocalX &&
398 this->fIsFlipped == s.fIsFlipped);
399 }
400
Brian Salomon587e08f2017-01-27 10:59:27 -0500401 static bool IsFlipped(const CreateArgs& args) {
402 // eww.
403 return static_cast<const SkTwoPointConicalGradient*>(args.fShader)->isFlippedGrad();
404 }
405
brianosman9557c272016-09-15 06:59:15 -0700406 FocalOutside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
Brian Salomon587e08f2017-01-27 10:59:27 -0500407 : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
408 , fFocalX(focalX)
409 , fIsFlipped(IsFlipped(args)) {
joshualitteb2a6762014-12-04 11:35:33 -0800410 this->initClassID<FocalOutside2PtConicalEffect>();
411 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000412
joshualittb0a8a372014-09-23 09:50:21 -0700413 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000414
415 SkScalar fFocalX;
416 bool fIsFlipped;
417
418 typedef GrGradientEffect INHERITED;
419};
420
Brian Salomon587e08f2017-01-27 10:59:27 -0500421class FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
fmenozzi55d318d2016-08-09 08:05:57 -0700422 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000423public:
fmenozzi55d318d2016-08-09 08:05:57 -0700424 GLSLFocalOutside2PtConicalProcessor(const GrProcessor&);
425 virtual ~GLSLFocalOutside2PtConicalProcessor() { }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000426
wangyix7c157a92015-07-22 15:08:53 -0700427 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000428
Brian Salomon94efbf52016-11-29 13:43:05 -0500429 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000430
431protected:
egdaniel018fb622015-10-28 07:26:40 -0700432 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700433
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000434 UniformHandle fParamUni;
435
436 const char* fVSVaryingName;
437 const char* fFSVaryingName;
438
439 bool fIsFlipped;
440
441 // @{
442 /// Values last uploaded as uniforms
443
444 SkScalar fCachedFocal;
445
446 // @}
447
448private:
fmenozzi55d318d2016-08-09 08:05:57 -0700449 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000450
451};
452
Brian Salomon94efbf52016-11-29 13:43:05 -0500453void FocalOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800454 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700455 FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800456}
457
egdaniel57d3b032015-11-13 11:57:27 -0800458GrGLSLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700459 return new FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000460}
461
joshualittb0a8a372014-09-23 09:50:21 -0700462GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000463
joshualitt01258472014-09-22 10:29:30 -0700464/*
465 * All Two point conical gradient test create functions may occasionally create edge case shaders
466 */
bungeman06ca8ec2016-06-09 08:01:03 -0700467sk_sp<GrFragmentProcessor> FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700468 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000469 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000470 SkPoint center2;
471 SkScalar radius2;
472 do {
joshualitt0067ff52015-07-08 14:26:19 -0700473 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000474 // Need to make sure the centers are not the same or else focal point will be inside
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000475 } while (center1 == center2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000476
Brian Osman3f748602016-10-03 18:29:03 -0400477 SkPoint diff = center2 - center1;
478 SkScalar diffLen = diff.length();
479 // Below makes sure that the focal point is not contained within circle two
480 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
481
482 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400483 auto shader = params.fUseColors4f ?
484 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
485 params.fColors4f, params.fColorSpace, params.fStops,
486 params.fColorCount, params.fTileMode) :
487 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
488 params.fColors, params.fStops,
489 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400490 GrTest::TestAsFPArgs asFPArgs(d);
491 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -0700492 GrAlwaysAssert(fp);
493 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000494}
495
fmenozzi55d318d2016-08-09 08:05:57 -0700496FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
497 ::GLSLFocalOutside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700498 : fVSVaryingName(nullptr)
499 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000500 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700501 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000502 fIsFlipped = data.isFlipped();
503}
504
fmenozzi55d318d2016-08-09 08:05:57 -0700505void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700506 const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800507 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
508 this->emitUniforms(uniformHandler, ge);
jvanverthde11ee42016-02-26 13:58:40 -0800509 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
510 kVec2f_GrSLType, kDefault_GrSLPrecision,
511 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000512 SkString tName("t");
513 SkString p0; // focalX
514 SkString p1; // 1 - focalX * focalX
515
jvanverthde11ee42016-02-26 13:58:40 -0800516 p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
517 p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000518
519 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800520 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700521 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000522 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000523
524 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
525
526 // output will default to transparent black (we simply won't write anything
527 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -0800528 fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000529
egdaniel4ca2e602015-11-18 08:01:26 -0800530 fragBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
531 fragBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
532 fragBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000533
534 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
535 // If so we must also flip sign on sqrt
536 if (!fIsFlipped) {
egdaniel4ca2e602015-11-18 08:01:26 -0800537 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
538 coords2D, p0.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000539 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800540 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
541 coords2D, p0.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000542 }
543
egdaniel4ca2e602015-11-18 08:01:26 -0800544 fragBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
545 fragBuilder->codeAppend("\t\t");
egdaniel7ea439b2015-12-03 09:20:44 -0800546 this->emitColor(fragBuilder,
547 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500548 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800549 ge,
550 tName.c_str(),
551 args.fOutputColor,
552 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700553 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -0800554 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000555}
556
fmenozzi55d318d2016-08-09 08:05:57 -0700557void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::onSetData(
558 const GrGLSLProgramDataManager& pdman,
559 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700560 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700561 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000562 SkASSERT(data.isFlipped() == fIsFlipped);
563 SkScalar focal = data.focal();
564
565 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000566 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000567
jvanverthde11ee42016-02-26 13:58:40 -0800568 pdman.set2f(fParamUni, SkScalarToFloat(focal), SkScalarToFloat(oneMinus2F));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000569 fCachedFocal = focal;
570 }
571}
572
fmenozzi55d318d2016-08-09 08:05:57 -0700573void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(
574 const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -0500575 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700576 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700577 key[0] = GenBaseGradientKey(processor);
578 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000579}
580
581//////////////////////////////////////////////////////////////////////////////
582
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000583class FocalInside2PtConicalEffect : public GrGradientEffect {
584public:
fmenozzi55d318d2016-08-09 08:05:57 -0700585 class GLSLFocalInside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000586
brianosman9557c272016-09-15 06:59:15 -0700587 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
bungeman06ca8ec2016-06-09 08:01:03 -0700588 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700589 new FocalInside2PtConicalEffect(args, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000590 }
591
592 virtual ~FocalInside2PtConicalEffect() {}
593
mtklein36352bf2015-03-25 18:17:31 -0700594 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800595 return "Two-Point Conical Gradient Focal Inside";
596 }
597
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000598 SkScalar focal() const { return fFocalX; }
599
fmenozzi55d318d2016-08-09 08:05:57 -0700600 typedef FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor GLSLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000601
602private:
egdaniel57d3b032015-11-13 11:57:27 -0800603 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700604
Brian Salomon94efbf52016-11-29 13:43:05 -0500605 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700606
mtklein36352bf2015-03-25 18:17:31 -0700607 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700608 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000609 return (INHERITED::onIsEqual(sBase) &&
610 this->fFocalX == s.fFocalX);
611 }
612
brianosman9557c272016-09-15 06:59:15 -0700613 FocalInside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
Brian Salomon587e08f2017-01-27 10:59:27 -0500614 : INHERITED(args, args.fShader->colorsAreOpaque()), fFocalX(focalX) {
joshualitteb2a6762014-12-04 11:35:33 -0800615 this->initClassID<FocalInside2PtConicalEffect>();
616 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000617
joshualittb0a8a372014-09-23 09:50:21 -0700618 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000619
620 SkScalar fFocalX;
621
622 typedef GrGradientEffect INHERITED;
623};
624
fmenozzi55d318d2016-08-09 08:05:57 -0700625class FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
626 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000627public:
fmenozzi55d318d2016-08-09 08:05:57 -0700628 GLSLFocalInside2PtConicalProcessor(const GrProcessor&);
629 virtual ~GLSLFocalInside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000630
wangyix7c157a92015-07-22 15:08:53 -0700631 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000632
Brian Salomon94efbf52016-11-29 13:43:05 -0500633 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000634
635protected:
egdaniel018fb622015-10-28 07:26:40 -0700636 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700637
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000638 UniformHandle fFocalUni;
639
640 const char* fVSVaryingName;
641 const char* fFSVaryingName;
642
643 // @{
644 /// Values last uploaded as uniforms
645
646 SkScalar fCachedFocal;
647
648 // @}
649
650private:
fmenozzi55d318d2016-08-09 08:05:57 -0700651 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000652
653};
654
Brian Salomon94efbf52016-11-29 13:43:05 -0500655void FocalInside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800656 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700657 FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800658}
659
egdaniel57d3b032015-11-13 11:57:27 -0800660GrGLSLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700661 return new FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000662}
663
joshualittb0a8a372014-09-23 09:50:21 -0700664GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000665
joshualitt01258472014-09-22 10:29:30 -0700666/*
667 * All Two point conical gradient test create functions may occasionally create edge case shaders
668 */
bungeman06ca8ec2016-06-09 08:01:03 -0700669sk_sp<GrFragmentProcessor> FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700670 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000671 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000672 SkPoint center2;
673 SkScalar radius2;
674 do {
joshualitt0067ff52015-07-08 14:26:19 -0700675 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000676 // Below makes sure radius2 is larger enouch such that the focal point
677 // is inside the end circle
joshualitt0067ff52015-07-08 14:26:19 -0700678 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000679 SkPoint diff = center2 - center1;
680 SkScalar diffLen = diff.length();
681 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000682 // If the circles are identical the factory will give us an empty shader.
683 } while (radius1 == radius2 && center1 == center2);
684
Brian Osman3f748602016-10-03 18:29:03 -0400685 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400686 auto shader = params.fUseColors4f ?
687 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
688 params.fColors4f, params.fColorSpace, params.fStops,
689 params.fColorCount, params.fTileMode) :
690 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
691 params.fColors, params.fStops,
692 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400693 GrTest::TestAsFPArgs asFPArgs(d);
694 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -0700695 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700696 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000697}
698
fmenozzi55d318d2016-08-09 08:05:57 -0700699FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
700 ::GLSLFocalInside2PtConicalProcessor(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700701 : fVSVaryingName(nullptr)
702 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000703 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000704
fmenozzi55d318d2016-08-09 08:05:57 -0700705void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700706 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800707 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
708 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800709 fFocalUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800710 kFloat_GrSLType, kDefault_GrSLPrecision,
711 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000712 SkString tName("t");
713
714 // this is the distance along x-axis from the end center to focal point in
715 // transformed coordinates
Brian Salomon99938a82016-11-21 13:41:08 -0500716 GrShaderVar focal = uniformHandler->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000717
718 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800719 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700720 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000721 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000722
723 // t = p.x * focalX + length(p)
egdaniel4ca2e602015-11-18 08:01:26 -0800724 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
egdaniel7ea439b2015-12-03 09:20:44 -0800725 coords2D, focal.c_str(), coords2D);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000726
egdaniel7ea439b2015-12-03 09:20:44 -0800727 this->emitColor(fragBuilder,
728 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500729 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800730 ge,
731 tName.c_str(),
732 args.fOutputColor,
733 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700734 args.fTexSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000735}
736
fmenozzi55d318d2016-08-09 08:05:57 -0700737void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::onSetData(
738 const GrGLSLProgramDataManager& pdman,
739 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700740 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700741 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000742 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000743
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000744 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700745 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000746 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000747 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000748}
749
fmenozzi55d318d2016-08-09 08:05:57 -0700750void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(
751 const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -0500752 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700753 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000754}
755
756//////////////////////////////////////////////////////////////////////////////
757// Circle Conical Gradients
758//////////////////////////////////////////////////////////////////////////////
759
760struct CircleConicalInfo {
761 SkPoint fCenterEnd;
762 SkScalar fA;
763 SkScalar fB;
764 SkScalar fC;
765};
766
767// Returns focal distance along x-axis in transformed coords
768static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
769 SkMatrix* invLMatrix, CircleConicalInfo* info) {
770 // Inverse of the current local matrix is passed in then,
771 // translate and scale such that start circle is on the origin and has radius 1
772 const SkPoint& centerStart = shader.getStartCenter();
773 const SkPoint& centerEnd = shader.getEndCenter();
774 SkScalar radiusStart = shader.getStartRadius();
775 SkScalar radiusEnd = shader.getEndRadius();
776
777 SkMatrix matrix;
778
779 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
780
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000781 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000782 matrix.postScale(invStartRad, invStartRad);
783
784 radiusEnd /= radiusStart;
785
786 SkPoint centerEndTrans;
787 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
788
789 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
790 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
791
792 // Check to see if start circle is inside end circle with edges touching.
793 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700794 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
795 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
796 // still accurate.
797 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000798 return kEdge_ConicalType;
799 }
800
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000801 SkScalar C = 1.f / A;
802 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000803
804 matrix.postScale(C, C);
805
806 invLMatrix->postConcat(matrix);
807
808 info->fCenterEnd = centerEndTrans;
809 info->fA = A;
810 info->fB = B;
811 info->fC = C;
812
813 // if A ends up being negative, the start circle is contained completely inside the end cirlce
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000814 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000815 return kInside_ConicalType;
816 }
817 return kOutside_ConicalType;
818}
819
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000820class CircleInside2PtConicalEffect : public GrGradientEffect {
821public:
fmenozzi55d318d2016-08-09 08:05:57 -0700822 class GLSLCircleInside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000823
brianosman9557c272016-09-15 06:59:15 -0700824 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
bungeman06ca8ec2016-06-09 08:01:03 -0700825 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700826 new CircleInside2PtConicalEffect(args, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000827 }
828
829 virtual ~CircleInside2PtConicalEffect() {}
830
mtklein36352bf2015-03-25 18:17:31 -0700831 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800832
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000833 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
834 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
835 SkScalar A() const { return fInfo.fA; }
836 SkScalar B() const { return fInfo.fB; }
837 SkScalar C() const { return fInfo.fC; }
838
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000839private:
egdaniel57d3b032015-11-13 11:57:27 -0800840 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700841
Brian Salomon94efbf52016-11-29 13:43:05 -0500842 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800843 GrProcessorKeyBuilder* b) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700844
mtklein36352bf2015-03-25 18:17:31 -0700845 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700846 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000847 return (INHERITED::onIsEqual(sBase) &&
848 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
849 this->fInfo.fA == s.fInfo.fA &&
850 this->fInfo.fB == s.fInfo.fB &&
851 this->fInfo.fC == s.fInfo.fC);
852 }
853
brianosman9557c272016-09-15 06:59:15 -0700854 CircleInside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
Brian Salomon587e08f2017-01-27 10:59:27 -0500855 : INHERITED(args, args.fShader->colorsAreOpaque()), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800856 this->initClassID<CircleInside2PtConicalEffect>();
857 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000858
joshualittb0a8a372014-09-23 09:50:21 -0700859 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000860
861 const CircleConicalInfo fInfo;
862
863 typedef GrGradientEffect INHERITED;
864};
865
fmenozzi55d318d2016-08-09 08:05:57 -0700866class CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
867 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000868public:
fmenozzi55d318d2016-08-09 08:05:57 -0700869 GLSLCircleInside2PtConicalProcessor(const GrProcessor&);
870 virtual ~GLSLCircleInside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000871
wangyix7c157a92015-07-22 15:08:53 -0700872 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000873
Brian Salomon94efbf52016-11-29 13:43:05 -0500874 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000875
876protected:
egdaniel018fb622015-10-28 07:26:40 -0700877 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700878
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000879 UniformHandle fCenterUni;
880 UniformHandle fParamUni;
881
882 const char* fVSVaryingName;
883 const char* fFSVaryingName;
884
885 // @{
886 /// Values last uploaded as uniforms
887
888 SkScalar fCachedCenterX;
889 SkScalar fCachedCenterY;
890 SkScalar fCachedA;
891 SkScalar fCachedB;
892 SkScalar fCachedC;
893
894 // @}
895
896private:
fmenozzi55d318d2016-08-09 08:05:57 -0700897 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000898
899};
900
Brian Salomon94efbf52016-11-29 13:43:05 -0500901void CircleInside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800902 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700903 CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800904}
905
egdaniel57d3b032015-11-13 11:57:27 -0800906GrGLSLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700907 return new CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000908}
909
joshualittb0a8a372014-09-23 09:50:21 -0700910GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000911
joshualitt01258472014-09-22 10:29:30 -0700912/*
913 * All Two point conical gradient test create functions may occasionally create edge case shaders
914 */
bungeman06ca8ec2016-06-09 08:01:03 -0700915sk_sp<GrFragmentProcessor> CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700916 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
917 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000918 SkPoint center2;
919 SkScalar radius2;
920 do {
joshualitt0067ff52015-07-08 14:26:19 -0700921 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000922 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700923 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000924 SkPoint diff = center2 - center1;
925 SkScalar diffLen = diff.length();
926 radius2 = radius1 + diffLen + increase;
927 // If the circles are identical the factory will give us an empty shader.
928 } while (radius1 == radius2 && center1 == center2);
929
Brian Osman3f748602016-10-03 18:29:03 -0400930 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400931 auto shader = params.fUseColors4f ?
932 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
933 params.fColors4f, params.fColorSpace, params.fStops,
934 params.fColorCount, params.fTileMode) :
935 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
936 params.fColors, params.fStops,
937 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400938 GrTest::TestAsFPArgs asFPArgs(d);
939 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -0700940 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -0700941 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000942}
943
fmenozzi55d318d2016-08-09 08:05:57 -0700944CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
945 ::GLSLCircleInside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700946 : fVSVaryingName(nullptr)
947 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000948 , fCachedCenterX(SK_ScalarMax)
949 , fCachedCenterY(SK_ScalarMax)
950 , fCachedA(SK_ScalarMax)
951 , fCachedB(SK_ScalarMax)
952 , fCachedC(SK_ScalarMax) {}
953
fmenozzi55d318d2016-08-09 08:05:57 -0700954void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700955 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800956 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
957 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800958 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800959 kVec2f_GrSLType, kDefault_GrSLPrecision,
960 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -0800961 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800962 kVec3f_GrSLType, kDefault_GrSLPrecision,
963 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000964 SkString tName("t");
965
Brian Salomon99938a82016-11-21 13:41:08 -0500966 GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000967 // params.x = A
968 // params.y = B
969 // params.z = C
Brian Salomon99938a82016-11-21 13:41:08 -0500970 GrShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000971
972 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800973 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700974 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000975 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000976
977 // p = coords2D
978 // e = center end
979 // r = radius end
980 // A = dot(e, e) - r^2 + 2 * r - 1
981 // B = (r -1) / A
982 // C = 1 / A
983 // d = dot(e, p) + B
984 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
egdaniel4ca2e602015-11-18 08:01:26 -0800985 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
986 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
987 params.c_str());
988 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
989 tName.c_str(), params.c_str(), params.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000990
egdaniel7ea439b2015-12-03 09:20:44 -0800991 this->emitColor(fragBuilder,
992 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500993 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800994 ge,
995 tName.c_str(),
996 args.fOutputColor,
997 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700998 args.fTexSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000999}
1000
fmenozzi55d318d2016-08-09 08:05:57 -07001001void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::onSetData(
1002 const GrGLSLProgramDataManager& pdman,
1003 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001004 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001005 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001006 SkScalar centerX = data.centerX();
1007 SkScalar centerY = data.centerY();
1008 SkScalar A = data.A();
1009 SkScalar B = data.B();
1010 SkScalar C = data.C();
1011
1012 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1013 fCachedA != A || fCachedB != B || fCachedC != C) {
1014
kkinnunen7510b222014-07-30 00:04:16 -07001015 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1016 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001017
1018 fCachedCenterX = centerX;
1019 fCachedCenterY = centerY;
1020 fCachedA = A;
1021 fCachedB = B;
1022 fCachedC = C;
1023 }
1024}
1025
fmenozzi55d318d2016-08-09 08:05:57 -07001026void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(
1027 const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -05001028 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001029 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001030}
1031
1032//////////////////////////////////////////////////////////////////////////////
1033
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001034class CircleOutside2PtConicalEffect : public GrGradientEffect {
1035public:
fmenozzi55d318d2016-08-09 08:05:57 -07001036 class GLSLCircleOutside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001037
brianosman9557c272016-09-15 06:59:15 -07001038 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
bungeman06ca8ec2016-06-09 08:01:03 -07001039 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -07001040 new CircleOutside2PtConicalEffect(args, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001041 }
1042
1043 virtual ~CircleOutside2PtConicalEffect() {}
1044
mtklein36352bf2015-03-25 18:17:31 -07001045 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001046
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001047 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1048 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1049 SkScalar A() const { return fInfo.fA; }
1050 SkScalar B() const { return fInfo.fB; }
1051 SkScalar C() const { return fInfo.fC; }
1052 SkScalar tLimit() const { return fTLimit; }
1053 bool isFlipped() const { return fIsFlipped; }
1054
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001055private:
egdaniel57d3b032015-11-13 11:57:27 -08001056 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -07001057
Brian Salomon94efbf52016-11-29 13:43:05 -05001058 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -07001059
mtklein36352bf2015-03-25 18:17:31 -07001060 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001061 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001062 return (INHERITED::onIsEqual(sBase) &&
1063 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1064 this->fInfo.fA == s.fInfo.fA &&
1065 this->fInfo.fB == s.fInfo.fB &&
1066 this->fInfo.fC == s.fInfo.fC &&
1067 this->fTLimit == s.fTLimit &&
1068 this->fIsFlipped == s.fIsFlipped);
1069 }
1070
brianosman9557c272016-09-15 06:59:15 -07001071 CircleOutside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
Brian Salomon587e08f2017-01-27 10:59:27 -05001072 : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
1073 , fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001074 this->initClassID<CircleOutside2PtConicalEffect>();
brianosman9557c272016-09-15 06:59:15 -07001075 const SkTwoPointConicalGradient& shader =
1076 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001077 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001078 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001079 } else {
1080 fTLimit = SK_ScalarMin;
1081 }
1082
1083 fIsFlipped = shader.isFlippedGrad();
1084 }
1085
joshualittb0a8a372014-09-23 09:50:21 -07001086 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001087
1088 const CircleConicalInfo fInfo;
1089 SkScalar fTLimit;
1090 bool fIsFlipped;
1091
1092 typedef GrGradientEffect INHERITED;
1093};
1094
fmenozzi55d318d2016-08-09 08:05:57 -07001095class CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
1096 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001097public:
fmenozzi55d318d2016-08-09 08:05:57 -07001098 GLSLCircleOutside2PtConicalProcessor(const GrProcessor&);
1099 virtual ~GLSLCircleOutside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001100
wangyix7c157a92015-07-22 15:08:53 -07001101 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001102
Brian Salomon94efbf52016-11-29 13:43:05 -05001103 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001104
1105protected:
egdaniel018fb622015-10-28 07:26:40 -07001106 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001107
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001108 UniformHandle fCenterUni;
1109 UniformHandle fParamUni;
1110
1111 const char* fVSVaryingName;
1112 const char* fFSVaryingName;
1113
1114 bool fIsFlipped;
1115
1116 // @{
1117 /// Values last uploaded as uniforms
1118
1119 SkScalar fCachedCenterX;
1120 SkScalar fCachedCenterY;
1121 SkScalar fCachedA;
1122 SkScalar fCachedB;
1123 SkScalar fCachedC;
1124 SkScalar fCachedTLimit;
1125
1126 // @}
1127
1128private:
fmenozzi55d318d2016-08-09 08:05:57 -07001129 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001130
1131};
1132
Brian Salomon94efbf52016-11-29 13:43:05 -05001133void CircleOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -08001134 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -07001135 CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -08001136}
1137
egdaniel57d3b032015-11-13 11:57:27 -08001138GrGLSLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -07001139 return new CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001140}
1141
joshualittb0a8a372014-09-23 09:50:21 -07001142GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001143
joshualitt01258472014-09-22 10:29:30 -07001144/*
1145 * All Two point conical gradient test create functions may occasionally create edge case shaders
1146 */
bungeman06ca8ec2016-06-09 08:01:03 -07001147sk_sp<GrFragmentProcessor> CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001148 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1149 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001150 SkPoint center2;
1151 SkScalar radius2;
1152 SkScalar diffLen;
1153 do {
joshualitt0067ff52015-07-08 14:26:19 -07001154 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001155 // If the circles share a center than we can't be in the outside case
1156 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001157 SkPoint diff = center2 - center1;
1158 diffLen = diff.length();
1159 // Below makes sure that circle one is not contained within circle two
1160 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001161 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001162
Brian Osman3f748602016-10-03 18:29:03 -04001163 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -04001164 auto shader = params.fUseColors4f ?
1165 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
1166 params.fColors4f, params.fColorSpace, params.fStops,
1167 params.fColorCount, params.fTileMode) :
1168 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
1169 params.fColors, params.fStops,
1170 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -04001171 GrTest::TestAsFPArgs asFPArgs(d);
1172 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -07001173 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -07001174 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001175}
1176
fmenozzi55d318d2016-08-09 08:05:57 -07001177CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
1178 ::GLSLCircleOutside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -07001179 : fVSVaryingName(nullptr)
1180 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001181 , fCachedCenterX(SK_ScalarMax)
1182 , fCachedCenterY(SK_ScalarMax)
1183 , fCachedA(SK_ScalarMax)
1184 , fCachedB(SK_ScalarMax)
1185 , fCachedC(SK_ScalarMax)
1186 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001187 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001188 fIsFlipped = data.isFlipped();
1189 }
1190
fmenozzi55d318d2016-08-09 08:05:57 -07001191void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -07001192 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -08001193 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1194 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -08001195 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001196 kVec2f_GrSLType, kDefault_GrSLPrecision,
1197 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -08001198 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001199 kVec4f_GrSLType, kDefault_GrSLPrecision,
1200 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001201 SkString tName("t");
1202
Brian Salomon99938a82016-11-21 13:41:08 -05001203 GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001204 // params.x = A
1205 // params.y = B
1206 // params.z = C
Brian Salomon99938a82016-11-21 13:41:08 -05001207 GrShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001208
1209 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -08001210 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -07001211 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001212 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001213
1214 // output will default to transparent black (we simply won't write anything
1215 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -08001216 fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001217
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001218 // p = coords2D
1219 // e = center end
1220 // r = radius end
1221 // A = dot(e, e) - r^2 + 2 * r - 1
1222 // B = (r -1) / A
1223 // C = 1 / A
1224 // d = dot(e, p) + B
1225 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001226
egdaniel4ca2e602015-11-18 08:01:26 -08001227 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
1228 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1229 params.c_str());
1230 fragBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1231 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001232
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001233 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1234 // If so we must also flip sign on sqrt
1235 if (!fIsFlipped) {
egdaniel4ca2e602015-11-18 08:01:26 -08001236 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001237 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001238 fragBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001239 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001240
egdaniel7ea439b2015-12-03 09:20:44 -08001241 fragBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n",
1242 tName.c_str(), params.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001243 fragBuilder->codeAppend("\t\t");
egdaniel7ea439b2015-12-03 09:20:44 -08001244 this->emitColor(fragBuilder,
1245 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -05001246 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -08001247 ge,
1248 tName.c_str(),
1249 args.fOutputColor,
1250 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -07001251 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -08001252 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001253}
1254
fmenozzi55d318d2016-08-09 08:05:57 -07001255void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::onSetData(
1256 const GrGLSLProgramDataManager& pdman,
egdaniel018fb622015-10-28 07:26:40 -07001257 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001258 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001259 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001260 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001261 SkScalar centerX = data.centerX();
1262 SkScalar centerY = data.centerY();
1263 SkScalar A = data.A();
1264 SkScalar B = data.B();
1265 SkScalar C = data.C();
1266 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001267
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001268 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1269 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001270
kkinnunen7510b222014-07-30 00:04:16 -07001271 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1272 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001273 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001274
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001275 fCachedCenterX = centerX;
1276 fCachedCenterY = centerY;
1277 fCachedA = A;
1278 fCachedB = B;
1279 fCachedC = C;
1280 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001281 }
1282}
1283
fmenozzi55d318d2016-08-09 08:05:57 -07001284void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(
1285 const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -05001286 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001287 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001288 key[0] = GenBaseGradientKey(processor);
1289 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001290}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001291
1292//////////////////////////////////////////////////////////////////////////////
1293
brianosman9557c272016-09-15 06:59:15 -07001294sk_sp<GrFragmentProcessor> Gr2PtConicalGradientEffect::Make(
1295 const GrGradientEffect::CreateArgs& args) {
1296 const SkTwoPointConicalGradient& shader =
1297 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
1298
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001299 SkMatrix matrix;
1300 if (!shader.getLocalMatrix().invert(&matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001301 return nullptr;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001302 }
brianosman9557c272016-09-15 06:59:15 -07001303 if (args.fMatrix) {
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001304 SkMatrix inv;
brianosman9557c272016-09-15 06:59:15 -07001305 if (!args.fMatrix->invert(&inv)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001306 return nullptr;
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001307 }
1308 matrix.postConcat(inv);
1309 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001310
brianosmanb9c51372016-09-15 11:09:45 -07001311 GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fTileMode,
1312 std::move(args.fColorSpaceXform), args.fGammaCorrect);
brianosman9557c272016-09-15 06:59:15 -07001313
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001314 if (shader.getStartRadius() < kErrorTol) {
1315 SkScalar focalX;
1316 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1317 if (type == kInside_ConicalType) {
brianosman9557c272016-09-15 06:59:15 -07001318 return FocalInside2PtConicalEffect::Make(newArgs, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001319 } else if(type == kEdge_ConicalType) {
1320 set_matrix_edge_conical(shader, &matrix);
brianosman9557c272016-09-15 06:59:15 -07001321 return Edge2PtConicalEffect::Make(newArgs);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001322 } else {
brianosman9557c272016-09-15 06:59:15 -07001323 return FocalOutside2PtConicalEffect::Make(newArgs, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001324 }
1325 }
1326
1327 CircleConicalInfo info;
1328 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1329
1330 if (type == kInside_ConicalType) {
brianosman9557c272016-09-15 06:59:15 -07001331 return CircleInside2PtConicalEffect::Make(newArgs, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001332 } else if (type == kEdge_ConicalType) {
1333 set_matrix_edge_conical(shader, &matrix);
brianosman9557c272016-09-15 06:59:15 -07001334 return Edge2PtConicalEffect::Make(newArgs);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001335 } else {
brianosman9557c272016-09-15 06:59:15 -07001336 return CircleOutside2PtConicalEffect::Make(newArgs, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001337 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001338}
1339
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001340#endif