blob: 8eb8b638f5dc7520ee69cb9bd41f80660bd743a4 [file] [log] [blame]
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00007
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00008
9#include "SkTwoPointConicalGradient.h"
10
commit-bot@chromium.orgef93d292014-04-10 15:37:52 +000011#if SK_SUPPORT_GPU
egdaniel7ea439b2015-12-03 09:20:44 -080012#include "GrCoordTransform.h"
13#include "GrInvariantOutput.h"
joshualitt8ca93e72015-07-08 06:51:43 -070014#include "GrPaint.h"
egdaniel2d721d32015-11-11 13:06:05 -080015#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070016#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080017#include "glsl/GrGLSLUniformHandler.h"
brianosman9557c272016-09-15 06:59:15 -070018#include "SkTwoPointConicalGradient_gpu.h"
19
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000020// For brevity
egdaniel018fb622015-10-28 07:26:40 -070021typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000022
commit-bot@chromium.org80894672014-04-22 21:24:22 +000023static const SkScalar kErrorTol = 0.00001f;
egdaniel8405ef92014-06-09 11:57:28 -070024static const SkScalar kEdgeErrorTol = 5.f * kErrorTol;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000025
26/**
27 * We have three general cases for 2pt conical gradients. First we always assume that
28 * the start radius <= end radius. Our first case (kInside_) is when the start circle
29 * is completely enclosed by the end circle. The second case (kOutside_) is the case
30 * when the start circle is either completely outside the end circle or the circles
31 * overlap. The final case (kEdge_) is when the start circle is inside the end one,
32 * but the two are just barely touching at 1 point along their edges.
33 */
34enum ConicalType {
35 kInside_ConicalType,
36 kOutside_ConicalType,
37 kEdge_ConicalType,
38};
39
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000040//////////////////////////////////////////////////////////////////////////////
41
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000042static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader,
43 SkMatrix* invLMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000044 // Inverse of the current local matrix is passed in then,
45 // translate to center1, rotate so center2 is on x axis.
46 const SkPoint& center1 = shader.getStartCenter();
47 const SkPoint& center2 = shader.getEndCenter();
48
49 invLMatrix->postTranslate(-center1.fX, -center1.fY);
50
51 SkPoint diff = center2 - center1;
52 SkScalar diffLen = diff.length();
53 if (0 != diffLen) {
54 SkScalar invDiffLen = SkScalarInvert(diffLen);
55 SkMatrix rot;
56 rot.setSinCos(-SkScalarMul(invDiffLen, diff.fY),
57 SkScalarMul(invDiffLen, diff.fX));
58 invLMatrix->postConcat(rot);
59 }
60}
61
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000062class Edge2PtConicalEffect : public GrGradientEffect {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000063public:
fmenozzi55d318d2016-08-09 08:05:57 -070064 class GLSLEdge2PtConicalProcessor;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000065
brianosman9557c272016-09-15 06:59:15 -070066 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args) {
67 return sk_sp<GrFragmentProcessor>(new Edge2PtConicalEffect(args));
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000068 }
69
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000070 virtual ~Edge2PtConicalEffect() {}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000071
mtklein36352bf2015-03-25 18:17:31 -070072 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -080073 return "Two-Point Conical Gradient Edge Touching";
74 }
75
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000076 // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000077 SkScalar center() const { return fCenterX1; }
78 SkScalar diffRadius() const { return fDiffRadius; }
79 SkScalar radius() const { return fRadius0; }
80
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000081private:
egdaniel57d3b032015-11-13 11:57:27 -080082 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -070083
egdaniel57d3b032015-11-13 11:57:27 -080084 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -070085
mtklein36352bf2015-03-25 18:17:31 -070086 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -070087 const Edge2PtConicalEffect& s = sBase.cast<Edge2PtConicalEffect>();
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000088 return (INHERITED::onIsEqual(sBase) &&
89 this->fCenterX1 == s.fCenterX1 &&
90 this->fRadius0 == s.fRadius0 &&
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000091 this->fDiffRadius == s.fDiffRadius);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000092 }
93
brianosman9557c272016-09-15 06:59:15 -070094 Edge2PtConicalEffect(const CreateArgs& args)
95 : INHERITED(args) {
96 const SkTwoPointConicalGradient& shader =
97 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
98 fCenterX1 = shader.getCenterX1();
99 fRadius0 = shader.getStartRadius();
100 fDiffRadius = shader.getDiffRadius();
joshualitteb2a6762014-12-04 11:35:33 -0800101 this->initClassID<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000102 // We should only be calling this shader if we are degenerate case with touching circles
egdaniel8405ef92014-06-09 11:57:28 -0700103 // When deciding if we are in edge case, we scaled by the end radius for cases when the
joshualitt01258472014-09-22 10:29:30 -0700104 // start radius was close to zero, otherwise we scaled by the start radius. In addition
105 // Our test for the edge case in set_matrix_circle_conical has a higher tolerance so we
106 // need the sqrt value below
107 SkASSERT(SkScalarAbs(SkScalarAbs(fDiffRadius) - fCenterX1) <
108 (fRadius0 < kErrorTol ? shader.getEndRadius() * kEdgeErrorTol :
109 fRadius0 * sqrt(kEdgeErrorTol)));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000110
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000111 // We pass the linear part of the quadratic as a varying.
112 // float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
113 fBTransform = this->getCoordTransform();
114 SkMatrix& bMatrix = *fBTransform.accessMatrix();
115 SkScalar r0dr = SkScalarMul(fRadius0, fDiffRadius);
116 bMatrix[SkMatrix::kMScaleX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMScaleX]) +
117 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp0]));
118 bMatrix[SkMatrix::kMSkewX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMSkewX]) +
119 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp1]));
120 bMatrix[SkMatrix::kMTransX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMTransX]) +
121 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp2]));
122 this->addCoordTransform(&fBTransform);
123 }
124
joshualittb0a8a372014-09-23 09:50:21 -0700125 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000126
127 // @{
128 // Cache of values - these can change arbitrarily, EXCEPT
129 // we shouldn't change between degenerate and non-degenerate?!
130
131 GrCoordTransform fBTransform;
132 SkScalar fCenterX1;
133 SkScalar fRadius0;
134 SkScalar fDiffRadius;
135
136 // @}
137
138 typedef GrGradientEffect INHERITED;
139};
140
fmenozzi55d318d2016-08-09 08:05:57 -0700141class Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000142public:
fmenozzi55d318d2016-08-09 08:05:57 -0700143 GLSLEdge2PtConicalProcessor(const GrProcessor&);
144 virtual ~GLSLEdge2PtConicalProcessor() { }
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000145
wangyix7c157a92015-07-22 15:08:53 -0700146 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000147
jvanverthcfc18862015-04-28 08:48:20 -0700148 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000149
150protected:
egdaniel018fb622015-10-28 07:26:40 -0700151 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700152
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000153 UniformHandle fParamUni;
154
155 const char* fVSVaryingName;
156 const char* fFSVaryingName;
157
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000158 // @{
159 /// Values last uploaded as uniforms
160
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000161 SkScalar fCachedRadius;
162 SkScalar fCachedDiffRadius;
163
164 // @}
165
166private:
fmenozzi55d318d2016-08-09 08:05:57 -0700167 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000168
169};
170
egdaniel57d3b032015-11-13 11:57:27 -0800171void Edge2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
172 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700173 Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800174}
175
egdaniel57d3b032015-11-13 11:57:27 -0800176GrGLSLFragmentProcessor* Edge2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700177 return new Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor(*this);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000178}
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000179
joshualittb0a8a372014-09-23 09:50:21 -0700180GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Edge2PtConicalEffect);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000181
joshualitt01258472014-09-22 10:29:30 -0700182/*
183 * All Two point conical gradient test create functions may occasionally create edge case shaders
184 */
bungeman06ca8ec2016-06-09 08:01:03 -0700185sk_sp<GrFragmentProcessor> Edge2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700186 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
187 SkScalar radius1 = d->fRandom->nextUScalar1();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000188 SkPoint center2;
189 SkScalar radius2;
190 do {
joshualitt0067ff52015-07-08 14:26:19 -0700191 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000192 // If the circles are identical the factory will give us an empty shader.
193 // This will happen if we pick identical centers
194 } while (center1 == center2);
195
196 // Below makes sure that circle one is contained within circle two
197 // and both circles are touching on an edge
198 SkPoint diff = center2 - center1;
199 SkScalar diffLen = diff.length();
200 radius2 = radius1 + diffLen;
201
Brian Osman3f748602016-10-03 18:29:03 -0400202 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400203 auto shader = params.fUseColors4f ?
204 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
205 params.fColors4f, params.fColorSpace, params.fStops,
206 params.fColorCount, params.fTileMode) :
207 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
208 params.fColors, params.fStops,
209 params.fColorCount, params.fTileMode);
brianosman839345d2016-07-22 11:04:53 -0700210 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
Brian Osman0d9dfe92016-10-03 15:24:44 -0400211 auto dstColorSpace = GrTest::TestColorSpace(d->fRandom);
brianosman839345d2016-07-22 11:04:53 -0700212 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(SkShader::AsFPArgs(
Brian Osman0d9dfe92016-10-03 15:24:44 -0400213 d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(),
brianosman1638c0d2016-07-25 05:12:53 -0700214 SkSourceGammaTreatment::kRespect));
bsalomonc21b09e2015-08-28 18:46:56 -0700215 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700216 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000217}
218
fmenozzi55d318d2016-08-09 08:05:57 -0700219Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GLSLEdge2PtConicalProcessor(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700220 : fVSVaryingName(nullptr)
221 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000222 , fCachedRadius(-SK_ScalarMax)
223 , fCachedDiffRadius(-SK_ScalarMax) {}
224
fmenozzi55d318d2016-08-09 08:05:57 -0700225void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700226 const Edge2PtConicalEffect& ge = args.fFp.cast<Edge2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800227 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
228 this->emitUniforms(uniformHandler, ge);
jvanverthde11ee42016-02-26 13:58:40 -0800229 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
230 kVec3f_GrSLType, kDefault_GrSLPrecision,
231 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000232
233 SkString cName("c");
234 SkString tName("t");
235 SkString p0; // start radius
236 SkString p1; // start radius squared
237 SkString p2; // difference in radii (r1 - r0)
238
jvanverthde11ee42016-02-26 13:58:40 -0800239
240 p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
241 p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
242 p2.appendf("%s.z", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000243
244 // We interpolate the linear component in coords[1].
bsalomon1a1aa932016-09-12 09:30:36 -0700245 SkASSERT(args.fTransformedCoords[0].getType() == args.fTransformedCoords[1].getType());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000246 const char* coords2D;
247 SkString bVar;
cdalton85285412016-02-18 12:37:07 -0800248 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700249 if (kVec3f_GrSLType == args.fTransformedCoords[0].getType()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800250 fragBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
bsalomon1a1aa932016-09-12 09:30:36 -0700251 args.fTransformedCoords[0].c_str(),
252 args.fTransformedCoords[0].c_str(),
253 args.fTransformedCoords[1].c_str(),
254 args.fTransformedCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000255 coords2D = "interpolants.xy";
256 bVar = "interpolants.z";
257 } else {
bsalomon1a1aa932016-09-12 09:30:36 -0700258 coords2D = args.fTransformedCoords[0].c_str();
259 bVar.printf("%s.x", args.fTransformedCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000260 }
261
262 // output will default to transparent black (we simply won't write anything
263 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -0800264 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 +0000265
266 // c = (x^2)+(y^2) - params[1]
egdaniel4ca2e602015-11-18 08:01:26 -0800267 fragBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000268 cName.c_str(), coords2D, coords2D, p1.c_str());
269
270 // linear case: t = -c/b
egdaniel4ca2e602015-11-18 08:01:26 -0800271 fragBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000272 cName.c_str(), bVar.c_str());
273
274 // if r(t) > 0, then t will be the x coordinate
egdaniel4ca2e602015-11-18 08:01:26 -0800275 fragBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000276 p2.c_str(), p0.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -0800277 fragBuilder->codeAppend("\t");
egdaniel7ea439b2015-12-03 09:20:44 -0800278 this->emitColor(fragBuilder,
279 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -0800280 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800281 ge,
282 tName.c_str(),
283 args.fOutputColor,
284 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700285 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -0800286 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000287}
288
fmenozzi55d318d2016-08-09 08:05:57 -0700289void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::onSetData(
290 const GrGLSLProgramDataManager& pdman,
291 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700292 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700293 const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000294 SkScalar radius0 = data.radius();
295 SkScalar diffRadius = data.diffRadius();
296
297 if (fCachedRadius != radius0 ||
298 fCachedDiffRadius != diffRadius) {
299
halcanary9d524f22016-03-29 09:03:52 -0700300 pdman.set3f(fParamUni, SkScalarToFloat(radius0),
jvanverthde11ee42016-02-26 13:58:40 -0800301 SkScalarToFloat(SkScalarMul(radius0, radius0)), SkScalarToFloat(diffRadius));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000302 fCachedRadius = radius0;
303 fCachedDiffRadius = diffRadius;
304 }
305}
306
fmenozzi55d318d2016-08-09 08:05:57 -0700307void Edge2PtConicalEffect::GLSLEdge2PtConicalProcessor::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700308 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700309 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000310}
311
312//////////////////////////////////////////////////////////////////////////////
313// Focal Conical Gradients
314//////////////////////////////////////////////////////////////////////////////
315
316static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
317 SkMatrix* invLMatrix, SkScalar* focalX) {
318 // Inverse of the current local matrix is passed in then,
319 // translate, scale, and rotate such that endCircle is unit circle on x-axis,
320 // and focal point is at the origin.
321 ConicalType conicalType;
322 const SkPoint& focal = shader.getStartCenter();
323 const SkPoint& centerEnd = shader.getEndCenter();
324 SkScalar radius = shader.getEndRadius();
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000325 SkScalar invRadius = 1.f / radius;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000326
327 SkMatrix matrix;
328
329 matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
330 matrix.postScale(invRadius, invRadius);
331
332 SkPoint focalTrans;
333 matrix.mapPoints(&focalTrans, &focal, 1);
334 *focalX = focalTrans.length();
335
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000336 if (0.f != *focalX) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000337 SkScalar invFocalX = SkScalarInvert(*focalX);
338 SkMatrix rot;
339 rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY),
340 SkScalarMul(invFocalX, focalTrans.fX));
341 matrix.postConcat(rot);
342 }
343
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000344 matrix.postTranslate(-(*focalX), 0.f);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000345
346 // If the focal point is touching the edge of the circle it will
347 // cause a degenerate case that must be handled separately
egdaniel8405ef92014-06-09 11:57:28 -0700348 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
349 // stability trade off versus the linear approx used in the Edge Shader
350 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000351 return kEdge_ConicalType;
352 }
353
354 // Scale factor 1 / (1 - focalX * focalX)
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000355 SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX);
reed80ea19c2015-05-12 10:37:34 -0700356 SkScalar s = SkScalarInvert(oneMinusF2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000357
358
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000359 if (s >= 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000360 conicalType = kInside_ConicalType;
361 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
362 } else {
363 conicalType = kOutside_ConicalType;
364 matrix.postScale(s, s);
365 }
366
367 invLMatrix->postConcat(matrix);
368
369 return conicalType;
370}
371
372//////////////////////////////////////////////////////////////////////////////
373
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000374class FocalOutside2PtConicalEffect : public GrGradientEffect {
375public:
fmenozzi55d318d2016-08-09 08:05:57 -0700376 class GLSLFocalOutside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000377
brianosman9557c272016-09-15 06:59:15 -0700378 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
bungeman06ca8ec2016-06-09 08:01:03 -0700379 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700380 new FocalOutside2PtConicalEffect(args, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000381 }
382
383 virtual ~FocalOutside2PtConicalEffect() { }
384
mtklein36352bf2015-03-25 18:17:31 -0700385 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800386 return "Two-Point Conical Gradient Focal Outside";
387 }
388
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000389 bool isFlipped() const { return fIsFlipped; }
390 SkScalar focal() const { return fFocalX; }
391
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000392private:
egdaniel57d3b032015-11-13 11:57:27 -0800393 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700394
egdaniel57d3b032015-11-13 11:57:27 -0800395 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700396
mtklein36352bf2015-03-25 18:17:31 -0700397 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700398 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000399 return (INHERITED::onIsEqual(sBase) &&
400 this->fFocalX == s.fFocalX &&
401 this->fIsFlipped == s.fIsFlipped);
402 }
403
brianosman9557c272016-09-15 06:59:15 -0700404 FocalOutside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
405 : INHERITED(args)
joshualittb2456052015-07-08 09:36:59 -0700406 , fFocalX(focalX)
brianosman9557c272016-09-15 06:59:15 -0700407 , fIsFlipped(static_cast<const SkTwoPointConicalGradient*>(args.fShader)->isFlippedGrad()) {
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
fmenozzi55d318d2016-08-09 08:05:57 -0700419class FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
420 : 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
jvanverthcfc18862015-04-28 08:48:20 -0700427 static void GenKey(const GrProcessor&, const GrGLSLCaps& 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
egdaniel57d3b032015-11-13 11:57:27 -0800451void FocalOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
452 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 */
bungeman06ca8ec2016-06-09 08:01:03 -0700465sk_sp<GrFragmentProcessor> FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700466 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000467 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000468 SkPoint center2;
469 SkScalar radius2;
470 do {
joshualitt0067ff52015-07-08 14:26:19 -0700471 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000472 // 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 +0000473 } while (center1 == center2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000474
Brian Osman3f748602016-10-03 18:29:03 -0400475 SkPoint diff = center2 - center1;
476 SkScalar diffLen = diff.length();
477 // Below makes sure that the focal point is not contained within circle two
478 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
479
480 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400481 auto shader = params.fUseColors4f ?
482 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
483 params.fColors4f, params.fColorSpace, params.fStops,
484 params.fColorCount, params.fTileMode) :
485 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
486 params.fColors, params.fStops,
487 params.fColorCount, params.fTileMode);
brianosman839345d2016-07-22 11:04:53 -0700488 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
Brian Osman0d9dfe92016-10-03 15:24:44 -0400489 auto dstColorSpace = GrTest::TestColorSpace(d->fRandom);
brianosman839345d2016-07-22 11:04:53 -0700490 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(SkShader::AsFPArgs(
Brian Osman0d9dfe92016-10-03 15:24:44 -0400491 d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(),
brianosman1638c0d2016-07-25 05:12:53 -0700492 SkSourceGammaTreatment::kRespect));
bsalomonc21b09e2015-08-28 18:46:56 -0700493 GrAlwaysAssert(fp);
494 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000495}
496
fmenozzi55d318d2016-08-09 08:05:57 -0700497FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor
498 ::GLSLFocalOutside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700499 : fVSVaryingName(nullptr)
500 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000501 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700502 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000503 fIsFlipped = data.isFlipped();
504}
505
fmenozzi55d318d2016-08-09 08:05:57 -0700506void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700507 const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800508 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
509 this->emitUniforms(uniformHandler, ge);
jvanverthde11ee42016-02-26 13:58:40 -0800510 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
511 kVec2f_GrSLType, kDefault_GrSLPrecision,
512 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000513 SkString tName("t");
514 SkString p0; // focalX
515 SkString p1; // 1 - focalX * focalX
516
jvanverthde11ee42016-02-26 13:58:40 -0800517 p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
518 p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000519
520 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800521 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700522 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000523 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000524
525 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
526
527 // output will default to transparent black (we simply won't write anything
528 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -0800529 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 +0000530
egdaniel4ca2e602015-11-18 08:01:26 -0800531 fragBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
532 fragBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
533 fragBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000534
535 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
536 // If so we must also flip sign on sqrt
537 if (!fIsFlipped) {
egdaniel4ca2e602015-11-18 08:01:26 -0800538 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
539 coords2D, p0.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000540 } else {
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 }
544
egdaniel4ca2e602015-11-18 08:01:26 -0800545 fragBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
546 fragBuilder->codeAppend("\t\t");
egdaniel7ea439b2015-12-03 09:20:44 -0800547 this->emitColor(fragBuilder,
548 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -0800549 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800550 ge,
551 tName.c_str(),
552 args.fOutputColor,
553 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700554 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -0800555 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000556}
557
fmenozzi55d318d2016-08-09 08:05:57 -0700558void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::onSetData(
559 const GrGLSLProgramDataManager& pdman,
560 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700561 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700562 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000563 SkASSERT(data.isFlipped() == fIsFlipped);
564 SkScalar focal = data.focal();
565
566 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000567 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000568
jvanverthde11ee42016-02-26 13:58:40 -0800569 pdman.set2f(fParamUni, SkScalarToFloat(focal), SkScalarToFloat(oneMinus2F));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000570 fCachedFocal = focal;
571 }
572}
573
fmenozzi55d318d2016-08-09 08:05:57 -0700574void FocalOutside2PtConicalEffect::GLSLFocalOutside2PtConicalProcessor::GenKey(
575 const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700576 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700577 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700578 key[0] = GenBaseGradientKey(processor);
579 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000580}
581
582//////////////////////////////////////////////////////////////////////////////
583
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000584class FocalInside2PtConicalEffect : public GrGradientEffect {
585public:
fmenozzi55d318d2016-08-09 08:05:57 -0700586 class GLSLFocalInside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000587
brianosman9557c272016-09-15 06:59:15 -0700588 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar focalX) {
bungeman06ca8ec2016-06-09 08:01:03 -0700589 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700590 new FocalInside2PtConicalEffect(args, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000591 }
592
593 virtual ~FocalInside2PtConicalEffect() {}
594
mtklein36352bf2015-03-25 18:17:31 -0700595 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800596 return "Two-Point Conical Gradient Focal Inside";
597 }
598
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000599 SkScalar focal() const { return fFocalX; }
600
fmenozzi55d318d2016-08-09 08:05:57 -0700601 typedef FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor GLSLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000602
603private:
egdaniel57d3b032015-11-13 11:57:27 -0800604 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700605
egdaniel57d3b032015-11-13 11:57:27 -0800606 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700607
mtklein36352bf2015-03-25 18:17:31 -0700608 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700609 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000610 return (INHERITED::onIsEqual(sBase) &&
611 this->fFocalX == s.fFocalX);
612 }
613
brianosman9557c272016-09-15 06:59:15 -0700614 FocalInside2PtConicalEffect(const CreateArgs& args, SkScalar focalX)
615 : INHERITED(args), fFocalX(focalX) {
joshualitteb2a6762014-12-04 11:35:33 -0800616 this->initClassID<FocalInside2PtConicalEffect>();
617 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000618
joshualittb0a8a372014-09-23 09:50:21 -0700619 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000620
621 SkScalar fFocalX;
622
623 typedef GrGradientEffect INHERITED;
624};
625
fmenozzi55d318d2016-08-09 08:05:57 -0700626class FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
627 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000628public:
fmenozzi55d318d2016-08-09 08:05:57 -0700629 GLSLFocalInside2PtConicalProcessor(const GrProcessor&);
630 virtual ~GLSLFocalInside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000631
wangyix7c157a92015-07-22 15:08:53 -0700632 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000633
jvanverthcfc18862015-04-28 08:48:20 -0700634 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000635
636protected:
egdaniel018fb622015-10-28 07:26:40 -0700637 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700638
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000639 UniformHandle fFocalUni;
640
641 const char* fVSVaryingName;
642 const char* fFSVaryingName;
643
644 // @{
645 /// Values last uploaded as uniforms
646
647 SkScalar fCachedFocal;
648
649 // @}
650
651private:
fmenozzi55d318d2016-08-09 08:05:57 -0700652 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000653
654};
655
egdaniel57d3b032015-11-13 11:57:27 -0800656void FocalInside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
657 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700658 FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800659}
660
egdaniel57d3b032015-11-13 11:57:27 -0800661GrGLSLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700662 return new FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000663}
664
joshualittb0a8a372014-09-23 09:50:21 -0700665GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000666
joshualitt01258472014-09-22 10:29:30 -0700667/*
668 * All Two point conical gradient test create functions may occasionally create edge case shaders
669 */
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);
brianosman839345d2016-07-22 11:04:53 -0700694 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
Brian Osman0d9dfe92016-10-03 15:24:44 -0400695 auto dstColorSpace = GrTest::TestColorSpace(d->fRandom);
brianosman839345d2016-07-22 11:04:53 -0700696 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(SkShader::AsFPArgs(
Brian Osman0d9dfe92016-10-03 15:24:44 -0400697 d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(),
brianosman1638c0d2016-07-25 05:12:53 -0700698 SkSourceGammaTreatment::kRespect));
bsalomonc21b09e2015-08-28 18:46:56 -0700699 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700700 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000701}
702
fmenozzi55d318d2016-08-09 08:05:57 -0700703FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor
704 ::GLSLFocalInside2PtConicalProcessor(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700705 : fVSVaryingName(nullptr)
706 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000707 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000708
fmenozzi55d318d2016-08-09 08:05:57 -0700709void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700710 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800711 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
712 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800713 fFocalUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800714 kFloat_GrSLType, kDefault_GrSLPrecision,
715 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000716 SkString tName("t");
717
718 // this is the distance along x-axis from the end center to focal point in
719 // transformed coordinates
egdaniel7ea439b2015-12-03 09:20:44 -0800720 GrGLSLShaderVar focal = uniformHandler->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000721
722 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800723 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700724 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000725 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000726
727 // t = p.x * focalX + length(p)
egdaniel4ca2e602015-11-18 08:01:26 -0800728 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
egdaniel7ea439b2015-12-03 09:20:44 -0800729 coords2D, focal.c_str(), coords2D);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000730
egdaniel7ea439b2015-12-03 09:20:44 -0800731 this->emitColor(fragBuilder,
732 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -0800733 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800734 ge,
735 tName.c_str(),
736 args.fOutputColor,
737 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700738 args.fTexSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000739}
740
fmenozzi55d318d2016-08-09 08:05:57 -0700741void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::onSetData(
742 const GrGLSLProgramDataManager& pdman,
743 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700744 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700745 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000746 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000747
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000748 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700749 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000750 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000751 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000752}
753
fmenozzi55d318d2016-08-09 08:05:57 -0700754void FocalInside2PtConicalEffect::GLSLFocalInside2PtConicalProcessor::GenKey(
755 const GrProcessor& processor,
756 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700757 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000758}
759
760//////////////////////////////////////////////////////////////////////////////
761// Circle Conical Gradients
762//////////////////////////////////////////////////////////////////////////////
763
764struct CircleConicalInfo {
765 SkPoint fCenterEnd;
766 SkScalar fA;
767 SkScalar fB;
768 SkScalar fC;
769};
770
771// Returns focal distance along x-axis in transformed coords
772static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
773 SkMatrix* invLMatrix, CircleConicalInfo* info) {
774 // Inverse of the current local matrix is passed in then,
775 // translate and scale such that start circle is on the origin and has radius 1
776 const SkPoint& centerStart = shader.getStartCenter();
777 const SkPoint& centerEnd = shader.getEndCenter();
778 SkScalar radiusStart = shader.getStartRadius();
779 SkScalar radiusEnd = shader.getEndRadius();
780
781 SkMatrix matrix;
782
783 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
784
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000785 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000786 matrix.postScale(invStartRad, invStartRad);
787
788 radiusEnd /= radiusStart;
789
790 SkPoint centerEndTrans;
791 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
792
793 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
794 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
795
796 // Check to see if start circle is inside end circle with edges touching.
797 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700798 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
799 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
800 // still accurate.
801 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000802 return kEdge_ConicalType;
803 }
804
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000805 SkScalar C = 1.f / A;
806 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000807
808 matrix.postScale(C, C);
809
810 invLMatrix->postConcat(matrix);
811
812 info->fCenterEnd = centerEndTrans;
813 info->fA = A;
814 info->fB = B;
815 info->fC = C;
816
817 // 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 +0000818 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000819 return kInside_ConicalType;
820 }
821 return kOutside_ConicalType;
822}
823
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000824class CircleInside2PtConicalEffect : public GrGradientEffect {
825public:
fmenozzi55d318d2016-08-09 08:05:57 -0700826 class GLSLCircleInside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000827
brianosman9557c272016-09-15 06:59:15 -0700828 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
bungeman06ca8ec2016-06-09 08:01:03 -0700829 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -0700830 new CircleInside2PtConicalEffect(args, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000831 }
832
833 virtual ~CircleInside2PtConicalEffect() {}
834
mtklein36352bf2015-03-25 18:17:31 -0700835 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800836
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000837 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
838 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
839 SkScalar A() const { return fInfo.fA; }
840 SkScalar B() const { return fInfo.fB; }
841 SkScalar C() const { return fInfo.fC; }
842
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000843private:
egdaniel57d3b032015-11-13 11:57:27 -0800844 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700845
egdaniel57d3b032015-11-13 11:57:27 -0800846 virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps,
847 GrProcessorKeyBuilder* b) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700848
mtklein36352bf2015-03-25 18:17:31 -0700849 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700850 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000851 return (INHERITED::onIsEqual(sBase) &&
852 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
853 this->fInfo.fA == s.fInfo.fA &&
854 this->fInfo.fB == s.fInfo.fB &&
855 this->fInfo.fC == s.fInfo.fC);
856 }
857
brianosman9557c272016-09-15 06:59:15 -0700858 CircleInside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
859 : INHERITED(args), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800860 this->initClassID<CircleInside2PtConicalEffect>();
861 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000862
joshualittb0a8a372014-09-23 09:50:21 -0700863 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000864
865 const CircleConicalInfo fInfo;
866
867 typedef GrGradientEffect INHERITED;
868};
869
fmenozzi55d318d2016-08-09 08:05:57 -0700870class CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
871 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000872public:
fmenozzi55d318d2016-08-09 08:05:57 -0700873 GLSLCircleInside2PtConicalProcessor(const GrProcessor&);
874 virtual ~GLSLCircleInside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000875
wangyix7c157a92015-07-22 15:08:53 -0700876 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000877
jvanverthcfc18862015-04-28 08:48:20 -0700878 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000879
880protected:
egdaniel018fb622015-10-28 07:26:40 -0700881 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700882
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000883 UniformHandle fCenterUni;
884 UniformHandle fParamUni;
885
886 const char* fVSVaryingName;
887 const char* fFSVaryingName;
888
889 // @{
890 /// Values last uploaded as uniforms
891
892 SkScalar fCachedCenterX;
893 SkScalar fCachedCenterY;
894 SkScalar fCachedA;
895 SkScalar fCachedB;
896 SkScalar fCachedC;
897
898 // @}
899
900private:
fmenozzi55d318d2016-08-09 08:05:57 -0700901 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000902
903};
904
egdaniel57d3b032015-11-13 11:57:27 -0800905void CircleInside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
906 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -0700907 CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800908}
909
egdaniel57d3b032015-11-13 11:57:27 -0800910GrGLSLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -0700911 return new CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000912}
913
joshualittb0a8a372014-09-23 09:50:21 -0700914GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000915
joshualitt01258472014-09-22 10:29:30 -0700916/*
917 * All Two point conical gradient test create functions may occasionally create edge case shaders
918 */
bungeman06ca8ec2016-06-09 08:01:03 -0700919sk_sp<GrFragmentProcessor> CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700920 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
921 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000922 SkPoint center2;
923 SkScalar radius2;
924 do {
joshualitt0067ff52015-07-08 14:26:19 -0700925 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000926 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700927 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000928 SkPoint diff = center2 - center1;
929 SkScalar diffLen = diff.length();
930 radius2 = radius1 + diffLen + increase;
931 // If the circles are identical the factory will give us an empty shader.
932 } while (radius1 == radius2 && center1 == center2);
933
Brian Osman3f748602016-10-03 18:29:03 -0400934 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -0400935 auto shader = params.fUseColors4f ?
936 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
937 params.fColors4f, params.fColorSpace, params.fStops,
938 params.fColorCount, params.fTileMode) :
939 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
940 params.fColors, params.fStops,
941 params.fColorCount, params.fTileMode);
brianosman839345d2016-07-22 11:04:53 -0700942 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
Brian Osman0d9dfe92016-10-03 15:24:44 -0400943 auto dstColorSpace = GrTest::TestColorSpace(d->fRandom);
brianosman839345d2016-07-22 11:04:53 -0700944 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(SkShader::AsFPArgs(
Brian Osman0d9dfe92016-10-03 15:24:44 -0400945 d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(),
brianosman1638c0d2016-07-25 05:12:53 -0700946 SkSourceGammaTreatment::kRespect));
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}
950
fmenozzi55d318d2016-08-09 08:05:57 -0700951CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor
952 ::GLSLCircleInside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700953 : fVSVaryingName(nullptr)
954 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000955 , fCachedCenterX(SK_ScalarMax)
956 , fCachedCenterY(SK_ScalarMax)
957 , fCachedA(SK_ScalarMax)
958 , fCachedB(SK_ScalarMax)
959 , fCachedC(SK_ScalarMax) {}
960
fmenozzi55d318d2016-08-09 08:05:57 -0700961void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -0700962 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800963 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
964 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800965 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800966 kVec2f_GrSLType, kDefault_GrSLPrecision,
967 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -0800968 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800969 kVec3f_GrSLType, kDefault_GrSLPrecision,
970 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000971 SkString tName("t");
972
egdaniel7ea439b2015-12-03 09:20:44 -0800973 GrGLSLShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000974 // params.x = A
975 // params.y = B
976 // params.z = C
egdaniel7ea439b2015-12-03 09:20:44 -0800977 GrGLSLShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000978
979 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800980 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -0700981 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000982 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000983
984 // p = coords2D
985 // e = center end
986 // r = radius end
987 // A = dot(e, e) - r^2 + 2 * r - 1
988 // B = (r -1) / A
989 // C = 1 / A
990 // d = dot(e, p) + B
991 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
egdaniel4ca2e602015-11-18 08:01:26 -0800992 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
993 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
994 params.c_str());
995 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
996 tName.c_str(), params.c_str(), params.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000997
egdaniel7ea439b2015-12-03 09:20:44 -0800998 this->emitColor(fragBuilder,
999 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -08001000 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -08001001 ge,
1002 tName.c_str(),
1003 args.fOutputColor,
1004 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -07001005 args.fTexSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001006}
1007
fmenozzi55d318d2016-08-09 08:05:57 -07001008void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::onSetData(
1009 const GrGLSLProgramDataManager& pdman,
1010 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001011 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001012 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001013 SkScalar centerX = data.centerX();
1014 SkScalar centerY = data.centerY();
1015 SkScalar A = data.A();
1016 SkScalar B = data.B();
1017 SkScalar C = data.C();
1018
1019 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1020 fCachedA != A || fCachedB != B || fCachedC != C) {
1021
kkinnunen7510b222014-07-30 00:04:16 -07001022 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1023 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001024
1025 fCachedCenterX = centerX;
1026 fCachedCenterY = centerY;
1027 fCachedA = A;
1028 fCachedB = B;
1029 fCachedC = C;
1030 }
1031}
1032
fmenozzi55d318d2016-08-09 08:05:57 -07001033void CircleInside2PtConicalEffect::GLSLCircleInside2PtConicalProcessor::GenKey(
1034 const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001035 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001036 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001037}
1038
1039//////////////////////////////////////////////////////////////////////////////
1040
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001041class CircleOutside2PtConicalEffect : public GrGradientEffect {
1042public:
fmenozzi55d318d2016-08-09 08:05:57 -07001043 class GLSLCircleOutside2PtConicalProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001044
brianosman9557c272016-09-15 06:59:15 -07001045 static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, const CircleConicalInfo& info) {
bungeman06ca8ec2016-06-09 08:01:03 -07001046 return sk_sp<GrFragmentProcessor>(
brianosman9557c272016-09-15 06:59:15 -07001047 new CircleOutside2PtConicalEffect(args, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001048 }
1049
1050 virtual ~CircleOutside2PtConicalEffect() {}
1051
mtklein36352bf2015-03-25 18:17:31 -07001052 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001053
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001054 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1055 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1056 SkScalar A() const { return fInfo.fA; }
1057 SkScalar B() const { return fInfo.fB; }
1058 SkScalar C() const { return fInfo.fC; }
1059 SkScalar tLimit() const { return fTLimit; }
1060 bool isFlipped() const { return fIsFlipped; }
1061
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001062private:
egdaniel57d3b032015-11-13 11:57:27 -08001063 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -07001064
egdaniel57d3b032015-11-13 11:57:27 -08001065 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -07001066
mtklein36352bf2015-03-25 18:17:31 -07001067 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001068 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001069 return (INHERITED::onIsEqual(sBase) &&
1070 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1071 this->fInfo.fA == s.fInfo.fA &&
1072 this->fInfo.fB == s.fInfo.fB &&
1073 this->fInfo.fC == s.fInfo.fC &&
1074 this->fTLimit == s.fTLimit &&
1075 this->fIsFlipped == s.fIsFlipped);
1076 }
1077
brianosman9557c272016-09-15 06:59:15 -07001078 CircleOutside2PtConicalEffect(const CreateArgs& args, const CircleConicalInfo& info)
1079 : INHERITED(args), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001080 this->initClassID<CircleOutside2PtConicalEffect>();
brianosman9557c272016-09-15 06:59:15 -07001081 const SkTwoPointConicalGradient& shader =
1082 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001083 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001084 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001085 } else {
1086 fTLimit = SK_ScalarMin;
1087 }
1088
1089 fIsFlipped = shader.isFlippedGrad();
1090 }
1091
joshualittb0a8a372014-09-23 09:50:21 -07001092 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001093
1094 const CircleConicalInfo fInfo;
1095 SkScalar fTLimit;
1096 bool fIsFlipped;
1097
1098 typedef GrGradientEffect INHERITED;
1099};
1100
fmenozzi55d318d2016-08-09 08:05:57 -07001101class CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
1102 : public GrGradientEffect::GLSLProcessor {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001103public:
fmenozzi55d318d2016-08-09 08:05:57 -07001104 GLSLCircleOutside2PtConicalProcessor(const GrProcessor&);
1105 virtual ~GLSLCircleOutside2PtConicalProcessor() {}
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001106
wangyix7c157a92015-07-22 15:08:53 -07001107 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001108
jvanverthcfc18862015-04-28 08:48:20 -07001109 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001110
1111protected:
egdaniel018fb622015-10-28 07:26:40 -07001112 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001113
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001114 UniformHandle fCenterUni;
1115 UniformHandle fParamUni;
1116
1117 const char* fVSVaryingName;
1118 const char* fFSVaryingName;
1119
1120 bool fIsFlipped;
1121
1122 // @{
1123 /// Values last uploaded as uniforms
1124
1125 SkScalar fCachedCenterX;
1126 SkScalar fCachedCenterY;
1127 SkScalar fCachedA;
1128 SkScalar fCachedB;
1129 SkScalar fCachedC;
1130 SkScalar fCachedTLimit;
1131
1132 // @}
1133
1134private:
fmenozzi55d318d2016-08-09 08:05:57 -07001135 typedef GrGradientEffect::GLSLProcessor INHERITED;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001136
1137};
1138
egdaniel57d3b032015-11-13 11:57:27 -08001139void CircleOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1140 GrProcessorKeyBuilder* b) const {
fmenozzi55d318d2016-08-09 08:05:57 -07001141 CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -08001142}
1143
egdaniel57d3b032015-11-13 11:57:27 -08001144GrGLSLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLSLInstance() const {
fmenozzi55d318d2016-08-09 08:05:57 -07001145 return new CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001146}
1147
joshualittb0a8a372014-09-23 09:50:21 -07001148GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001149
joshualitt01258472014-09-22 10:29:30 -07001150/*
1151 * All Two point conical gradient test create functions may occasionally create edge case shaders
1152 */
bungeman06ca8ec2016-06-09 08:01:03 -07001153sk_sp<GrFragmentProcessor> CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001154 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1155 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001156 SkPoint center2;
1157 SkScalar radius2;
1158 SkScalar diffLen;
1159 do {
joshualitt0067ff52015-07-08 14:26:19 -07001160 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001161 // If the circles share a center than we can't be in the outside case
1162 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001163 SkPoint diff = center2 - center1;
1164 diffLen = diff.length();
1165 // Below makes sure that circle one is not contained within circle two
1166 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001167 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001168
Brian Osman3f748602016-10-03 18:29:03 -04001169 RandomGradientParams params(d->fRandom);
Brian Osmana2196532016-10-17 12:48:13 -04001170 auto shader = params.fUseColors4f ?
1171 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
1172 params.fColors4f, params.fColorSpace, params.fStops,
1173 params.fColorCount, params.fTileMode) :
1174 SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
1175 params.fColors, params.fStops,
1176 params.fColorCount, params.fTileMode);
brianosman839345d2016-07-22 11:04:53 -07001177 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
Brian Osman0d9dfe92016-10-03 15:24:44 -04001178 auto dstColorSpace = GrTest::TestColorSpace(d->fRandom);
brianosman839345d2016-07-22 11:04:53 -07001179 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(SkShader::AsFPArgs(
Brian Osman0d9dfe92016-10-03 15:24:44 -04001180 d->fContext, &viewMatrix, NULL, kNone_SkFilterQuality, dstColorSpace.get(),
brianosman1638c0d2016-07-25 05:12:53 -07001181 SkSourceGammaTreatment::kRespect));
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}
1185
fmenozzi55d318d2016-08-09 08:05:57 -07001186CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor
1187 ::GLSLCircleOutside2PtConicalProcessor(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -07001188 : fVSVaryingName(nullptr)
1189 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001190 , fCachedCenterX(SK_ScalarMax)
1191 , fCachedCenterY(SK_ScalarMax)
1192 , fCachedA(SK_ScalarMax)
1193 , fCachedB(SK_ScalarMax)
1194 , fCachedC(SK_ScalarMax)
1195 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001196 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001197 fIsFlipped = data.isFlipped();
1198 }
1199
fmenozzi55d318d2016-08-09 08:05:57 -07001200void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::emitCode(EmitArgs& args) {
wangyix7c157a92015-07-22 15:08:53 -07001201 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -08001202 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1203 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -08001204 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001205 kVec2f_GrSLType, kDefault_GrSLPrecision,
1206 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -08001207 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001208 kVec4f_GrSLType, kDefault_GrSLPrecision,
1209 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001210 SkString tName("t");
1211
egdaniel7ea439b2015-12-03 09:20:44 -08001212 GrGLSLShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001213 // params.x = A
1214 // params.y = B
1215 // params.z = C
egdaniel7ea439b2015-12-03 09:20:44 -08001216 GrGLSLShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001217
1218 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -08001219 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomon1a1aa932016-09-12 09:30:36 -07001220 SkString coords2DString = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001221 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001222
1223 // output will default to transparent black (we simply won't write anything
1224 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -08001225 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 +00001226
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001227 // p = coords2D
1228 // e = center end
1229 // r = radius end
1230 // A = dot(e, e) - r^2 + 2 * r - 1
1231 // B = (r -1) / A
1232 // C = 1 / A
1233 // d = dot(e, p) + B
1234 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001235
egdaniel4ca2e602015-11-18 08:01:26 -08001236 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
1237 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1238 params.c_str());
1239 fragBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1240 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001241
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001242 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1243 // If so we must also flip sign on sqrt
1244 if (!fIsFlipped) {
egdaniel4ca2e602015-11-18 08:01:26 -08001245 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001246 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001247 fragBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001248 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001249
egdaniel7ea439b2015-12-03 09:20:44 -08001250 fragBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n",
1251 tName.c_str(), params.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001252 fragBuilder->codeAppend("\t\t");
egdaniel7ea439b2015-12-03 09:20:44 -08001253 this->emitColor(fragBuilder,
1254 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -08001255 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -08001256 ge,
1257 tName.c_str(),
1258 args.fOutputColor,
1259 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -07001260 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -08001261 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001262}
1263
fmenozzi55d318d2016-08-09 08:05:57 -07001264void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::onSetData(
1265 const GrGLSLProgramDataManager& pdman,
egdaniel018fb622015-10-28 07:26:40 -07001266 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001267 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001268 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001269 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001270 SkScalar centerX = data.centerX();
1271 SkScalar centerY = data.centerY();
1272 SkScalar A = data.A();
1273 SkScalar B = data.B();
1274 SkScalar C = data.C();
1275 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001276
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001277 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1278 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001279
kkinnunen7510b222014-07-30 00:04:16 -07001280 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1281 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001282 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001283
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001284 fCachedCenterX = centerX;
1285 fCachedCenterY = centerY;
1286 fCachedA = A;
1287 fCachedB = B;
1288 fCachedC = C;
1289 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001290 }
1291}
1292
fmenozzi55d318d2016-08-09 08:05:57 -07001293void CircleOutside2PtConicalEffect::GLSLCircleOutside2PtConicalProcessor::GenKey(
1294 const GrProcessor& processor,
1295 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001296 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001297 key[0] = GenBaseGradientKey(processor);
1298 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001299}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001300
1301//////////////////////////////////////////////////////////////////////////////
1302
brianosman9557c272016-09-15 06:59:15 -07001303sk_sp<GrFragmentProcessor> Gr2PtConicalGradientEffect::Make(
1304 const GrGradientEffect::CreateArgs& args) {
1305 const SkTwoPointConicalGradient& shader =
1306 *static_cast<const SkTwoPointConicalGradient*>(args.fShader);
1307
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001308 SkMatrix matrix;
1309 if (!shader.getLocalMatrix().invert(&matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001310 return nullptr;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001311 }
brianosman9557c272016-09-15 06:59:15 -07001312 if (args.fMatrix) {
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001313 SkMatrix inv;
brianosman9557c272016-09-15 06:59:15 -07001314 if (!args.fMatrix->invert(&inv)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001315 return nullptr;
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001316 }
1317 matrix.postConcat(inv);
1318 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001319
brianosmanb9c51372016-09-15 11:09:45 -07001320 GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fTileMode,
1321 std::move(args.fColorSpaceXform), args.fGammaCorrect);
brianosman9557c272016-09-15 06:59:15 -07001322
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001323 if (shader.getStartRadius() < kErrorTol) {
1324 SkScalar focalX;
1325 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1326 if (type == kInside_ConicalType) {
brianosman9557c272016-09-15 06:59:15 -07001327 return FocalInside2PtConicalEffect::Make(newArgs, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001328 } else if(type == kEdge_ConicalType) {
1329 set_matrix_edge_conical(shader, &matrix);
brianosman9557c272016-09-15 06:59:15 -07001330 return Edge2PtConicalEffect::Make(newArgs);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001331 } else {
brianosman9557c272016-09-15 06:59:15 -07001332 return FocalOutside2PtConicalEffect::Make(newArgs, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001333 }
1334 }
1335
1336 CircleConicalInfo info;
1337 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1338
1339 if (type == kInside_ConicalType) {
brianosman9557c272016-09-15 06:59:15 -07001340 return CircleInside2PtConicalEffect::Make(newArgs, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001341 } else if (type == kEdge_ConicalType) {
1342 set_matrix_edge_conical(shader, &matrix);
brianosman9557c272016-09-15 06:59:15 -07001343 return Edge2PtConicalEffect::Make(newArgs);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001344 } else {
brianosman9557c272016-09-15 06:59:15 -07001345 return CircleOutside2PtConicalEffect::Make(newArgs, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001346 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001347}
1348
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001349#endif