blob: a301d64aca40bd34ca2766b3a695ecd45826f36a [file] [log] [blame]
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00007
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00008
9#include "SkTwoPointConicalGradient.h"
10
commit-bot@chromium.orgef93d292014-04-10 15:37:52 +000011#if SK_SUPPORT_GPU
egdaniel7ea439b2015-12-03 09:20:44 -080012#include "GrCoordTransform.h"
13#include "GrInvariantOutput.h"
joshualitt8ca93e72015-07-08 06:51:43 -070014#include "GrPaint.h"
egdaniel2d721d32015-11-11 13:06:05 -080015#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070016#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080017#include "glsl/GrGLSLUniformHandler.h"
brianosman9557c272016-09-15 06:59:15 -070018#include "SkTwoPointConicalGradient_gpu.h"
19
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000020// For brevity
egdaniel018fb622015-10-28 07:26:40 -070021typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000022
commit-bot@chromium.org80894672014-04-22 21:24:22 +000023static const SkScalar kErrorTol = 0.00001f;
egdaniel8405ef92014-06-09 11:57:28 -070024static const SkScalar kEdgeErrorTol = 5.f * kErrorTol;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000025
26/**
27 * We have three general cases for 2pt conical gradients. First we always assume that
28 * the start radius <= end radius. Our first case (kInside_) is when the start circle
29 * is completely enclosed by the end circle. The second case (kOutside_) is the case
30 * when the start circle is either completely outside the end circle or the circles
31 * overlap. The final case (kEdge_) is when the start circle is inside the end one,
32 * but the two are just barely touching at 1 point along their edges.
33 */
34enum ConicalType {
35 kInside_ConicalType,
36 kOutside_ConicalType,
37 kEdge_ConicalType,
38};
39
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000040//////////////////////////////////////////////////////////////////////////////
41
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000042static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader,
43 SkMatrix* invLMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000044 // Inverse of the current local matrix is passed in then,
45 // translate to center1, rotate so center2 is on x axis.
46 const SkPoint& center1 = shader.getStartCenter();
47 const SkPoint& center2 = shader.getEndCenter();
48
49 invLMatrix->postTranslate(-center1.fX, -center1.fY);
50
51 SkPoint diff = center2 - center1;
52 SkScalar diffLen = diff.length();
53 if (0 != diffLen) {
54 SkScalar invDiffLen = SkScalarInvert(diffLen);
55 SkMatrix rot;
56 rot.setSinCos(-SkScalarMul(invDiffLen, diff.fY),
57 SkScalarMul(invDiffLen, diff.fX));
58 invLMatrix->postConcat(rot);
59 }
60}
61
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000062class Edge2PtConicalEffect : public GrGradientEffect {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000063public:
fmenozzi55d318d2016-08-09 08:05:57 -070064 class GLSLEdge2PtConicalProcessor;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000065
brianosman9557c272016-09-15 06:59:15 -070066 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
67 return sk_sp<GrFragmentProcessor>(new Edge2PtConicalEffect(args));
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000068 }
69
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000070 virtual ~Edge2PtConicalEffect() {}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000071
mtklein36352bf2015-03-25 18:17:31 -070072 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -080073 return "Two-Point Conical Gradient Edge Touching";
74 }
75
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000076 // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000077 SkScalar center() const { return fCenterX1; }
78 SkScalar diffRadius() const { return fDiffRadius; }
79 SkScalar radius() const { return fRadius0; }
80
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000081private:
egdaniel57d3b032015-11-13 11:57:27 -080082 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -070083
Brian Salomon94efbf52016-11-29 13:43:05 -050084 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -070085
mtklein36352bf2015-03-25 18:17:31 -070086 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -070087 const Edge2PtConicalEffect& s = sBase.cast<Edge2PtConicalEffect>();
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000088 return (INHERITED::onIsEqual(sBase) &&
89 this->fCenterX1 == s.fCenterX1 &&
90 this->fRadius0 == s.fRadius0 &&
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000091 this->fDiffRadius == s.fDiffRadius);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000092 }
93
brianosman9557c272016-09-15 06:59:15 -070094 Edge2PtConicalEffect(const CreateArgs& args)
Brian Salomon587e08f2017-01-27 10:59:27 -050095 : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */) {
brianosman9557c272016-09-15 06:59:15 -070096 const SkTwoPointConicalGradient& shader =
97 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
98 fCenterX1 = shader.getCenterX1();
99 fRadius0 = shader.getStartRadius();
100 fDiffRadius = shader.getDiffRadius();
joshualitteb2a6762014-12-04 11:35:33 -0800101 this->initClassID<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000102 // We should only be calling this shader if we are degenerate case with touching circles
egdaniel8405ef92014-06-09 11:57:28 -0700103 // When deciding if we are in edge case, we scaled by the end radius for cases when the
joshualitt01258472014-09-22 10:29:30 -0700104 // start radius was close to zero, otherwise we scaled by the start radius. In addition
105 // Our test for the edge case in set_matrix_circle_conical has a higher tolerance so we
106 // need the sqrt value below
107 SkASSERT(SkScalarAbs(SkScalarAbs(fDiffRadius) - fCenterX1) <
108 (fRadius0 < kErrorTol ? shader.getEndRadius() * kEdgeErrorTol :
109 fRadius0 * sqrt(kEdgeErrorTol)));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000110
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000111 // We pass the linear part of the quadratic as a varying.
112 // float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
113 fBTransform = this->getCoordTransform();
114 SkMatrix& bMatrix = *fBTransform.accessMatrix();
115 SkScalar r0dr = SkScalarMul(fRadius0, fDiffRadius);
116 bMatrix[SkMatrix::kMScaleX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMScaleX]) +
117 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp0]));
118 bMatrix[SkMatrix::kMSkewX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMSkewX]) +
119 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp1]));
120 bMatrix[SkMatrix::kMTransX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMTransX]) +
121 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp2]));
122 this->addCoordTransform(&fBTransform);
123 }
124
joshualittb0a8a372014-09-23 09:50:21 -0700125 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000126
127 // @{
128 // Cache of values - these can change arbitrarily, EXCEPT
129 // we shouldn't change between degenerate and non-degenerate?!
130
131 GrCoordTransform fBTransform;
132 SkScalar fCenterX1;
133 SkScalar fRadius0;
134 SkScalar fDiffRadius;
135
136 // @}
137
138 typedef GrGradientEffect INHERITED;
139};
140
fmenozzi55d318d2016-08-09 08:05:57 -0700141class Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000142public:
fmenozzi55d318d2016-08-09 08:05:57 -0700143 GLSLEdge2PtConicalProcessor(const GrProcessor&);
144 virtual ~GLSLEdge2PtConicalProcessor() { }
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000145
wangyix7c157a92015-07-22 15:08:53 -0700146 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000147
Brian Salomon94efbf52016-11-29 13:43:05 -0500148 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000149
150protected:
egdaniel018fb622015-10-28 07:26:40 -0700151 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700152
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000153 UniformHandle fParamUni;
154
155 const char* fVSVaryingName;
156 const char* fFSVaryingName;
157
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000158 // @{
159 /// Values last uploaded as uniforms
160
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000161 SkScalar fCachedRadius;
162 SkScalar fCachedDiffRadius;
163
164 // @}
165
166private:
fmenozzi55d318d2016-08-09 08:05:57 -0700167 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000168
169};
170
Brian Salomon94efbf52016-11-29 13:43:05 -0500171void Edge2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800172 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700173 Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800174}
175
egdaniel57d3b032015-11-13 11:57:27 -0800176GrGLSLFragmentProcessor* Edge2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700177 return new Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor(*this);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000178}
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000179
joshualittb0a8a372014-09-23 09:50:21 -0700180GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Edge2PtConicalEffect);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000181
joshualitt01258472014-09-22 10:29:30 -0700182/*
183 * All Two point conical gradient test create functions may occasionally create edge case shaders
184 */
Hal Canary6f6961e2017-01-31 13:50:44 -0500185#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -0700186sk_sp<GrFragmentProcessor> Edge2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700187 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
188 SkScalar radius1 = d->fRandom->nextUScalar1();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000189 SkPoint center2;
190 SkScalar radius2;
191 do {
joshualitt0067ff52015-07-08 14:26:19 -0700192 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000193 // If the circles are identical the factory will give us an empty shader.
194 // This will happen if we pick identical centers
195 } while (center1 == center2);
196
197 // Below makes sure that circle one is contained within circle two
198 // and both circles are touching on an edge
199 SkPoint diff = center2 - center1;
200 SkScalar diffLen = diff.length();
201 radius2 = radius1 + diffLen;
202
Brian Osman3f748602016-10-03 18:29:03 -0400203 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400204 auto shader = params.fUseColors4f ?
205 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
206 params.fColors4f, params.fColorSpace, params.fStops,
207 params.fColorCount, params.fTileMode) :
208 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
209 params.fColors, params.fStops,
210 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400211 GrTest::TestAsFPArgs asFPArgs(d);
212 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -0700213 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700214 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000215}
Hal Canary6f6961e2017-01-31 13:50:44 -0500216#endif
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000217
fmenozzi55d318d2016-08-09 08:05:57 -0700218Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GLSLEdge2PtConicalProcessor(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700219 : fVSVaryingName(nullptr)
220 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000221 , fCachedRadius(-SK_ScalarMax)
222 , fCachedDiffRadius(-SK_ScalarMax) {}
223
fmenozzi55d318d2016-08-09 08:05:57 -0700224void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700225 const Edge2PtConicalEffect& ge = args.fFp.cast<Edge2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800226 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
227 this->emitUniforms(uniformHandler, ge);
jvanverthde11ee42016-02-26 13:58:40 -0800228 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
229 kVec3f_GrSLType, kDefault_GrSLPrecision,
230 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000231
232 SkString cName("c");
233 SkString tName("t");
234 SkString p0; // start radius
235 SkString p1; // start radius squared
236 SkString p2; // difference in radii (r1 - r0)
237
jvanverthde11ee42016-02-26 13:58:40 -0800238
239 p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
240 p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
241 p2.appendf("%s.z", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000242
243 // We interpolate the linear component in coords[1].
bsalomon1a1aa932016-09-12 09:30:36 -0700244 SkASSERT(args.fTransformedCoords[0].getType() == args.fTransformedCoords[1].getType());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000245 const char* coords2D;
246 SkString bVar;
cdalton85285412016-02-18 12:37:07 -0800247 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700248 if (kVec3f_GrSLType == args.fTransformedCoords[0].getType()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800249 fragBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
bsalomon1a1aa932016-09-12 09:30:36 -0700250 args.fTransformedCoords[0].c_str(),
251 args.fTransformedCoords[0].c_str(),
252 args.fTransformedCoords[1].c_str(),
253 args.fTransformedCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000254 coords2D = "interpolants.xy";
255 bVar = "interpolants.z";
256 } else {
bsalomon1a1aa932016-09-12 09:30:36 -0700257 coords2D = args.fTransformedCoords[0].c_str();
258 bVar.printf("%s.x", args.fTransformedCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000259 }
260
261 // output will default to transparent black (we simply won't write anything
262 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -0800263 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 +0000264
265 // c = (x^2)+(y^2) - params[1]
egdaniel4ca2e602015-11-18 08:01:26 -0800266 fragBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000267 cName.c_str(), coords2D, coords2D, p1.c_str());
268
269 // linear case: t = -c/b
egdaniel4ca2e602015-11-18 08:01:26 -0800270 fragBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000271 cName.c_str(), bVar.c_str());
272
273 // if r(t) > 0, then t will be the x coordinate
egdaniel4ca2e602015-11-18 08:01:26 -0800274 fragBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000275 p2.c_str(), p0.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -0800276 fragBuilder->codeAppend("\t");
egdaniel7ea439b2015-12-03 09:20:44 -0800277 this->emitColor(fragBuilder,
278 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500279 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800280 ge,
281 tName.c_str(),
282 args.fOutputColor,
283 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700284 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -0800285 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000286}
287
fmenozzi55d318d2016-08-09 08:05:57 -0700288void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::onSetData(
289 const GrGLSLProgramDataManager& pdman,
290 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700291 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700292 const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000293 SkScalar radius0 = data.radius();
294 SkScalar diffRadius = data.diffRadius();
295
296 if (fCachedRadius != radius0 ||
297 fCachedDiffRadius != diffRadius) {
298
halcanary9d524f22016-03-29 09:03:52 -0700299 pdman.set3f(fParamUni, SkScalarToFloat(radius0),
jvanverthde11ee42016-02-26 13:58:40 -0800300 SkScalarToFloat(SkScalarMul(radius0, radius0)), SkScalarToFloat(diffRadius));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000301 fCachedRadius = radius0;
302 fCachedDiffRadius = diffRadius;
303 }
304}
305
fmenozzi55d318d2016-08-09 08:05:57 -0700306void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -0500307 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700308 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000309}
310
311//////////////////////////////////////////////////////////////////////////////
312// Focal Conical Gradients
313//////////////////////////////////////////////////////////////////////////////
314
315static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
316 SkMatrix* invLMatrix, SkScalar* focalX) {
317 // Inverse of the current local matrix is passed in then,
318 // translate, scale, and rotate such that endCircle is unit circle on x-axis,
319 // and focal point is at the origin.
320 ConicalType conicalType;
321 const SkPoint& focal = shader.getStartCenter();
322 const SkPoint& centerEnd = shader.getEndCenter();
323 SkScalar radius = shader.getEndRadius();
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000324 SkScalar invRadius = 1.f / radius;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000325
326 SkMatrix matrix;
327
328 matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
329 matrix.postScale(invRadius, invRadius);
330
331 SkPoint focalTrans;
332 matrix.mapPoints(&focalTrans, &focal, 1);
333 *focalX = focalTrans.length();
334
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000335 if (0.f != *focalX) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000336 SkScalar invFocalX = SkScalarInvert(*focalX);
337 SkMatrix rot;
338 rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY),
339 SkScalarMul(invFocalX, focalTrans.fX));
340 matrix.postConcat(rot);
341 }
342
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000343 matrix.postTranslate(-(*focalX), 0.f);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000344
345 // If the focal point is touching the edge of the circle it will
346 // cause a degenerate case that must be handled separately
egdaniel8405ef92014-06-09 11:57:28 -0700347 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
348 // stability trade off versus the linear approx used in the Edge Shader
349 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000350 return kEdge_ConicalType;
351 }
352
353 // Scale factor 1 / (1 - focalX * focalX)
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000354 SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX);
reed80ea19c2015-05-12 10:37:34 -0700355 SkScalar s = SkScalarInvert(oneMinusF2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000356
357
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000358 if (s >= 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000359 conicalType = kInside_ConicalType;
360 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
361 } else {
362 conicalType = kOutside_ConicalType;
363 matrix.postScale(s, s);
364 }
365
366 invLMatrix->postConcat(matrix);
367
368 return conicalType;
369}
370
371//////////////////////////////////////////////////////////////////////////////
372
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000373class FocalOutside2PtConicalEffect : public GrGradientEffect {
374public:
fmenozzi55d318d2016-08-09 08:05:57 -0700375 class GLSLFocalOutside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000376
brianosman9557c272016-09-15 06:59:15 -0700377 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
bungeman06ca8ec2016-06-09 08:01:03 -0700378 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700379 new FocalOutside2PtConicalEffect(args, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000380 }
381
382 virtual ~FocalOutside2PtConicalEffect() { }
383
mtklein36352bf2015-03-25 18:17:31 -0700384 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800385 return "Two-Point Conical Gradient Focal Outside";
386 }
387
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000388 bool isFlipped() const { return fIsFlipped; }
389 SkScalar focal() const { return fFocalX; }
390
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000391private:
egdaniel57d3b032015-11-13 11:57:27 -0800392 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700393
Brian Salomon94efbf52016-11-29 13:43:05 -0500394 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700395
mtklein36352bf2015-03-25 18:17:31 -0700396 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700397 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000398 return (INHERITED::onIsEqual(sBase) &&
399 this->fFocalX == s.fFocalX &&
400 this->fIsFlipped == s.fIsFlipped);
401 }
402
Brian Salomon587e08f2017-01-27 10:59:27 -0500403 static bool IsFlipped(const CreateArgs& args) {
404 // eww.
405 return static_cast<const SkTwoPointConicalGradient*>(args.fShader)->isFlippedGrad();
406 }
407
brianosman9557c272016-09-15 06:59:15 -0700408 FocalOutside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
Brian Salomon587e08f2017-01-27 10:59:27 -0500409 : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
410 , fFocalX(focalX)
411 , fIsFlipped(IsFlipped(args)) {
joshualitteb2a6762014-12-04 11:35:33 -0800412 this->initClassID<FocalOutside2PtConicalEffect>();
413 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000414
joshualittb0a8a372014-09-23 09:50:21 -0700415 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000416
417 SkScalar fFocalX;
418 bool fIsFlipped;
419
420 typedef GrGradientEffect INHERITED;
421};
422
Brian Salomon587e08f2017-01-27 10:59:27 -0500423class FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
fmenozzi55d318d2016-08-09 08:05:57 -0700424 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000425public:
fmenozzi55d318d2016-08-09 08:05:57 -0700426 GLSLFocalOutside2PtConicalProcessor(const GrProcessor&);
427 virtual ~GLSLFocalOutside2PtConicalProcessor() { }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000428
wangyix7c157a92015-07-22 15:08:53 -0700429 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000430
Brian Salomon94efbf52016-11-29 13:43:05 -0500431 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000432
433protected:
egdaniel018fb622015-10-28 07:26:40 -0700434 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700435
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000436 UniformHandle fParamUni;
437
438 const char* fVSVaryingName;
439 const char* fFSVaryingName;
440
441 bool fIsFlipped;
442
443 // @{
444 /// Values last uploaded as uniforms
445
446 SkScalar fCachedFocal;
447
448 // @}
449
450private:
fmenozzi55d318d2016-08-09 08:05:57 -0700451 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000452
453};
454
Brian Salomon94efbf52016-11-29 13:43:05 -0500455void FocalOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800456 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700457 FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800458}
459
egdaniel57d3b032015-11-13 11:57:27 -0800460GrGLSLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700461 return new FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000462}
463
joshualittb0a8a372014-09-23 09:50:21 -0700464GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000465
joshualitt01258472014-09-22 10:29:30 -0700466/*
467 * All Two point conical gradient test create functions may occasionally create edge case shaders
468 */
Hal Canary6f6961e2017-01-31 13:50:44 -0500469#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -0700470sk_sp<GrFragmentProcessor> FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700471 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000472 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000473 SkPoint center2;
474 SkScalar radius2;
475 do {
joshualitt0067ff52015-07-08 14:26:19 -0700476 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000477 // 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 +0000478 } while (center1 == center2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000479
Brian Osman3f748602016-10-03 18:29:03 -0400480 SkPoint diff = center2 - center1;
481 SkScalar diffLen = diff.length();
482 // Below makes sure that the focal point is not contained within circle two
483 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
484
485 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400486 auto shader = params.fUseColors4f ?
487 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
488 params.fColors4f, params.fColorSpace, params.fStops,
489 params.fColorCount, params.fTileMode) :
490 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
491 params.fColors, params.fStops,
492 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400493 GrTest::TestAsFPArgs asFPArgs(d);
494 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -0700495 GrAlwaysAssert(fp);
496 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000497}
Hal Canary6f6961e2017-01-31 13:50:44 -0500498#endif
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000499
fmenozzi55d318d2016-08-09 08:05:57 -0700500FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
501 ::GLSLFocalOutside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700502 : fVSVaryingName(nullptr)
503 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000504 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700505 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000506 fIsFlipped = data.isFlipped();
507}
508
fmenozzi55d318d2016-08-09 08:05:57 -0700509void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700510 const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800511 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
512 this->emitUniforms(uniformHandler, ge);
jvanverthde11ee42016-02-26 13:58:40 -0800513 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
514 kVec2f_GrSLType, kDefault_GrSLPrecision,
515 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000516 SkString tName("t");
517 SkString p0; // focalX
518 SkString p1; // 1 - focalX * focalX
519
jvanverthde11ee42016-02-26 13:58:40 -0800520 p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
521 p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000522
523 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800524 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700525 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000526 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000527
528 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
529
530 // output will default to transparent black (we simply won't write anything
531 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -0800532 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 +0000533
egdaniel4ca2e602015-11-18 08:01:26 -0800534 fragBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
535 fragBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
536 fragBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000537
538 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
539 // If so we must also flip sign on sqrt
540 if (!fIsFlipped) {
egdaniel4ca2e602015-11-18 08:01:26 -0800541 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
542 coords2D, p0.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000543 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800544 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
545 coords2D, p0.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000546 }
547
egdaniel4ca2e602015-11-18 08:01:26 -0800548 fragBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
549 fragBuilder->codeAppend("\t\t");
egdaniel7ea439b2015-12-03 09:20:44 -0800550 this->emitColor(fragBuilder,
551 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500552 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800553 ge,
554 tName.c_str(),
555 args.fOutputColor,
556 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700557 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -0800558 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000559}
560
fmenozzi55d318d2016-08-09 08:05:57 -0700561void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::onSetData(
562 const GrGLSLProgramDataManager& pdman,
563 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700564 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700565 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000566 SkASSERT(data.isFlipped() == fIsFlipped);
567 SkScalar focal = data.focal();
568
569 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000570 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000571
jvanverthde11ee42016-02-26 13:58:40 -0800572 pdman.set2f(fParamUni, SkScalarToFloat(focal), SkScalarToFloat(oneMinus2F));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000573 fCachedFocal = focal;
574 }
575}
576
fmenozzi55d318d2016-08-09 08:05:57 -0700577void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(
578 const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -0500579 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700580 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700581 key[0] = GenBaseGradientKey(processor);
582 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000583}
584
585//////////////////////////////////////////////////////////////////////////////
586
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000587class FocalInside2PtConicalEffect : public GrGradientEffect {
588public:
fmenozzi55d318d2016-08-09 08:05:57 -0700589 class GLSLFocalInside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000590
brianosman9557c272016-09-15 06:59:15 -0700591 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
bungeman06ca8ec2016-06-09 08:01:03 -0700592 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700593 new FocalInside2PtConicalEffect(args, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000594 }
595
596 virtual ~FocalInside2PtConicalEffect() {}
597
mtklein36352bf2015-03-25 18:17:31 -0700598 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800599 return "Two-Point Conical Gradient Focal Inside";
600 }
601
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000602 SkScalar focal() const { return fFocalX; }
603
fmenozzi55d318d2016-08-09 08:05:57 -0700604 typedef FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor GLSLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000605
606private:
egdaniel57d3b032015-11-13 11:57:27 -0800607 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700608
Brian Salomon94efbf52016-11-29 13:43:05 -0500609 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700610
mtklein36352bf2015-03-25 18:17:31 -0700611 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700612 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000613 return (INHERITED::onIsEqual(sBase) &&
614 this->fFocalX == s.fFocalX);
615 }
616
brianosman9557c272016-09-15 06:59:15 -0700617 FocalInside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
Brian Salomon587e08f2017-01-27 10:59:27 -0500618 : INHERITED(args, args.fShader->colorsAreOpaque()), fFocalX(focalX) {
joshualitteb2a6762014-12-04 11:35:33 -0800619 this->initClassID<FocalInside2PtConicalEffect>();
620 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000621
joshualittb0a8a372014-09-23 09:50:21 -0700622 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000623
624 SkScalar fFocalX;
625
626 typedef GrGradientEffect INHERITED;
627};
628
fmenozzi55d318d2016-08-09 08:05:57 -0700629class FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
630 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000631public:
fmenozzi55d318d2016-08-09 08:05:57 -0700632 GLSLFocalInside2PtConicalProcessor(const GrProcessor&);
633 virtual ~GLSLFocalInside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000634
wangyix7c157a92015-07-22 15:08:53 -0700635 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000636
Brian Salomon94efbf52016-11-29 13:43:05 -0500637 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000638
639protected:
egdaniel018fb622015-10-28 07:26:40 -0700640 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700641
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000642 UniformHandle fFocalUni;
643
644 const char* fVSVaryingName;
645 const char* fFSVaryingName;
646
647 // @{
648 /// Values last uploaded as uniforms
649
650 SkScalar fCachedFocal;
651
652 // @}
653
654private:
fmenozzi55d318d2016-08-09 08:05:57 -0700655 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000656
657};
658
Brian Salomon94efbf52016-11-29 13:43:05 -0500659void FocalInside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800660 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700661 FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800662}
663
egdaniel57d3b032015-11-13 11:57:27 -0800664GrGLSLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700665 return new FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000666}
667
joshualittb0a8a372014-09-23 09:50:21 -0700668GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000669
joshualitt01258472014-09-22 10:29:30 -0700670/*
671 * All Two point conical gradient test create functions may occasionally create edge case shaders
672 */
Hal Canary6f6961e2017-01-31 13:50:44 -0500673#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -0700674sk_sp<GrFragmentProcessor> FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700675 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000676 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000677 SkPoint center2;
678 SkScalar radius2;
679 do {
joshualitt0067ff52015-07-08 14:26:19 -0700680 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000681 // Below makes sure radius2 is larger enouch such that the focal point
682 // is inside the end circle
joshualitt0067ff52015-07-08 14:26:19 -0700683 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000684 SkPoint diff = center2 - center1;
685 SkScalar diffLen = diff.length();
686 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000687 // If the circles are identical the factory will give us an empty shader.
688 } while (radius1 == radius2 && center1 == center2);
689
Brian Osman3f748602016-10-03 18:29:03 -0400690 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400691 auto shader = params.fUseColors4f ?
692 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
693 params.fColors4f, params.fColorSpace, params.fStops,
694 params.fColorCount, params.fTileMode) :
695 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
696 params.fColors, params.fStops,
697 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400698 GrTest::TestAsFPArgs asFPArgs(d);
699 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -0700700 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700701 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000702}
Hal Canary6f6961e2017-01-31 13:50:44 -0500703#endif
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000704
fmenozzi55d318d2016-08-09 08:05:57 -0700705FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
706 ::GLSLFocalInside2PtConicalProcessor(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700707 : fVSVaryingName(nullptr)
708 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000709 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000710
fmenozzi55d318d2016-08-09 08:05:57 -0700711void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700712 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800713 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
714 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800715 fFocalUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800716 kFloat_GrSLType, kDefault_GrSLPrecision,
717 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000718 SkString tName("t");
719
720 // this is the distance along x-axis from the end center to focal point in
721 // transformed coordinates
Brian Salomon99938a82016-11-21 13:41:08 -0500722 GrShaderVar focal = uniformHandler->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000723
724 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800725 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700726 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000727 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000728
729 // t = p.x * focalX + length(p)
egdaniel4ca2e602015-11-18 08:01:26 -0800730 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
egdaniel7ea439b2015-12-03 09:20:44 -0800731 coords2D, focal.c_str(), coords2D);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000732
egdaniel7ea439b2015-12-03 09:20:44 -0800733 this->emitColor(fragBuilder,
734 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -0500735 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800736 ge,
737 tName.c_str(),
738 args.fOutputColor,
739 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700740 args.fTexSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000741}
742
fmenozzi55d318d2016-08-09 08:05:57 -0700743void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::onSetData(
744 const GrGLSLProgramDataManager& pdman,
745 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700746 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700747 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000748 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000749
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000750 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700751 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000752 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000753 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000754}
755
fmenozzi55d318d2016-08-09 08:05:57 -0700756void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(
757 const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -0500758 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700759 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000760}
761
762//////////////////////////////////////////////////////////////////////////////
763// Circle Conical Gradients
764//////////////////////////////////////////////////////////////////////////////
765
766struct CircleConicalInfo {
767 SkPoint fCenterEnd;
768 SkScalar fA;
769 SkScalar fB;
770 SkScalar fC;
771};
772
773// Returns focal distance along x-axis in transformed coords
774static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
775 SkMatrix* invLMatrix, CircleConicalInfo* info) {
776 // Inverse of the current local matrix is passed in then,
777 // translate and scale such that start circle is on the origin and has radius 1
778 const SkPoint& centerStart = shader.getStartCenter();
779 const SkPoint& centerEnd = shader.getEndCenter();
780 SkScalar radiusStart = shader.getStartRadius();
781 SkScalar radiusEnd = shader.getEndRadius();
782
783 SkMatrix matrix;
784
785 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
786
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000787 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000788 matrix.postScale(invStartRad, invStartRad);
789
790 radiusEnd /= radiusStart;
791
792 SkPoint centerEndTrans;
793 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
794
795 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
796 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
797
798 // Check to see if start circle is inside end circle with edges touching.
799 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700800 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
801 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
802 // still accurate.
803 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000804 return kEdge_ConicalType;
805 }
806
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000807 SkScalar C = 1.f / A;
808 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000809
810 matrix.postScale(C, C);
811
812 invLMatrix->postConcat(matrix);
813
814 info->fCenterEnd = centerEndTrans;
815 info->fA = A;
816 info->fB = B;
817 info->fC = C;
818
819 // 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 +0000820 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000821 return kInside_ConicalType;
822 }
823 return kOutside_ConicalType;
824}
825
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000826class CircleInside2PtConicalEffect : public GrGradientEffect {
827public:
fmenozzi55d318d2016-08-09 08:05:57 -0700828 class GLSLCircleInside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000829
brianosman9557c272016-09-15 06:59:15 -0700830 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
bungeman06ca8ec2016-06-09 08:01:03 -0700831 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700832 new CircleInside2PtConicalEffect(args, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000833 }
834
835 virtual ~CircleInside2PtConicalEffect() {}
836
mtklein36352bf2015-03-25 18:17:31 -0700837 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800838
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000839 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
840 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
841 SkScalar A() const { return fInfo.fA; }
842 SkScalar B() const { return fInfo.fB; }
843 SkScalar C() const { return fInfo.fC; }
844
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000845private:
egdaniel57d3b032015-11-13 11:57:27 -0800846 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700847
Brian Salomon94efbf52016-11-29 13:43:05 -0500848 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800849 GrProcessorKeyBuilder* b) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700850
mtklein36352bf2015-03-25 18:17:31 -0700851 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700852 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000853 return (INHERITED::onIsEqual(sBase) &&
854 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
855 this->fInfo.fA == s.fInfo.fA &&
856 this->fInfo.fB == s.fInfo.fB &&
857 this->fInfo.fC == s.fInfo.fC);
858 }
859
brianosman9557c272016-09-15 06:59:15 -0700860 CircleInside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
Brian Salomon587e08f2017-01-27 10:59:27 -0500861 : INHERITED(args, args.fShader->colorsAreOpaque()), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800862 this->initClassID<CircleInside2PtConicalEffect>();
863 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000864
joshualittb0a8a372014-09-23 09:50:21 -0700865 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000866
867 const CircleConicalInfo fInfo;
868
869 typedef GrGradientEffect INHERITED;
870};
871
fmenozzi55d318d2016-08-09 08:05:57 -0700872class CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
873 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000874public:
fmenozzi55d318d2016-08-09 08:05:57 -0700875 GLSLCircleInside2PtConicalProcessor(const GrProcessor&);
876 virtual ~GLSLCircleInside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000877
wangyix7c157a92015-07-22 15:08:53 -0700878 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000879
Brian Salomon94efbf52016-11-29 13:43:05 -0500880 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000881
882protected:
egdaniel018fb622015-10-28 07:26:40 -0700883 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700884
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000885 UniformHandle fCenterUni;
886 UniformHandle fParamUni;
887
888 const char* fVSVaryingName;
889 const char* fFSVaryingName;
890
891 // @{
892 /// Values last uploaded as uniforms
893
894 SkScalar fCachedCenterX;
895 SkScalar fCachedCenterY;
896 SkScalar fCachedA;
897 SkScalar fCachedB;
898 SkScalar fCachedC;
899
900 // @}
901
902private:
fmenozzi55d318d2016-08-09 08:05:57 -0700903 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000904
905};
906
Brian Salomon94efbf52016-11-29 13:43:05 -0500907void CircleInside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800908 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700909 CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800910}
911
egdaniel57d3b032015-11-13 11:57:27 -0800912GrGLSLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700913 return new CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000914}
915
joshualittb0a8a372014-09-23 09:50:21 -0700916GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000917
joshualitt01258472014-09-22 10:29:30 -0700918/*
919 * All Two point conical gradient test create functions may occasionally create edge case shaders
920 */
Hal Canary6f6961e2017-01-31 13:50:44 -0500921#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -0700922sk_sp<GrFragmentProcessor> CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700923 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
924 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000925 SkPoint center2;
926 SkScalar radius2;
927 do {
joshualitt0067ff52015-07-08 14:26:19 -0700928 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000929 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700930 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000931 SkPoint diff = center2 - center1;
932 SkScalar diffLen = diff.length();
933 radius2 = radius1 + diffLen + increase;
934 // If the circles are identical the factory will give us an empty shader.
935 } while (radius1 == radius2 && center1 == center2);
936
Brian Osman3f748602016-10-03 18:29:03 -0400937 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400938 auto shader = params.fUseColors4f ?
939 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
940 params.fColors4f, params.fColorSpace, params.fStops,
941 params.fColorCount, params.fTileMode) :
942 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
943 params.fColors, params.fStops,
944 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -0400945 GrTest::TestAsFPArgs asFPArgs(d);
946 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -0700947 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -0700948 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000949}
Hal Canary6f6961e2017-01-31 13:50:44 -0500950#endif
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000951
fmenozzi55d318d2016-08-09 08:05:57 -0700952CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
953 ::GLSLCircleInside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700954 : fVSVaryingName(nullptr)
955 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000956 , fCachedCenterX(SK_ScalarMax)
957 , fCachedCenterY(SK_ScalarMax)
958 , fCachedA(SK_ScalarMax)
959 , fCachedB(SK_ScalarMax)
960 , fCachedC(SK_ScalarMax) {}
961
fmenozzi55d318d2016-08-09 08:05:57 -0700962void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700963 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800964 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
965 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800966 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800967 kVec2f_GrSLType, kDefault_GrSLPrecision,
968 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -0800969 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800970 kVec3f_GrSLType, kDefault_GrSLPrecision,
971 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000972 SkString tName("t");
973
Brian Salomon99938a82016-11-21 13:41:08 -0500974 GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000975 // params.x = A
976 // params.y = B
977 // params.z = C
Brian Salomon99938a82016-11-21 13:41:08 -0500978 GrShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000979
980 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800981 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700982 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000983 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000984
985 // p = coords2D
986 // e = center end
987 // r = radius end
988 // A = dot(e, e) - r^2 + 2 * r - 1
989 // B = (r -1) / A
990 // C = 1 / A
991 // d = dot(e, p) + B
992 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
egdaniel4ca2e602015-11-18 08:01:26 -0800993 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
994 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
995 params.c_str());
996 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
997 tName.c_str(), params.c_str(), params.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000998
egdaniel7ea439b2015-12-03 09:20:44 -0800999 this->emitColor(fragBuilder,
1000 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -05001001 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -08001002 ge,
1003 tName.c_str(),
1004 args.fOutputColor,
1005 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -07001006 args.fTexSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001007}
1008
fmenozzi55d318d2016-08-09 08:05:57 -07001009void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::onSetData(
1010 const GrGLSLProgramDataManager& pdman,
1011 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001012 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001013 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001014 SkScalar centerX = data.centerX();
1015 SkScalar centerY = data.centerY();
1016 SkScalar A = data.A();
1017 SkScalar B = data.B();
1018 SkScalar C = data.C();
1019
1020 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1021 fCachedA != A || fCachedB != B || fCachedC != C) {
1022
kkinnunen7510b222014-07-30 00:04:16 -07001023 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1024 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001025
1026 fCachedCenterX = centerX;
1027 fCachedCenterY = centerY;
1028 fCachedA = A;
1029 fCachedB = B;
1030 fCachedC = C;
1031 }
1032}
1033
fmenozzi55d318d2016-08-09 08:05:57 -07001034void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(
1035 const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -05001036 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001037 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001038}
1039
1040//////////////////////////////////////////////////////////////////////////////
1041
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001042class CircleOutside2PtConicalEffect : public GrGradientEffect {
1043public:
fmenozzi55d318d2016-08-09 08:05:57 -07001044 class GLSLCircleOutside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001045
brianosman9557c272016-09-15 06:59:15 -07001046 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
bungeman06ca8ec2016-06-09 08:01:03 -07001047 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -07001048 new CircleOutside2PtConicalEffect(args, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001049 }
1050
1051 virtual ~CircleOutside2PtConicalEffect() {}
1052
mtklein36352bf2015-03-25 18:17:31 -07001053 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001054
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001055 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1056 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1057 SkScalar A() const { return fInfo.fA; }
1058 SkScalar B() const { return fInfo.fB; }
1059 SkScalar C() const { return fInfo.fC; }
1060 SkScalar tLimit() const { return fTLimit; }
1061 bool isFlipped() const { return fIsFlipped; }
1062
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001063private:
egdaniel57d3b032015-11-13 11:57:27 -08001064 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -07001065
Brian Salomon94efbf52016-11-29 13:43:05 -05001066 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -07001067
mtklein36352bf2015-03-25 18:17:31 -07001068 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001069 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001070 return (INHERITED::onIsEqual(sBase) &&
1071 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1072 this->fInfo.fA == s.fInfo.fA &&
1073 this->fInfo.fB == s.fInfo.fB &&
1074 this->fInfo.fC == s.fInfo.fC &&
1075 this->fTLimit == s.fTLimit &&
1076 this->fIsFlipped == s.fIsFlipped);
1077 }
1078
brianosman9557c272016-09-15 06:59:15 -07001079 CircleOutside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
Brian Salomon587e08f2017-01-27 10:59:27 -05001080 : INHERITED(args, false /* opaque: draws transparent black outside of the cone. */)
1081 , fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001082 this->initClassID<CircleOutside2PtConicalEffect>();
brianosman9557c272016-09-15 06:59:15 -07001083 const SkTwoPointConicalGradient& shader =
1084 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001085 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001086 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001087 } else {
1088 fTLimit = SK_ScalarMin;
1089 }
1090
1091 fIsFlipped = shader.isFlippedGrad();
1092 }
1093
joshualittb0a8a372014-09-23 09:50:21 -07001094 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001095
1096 const CircleConicalInfo fInfo;
1097 SkScalar fTLimit;
1098 bool fIsFlipped;
1099
1100 typedef GrGradientEffect INHERITED;
1101};
1102
fmenozzi55d318d2016-08-09 08:05:57 -07001103class CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
1104 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001105public:
fmenozzi55d318d2016-08-09 08:05:57 -07001106 GLSLCircleOutside2PtConicalProcessor(const GrProcessor&);
1107 virtual ~GLSLCircleOutside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001108
wangyix7c157a92015-07-22 15:08:53 -07001109 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001110
Brian Salomon94efbf52016-11-29 13:43:05 -05001111 static void GenKey(const GrProcessor&, const GrShaderCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001112
1113protected:
egdaniel018fb622015-10-28 07:26:40 -07001114 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001115
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001116 UniformHandle fCenterUni;
1117 UniformHandle fParamUni;
1118
1119 const char* fVSVaryingName;
1120 const char* fFSVaryingName;
1121
1122 bool fIsFlipped;
1123
1124 // @{
1125 /// Values last uploaded as uniforms
1126
1127 SkScalar fCachedCenterX;
1128 SkScalar fCachedCenterY;
1129 SkScalar fCachedA;
1130 SkScalar fCachedB;
1131 SkScalar fCachedC;
1132 SkScalar fCachedTLimit;
1133
1134 // @}
1135
1136private:
fmenozzi55d318d2016-08-09 08:05:57 -07001137 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001138
1139};
1140
Brian Salomon94efbf52016-11-29 13:43:05 -05001141void CircleOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -08001142 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -07001143 CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -08001144}
1145
egdaniel57d3b032015-11-13 11:57:27 -08001146GrGLSLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -07001147 return new CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001148}
1149
joshualittb0a8a372014-09-23 09:50:21 -07001150GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001151
joshualitt01258472014-09-22 10:29:30 -07001152/*
1153 * All Two point conical gradient test create functions may occasionally create edge case shaders
1154 */
Hal Canary6f6961e2017-01-31 13:50:44 -05001155#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -07001156sk_sp<GrFragmentProcessor> CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001157 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1158 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001159 SkPoint center2;
1160 SkScalar radius2;
1161 SkScalar diffLen;
1162 do {
joshualitt0067ff52015-07-08 14:26:19 -07001163 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001164 // If the circles share a center than we can't be in the outside case
1165 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001166 SkPoint diff = center2 - center1;
1167 diffLen = diff.length();
1168 // Below makes sure that circle one is not contained within circle two
1169 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001170 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001171
Brian Osman3f748602016-10-03 18:29:03 -04001172 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -04001173 auto shader = params.fUseColors4f ?
1174 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
1175 params.fColors4f, params.fColorSpace, params.fStops,
1176 params.fColorCount, params.fTileMode) :
1177 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
1178 params.fColors, params.fStops,
1179 params.fColorCount, params.fTileMode);
Brian Osman9f532a32016-10-19 11:12:09 -04001180 GrTest::TestAsFPArgs asFPArgs(d);
1181 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(asFPArgs.args());
bsalomonc21b09e2015-08-28 18:46:56 -07001182 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -07001183 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001184}
Hal Canary6f6961e2017-01-31 13:50:44 -05001185#endif
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001186
fmenozzi55d318d2016-08-09 08:05:57 -07001187CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
1188 ::GLSLCircleOutside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -07001189 : fVSVaryingName(nullptr)
1190 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001191 , fCachedCenterX(SK_ScalarMax)
1192 , fCachedCenterY(SK_ScalarMax)
1193 , fCachedA(SK_ScalarMax)
1194 , fCachedB(SK_ScalarMax)
1195 , fCachedC(SK_ScalarMax)
1196 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001197 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001198 fIsFlipped = data.isFlipped();
1199 }
1200
fmenozzi55d318d2016-08-09 08:05:57 -07001201void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -07001202 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -08001203 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1204 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -08001205 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001206 kVec2f_GrSLType, kDefault_GrSLPrecision,
1207 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -08001208 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001209 kVec4f_GrSLType, kDefault_GrSLPrecision,
1210 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001211 SkString tName("t");
1212
Brian Salomon99938a82016-11-21 13:41:08 -05001213 GrShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001214 // params.x = A
1215 // params.y = B
1216 // params.z = C
Brian Salomon99938a82016-11-21 13:41:08 -05001217 GrShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001218
1219 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -08001220 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -07001221 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001222 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001223
1224 // output will default to transparent black (we simply won't write anything
1225 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -08001226 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 +00001227
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001228 // p = coords2D
1229 // e = center end
1230 // r = radius end
1231 // A = dot(e, e) - r^2 + 2 * r - 1
1232 // B = (r -1) / A
1233 // C = 1 / A
1234 // d = dot(e, p) + B
1235 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001236
egdaniel4ca2e602015-11-18 08:01:26 -08001237 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
1238 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1239 params.c_str());
1240 fragBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1241 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001242
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001243 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1244 // If so we must also flip sign on sqrt
1245 if (!fIsFlipped) {
egdaniel4ca2e602015-11-18 08:01:26 -08001246 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001247 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001248 fragBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001249 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001250
egdaniel7ea439b2015-12-03 09:20:44 -08001251 fragBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n",
1252 tName.c_str(), params.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001253 fragBuilder->codeAppend("\t\t");
egdaniel7ea439b2015-12-03 09:20:44 -08001254 this->emitColor(fragBuilder,
1255 uniformHandler,
Brian Salomon1edc5b92016-11-29 13:43:46 -05001256 args.fShaderCaps,
egdaniel4ca2e602015-11-18 08:01:26 -08001257 ge,
1258 tName.c_str(),
1259 args.fOutputColor,
1260 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -07001261 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -08001262 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001263}
1264
fmenozzi55d318d2016-08-09 08:05:57 -07001265void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::onSetData(
1266 const GrGLSLProgramDataManager& pdman,
egdaniel018fb622015-10-28 07:26:40 -07001267 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001268 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001269 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001270 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001271 SkScalar centerX = data.centerX();
1272 SkScalar centerY = data.centerY();
1273 SkScalar A = data.A();
1274 SkScalar B = data.B();
1275 SkScalar C = data.C();
1276 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001277
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001278 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1279 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001280
kkinnunen7510b222014-07-30 00:04:16 -07001281 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1282 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001283 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001284
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001285 fCachedCenterX = centerX;
1286 fCachedCenterY = centerY;
1287 fCachedA = A;
1288 fCachedB = B;
1289 fCachedC = C;
1290 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001291 }
1292}
1293
fmenozzi55d318d2016-08-09 08:05:57 -07001294void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(
1295 const GrProcessor& processor,
Brian Salomon94efbf52016-11-29 13:43:05 -05001296 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001297 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001298 key[0] = GenBaseGradientKey(processor);
1299 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001300}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001301
1302//////////////////////////////////////////////////////////////////////////////
1303
brianosman9557c272016-09-15 06:59:15 -07001304sk_sp<GrFragmentProcessor> Gr2PtConicalGradientEffect::Make(
1305 const GrGradientEffect::CreateArgs& args) {
1306 const SkTwoPointConicalGradient& shader =
1307 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
1308
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001309 SkMatrix matrix;
1310 if (!shader.getLocalMatrix().invert(&matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001311 return nullptr;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001312 }
brianosman9557c272016-09-15 06:59:15 -07001313 if (args.fMatrix) {
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001314 SkMatrix inv;
brianosman9557c272016-09-15 06:59:15 -07001315 if (!args.fMatrix->invert(&inv)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001316 return nullptr;
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001317 }
1318 matrix.postConcat(inv);
1319 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001320
brianosmanb9c51372016-09-15 11:09:45 -07001321 GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fTileMode,
1322 std::move(args.fColorSpaceXform), args.fGammaCorrect);
brianosman9557c272016-09-15 06:59:15 -07001323
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001324 if (shader.getStartRadius() < kErrorTol) {
1325 SkScalar focalX;
1326 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1327 if (type == kInside_ConicalType) {
brianosman9557c272016-09-15 06:59:15 -07001328 return FocalInside2PtConicalEffect::Make(newArgs, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001329 } else if(type == kEdge_ConicalType) {
1330 set_matrix_edge_conical(shader, &matrix);
brianosman9557c272016-09-15 06:59:15 -07001331 return Edge2PtConicalEffect::Make(newArgs);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001332 } else {
brianosman9557c272016-09-15 06:59:15 -07001333 return FocalOutside2PtConicalEffect::Make(newArgs, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001334 }
1335 }
1336
1337 CircleConicalInfo info;
1338 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1339
1340 if (type == kInside_ConicalType) {
brianosman9557c272016-09-15 06:59:15 -07001341 return CircleInside2PtConicalEffect::Make(newArgs, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001342 } else if (type == kEdge_ConicalType) {
1343 set_matrix_edge_conical(shader, &matrix);
brianosman9557c272016-09-15 06:59:15 -07001344 return Edge2PtConicalEffect::Make(newArgs);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001345 } else {
brianosman9557c272016-09-15 06:59:15 -07001346 return CircleOutside2PtConicalEffect::Make(newArgs, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001347 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001348}
1349
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001350#endif