blob: 3bf9c1e3421d4fce94f38cd2b875e1943f988adb [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"
joshualitt8ca93e72015-07-08 06:51:43 -070013#include "GrPaint.h"
egdaniel2d721d32015-11-11 13:06:05 -080014#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070015#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080016#include "glsl/GrGLSLUniformHandler.h"
brianosman9557c272016-09-15 06:59:15 -070017#include "SkTwoPointConicalGradient_gpu.h"
18
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000019// For brevity
egdaniel018fb622015-10-28 07:26:40 -070020typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000021
commit-bot@chromium.org80894672014-04-22 21:24:22 +000022static const SkScalar kErrorTol = 0.00001f;
egdaniel8405ef92014-06-09 11:57:28 -070023static const SkScalar kEdgeErrorTol = 5.f * kErrorTol;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000024
25/**
26 * We have three general cases for 2pt conical gradients. First we always assume that
27 * the start radius <= end radius. Our first case (kInside_) is when the start circle
28 * is completely enclosed by the end circle. The second case (kOutside_) is the case
29 * when the start circle is either completely outside the end circle or the circles
30 * overlap. The final case (kEdge_) is when the start circle is inside the end one,
31 * but the two are just barely touching at 1 point along their edges.
32 */
33enum ConicalType {
34 kInside_ConicalType,
35 kOutside_ConicalType,
36 kEdge_ConicalType,
37};
38
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000039//////////////////////////////////////////////////////////////////////////////
40
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000041static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader,
42 SkMatrix* invLMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000043 // Inverse of the current local matrix is passed in then,
44 // translate to center1, rotate so center2 is on x axis.
45 const SkPoint& center1 = shader.getStartCenter();
46 const SkPoint& center2 = shader.getEndCenter();
47
48 invLMatrix->postTranslate(-center1.fX, -center1.fY);
49
50 SkPoint diff = center2 - center1;
51 SkScalar diffLen = diff.length();
52 if (0 != diffLen) {
53 SkScalar invDiffLen = SkScalarInvert(diffLen);
54 SkMatrix rot;
Mike Reed8be952a2017-02-13 20:44:33 -050055 rot.setSinCos(-invDiffLen * diff.fY, invDiffLen * diff.fX);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000056 invLMatrix->postConcat(rot);
57 }
58}
59
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000060class Edge2PtConicalEffect : public GrGradientEffect {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000061public:
fmenozzi55d318d2016-08-09 08:05:57 -070062 class GLSLEdge2PtConicalProcessor;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000063
brianosman9557c272016-09-15 06:59:15 -070064 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
65 return sk_sp<GrFragmentProcessor>(new Edge2PtConicalEffect(args));
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000066 }
67
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000068 virtual ~Edge2PtConicalEffect() {}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000069
mtklein36352bf2015-03-25 18:17:31 -070070 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -080071 return "Two-Point Conical Gradient Edge Touching";
72 }
73
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000074 // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000075 SkScalar center() const { return fCenterX1; }
76 SkScalar diffRadius() const { return fDiffRadius; }
77 SkScalar radius() const { return fRadius0; }
78
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000079private:
egdaniel57d3b032015-11-13 11:57:27 -080080 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -070081
Brian Salomon94efbf52016-11-29 13:43:05 -050082 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -070083
mtklein36352bf2015-03-25 18:17:31 -070084 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -070085 const Edge2PtConicalEffect& s = sBase.cast<Edge2PtConicalEffect>();
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000086 return (INHERITED::onIsEqual(sBase) &&
87 this->fCenterX1 == s.fCenterX1 &&
88 this->fRadius0 == s.fRadius0 &&
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000089 this->fDiffRadius == s.fDiffRadius);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000090 }
91
brianosman9557c272016-09-15 06:59:15 -070092 Edge2PtConicalEffect(const CreateArgs& args)
Brian Salomon587e08f2017-01-27 10:59:27 -050093 : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */) {
brianosman9557c272016-09-15 06:59:15 -070094 const SkTwoPointConicalGradient& shader =
95 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
96 fCenterX1 = shader.getCenterX1();
97 fRadius0 = shader.getStartRadius();
98 fDiffRadius = shader.getDiffRadius();
joshualitteb2a6762014-12-04 11:35:33 -080099 this->initClassID<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000100 // We should only be calling this shader if we are degenerate case with touching circles
egdaniel8405ef92014-06-09 11:57:28 -0700101 // When deciding if we are in edge case, we scaled by the end radius for cases when the
joshualitt01258472014-09-22 10:29:30 -0700102 // start radius was close to zero, otherwise we scaled by the start radius. In addition
103 // Our test for the edge case in set_matrix_circle_conical has a higher tolerance so we
104 // need the sqrt value below
105 SkASSERT(SkScalarAbs(SkScalarAbs(fDiffRadius) - fCenterX1) <
106 (fRadius0 < kErrorTol ? shader.getEndRadius() * kEdgeErrorTol :
107 fRadius0 * sqrt(kEdgeErrorTol)));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000108
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000109 // We pass the linear part of the quadratic as a varying.
110 // float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
111 fBTransform = this->getCoordTransform();
112 SkMatrix& bMatrix = *fBTransform.accessMatrix();
Mike Reed8be952a2017-02-13 20:44:33 -0500113 SkScalar r0dr = fRadius0 * fDiffRadius;
114 bMatrix[SkMatrix::kMScaleX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMScaleX] +
115 r0dr * bMatrix[SkMatrix::kMPersp0]);
116 bMatrix[SkMatrix::kMSkewX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMSkewX] +
117 r0dr * bMatrix[SkMatrix::kMPersp1]);
118 bMatrix[SkMatrix::kMTransX] = -2 * (fCenterX1 * bMatrix[SkMatrix::kMTransX] +
119 r0dr * bMatrix[SkMatrix::kMPersp2]);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000120 this->addCoordTransform(&fBTransform);
121 }
122
joshualittb0a8a372014-09-23 09:50:21 -0700123 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000124
125 // @{
126 // Cache of values - these can change arbitrarily, EXCEPT
127 // we shouldn't change between degenerate and non-degenerate?!
128
129 GrCoordTransform fBTransform;
130 SkScalar fCenterX1;
131 SkScalar fRadius0;
132 SkScalar fDiffRadius;
133
134 // @}
135
136 typedef GrGradientEffect INHERITED;
137};
138
fmenozzi55d318d2016-08-09 08:05:57 -0700139class Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000140public:
fmenozzi55d318d2016-08-09 08:05:57 -0700141 GLSLEdge2PtConicalProcessor(const GrProcessor&);
142 virtual ~GLSLEdge2PtConicalProcessor() { }
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000143
wangyix7c157a92015-07-22 15:08:53 -0700144 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000145
Brian Salomon94efbf52016-11-29 13:43:05 -0500146 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000147
148protected:
egdaniel018fb622015-10-28 07:26:40 -0700149 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700150
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000151 UniformHandle fParamUni;
152
153 const char* fVSVaryingName;
154 const char* fFSVaryingName;
155
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000156 // @{
157 /// Values last uploaded as uniforms
158
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000159 SkScalar fCachedRadius;
160 SkScalar fCachedDiffRadius;
161
162 // @}
163
164private:
fmenozzi55d318d2016-08-09 08:05:57 -0700165 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000166
167};
168
Brian Salomon94efbf52016-11-29 13:43:05 -0500169void Edge2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800170 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700171 Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800172}
173
egdaniel57d3b032015-11-13 11:57:27 -0800174GrGLSLFragmentProcessor* Edge2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700175 return new Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor(*this);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000176}
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000177
joshualittb0a8a372014-09-23 09:50:21 -0700178GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Edge2PtConicalEffect);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000179
joshualitt01258472014-09-22 10:29:30 -0700180/*
181 * All Two point conical gradient test create functions may occasionally create edge case shaders
182 */
Hal Canary6f6961e2017-01-31 13:50:44 -0500183#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -0700184sk_sp<GrFragmentProcessor> Edge2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700185 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
186 SkScalar radius1 = d->fRandom->nextUScalar1();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000187 SkPoint center2;
188 SkScalar radius2;
189 do {
joshualitt0067ff52015-07-08 14:26:19 -0700190 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000191 // If the circles are identical the factory will give us an empty shader.
192 // This will happen if we pick identical centers
193 } while (center1 == center2);
194
195 // Below makes sure that circle one is contained within circle two
196 // and both circles are touching on an edge
197 SkPoint diff = center2 - center1;
198 SkScalar diffLen = diff.length();
199 radius2 = radius1 + diffLen;
200
Brian Osman3f748602016-10-03 18:29:03 -0400201 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400202 auto shader = params.fUseColors4f ?
203 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
204 params.fColors4f, params.fColorSpace, params.fStops,
205 params.fColorCount, params.fTileMode) :
206 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
207 params.fColors, params.fStops,
208 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400209 GrTest::TestAsFPArgs asFPArgs(d);
210 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
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}
Hal Canary6f6961e2017-01-31 13:50:44 -0500214#endif
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000215
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
Mike Reed8be952a2017-02-13 20:44:33 -0500297 pdman.set3f(fParamUni, radius0, radius0 * radius0, 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,
Brian Salomon94efbf52016-11-29 13:43:05 -0500304 const GrShaderCaps&, 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;
Mike Reed8be952a2017-02-13 20:44:33 -0500335 rot.setSinCos(-invFocalX * focalTrans.fY, invFocalX * focalTrans.fX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000336 matrix.postConcat(rot);
337 }
338
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000339 matrix.postTranslate(-(*focalX), 0.f);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000340
341 // If the focal point is touching the edge of the circle it will
342 // cause a degenerate case that must be handled separately
egdaniel8405ef92014-06-09 11:57:28 -0700343 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
344 // stability trade off versus the linear approx used in the Edge Shader
345 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000346 return kEdge_ConicalType;
347 }
348
349 // Scale factor 1 / (1 - focalX * focalX)
Mike Reed8be952a2017-02-13 20:44:33 -0500350 SkScalar oneMinusF2 = 1.f - *focalX * *focalX;
reed80ea19c2015-05-12 10:37:34 -0700351 SkScalar s = SkScalarInvert(oneMinusF2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000352
353
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000354 if (s >= 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000355 conicalType = kInside_ConicalType;
356 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
357 } else {
358 conicalType = kOutside_ConicalType;
359 matrix.postScale(s, s);
360 }
361
362 invLMatrix->postConcat(matrix);
363
364 return conicalType;
365}
366
367//////////////////////////////////////////////////////////////////////////////
368
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000369class FocalOutside2PtConicalEffect : public GrGradientEffect {
370public:
fmenozzi55d318d2016-08-09 08:05:57 -0700371 class GLSLFocalOutside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000372
brianosman9557c272016-09-15 06:59:15 -0700373 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
bungeman06ca8ec2016-06-09 08:01:03 -0700374 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700375 new FocalOutside2PtConicalEffect(args, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000376 }
377
378 virtual ~FocalOutside2PtConicalEffect() { }
379
mtklein36352bf2015-03-25 18:17:31 -0700380 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800381 return "Two-Point Conical Gradient Focal Outside";
382 }
383
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000384 bool isFlipped() const { return fIsFlipped; }
385 SkScalar focal() const { return fFocalX; }
386
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000387private:
egdaniel57d3b032015-11-13 11:57:27 -0800388 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700389
Brian Salomon94efbf52016-11-29 13:43:05 -0500390 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700391
mtklein36352bf2015-03-25 18:17:31 -0700392 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700393 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000394 return (INHERITED::onIsEqual(sBase) &&
395 this->fFocalX == s.fFocalX &&
396 this->fIsFlipped == s.fIsFlipped);
397 }
398
Brian Salomon587e08f2017-01-27 10:59:27 -0500399 static bool IsFlipped(const CreateArgs& args) {
400 // eww.
401 return static_cast<const SkTwoPointConicalGradient*>(args.fShader)->isFlippedGrad();
402 }
403
brianosman9557c272016-09-15 06:59:15 -0700404 FocalOutside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
Brian Salomon587e08f2017-01-27 10:59:27 -0500405 : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
406 , fFocalX(focalX)
407 , fIsFlipped(IsFlipped(args)) {
joshualitteb2a6762014-12-04 11:35:33 -0800408 this->initClassID<FocalOutside2PtConicalEffect>();
409 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000410
joshualittb0a8a372014-09-23 09:50:21 -0700411 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000412
413 SkScalar fFocalX;
414 bool fIsFlipped;
415
416 typedef GrGradientEffect INHERITED;
417};
418
Brian Salomon587e08f2017-01-27 10:59:27 -0500419class FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
fmenozzi55d318d2016-08-09 08:05:57 -0700420 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000421public:
fmenozzi55d318d2016-08-09 08:05:57 -0700422 GLSLFocalOutside2PtConicalProcessor(const GrProcessor&);
423 virtual ~GLSLFocalOutside2PtConicalProcessor() { }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000424
wangyix7c157a92015-07-22 15:08:53 -0700425 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000426
Brian Salomon94efbf52016-11-29 13:43:05 -0500427 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000428
429protected:
egdaniel018fb622015-10-28 07:26:40 -0700430 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700431
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000432 UniformHandle fParamUni;
433
434 const char* fVSVaryingName;
435 const char* fFSVaryingName;
436
437 bool fIsFlipped;
438
439 // @{
440 /// Values last uploaded as uniforms
441
442 SkScalar fCachedFocal;
443
444 // @}
445
446private:
fmenozzi55d318d2016-08-09 08:05:57 -0700447 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000448
449};
450
Brian Salomon94efbf52016-11-29 13:43:05 -0500451void FocalOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800452 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700453 FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800454}
455
egdaniel57d3b032015-11-13 11:57:27 -0800456GrGLSLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700457 return new FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000458}
459
joshualittb0a8a372014-09-23 09:50:21 -0700460GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000461
joshualitt01258472014-09-22 10:29:30 -0700462/*
463 * All Two point conical gradient test create functions may occasionally create edge case shaders
464 */
Hal Canary6f6961e2017-01-31 13:50:44 -0500465#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -0700466sk_sp<GrFragmentProcessor> FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700467 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000468 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000469 SkPoint center2;
470 SkScalar radius2;
471 do {
joshualitt0067ff52015-07-08 14:26:19 -0700472 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000473 // 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 +0000474 } while (center1 == center2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000475
Brian Osman3f748602016-10-03 18:29:03 -0400476 SkPoint diff = center2 - center1;
477 SkScalar diffLen = diff.length();
478 // Below makes sure that the focal point is not contained within circle two
479 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
480
481 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400482 auto shader = params.fUseColors4f ?
483 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
484 params.fColors4f, params.fColorSpace, params.fStops,
485 params.fColorCount, params.fTileMode) :
486 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
487 params.fColors, params.fStops,
488 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400489 GrTest::TestAsFPArgs asFPArgs(d);
490 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -0700491 GrAlwaysAssert(fp);
492 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000493}
Hal Canary6f6961e2017-01-31 13:50:44 -0500494#endif
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000495
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) {
Mike Reed8be952a2017-02-13 20:44:33 -0500566 SkScalar oneMinus2F = 1.f - 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 */
Hal Canary6f6961e2017-01-31 13:50:44 -0500669#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -0700670sk_sp<GrFragmentProcessor> FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700671 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000672 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000673 SkPoint center2;
674 SkScalar radius2;
675 do {
joshualitt0067ff52015-07-08 14:26:19 -0700676 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000677 // Below makes sure radius2 is larger enouch such that the focal point
678 // is inside the end circle
joshualitt0067ff52015-07-08 14:26:19 -0700679 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000680 SkPoint diff = center2 - center1;
681 SkScalar diffLen = diff.length();
682 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000683 // If the circles are identical the factory will give us an empty shader.
684 } while (radius1 == radius2 && center1 == center2);
685
Brian Osman3f748602016-10-03 18:29:03 -0400686 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400687 auto shader = params.fUseColors4f ?
688 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
689 params.fColors4f, params.fColorSpace, params.fStops,
690 params.fColorCount, params.fTileMode) :
691 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
692 params.fColors, params.fStops,
693 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400694 GrTest::TestAsFPArgs asFPArgs(d);
695 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -0700696 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700697 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000698}
Hal Canary6f6961e2017-01-31 13:50:44 -0500699#endif
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000700
fmenozzi55d318d2016-08-09 08:05:57 -0700701FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
702 ::GLSLFocalInside2PtConicalProcessor(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700703 : fVSVaryingName(nullptr)
704 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000705 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000706
fmenozzi55d318d2016-08-09 08:05:57 -0700707void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700708 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800709 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
710 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800711 fFocalUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800712 kFloat_GrSLType, kDefault_GrSLPrecision,
713 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000714 SkString tName("t");
715
716 // this is the distance along x-axis from the end center to focal point in
717 // transformed coordinates
Brian Salomon99938a82016-11-21 13:41:08 -0500718 GrShaderVar focal = uniformHandler->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000719
720 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800721 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700722 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000723 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000724
725 // t = p.x * focalX + length(p)
egdaniel4ca2e602015-11-18 08:01:26 -0800726 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
egdaniel7ea439b2015-12-03 09:20:44 -0800727 coords2D, focal.c_str(), coords2D);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000728
egdaniel7ea439b2015-12-03 09:20:44 -0800729 this->emitColor(fragBuilder,
730 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500731 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800732 ge,
733 tName.c_str(),
734 args.fOutputColor,
735 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700736 args.fTexSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000737}
738
fmenozzi55d318d2016-08-09 08:05:57 -0700739void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::onSetData(
740 const GrGLSLProgramDataManager& pdman,
741 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700742 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700743 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000744 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000745
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000746 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700747 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000748 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000749 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000750}
751
fmenozzi55d318d2016-08-09 08:05:57 -0700752void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(
753 const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -0500754 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700755 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000756}
757
758//////////////////////////////////////////////////////////////////////////////
759// Circle Conical Gradients
760//////////////////////////////////////////////////////////////////////////////
761
762struct CircleConicalInfo {
763 SkPoint fCenterEnd;
764 SkScalar fA;
765 SkScalar fB;
766 SkScalar fC;
767};
768
769// Returns focal distance along x-axis in transformed coords
770static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
771 SkMatrix* invLMatrix, CircleConicalInfo* info) {
772 // Inverse of the current local matrix is passed in then,
773 // translate and scale such that start circle is on the origin and has radius 1
774 const SkPoint& centerStart = shader.getStartCenter();
775 const SkPoint& centerEnd = shader.getEndCenter();
776 SkScalar radiusStart = shader.getStartRadius();
777 SkScalar radiusEnd = shader.getEndRadius();
778
779 SkMatrix matrix;
780
781 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
782
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000783 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000784 matrix.postScale(invStartRad, invStartRad);
785
786 radiusEnd /= radiusStart;
787
788 SkPoint centerEndTrans;
789 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
790
791 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
792 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
793
794 // Check to see if start circle is inside end circle with edges touching.
795 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700796 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
797 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
798 // still accurate.
799 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000800 return kEdge_ConicalType;
801 }
802
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000803 SkScalar C = 1.f / A;
804 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000805
806 matrix.postScale(C, C);
807
808 invLMatrix->postConcat(matrix);
809
810 info->fCenterEnd = centerEndTrans;
811 info->fA = A;
812 info->fB = B;
813 info->fC = C;
814
815 // 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 +0000816 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000817 return kInside_ConicalType;
818 }
819 return kOutside_ConicalType;
820}
821
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000822class CircleInside2PtConicalEffect : public GrGradientEffect {
823public:
fmenozzi55d318d2016-08-09 08:05:57 -0700824 class GLSLCircleInside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000825
brianosman9557c272016-09-15 06:59:15 -0700826 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
bungeman06ca8ec2016-06-09 08:01:03 -0700827 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700828 new CircleInside2PtConicalEffect(args, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000829 }
830
831 virtual ~CircleInside2PtConicalEffect() {}
832
mtklein36352bf2015-03-25 18:17:31 -0700833 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800834
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000835 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
836 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
837 SkScalar A() const { return fInfo.fA; }
838 SkScalar B() const { return fInfo.fB; }
839 SkScalar C() const { return fInfo.fC; }
840
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000841private:
egdaniel57d3b032015-11-13 11:57:27 -0800842 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700843
Brian Salomon94efbf52016-11-29 13:43:05 -0500844 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800845 GrProcessorKeyBuilder* b) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700846
mtklein36352bf2015-03-25 18:17:31 -0700847 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700848 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000849 return (INHERITED::onIsEqual(sBase) &&
850 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
851 this->fInfo.fA == s.fInfo.fA &&
852 this->fInfo.fB == s.fInfo.fB &&
853 this->fInfo.fC == s.fInfo.fC);
854 }
855
brianosman9557c272016-09-15 06:59:15 -0700856 CircleInside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
Brian Salomon587e08f2017-01-27 10:59:27 -0500857 : INHERITED(args, args.fShader->colorsAreOpaque()), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800858 this->initClassID<CircleInside2PtConicalEffect>();
859 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000860
joshualittb0a8a372014-09-23 09:50:21 -0700861 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000862
863 const CircleConicalInfo fInfo;
864
865 typedef GrGradientEffect INHERITED;
866};
867
fmenozzi55d318d2016-08-09 08:05:57 -0700868class CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
869 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000870public:
fmenozzi55d318d2016-08-09 08:05:57 -0700871 GLSLCircleInside2PtConicalProcessor(const GrProcessor&);
872 virtual ~GLSLCircleInside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000873
wangyix7c157a92015-07-22 15:08:53 -0700874 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000875
Brian Salomon94efbf52016-11-29 13:43:05 -0500876 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000877
878protected:
egdaniel018fb622015-10-28 07:26:40 -0700879 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700880
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000881 UniformHandle fCenterUni;
882 UniformHandle fParamUni;
883
884 const char* fVSVaryingName;
885 const char* fFSVaryingName;
886
887 // @{
888 /// Values last uploaded as uniforms
889
890 SkScalar fCachedCenterX;
891 SkScalar fCachedCenterY;
892 SkScalar fCachedA;
893 SkScalar fCachedB;
894 SkScalar fCachedC;
895
896 // @}
897
898private:
fmenozzi55d318d2016-08-09 08:05:57 -0700899 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000900
901};
902
Brian Salomon94efbf52016-11-29 13:43:05 -0500903void CircleInside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800904 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700905 CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800906}
907
egdaniel57d3b032015-11-13 11:57:27 -0800908GrGLSLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700909 return new CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000910}
911
joshualittb0a8a372014-09-23 09:50:21 -0700912GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000913
joshualitt01258472014-09-22 10:29:30 -0700914/*
915 * All Two point conical gradient test create functions may occasionally create edge case shaders
916 */
Hal Canary6f6961e2017-01-31 13:50:44 -0500917#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -0700918sk_sp<GrFragmentProcessor> CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700919 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
920 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000921 SkPoint center2;
922 SkScalar radius2;
923 do {
joshualitt0067ff52015-07-08 14:26:19 -0700924 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000925 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700926 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000927 SkPoint diff = center2 - center1;
928 SkScalar diffLen = diff.length();
929 radius2 = radius1 + diffLen + increase;
930 // If the circles are identical the factory will give us an empty shader.
931 } while (radius1 == radius2 && center1 == center2);
932
Brian Osman3f748602016-10-03 18:29:03 -0400933 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400934 auto shader = params.fUseColors4f ?
935 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
936 params.fColors4f, params.fColorSpace, params.fStops,
937 params.fColorCount, params.fTileMode) :
938 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
939 params.fColors, params.fStops,
940 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400941 GrTest::TestAsFPArgs asFPArgs(d);
942 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -0700943 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -0700944 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000945}
Hal Canary6f6961e2017-01-31 13:50:44 -0500946#endif
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000947
fmenozzi55d318d2016-08-09 08:05:57 -0700948CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
949 ::GLSLCircleInside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700950 : fVSVaryingName(nullptr)
951 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000952 , fCachedCenterX(SK_ScalarMax)
953 , fCachedCenterY(SK_ScalarMax)
954 , fCachedA(SK_ScalarMax)
955 , fCachedB(SK_ScalarMax)
956 , fCachedC(SK_ScalarMax) {}
957
fmenozzi55d318d2016-08-09 08:05:57 -0700958void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700959 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800960 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
961 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800962 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800963 kVec2f_GrSLType, kDefault_GrSLPrecision,
964 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -0800965 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800966 kVec3f_GrSLType, kDefault_GrSLPrecision,
967 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000968 SkString tName("t");
969
Brian Salomon99938a82016-11-21 13:41:08 -0500970 GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000971 // params.x = A
972 // params.y = B
973 // params.z = C
Brian Salomon99938a82016-11-21 13:41:08 -0500974 GrShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000975
976 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800977 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700978 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000979 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000980
981 // p = coords2D
982 // e = center end
983 // r = radius end
984 // A = dot(e, e) - r^2 + 2 * r - 1
985 // B = (r -1) / A
986 // C = 1 / A
987 // d = dot(e, p) + B
988 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
egdaniel4ca2e602015-11-18 08:01:26 -0800989 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
990 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
991 params.c_str());
992 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
993 tName.c_str(), params.c_str(), params.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000994
egdaniel7ea439b2015-12-03 09:20:44 -0800995 this->emitColor(fragBuilder,
996 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500997 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800998 ge,
999 tName.c_str(),
1000 args.fOutputColor,
1001 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -07001002 args.fTexSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001003}
1004
fmenozzi55d318d2016-08-09 08:05:57 -07001005void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::onSetData(
1006 const GrGLSLProgramDataManager& pdman,
1007 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001008 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001009 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001010 SkScalar centerX = data.centerX();
1011 SkScalar centerY = data.centerY();
1012 SkScalar A = data.A();
1013 SkScalar B = data.B();
1014 SkScalar C = data.C();
1015
1016 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1017 fCachedA != A || fCachedB != B || fCachedC != C) {
1018
kkinnunen7510b222014-07-30 00:04:16 -07001019 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1020 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001021
1022 fCachedCenterX = centerX;
1023 fCachedCenterY = centerY;
1024 fCachedA = A;
1025 fCachedB = B;
1026 fCachedC = C;
1027 }
1028}
1029
fmenozzi55d318d2016-08-09 08:05:57 -07001030void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(
1031 const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -05001032 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001033 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001034}
1035
1036//////////////////////////////////////////////////////////////////////////////
1037
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001038class CircleOutside2PtConicalEffect : public GrGradientEffect {
1039public:
fmenozzi55d318d2016-08-09 08:05:57 -07001040 class GLSLCircleOutside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001041
brianosman9557c272016-09-15 06:59:15 -07001042 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
bungeman06ca8ec2016-06-09 08:01:03 -07001043 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -07001044 new CircleOutside2PtConicalEffect(args, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001045 }
1046
1047 virtual ~CircleOutside2PtConicalEffect() {}
1048
mtklein36352bf2015-03-25 18:17:31 -07001049 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001050
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001051 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1052 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1053 SkScalar A() const { return fInfo.fA; }
1054 SkScalar B() const { return fInfo.fB; }
1055 SkScalar C() const { return fInfo.fC; }
1056 SkScalar tLimit() const { return fTLimit; }
1057 bool isFlipped() const { return fIsFlipped; }
1058
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001059private:
egdaniel57d3b032015-11-13 11:57:27 -08001060 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -07001061
Brian Salomon94efbf52016-11-29 13:43:05 -05001062 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -07001063
mtklein36352bf2015-03-25 18:17:31 -07001064 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001065 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001066 return (INHERITED::onIsEqual(sBase) &&
1067 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1068 this->fInfo.fA == s.fInfo.fA &&
1069 this->fInfo.fB == s.fInfo.fB &&
1070 this->fInfo.fC == s.fInfo.fC &&
1071 this->fTLimit == s.fTLimit &&
1072 this->fIsFlipped == s.fIsFlipped);
1073 }
1074
brianosman9557c272016-09-15 06:59:15 -07001075 CircleOutside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
Brian Salomon587e08f2017-01-27 10:59:27 -05001076 : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
1077 , fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001078 this->initClassID<CircleOutside2PtConicalEffect>();
brianosman9557c272016-09-15 06:59:15 -07001079 const SkTwoPointConicalGradient& shader =
1080 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001081 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001082 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001083 } else {
1084 fTLimit = SK_ScalarMin;
1085 }
1086
1087 fIsFlipped = shader.isFlippedGrad();
1088 }
1089
joshualittb0a8a372014-09-23 09:50:21 -07001090 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001091
1092 const CircleConicalInfo fInfo;
1093 SkScalar fTLimit;
1094 bool fIsFlipped;
1095
1096 typedef GrGradientEffect INHERITED;
1097};
1098
fmenozzi55d318d2016-08-09 08:05:57 -07001099class CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
1100 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001101public:
fmenozzi55d318d2016-08-09 08:05:57 -07001102 GLSLCircleOutside2PtConicalProcessor(const GrProcessor&);
1103 virtual ~GLSLCircleOutside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001104
wangyix7c157a92015-07-22 15:08:53 -07001105 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001106
Brian Salomon94efbf52016-11-29 13:43:05 -05001107 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001108
1109protected:
egdaniel018fb622015-10-28 07:26:40 -07001110 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001111
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001112 UniformHandle fCenterUni;
1113 UniformHandle fParamUni;
1114
1115 const char* fVSVaryingName;
1116 const char* fFSVaryingName;
1117
1118 bool fIsFlipped;
1119
1120 // @{
1121 /// Values last uploaded as uniforms
1122
1123 SkScalar fCachedCenterX;
1124 SkScalar fCachedCenterY;
1125 SkScalar fCachedA;
1126 SkScalar fCachedB;
1127 SkScalar fCachedC;
1128 SkScalar fCachedTLimit;
1129
1130 // @}
1131
1132private:
fmenozzi55d318d2016-08-09 08:05:57 -07001133 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001134
1135};
1136
Brian Salomon94efbf52016-11-29 13:43:05 -05001137void CircleOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -08001138 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -07001139 CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -08001140}
1141
egdaniel57d3b032015-11-13 11:57:27 -08001142GrGLSLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -07001143 return new CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001144}
1145
joshualittb0a8a372014-09-23 09:50:21 -07001146GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001147
joshualitt01258472014-09-22 10:29:30 -07001148/*
1149 * All Two point conical gradient test create functions may occasionally create edge case shaders
1150 */
Hal Canary6f6961e2017-01-31 13:50:44 -05001151#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -07001152sk_sp<GrFragmentProcessor> CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001153 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1154 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001155 SkPoint center2;
1156 SkScalar radius2;
1157 SkScalar diffLen;
1158 do {
joshualitt0067ff52015-07-08 14:26:19 -07001159 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001160 // If the circles share a center than we can't be in the outside case
1161 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001162 SkPoint diff = center2 - center1;
1163 diffLen = diff.length();
1164 // Below makes sure that circle one is not contained within circle two
1165 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001166 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001167
Brian Osman3f748602016-10-03 18:29:03 -04001168 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -04001169 auto shader = params.fUseColors4f ?
1170 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
1171 params.fColors4f, params.fColorSpace, params.fStops,
1172 params.fColorCount, params.fTileMode) :
1173 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
1174 params.fColors, params.fStops,
1175 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -04001176 GrTest::TestAsFPArgs asFPArgs(d);
1177 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -07001178 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -07001179 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001180}
Hal Canary6f6961e2017-01-31 13:50:44 -05001181#endif
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001182
fmenozzi55d318d2016-08-09 08:05:57 -07001183CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
1184 ::GLSLCircleOutside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -07001185 : fVSVaryingName(nullptr)
1186 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001187 , fCachedCenterX(SK_ScalarMax)
1188 , fCachedCenterY(SK_ScalarMax)
1189 , fCachedA(SK_ScalarMax)
1190 , fCachedB(SK_ScalarMax)
1191 , fCachedC(SK_ScalarMax)
1192 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001193 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001194 fIsFlipped = data.isFlipped();
1195 }
1196
fmenozzi55d318d2016-08-09 08:05:57 -07001197void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -07001198 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -08001199 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1200 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -08001201 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001202 kVec2f_GrSLType, kDefault_GrSLPrecision,
1203 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -08001204 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001205 kVec4f_GrSLType, kDefault_GrSLPrecision,
1206 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001207 SkString tName("t");
1208
Brian Salomon99938a82016-11-21 13:41:08 -05001209 GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001210 // params.x = A
1211 // params.y = B
1212 // params.z = C
Brian Salomon99938a82016-11-21 13:41:08 -05001213 GrShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001214
1215 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -08001216 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -07001217 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001218 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001219
1220 // output will default to transparent black (we simply won't write anything
1221 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -08001222 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 +00001223
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001224 // p = coords2D
1225 // e = center end
1226 // r = radius end
1227 // A = dot(e, e) - r^2 + 2 * r - 1
1228 // B = (r -1) / A
1229 // C = 1 / A
1230 // d = dot(e, p) + B
1231 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001232
egdaniel4ca2e602015-11-18 08:01:26 -08001233 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
1234 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1235 params.c_str());
1236 fragBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1237 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001238
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001239 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1240 // If so we must also flip sign on sqrt
1241 if (!fIsFlipped) {
egdaniel4ca2e602015-11-18 08:01:26 -08001242 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001243 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001244 fragBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001245 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001246
egdaniel7ea439b2015-12-03 09:20:44 -08001247 fragBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n",
1248 tName.c_str(), params.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001249 fragBuilder->codeAppend("\t\t");
egdaniel7ea439b2015-12-03 09:20:44 -08001250 this->emitColor(fragBuilder,
1251 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -05001252 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -08001253 ge,
1254 tName.c_str(),
1255 args.fOutputColor,
1256 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -07001257 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -08001258 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001259}
1260
fmenozzi55d318d2016-08-09 08:05:57 -07001261void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::onSetData(
1262 const GrGLSLProgramDataManager& pdman,
egdaniel018fb622015-10-28 07:26:40 -07001263 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001264 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001265 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001266 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001267 SkScalar centerX = data.centerX();
1268 SkScalar centerY = data.centerY();
1269 SkScalar A = data.A();
1270 SkScalar B = data.B();
1271 SkScalar C = data.C();
1272 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001273
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001274 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1275 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001276
kkinnunen7510b222014-07-30 00:04:16 -07001277 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1278 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001279 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001280
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001281 fCachedCenterX = centerX;
1282 fCachedCenterY = centerY;
1283 fCachedA = A;
1284 fCachedB = B;
1285 fCachedC = C;
1286 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001287 }
1288}
1289
fmenozzi55d318d2016-08-09 08:05:57 -07001290void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(
1291 const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -05001292 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001293 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001294 key[0] = GenBaseGradientKey(processor);
1295 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001296}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001297
1298//////////////////////////////////////////////////////////////////////////////
1299
brianosman9557c272016-09-15 06:59:15 -07001300sk_sp<GrFragmentProcessor> Gr2PtConicalGradientEffect::Make(
1301 const GrGradientEffect::CreateArgs& args) {
1302 const SkTwoPointConicalGradient& shader =
1303 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
1304
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001305 SkMatrix matrix;
1306 if (!shader.getLocalMatrix().invert(&matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001307 return nullptr;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001308 }
brianosman9557c272016-09-15 06:59:15 -07001309 if (args.fMatrix) {
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001310 SkMatrix inv;
brianosman9557c272016-09-15 06:59:15 -07001311 if (!args.fMatrix->invert(&inv)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001312 return nullptr;
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001313 }
1314 matrix.postConcat(inv);
1315 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001316
brianosmanb9c51372016-09-15 11:09:45 -07001317 GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fTileMode,
1318 std::move(args.fColorSpaceXform), args.fGammaCorrect);
brianosman9557c272016-09-15 06:59:15 -07001319
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001320 if (shader.getStartRadius() < kErrorTol) {
1321 SkScalar focalX;
1322 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1323 if (type == kInside_ConicalType) {
brianosman9557c272016-09-15 06:59:15 -07001324 return FocalInside2PtConicalEffect::Make(newArgs, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001325 } else if(type == kEdge_ConicalType) {
1326 set_matrix_edge_conical(shader, &matrix);
brianosman9557c272016-09-15 06:59:15 -07001327 return Edge2PtConicalEffect::Make(newArgs);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001328 } else {
brianosman9557c272016-09-15 06:59:15 -07001329 return FocalOutside2PtConicalEffect::Make(newArgs, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001330 }
1331 }
1332
1333 CircleConicalInfo info;
1334 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1335
1336 if (type == kInside_ConicalType) {
brianosman9557c272016-09-15 06:59:15 -07001337 return CircleInside2PtConicalEffect::Make(newArgs, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001338 } else if (type == kEdge_ConicalType) {
1339 set_matrix_edge_conical(shader, &matrix);
brianosman9557c272016-09-15 06:59:15 -07001340 return Edge2PtConicalEffect::Make(newArgs);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001341 } else {
brianosman9557c272016-09-15 06:59:15 -07001342 return CircleOutside2PtConicalEffect::Make(newArgs, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001343 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001344}
1345
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001346#endif