blob: 00d8fac73ff9098f3c0b2fa65d335e03f25277fd [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
egdaniel57d3b032015-11-13 11:57:27 -080084 void onGetGLSLProcessorKey(const GrGLSLCaps&, 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)
95 : INHERITED(args) {
96 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
jvanverthcfc18862015-04-28 08:48:20 -0700148 static void GenKey(const GrProcessor&, const GrGLSLCaps& 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
egdaniel57d3b032015-11-13 11:57:27 -0800171void Edge2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
172 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);
reed8a21c9f2016-03-08 18:50:00 -0800203 auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
Brian Osman3f748602016-10-03 18:29:03 -0400204 params.fColors, params.fStops,
205 params.fColorCount, params.fTileMode);
brianosman839345d2016-07-22 11:04:53 -0700206 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
Brian Osman0d9dfe92016-10-03 15:24:44 -0400207 auto dstColorSpace = GrTest::TestColorSpace(d->fRandom);
brianosman839345d2016-07-22 11:04:53 -0700208 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(SkShader::AsFPArgs(
Brian Osman0d9dfe92016-10-03 15:24:44 -0400209 d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(),
brianosman1638c0d2016-07-25 05:12:53 -0700210 SkSourceGammaTreatment::kRespect));
bsalomonc21b09e2015-08-28 18:46:56 -0700211 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700212 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000213}
214
fmenozzi55d318d2016-08-09 08:05:57 -0700215Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GLSLEdge2PtConicalProcessor(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700216 : fVSVaryingName(nullptr)
217 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000218 , fCachedRadius(-SK_ScalarMax)
219 , fCachedDiffRadius(-SK_ScalarMax) {}
220
fmenozzi55d318d2016-08-09 08:05:57 -0700221void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700222 const Edge2PtConicalEffect& ge = args.fFp.cast<Edge2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800223 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
224 this->emitUniforms(uniformHandler, ge);
jvanverthde11ee42016-02-26 13:58:40 -0800225 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
226 kVec3f_GrSLType, kDefault_GrSLPrecision,
227 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000228
229 SkString cName("c");
230 SkString tName("t");
231 SkString p0; // start radius
232 SkString p1; // start radius squared
233 SkString p2; // difference in radii (r1 - r0)
234
jvanverthde11ee42016-02-26 13:58:40 -0800235
236 p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
237 p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
238 p2.appendf("%s.z", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000239
240 // We interpolate the linear component in coords[1].
bsalomon1a1aa932016-09-12 09:30:36 -0700241 SkASSERT(args.fTransformedCoords[0].getType() == args.fTransformedCoords[1].getType());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000242 const char* coords2D;
243 SkString bVar;
cdalton85285412016-02-18 12:37:07 -0800244 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700245 if (kVec3f_GrSLType == args.fTransformedCoords[0].getType()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800246 fragBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
bsalomon1a1aa932016-09-12 09:30:36 -0700247 args.fTransformedCoords[0].c_str(),
248 args.fTransformedCoords[0].c_str(),
249 args.fTransformedCoords[1].c_str(),
250 args.fTransformedCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000251 coords2D = "interpolants.xy";
252 bVar = "interpolants.z";
253 } else {
bsalomon1a1aa932016-09-12 09:30:36 -0700254 coords2D = args.fTransformedCoords[0].c_str();
255 bVar.printf("%s.x", args.fTransformedCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000256 }
257
258 // output will default to transparent black (we simply won't write anything
259 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -0800260 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 +0000261
262 // c = (x^2)+(y^2) - params[1]
egdaniel4ca2e602015-11-18 08:01:26 -0800263 fragBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000264 cName.c_str(), coords2D, coords2D, p1.c_str());
265
266 // linear case: t = -c/b
egdaniel4ca2e602015-11-18 08:01:26 -0800267 fragBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000268 cName.c_str(), bVar.c_str());
269
270 // if r(t) > 0, then t will be the x coordinate
egdaniel4ca2e602015-11-18 08:01:26 -0800271 fragBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000272 p2.c_str(), p0.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -0800273 fragBuilder->codeAppend("\t");
egdaniel7ea439b2015-12-03 09:20:44 -0800274 this->emitColor(fragBuilder,
275 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -0800276 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800277 ge,
278 tName.c_str(),
279 args.fOutputColor,
280 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700281 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -0800282 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000283}
284
fmenozzi55d318d2016-08-09 08:05:57 -0700285void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::onSetData(
286 const GrGLSLProgramDataManager& pdman,
287 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700288 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700289 const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000290 SkScalar radius0 = data.radius();
291 SkScalar diffRadius = data.diffRadius();
292
293 if (fCachedRadius != radius0 ||
294 fCachedDiffRadius != diffRadius) {
295
halcanary9d524f22016-03-29 09:03:52 -0700296 pdman.set3f(fParamUni, SkScalarToFloat(radius0),
jvanverthde11ee42016-02-26 13:58:40 -0800297 SkScalarToFloat(SkScalarMul(radius0, radius0)), SkScalarToFloat(diffRadius));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000298 fCachedRadius = radius0;
299 fCachedDiffRadius = diffRadius;
300 }
301}
302
fmenozzi55d318d2016-08-09 08:05:57 -0700303void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700304 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700305 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000306}
307
308//////////////////////////////////////////////////////////////////////////////
309// Focal Conical Gradients
310//////////////////////////////////////////////////////////////////////////////
311
312static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
313 SkMatrix* invLMatrix, SkScalar* focalX) {
314 // Inverse of the current local matrix is passed in then,
315 // translate, scale, and rotate such that endCircle is unit circle on x-axis,
316 // and focal point is at the origin.
317 ConicalType conicalType;
318 const SkPoint& focal = shader.getStartCenter();
319 const SkPoint& centerEnd = shader.getEndCenter();
320 SkScalar radius = shader.getEndRadius();
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000321 SkScalar invRadius = 1.f / radius;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000322
323 SkMatrix matrix;
324
325 matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
326 matrix.postScale(invRadius, invRadius);
327
328 SkPoint focalTrans;
329 matrix.mapPoints(&focalTrans, &focal, 1);
330 *focalX = focalTrans.length();
331
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000332 if (0.f != *focalX) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000333 SkScalar invFocalX = SkScalarInvert(*focalX);
334 SkMatrix rot;
335 rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY),
336 SkScalarMul(invFocalX, focalTrans.fX));
337 matrix.postConcat(rot);
338 }
339
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000340 matrix.postTranslate(-(*focalX), 0.f);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000341
342 // If the focal point is touching the edge of the circle it will
343 // cause a degenerate case that must be handled separately
egdaniel8405ef92014-06-09 11:57:28 -0700344 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
345 // stability trade off versus the linear approx used in the Edge Shader
346 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000347 return kEdge_ConicalType;
348 }
349
350 // Scale factor 1 / (1 - focalX * focalX)
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000351 SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX);
reed80ea19c2015-05-12 10:37:34 -0700352 SkScalar s = SkScalarInvert(oneMinusF2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000353
354
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000355 if (s >= 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000356 conicalType = kInside_ConicalType;
357 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
358 } else {
359 conicalType = kOutside_ConicalType;
360 matrix.postScale(s, s);
361 }
362
363 invLMatrix->postConcat(matrix);
364
365 return conicalType;
366}
367
368//////////////////////////////////////////////////////////////////////////////
369
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000370class FocalOutside2PtConicalEffect : public GrGradientEffect {
371public:
fmenozzi55d318d2016-08-09 08:05:57 -0700372 class GLSLFocalOutside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000373
brianosman9557c272016-09-15 06:59:15 -0700374 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
bungeman06ca8ec2016-06-09 08:01:03 -0700375 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700376 new FocalOutside2PtConicalEffect(args, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000377 }
378
379 virtual ~FocalOutside2PtConicalEffect() { }
380
mtklein36352bf2015-03-25 18:17:31 -0700381 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800382 return "Two-Point Conical Gradient Focal Outside";
383 }
384
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000385 bool isFlipped() const { return fIsFlipped; }
386 SkScalar focal() const { return fFocalX; }
387
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000388private:
egdaniel57d3b032015-11-13 11:57:27 -0800389 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700390
egdaniel57d3b032015-11-13 11:57:27 -0800391 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700392
mtklein36352bf2015-03-25 18:17:31 -0700393 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700394 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000395 return (INHERITED::onIsEqual(sBase) &&
396 this->fFocalX == s.fFocalX &&
397 this->fIsFlipped == s.fIsFlipped);
398 }
399
brianosman9557c272016-09-15 06:59:15 -0700400 FocalOutside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
401 : INHERITED(args)
joshualittb2456052015-07-08 09:36:59 -0700402 , fFocalX(focalX)
brianosman9557c272016-09-15 06:59:15 -0700403 , fIsFlipped(static_cast<const SkTwoPointConicalGradient*>(args.fShader)->isFlippedGrad()) {
joshualitteb2a6762014-12-04 11:35:33 -0800404 this->initClassID<FocalOutside2PtConicalEffect>();
405 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000406
joshualittb0a8a372014-09-23 09:50:21 -0700407 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000408
409 SkScalar fFocalX;
410 bool fIsFlipped;
411
412 typedef GrGradientEffect INHERITED;
413};
414
fmenozzi55d318d2016-08-09 08:05:57 -0700415class FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
416 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000417public:
fmenozzi55d318d2016-08-09 08:05:57 -0700418 GLSLFocalOutside2PtConicalProcessor(const GrProcessor&);
419 virtual ~GLSLFocalOutside2PtConicalProcessor() { }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000420
wangyix7c157a92015-07-22 15:08:53 -0700421 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000422
jvanverthcfc18862015-04-28 08:48:20 -0700423 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000424
425protected:
egdaniel018fb622015-10-28 07:26:40 -0700426 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700427
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000428 UniformHandle fParamUni;
429
430 const char* fVSVaryingName;
431 const char* fFSVaryingName;
432
433 bool fIsFlipped;
434
435 // @{
436 /// Values last uploaded as uniforms
437
438 SkScalar fCachedFocal;
439
440 // @}
441
442private:
fmenozzi55d318d2016-08-09 08:05:57 -0700443 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000444
445};
446
egdaniel57d3b032015-11-13 11:57:27 -0800447void FocalOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
448 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700449 FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800450}
451
egdaniel57d3b032015-11-13 11:57:27 -0800452GrGLSLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700453 return new FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000454}
455
joshualittb0a8a372014-09-23 09:50:21 -0700456GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000457
joshualitt01258472014-09-22 10:29:30 -0700458/*
459 * All Two point conical gradient test create functions may occasionally create edge case shaders
460 */
bungeman06ca8ec2016-06-09 08:01:03 -0700461sk_sp<GrFragmentProcessor> FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700462 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000463 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000464 SkPoint center2;
465 SkScalar radius2;
466 do {
joshualitt0067ff52015-07-08 14:26:19 -0700467 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000468 // 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 +0000469 } while (center1 == center2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000470
Brian Osman3f748602016-10-03 18:29:03 -0400471 SkPoint diff = center2 - center1;
472 SkScalar diffLen = diff.length();
473 // Below makes sure that the focal point is not contained within circle two
474 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
475
476 RandomGradientParams params(d->fRandom);
reed8a21c9f2016-03-08 18:50:00 -0800477 auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
Brian Osman3f748602016-10-03 18:29:03 -0400478 params.fColors, params.fStops,
479 params.fColorCount, params.fTileMode);
brianosman839345d2016-07-22 11:04:53 -0700480 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
Brian Osman0d9dfe92016-10-03 15:24:44 -0400481 auto dstColorSpace = GrTest::TestColorSpace(d->fRandom);
brianosman839345d2016-07-22 11:04:53 -0700482 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(SkShader::AsFPArgs(
Brian Osman0d9dfe92016-10-03 15:24:44 -0400483 d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(),
brianosman1638c0d2016-07-25 05:12:53 -0700484 SkSourceGammaTreatment::kRespect));
bsalomonc21b09e2015-08-28 18:46:56 -0700485 GrAlwaysAssert(fp);
486 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000487}
488
fmenozzi55d318d2016-08-09 08:05:57 -0700489FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
490 ::GLSLFocalOutside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700491 : fVSVaryingName(nullptr)
492 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000493 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700494 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000495 fIsFlipped = data.isFlipped();
496}
497
fmenozzi55d318d2016-08-09 08:05:57 -0700498void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700499 const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800500 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
501 this->emitUniforms(uniformHandler, ge);
jvanverthde11ee42016-02-26 13:58:40 -0800502 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
503 kVec2f_GrSLType, kDefault_GrSLPrecision,
504 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000505 SkString tName("t");
506 SkString p0; // focalX
507 SkString p1; // 1 - focalX * focalX
508
jvanverthde11ee42016-02-26 13:58:40 -0800509 p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
510 p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000511
512 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800513 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700514 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000515 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000516
517 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
518
519 // output will default to transparent black (we simply won't write anything
520 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -0800521 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 +0000522
egdaniel4ca2e602015-11-18 08:01:26 -0800523 fragBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
524 fragBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
525 fragBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000526
527 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
528 // If so we must also flip sign on sqrt
529 if (!fIsFlipped) {
egdaniel4ca2e602015-11-18 08:01:26 -0800530 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
531 coords2D, p0.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000532 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800533 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
534 coords2D, p0.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000535 }
536
egdaniel4ca2e602015-11-18 08:01:26 -0800537 fragBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
538 fragBuilder->codeAppend("\t\t");
egdaniel7ea439b2015-12-03 09:20:44 -0800539 this->emitColor(fragBuilder,
540 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -0800541 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800542 ge,
543 tName.c_str(),
544 args.fOutputColor,
545 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700546 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -0800547 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000548}
549
fmenozzi55d318d2016-08-09 08:05:57 -0700550void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::onSetData(
551 const GrGLSLProgramDataManager& pdman,
552 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700553 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700554 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000555 SkASSERT(data.isFlipped() == fIsFlipped);
556 SkScalar focal = data.focal();
557
558 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000559 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000560
jvanverthde11ee42016-02-26 13:58:40 -0800561 pdman.set2f(fParamUni, SkScalarToFloat(focal), SkScalarToFloat(oneMinus2F));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000562 fCachedFocal = focal;
563 }
564}
565
fmenozzi55d318d2016-08-09 08:05:57 -0700566void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(
567 const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700568 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700569 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700570 key[0] = GenBaseGradientKey(processor);
571 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000572}
573
574//////////////////////////////////////////////////////////////////////////////
575
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000576class FocalInside2PtConicalEffect : public GrGradientEffect {
577public:
fmenozzi55d318d2016-08-09 08:05:57 -0700578 class GLSLFocalInside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000579
brianosman9557c272016-09-15 06:59:15 -0700580 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
bungeman06ca8ec2016-06-09 08:01:03 -0700581 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700582 new FocalInside2PtConicalEffect(args, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000583 }
584
585 virtual ~FocalInside2PtConicalEffect() {}
586
mtklein36352bf2015-03-25 18:17:31 -0700587 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800588 return "Two-Point Conical Gradient Focal Inside";
589 }
590
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000591 SkScalar focal() const { return fFocalX; }
592
fmenozzi55d318d2016-08-09 08:05:57 -0700593 typedef FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor GLSLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000594
595private:
egdaniel57d3b032015-11-13 11:57:27 -0800596 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700597
egdaniel57d3b032015-11-13 11:57:27 -0800598 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700599
mtklein36352bf2015-03-25 18:17:31 -0700600 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700601 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000602 return (INHERITED::onIsEqual(sBase) &&
603 this->fFocalX == s.fFocalX);
604 }
605
brianosman9557c272016-09-15 06:59:15 -0700606 FocalInside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
607 : INHERITED(args), fFocalX(focalX) {
joshualitteb2a6762014-12-04 11:35:33 -0800608 this->initClassID<FocalInside2PtConicalEffect>();
609 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000610
joshualittb0a8a372014-09-23 09:50:21 -0700611 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000612
613 SkScalar fFocalX;
614
615 typedef GrGradientEffect INHERITED;
616};
617
fmenozzi55d318d2016-08-09 08:05:57 -0700618class FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
619 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000620public:
fmenozzi55d318d2016-08-09 08:05:57 -0700621 GLSLFocalInside2PtConicalProcessor(const GrProcessor&);
622 virtual ~GLSLFocalInside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000623
wangyix7c157a92015-07-22 15:08:53 -0700624 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000625
jvanverthcfc18862015-04-28 08:48:20 -0700626 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000627
628protected:
egdaniel018fb622015-10-28 07:26:40 -0700629 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700630
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000631 UniformHandle fFocalUni;
632
633 const char* fVSVaryingName;
634 const char* fFSVaryingName;
635
636 // @{
637 /// Values last uploaded as uniforms
638
639 SkScalar fCachedFocal;
640
641 // @}
642
643private:
fmenozzi55d318d2016-08-09 08:05:57 -0700644 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000645
646};
647
egdaniel57d3b032015-11-13 11:57:27 -0800648void FocalInside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
649 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700650 FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800651}
652
egdaniel57d3b032015-11-13 11:57:27 -0800653GrGLSLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700654 return new FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000655}
656
joshualittb0a8a372014-09-23 09:50:21 -0700657GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000658
joshualitt01258472014-09-22 10:29:30 -0700659/*
660 * All Two point conical gradient test create functions may occasionally create edge case shaders
661 */
bungeman06ca8ec2016-06-09 08:01:03 -0700662sk_sp<GrFragmentProcessor> FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700663 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000664 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000665 SkPoint center2;
666 SkScalar radius2;
667 do {
joshualitt0067ff52015-07-08 14:26:19 -0700668 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000669 // Below makes sure radius2 is larger enouch such that the focal point
670 // is inside the end circle
joshualitt0067ff52015-07-08 14:26:19 -0700671 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000672 SkPoint diff = center2 - center1;
673 SkScalar diffLen = diff.length();
674 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000675 // If the circles are identical the factory will give us an empty shader.
676 } while (radius1 == radius2 && center1 == center2);
677
Brian Osman3f748602016-10-03 18:29:03 -0400678 RandomGradientParams params(d->fRandom);
reed8a21c9f2016-03-08 18:50:00 -0800679 auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
Brian Osman3f748602016-10-03 18:29:03 -0400680 params.fColors, params.fStops,
681 params.fColorCount, params.fTileMode);
brianosman839345d2016-07-22 11:04:53 -0700682 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
Brian Osman0d9dfe92016-10-03 15:24:44 -0400683 auto dstColorSpace = GrTest::TestColorSpace(d->fRandom);
brianosman839345d2016-07-22 11:04:53 -0700684 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(SkShader::AsFPArgs(
Brian Osman0d9dfe92016-10-03 15:24:44 -0400685 d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(),
brianosman1638c0d2016-07-25 05:12:53 -0700686 SkSourceGammaTreatment::kRespect));
bsalomonc21b09e2015-08-28 18:46:56 -0700687 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700688 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000689}
690
fmenozzi55d318d2016-08-09 08:05:57 -0700691FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
692 ::GLSLFocalInside2PtConicalProcessor(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700693 : fVSVaryingName(nullptr)
694 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000695 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000696
fmenozzi55d318d2016-08-09 08:05:57 -0700697void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700698 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800699 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
700 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800701 fFocalUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800702 kFloat_GrSLType, kDefault_GrSLPrecision,
703 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000704 SkString tName("t");
705
706 // this is the distance along x-axis from the end center to focal point in
707 // transformed coordinates
egdaniel7ea439b2015-12-03 09:20:44 -0800708 GrGLSLShaderVar focal = uniformHandler->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000709
710 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800711 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700712 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000713 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000714
715 // t = p.x * focalX + length(p)
egdaniel4ca2e602015-11-18 08:01:26 -0800716 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
egdaniel7ea439b2015-12-03 09:20:44 -0800717 coords2D, focal.c_str(), coords2D);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000718
egdaniel7ea439b2015-12-03 09:20:44 -0800719 this->emitColor(fragBuilder,
720 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -0800721 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800722 ge,
723 tName.c_str(),
724 args.fOutputColor,
725 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700726 args.fTexSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000727}
728
fmenozzi55d318d2016-08-09 08:05:57 -0700729void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::onSetData(
730 const GrGLSLProgramDataManager& pdman,
731 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700732 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700733 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000734 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000735
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000736 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700737 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000738 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000739 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000740}
741
fmenozzi55d318d2016-08-09 08:05:57 -0700742void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(
743 const GrProcessor& processor,
744 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700745 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000746}
747
748//////////////////////////////////////////////////////////////////////////////
749// Circle Conical Gradients
750//////////////////////////////////////////////////////////////////////////////
751
752struct CircleConicalInfo {
753 SkPoint fCenterEnd;
754 SkScalar fA;
755 SkScalar fB;
756 SkScalar fC;
757};
758
759// Returns focal distance along x-axis in transformed coords
760static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
761 SkMatrix* invLMatrix, CircleConicalInfo* info) {
762 // Inverse of the current local matrix is passed in then,
763 // translate and scale such that start circle is on the origin and has radius 1
764 const SkPoint& centerStart = shader.getStartCenter();
765 const SkPoint& centerEnd = shader.getEndCenter();
766 SkScalar radiusStart = shader.getStartRadius();
767 SkScalar radiusEnd = shader.getEndRadius();
768
769 SkMatrix matrix;
770
771 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
772
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000773 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000774 matrix.postScale(invStartRad, invStartRad);
775
776 radiusEnd /= radiusStart;
777
778 SkPoint centerEndTrans;
779 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
780
781 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
782 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
783
784 // Check to see if start circle is inside end circle with edges touching.
785 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700786 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
787 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
788 // still accurate.
789 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000790 return kEdge_ConicalType;
791 }
792
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000793 SkScalar C = 1.f / A;
794 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000795
796 matrix.postScale(C, C);
797
798 invLMatrix->postConcat(matrix);
799
800 info->fCenterEnd = centerEndTrans;
801 info->fA = A;
802 info->fB = B;
803 info->fC = C;
804
805 // 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 +0000806 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000807 return kInside_ConicalType;
808 }
809 return kOutside_ConicalType;
810}
811
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000812class CircleInside2PtConicalEffect : public GrGradientEffect {
813public:
fmenozzi55d318d2016-08-09 08:05:57 -0700814 class GLSLCircleInside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000815
brianosman9557c272016-09-15 06:59:15 -0700816 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
bungeman06ca8ec2016-06-09 08:01:03 -0700817 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700818 new CircleInside2PtConicalEffect(args, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000819 }
820
821 virtual ~CircleInside2PtConicalEffect() {}
822
mtklein36352bf2015-03-25 18:17:31 -0700823 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800824
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000825 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
826 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
827 SkScalar A() const { return fInfo.fA; }
828 SkScalar B() const { return fInfo.fB; }
829 SkScalar C() const { return fInfo.fC; }
830
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000831private:
egdaniel57d3b032015-11-13 11:57:27 -0800832 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700833
egdaniel57d3b032015-11-13 11:57:27 -0800834 virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps,
835 GrProcessorKeyBuilder* b) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700836
mtklein36352bf2015-03-25 18:17:31 -0700837 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700838 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000839 return (INHERITED::onIsEqual(sBase) &&
840 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
841 this->fInfo.fA == s.fInfo.fA &&
842 this->fInfo.fB == s.fInfo.fB &&
843 this->fInfo.fC == s.fInfo.fC);
844 }
845
brianosman9557c272016-09-15 06:59:15 -0700846 CircleInside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
847 : INHERITED(args), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800848 this->initClassID<CircleInside2PtConicalEffect>();
849 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000850
joshualittb0a8a372014-09-23 09:50:21 -0700851 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000852
853 const CircleConicalInfo fInfo;
854
855 typedef GrGradientEffect INHERITED;
856};
857
fmenozzi55d318d2016-08-09 08:05:57 -0700858class CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
859 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000860public:
fmenozzi55d318d2016-08-09 08:05:57 -0700861 GLSLCircleInside2PtConicalProcessor(const GrProcessor&);
862 virtual ~GLSLCircleInside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000863
wangyix7c157a92015-07-22 15:08:53 -0700864 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000865
jvanverthcfc18862015-04-28 08:48:20 -0700866 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000867
868protected:
egdaniel018fb622015-10-28 07:26:40 -0700869 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700870
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000871 UniformHandle fCenterUni;
872 UniformHandle fParamUni;
873
874 const char* fVSVaryingName;
875 const char* fFSVaryingName;
876
877 // @{
878 /// Values last uploaded as uniforms
879
880 SkScalar fCachedCenterX;
881 SkScalar fCachedCenterY;
882 SkScalar fCachedA;
883 SkScalar fCachedB;
884 SkScalar fCachedC;
885
886 // @}
887
888private:
fmenozzi55d318d2016-08-09 08:05:57 -0700889 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000890
891};
892
egdaniel57d3b032015-11-13 11:57:27 -0800893void CircleInside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
894 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700895 CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800896}
897
egdaniel57d3b032015-11-13 11:57:27 -0800898GrGLSLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700899 return new CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000900}
901
joshualittb0a8a372014-09-23 09:50:21 -0700902GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000903
joshualitt01258472014-09-22 10:29:30 -0700904/*
905 * All Two point conical gradient test create functions may occasionally create edge case shaders
906 */
bungeman06ca8ec2016-06-09 08:01:03 -0700907sk_sp<GrFragmentProcessor> CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700908 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
909 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000910 SkPoint center2;
911 SkScalar radius2;
912 do {
joshualitt0067ff52015-07-08 14:26:19 -0700913 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000914 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700915 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000916 SkPoint diff = center2 - center1;
917 SkScalar diffLen = diff.length();
918 radius2 = radius1 + diffLen + increase;
919 // If the circles are identical the factory will give us an empty shader.
920 } while (radius1 == radius2 && center1 == center2);
921
Brian Osman3f748602016-10-03 18:29:03 -0400922 RandomGradientParams params(d->fRandom);
reed8a21c9f2016-03-08 18:50:00 -0800923 auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
Brian Osman3f748602016-10-03 18:29:03 -0400924 params.fColors, params.fStops,
925 params.fColorCount, params.fTileMode);
brianosman839345d2016-07-22 11:04:53 -0700926 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
Brian Osman0d9dfe92016-10-03 15:24:44 -0400927 auto dstColorSpace = GrTest::TestColorSpace(d->fRandom);
brianosman839345d2016-07-22 11:04:53 -0700928 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(SkShader::AsFPArgs(
Brian Osman0d9dfe92016-10-03 15:24:44 -0400929 d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(),
brianosman1638c0d2016-07-25 05:12:53 -0700930 SkSourceGammaTreatment::kRespect));
bsalomonc21b09e2015-08-28 18:46:56 -0700931 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -0700932 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000933}
934
fmenozzi55d318d2016-08-09 08:05:57 -0700935CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
936 ::GLSLCircleInside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700937 : fVSVaryingName(nullptr)
938 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000939 , fCachedCenterX(SK_ScalarMax)
940 , fCachedCenterY(SK_ScalarMax)
941 , fCachedA(SK_ScalarMax)
942 , fCachedB(SK_ScalarMax)
943 , fCachedC(SK_ScalarMax) {}
944
fmenozzi55d318d2016-08-09 08:05:57 -0700945void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700946 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800947 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
948 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800949 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800950 kVec2f_GrSLType, kDefault_GrSLPrecision,
951 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -0800952 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800953 kVec3f_GrSLType, kDefault_GrSLPrecision,
954 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000955 SkString tName("t");
956
egdaniel7ea439b2015-12-03 09:20:44 -0800957 GrGLSLShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000958 // params.x = A
959 // params.y = B
960 // params.z = C
egdaniel7ea439b2015-12-03 09:20:44 -0800961 GrGLSLShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000962
963 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800964 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700965 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000966 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000967
968 // p = coords2D
969 // e = center end
970 // r = radius end
971 // A = dot(e, e) - r^2 + 2 * r - 1
972 // B = (r -1) / A
973 // C = 1 / A
974 // d = dot(e, p) + B
975 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
egdaniel4ca2e602015-11-18 08:01:26 -0800976 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
977 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
978 params.c_str());
979 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
980 tName.c_str(), params.c_str(), params.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000981
egdaniel7ea439b2015-12-03 09:20:44 -0800982 this->emitColor(fragBuilder,
983 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -0800984 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800985 ge,
986 tName.c_str(),
987 args.fOutputColor,
988 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700989 args.fTexSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000990}
991
fmenozzi55d318d2016-08-09 08:05:57 -0700992void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::onSetData(
993 const GrGLSLProgramDataManager& pdman,
994 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700995 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700996 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000997 SkScalar centerX = data.centerX();
998 SkScalar centerY = data.centerY();
999 SkScalar A = data.A();
1000 SkScalar B = data.B();
1001 SkScalar C = data.C();
1002
1003 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1004 fCachedA != A || fCachedB != B || fCachedC != C) {
1005
kkinnunen7510b222014-07-30 00:04:16 -07001006 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1007 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001008
1009 fCachedCenterX = centerX;
1010 fCachedCenterY = centerY;
1011 fCachedA = A;
1012 fCachedB = B;
1013 fCachedC = C;
1014 }
1015}
1016
fmenozzi55d318d2016-08-09 08:05:57 -07001017void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(
1018 const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001019 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001020 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001021}
1022
1023//////////////////////////////////////////////////////////////////////////////
1024
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001025class CircleOutside2PtConicalEffect : public GrGradientEffect {
1026public:
fmenozzi55d318d2016-08-09 08:05:57 -07001027 class GLSLCircleOutside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001028
brianosman9557c272016-09-15 06:59:15 -07001029 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
bungeman06ca8ec2016-06-09 08:01:03 -07001030 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -07001031 new CircleOutside2PtConicalEffect(args, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001032 }
1033
1034 virtual ~CircleOutside2PtConicalEffect() {}
1035
mtklein36352bf2015-03-25 18:17:31 -07001036 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001037
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001038 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1039 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1040 SkScalar A() const { return fInfo.fA; }
1041 SkScalar B() const { return fInfo.fB; }
1042 SkScalar C() const { return fInfo.fC; }
1043 SkScalar tLimit() const { return fTLimit; }
1044 bool isFlipped() const { return fIsFlipped; }
1045
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001046private:
egdaniel57d3b032015-11-13 11:57:27 -08001047 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -07001048
egdaniel57d3b032015-11-13 11:57:27 -08001049 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -07001050
mtklein36352bf2015-03-25 18:17:31 -07001051 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001052 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001053 return (INHERITED::onIsEqual(sBase) &&
1054 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1055 this->fInfo.fA == s.fInfo.fA &&
1056 this->fInfo.fB == s.fInfo.fB &&
1057 this->fInfo.fC == s.fInfo.fC &&
1058 this->fTLimit == s.fTLimit &&
1059 this->fIsFlipped == s.fIsFlipped);
1060 }
1061
brianosman9557c272016-09-15 06:59:15 -07001062 CircleOutside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
1063 : INHERITED(args), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001064 this->initClassID<CircleOutside2PtConicalEffect>();
brianosman9557c272016-09-15 06:59:15 -07001065 const SkTwoPointConicalGradient& shader =
1066 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001067 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001068 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001069 } else {
1070 fTLimit = SK_ScalarMin;
1071 }
1072
1073 fIsFlipped = shader.isFlippedGrad();
1074 }
1075
joshualittb0a8a372014-09-23 09:50:21 -07001076 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001077
1078 const CircleConicalInfo fInfo;
1079 SkScalar fTLimit;
1080 bool fIsFlipped;
1081
1082 typedef GrGradientEffect INHERITED;
1083};
1084
fmenozzi55d318d2016-08-09 08:05:57 -07001085class CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
1086 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001087public:
fmenozzi55d318d2016-08-09 08:05:57 -07001088 GLSLCircleOutside2PtConicalProcessor(const GrProcessor&);
1089 virtual ~GLSLCircleOutside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001090
wangyix7c157a92015-07-22 15:08:53 -07001091 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001092
jvanverthcfc18862015-04-28 08:48:20 -07001093 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001094
1095protected:
egdaniel018fb622015-10-28 07:26:40 -07001096 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001097
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001098 UniformHandle fCenterUni;
1099 UniformHandle fParamUni;
1100
1101 const char* fVSVaryingName;
1102 const char* fFSVaryingName;
1103
1104 bool fIsFlipped;
1105
1106 // @{
1107 /// Values last uploaded as uniforms
1108
1109 SkScalar fCachedCenterX;
1110 SkScalar fCachedCenterY;
1111 SkScalar fCachedA;
1112 SkScalar fCachedB;
1113 SkScalar fCachedC;
1114 SkScalar fCachedTLimit;
1115
1116 // @}
1117
1118private:
fmenozzi55d318d2016-08-09 08:05:57 -07001119 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001120
1121};
1122
egdaniel57d3b032015-11-13 11:57:27 -08001123void CircleOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1124 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -07001125 CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -08001126}
1127
egdaniel57d3b032015-11-13 11:57:27 -08001128GrGLSLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -07001129 return new CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001130}
1131
joshualittb0a8a372014-09-23 09:50:21 -07001132GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001133
joshualitt01258472014-09-22 10:29:30 -07001134/*
1135 * All Two point conical gradient test create functions may occasionally create edge case shaders
1136 */
bungeman06ca8ec2016-06-09 08:01:03 -07001137sk_sp<GrFragmentProcessor> CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001138 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1139 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001140 SkPoint center2;
1141 SkScalar radius2;
1142 SkScalar diffLen;
1143 do {
joshualitt0067ff52015-07-08 14:26:19 -07001144 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001145 // If the circles share a center than we can't be in the outside case
1146 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001147 SkPoint diff = center2 - center1;
1148 diffLen = diff.length();
1149 // Below makes sure that circle one is not contained within circle two
1150 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001151 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001152
Brian Osman3f748602016-10-03 18:29:03 -04001153 RandomGradientParams params(d->fRandom);
reed8a21c9f2016-03-08 18:50:00 -08001154 auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
Brian Osman3f748602016-10-03 18:29:03 -04001155 params.fColors, params.fStops,
1156 params.fColorCount, params.fTileMode);
brianosman839345d2016-07-22 11:04:53 -07001157 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
Brian Osman0d9dfe92016-10-03 15:24:44 -04001158 auto dstColorSpace = GrTest::TestColorSpace(d->fRandom);
brianosman839345d2016-07-22 11:04:53 -07001159 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(SkShader::AsFPArgs(
Brian Osman0d9dfe92016-10-03 15:24:44 -04001160 d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(),
brianosman1638c0d2016-07-25 05:12:53 -07001161 SkSourceGammaTreatment::kRespect));
bsalomonc21b09e2015-08-28 18:46:56 -07001162 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -07001163 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001164}
1165
fmenozzi55d318d2016-08-09 08:05:57 -07001166CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
1167 ::GLSLCircleOutside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -07001168 : fVSVaryingName(nullptr)
1169 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001170 , fCachedCenterX(SK_ScalarMax)
1171 , fCachedCenterY(SK_ScalarMax)
1172 , fCachedA(SK_ScalarMax)
1173 , fCachedB(SK_ScalarMax)
1174 , fCachedC(SK_ScalarMax)
1175 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001176 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001177 fIsFlipped = data.isFlipped();
1178 }
1179
fmenozzi55d318d2016-08-09 08:05:57 -07001180void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -07001181 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -08001182 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1183 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -08001184 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001185 kVec2f_GrSLType, kDefault_GrSLPrecision,
1186 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -08001187 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001188 kVec4f_GrSLType, kDefault_GrSLPrecision,
1189 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001190 SkString tName("t");
1191
egdaniel7ea439b2015-12-03 09:20:44 -08001192 GrGLSLShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001193 // params.x = A
1194 // params.y = B
1195 // params.z = C
egdaniel7ea439b2015-12-03 09:20:44 -08001196 GrGLSLShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001197
1198 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -08001199 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -07001200 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001201 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001202
1203 // output will default to transparent black (we simply won't write anything
1204 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -08001205 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 +00001206
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001207 // p = coords2D
1208 // e = center end
1209 // r = radius end
1210 // A = dot(e, e) - r^2 + 2 * r - 1
1211 // B = (r -1) / A
1212 // C = 1 / A
1213 // d = dot(e, p) + B
1214 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001215
egdaniel4ca2e602015-11-18 08:01:26 -08001216 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
1217 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1218 params.c_str());
1219 fragBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1220 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001221
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001222 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1223 // If so we must also flip sign on sqrt
1224 if (!fIsFlipped) {
egdaniel4ca2e602015-11-18 08:01:26 -08001225 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001226 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001227 fragBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001228 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001229
egdaniel7ea439b2015-12-03 09:20:44 -08001230 fragBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n",
1231 tName.c_str(), params.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001232 fragBuilder->codeAppend("\t\t");
egdaniel7ea439b2015-12-03 09:20:44 -08001233 this->emitColor(fragBuilder,
1234 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -08001235 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -08001236 ge,
1237 tName.c_str(),
1238 args.fOutputColor,
1239 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -07001240 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -08001241 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001242}
1243
fmenozzi55d318d2016-08-09 08:05:57 -07001244void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::onSetData(
1245 const GrGLSLProgramDataManager& pdman,
egdaniel018fb622015-10-28 07:26:40 -07001246 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001247 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001248 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001249 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001250 SkScalar centerX = data.centerX();
1251 SkScalar centerY = data.centerY();
1252 SkScalar A = data.A();
1253 SkScalar B = data.B();
1254 SkScalar C = data.C();
1255 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001256
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001257 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1258 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001259
kkinnunen7510b222014-07-30 00:04:16 -07001260 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1261 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001262 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001263
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001264 fCachedCenterX = centerX;
1265 fCachedCenterY = centerY;
1266 fCachedA = A;
1267 fCachedB = B;
1268 fCachedC = C;
1269 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001270 }
1271}
1272
fmenozzi55d318d2016-08-09 08:05:57 -07001273void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(
1274 const GrProcessor& processor,
1275 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001276 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001277 key[0] = GenBaseGradientKey(processor);
1278 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001279}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001280
1281//////////////////////////////////////////////////////////////////////////////
1282
brianosman9557c272016-09-15 06:59:15 -07001283sk_sp<GrFragmentProcessor> Gr2PtConicalGradientEffect::Make(
1284 const GrGradientEffect::CreateArgs& args) {
1285 const SkTwoPointConicalGradient& shader =
1286 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
1287
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001288 SkMatrix matrix;
1289 if (!shader.getLocalMatrix().invert(&matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001290 return nullptr;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001291 }
brianosman9557c272016-09-15 06:59:15 -07001292 if (args.fMatrix) {
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001293 SkMatrix inv;
brianosman9557c272016-09-15 06:59:15 -07001294 if (!args.fMatrix->invert(&inv)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001295 return nullptr;
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001296 }
1297 matrix.postConcat(inv);
1298 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001299
brianosmanb9c51372016-09-15 11:09:45 -07001300 GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fTileMode,
1301 std::move(args.fColorSpaceXform), args.fGammaCorrect);
brianosman9557c272016-09-15 06:59:15 -07001302
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001303 if (shader.getStartRadius() < kErrorTol) {
1304 SkScalar focalX;
1305 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1306 if (type == kInside_ConicalType) {
brianosman9557c272016-09-15 06:59:15 -07001307 return FocalInside2PtConicalEffect::Make(newArgs, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001308 } else if(type == kEdge_ConicalType) {
1309 set_matrix_edge_conical(shader, &matrix);
brianosman9557c272016-09-15 06:59:15 -07001310 return Edge2PtConicalEffect::Make(newArgs);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001311 } else {
brianosman9557c272016-09-15 06:59:15 -07001312 return FocalOutside2PtConicalEffect::Make(newArgs, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001313 }
1314 }
1315
1316 CircleConicalInfo info;
1317 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1318
1319 if (type == kInside_ConicalType) {
brianosman9557c272016-09-15 06:59:15 -07001320 return CircleInside2PtConicalEffect::Make(newArgs, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001321 } else if (type == kEdge_ConicalType) {
1322 set_matrix_edge_conical(shader, &matrix);
brianosman9557c272016-09-15 06:59:15 -07001323 return Edge2PtConicalEffect::Make(newArgs);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001324 } else {
brianosman9557c272016-09-15 06:59:15 -07001325 return CircleOutside2PtConicalEffect::Make(newArgs, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001326 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001327}
1328
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001329#endif