blob: b5716b1de00331355e066e9859450ea5620ef4c7 [file] [log] [blame]
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00002/*
3 * Copyright 2014 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00008
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00009#include "SkTwoPointConicalGradient_gpu.h"
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000010
11#include "SkTwoPointConicalGradient.h"
12
commit-bot@chromium.orgef93d292014-04-10 15:37:52 +000013#if SK_SUPPORT_GPU
joshualitt8ca93e72015-07-08 06:51:43 -070014#include "GrPaint.h"
joshualitt30ba4362014-08-21 20:18:45 -070015#include "gl/builders/GrGLProgramBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070016#include "glsl/GrGLSLProgramDataManager.h"
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000017// For brevity
egdaniel018fb622015-10-28 07:26:40 -070018typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000019
commit-bot@chromium.org80894672014-04-22 21:24:22 +000020static const SkScalar kErrorTol = 0.00001f;
egdaniel8405ef92014-06-09 11:57:28 -070021static const SkScalar kEdgeErrorTol = 5.f * kErrorTol;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000022
23/**
24 * We have three general cases for 2pt conical gradients. First we always assume that
25 * the start radius <= end radius. Our first case (kInside_) is when the start circle
26 * is completely enclosed by the end circle. The second case (kOutside_) is the case
27 * when the start circle is either completely outside the end circle or the circles
28 * overlap. The final case (kEdge_) is when the start circle is inside the end one,
29 * but the two are just barely touching at 1 point along their edges.
30 */
31enum ConicalType {
32 kInside_ConicalType,
33 kOutside_ConicalType,
34 kEdge_ConicalType,
35};
36
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000037//////////////////////////////////////////////////////////////////////////////
38
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000039static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader,
40 SkMatrix* invLMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000041 // Inverse of the current local matrix is passed in then,
42 // translate to center1, rotate so center2 is on x axis.
43 const SkPoint& center1 = shader.getStartCenter();
44 const SkPoint& center2 = shader.getEndCenter();
45
46 invLMatrix->postTranslate(-center1.fX, -center1.fY);
47
48 SkPoint diff = center2 - center1;
49 SkScalar diffLen = diff.length();
50 if (0 != diffLen) {
51 SkScalar invDiffLen = SkScalarInvert(diffLen);
52 SkMatrix rot;
53 rot.setSinCos(-SkScalarMul(invDiffLen, diff.fY),
54 SkScalarMul(invDiffLen, diff.fX));
55 invLMatrix->postConcat(rot);
56 }
57}
58
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000059class Edge2PtConicalEffect : public GrGradientEffect {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000060public:
61
joshualittb0a8a372014-09-23 09:50:21 -070062 static GrFragmentProcessor* Create(GrContext* ctx,
63 const SkTwoPointConicalGradient& shader,
64 const SkMatrix& matrix,
65 SkShader::TileMode tm) {
bsalomon4a339522015-10-06 08:40:50 -070066 return new Edge2PtConicalEffect(ctx, shader, matrix, tm);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000067 }
68
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000069 virtual ~Edge2PtConicalEffect() {}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000070
mtklein36352bf2015-03-25 18:17:31 -070071 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -080072 return "Two-Point Conical Gradient Edge Touching";
73 }
74
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000075 // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000076 SkScalar center() const { return fCenterX1; }
77 SkScalar diffRadius() const { return fDiffRadius; }
78 SkScalar radius() const { return fRadius0; }
79
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000080private:
wangyixb1daa862015-08-18 11:29:31 -070081 GrGLFragmentProcessor* onCreateGLInstance() const override;
82
wangyix4b3050b2015-08-04 07:59:37 -070083 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
84
mtklein36352bf2015-03-25 18:17:31 -070085 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -070086 const Edge2PtConicalEffect& s = sBase.cast<Edge2PtConicalEffect>();
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000087 return (INHERITED::onIsEqual(sBase) &&
88 this->fCenterX1 == s.fCenterX1 &&
89 this->fRadius0 == s.fRadius0 &&
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000090 this->fDiffRadius == s.fDiffRadius);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000091 }
92
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000093 Edge2PtConicalEffect(GrContext* ctx,
94 const SkTwoPointConicalGradient& shader,
95 const SkMatrix& matrix,
96 SkShader::TileMode tm)
bsalomon4a339522015-10-06 08:40:50 -070097 : INHERITED(ctx, shader, matrix, tm),
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000098 fCenterX1(shader.getCenterX1()),
99 fRadius0(shader.getStartRadius()),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000100 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
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000141class GLEdge2PtConicalEffect : public GrGLGradientEffect {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000142public:
joshualitteb2a6762014-12-04 11:35:33 -0800143 GLEdge2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000144 virtual ~GLEdge2PtConicalEffect() { }
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:
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000167 typedef GrGLGradientEffect INHERITED;
168
169};
170
wangyix4b3050b2015-08-04 07:59:37 -0700171void Edge2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800172 GrProcessorKeyBuilder* b) const {
173 GLEdge2PtConicalEffect::GenKey(*this, caps, b);
174}
175
wangyixb1daa862015-08-18 11:29:31 -0700176GrGLFragmentProcessor* Edge2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700177 return new GLEdge2PtConicalEffect(*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 */
bsalomonc21b09e2015-08-28 18:46:56 -0700185const 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
202 SkColor colors[kMaxRandomGradientColors];
203 SkScalar stopsArray[kMaxRandomGradientColors];
204 SkScalar* stops = stopsArray;
205 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700206 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000207 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
208 center2, radius2,
209 colors, stops, colorCount,
210 tm));
bsalomonc21b09e2015-08-28 18:46:56 -0700211 const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
bsalomon4a339522015-10-06 08:40:50 -0700212 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality);
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}
216
joshualitteb2a6762014-12-04 11:35:33 -0800217GLEdge2PtConicalEffect::GLEdge2PtConicalEffect(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700218 : fVSVaryingName(nullptr)
219 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000220 , fCachedRadius(-SK_ScalarMax)
221 , fCachedDiffRadius(-SK_ScalarMax) {}
222
wangyix7c157a92015-07-22 15:08:53 -0700223void GLEdge2PtConicalEffect::emitCode(EmitArgs& args) {
224 const Edge2PtConicalEffect& ge = args.fFp.cast<Edge2PtConicalEffect>();
225 this->emitUniforms(args.fBuilder, ge);
226 fParamUni = args.fBuilder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800227 kFloat_GrSLType, kDefault_GrSLPrecision,
228 "Conical2FSParams", 3);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000229
230 SkString cName("c");
231 SkString tName("t");
232 SkString p0; // start radius
233 SkString p1; // start radius squared
234 SkString p2; // difference in radii (r1 - r0)
235
wangyix7c157a92015-07-22 15:08:53 -0700236 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
237 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
238 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000239
240 // We interpolate the linear component in coords[1].
wangyix7c157a92015-07-22 15:08:53 -0700241 SkASSERT(args.fCoords[0].getType() == args.fCoords[1].getType());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000242 const char* coords2D;
243 SkString bVar;
wangyix7c157a92015-07-22 15:08:53 -0700244 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
245 if (kVec3f_GrSLType == args.fCoords[0].getType()) {
joshualitt30ba4362014-08-21 20:18:45 -0700246 fsBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
wangyix7c157a92015-07-22 15:08:53 -0700247 args.fCoords[0].c_str(), args.fCoords[0].c_str(),
248 args.fCoords[1].c_str(), args.fCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000249 coords2D = "interpolants.xy";
250 bVar = "interpolants.z";
251 } else {
wangyix7c157a92015-07-22 15:08:53 -0700252 coords2D = args.fCoords[0].c_str();
253 bVar.printf("%s.x", args.fCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000254 }
255
256 // output will default to transparent black (we simply won't write anything
257 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -0700258 fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000259
260 // c = (x^2)+(y^2) - params[1]
joshualitt30ba4362014-08-21 20:18:45 -0700261 fsBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000262 cName.c_str(), coords2D, coords2D, p1.c_str());
263
264 // linear case: t = -c/b
joshualitt30ba4362014-08-21 20:18:45 -0700265 fsBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000266 cName.c_str(), bVar.c_str());
267
268 // if r(t) > 0, then t will be the x coordinate
joshualitt30ba4362014-08-21 20:18:45 -0700269 fsBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000270 p2.c_str(), p0.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700271 fsBuilder->codeAppend("\t");
wangyix7c157a92015-07-22 15:08:53 -0700272 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
273 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -0700274 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000275}
276
egdaniel018fb622015-10-28 07:26:40 -0700277void GLEdge2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
278 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700279 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700280 const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000281 SkScalar radius0 = data.radius();
282 SkScalar diffRadius = data.diffRadius();
283
284 if (fCachedRadius != radius0 ||
285 fCachedDiffRadius != diffRadius) {
286
287 float values[3] = {
288 SkScalarToFloat(radius0),
289 SkScalarToFloat(SkScalarMul(radius0, radius0)),
290 SkScalarToFloat(diffRadius)
291 };
292
kkinnunen7510b222014-07-30 00:04:16 -0700293 pdman.set1fv(fParamUni, 3, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000294 fCachedRadius = radius0;
295 fCachedDiffRadius = diffRadius;
296 }
297}
298
joshualittb0a8a372014-09-23 09:50:21 -0700299void GLEdge2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700300 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700301 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000302}
303
304//////////////////////////////////////////////////////////////////////////////
305// Focal Conical Gradients
306//////////////////////////////////////////////////////////////////////////////
307
308static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
309 SkMatrix* invLMatrix, SkScalar* focalX) {
310 // Inverse of the current local matrix is passed in then,
311 // translate, scale, and rotate such that endCircle is unit circle on x-axis,
312 // and focal point is at the origin.
313 ConicalType conicalType;
314 const SkPoint& focal = shader.getStartCenter();
315 const SkPoint& centerEnd = shader.getEndCenter();
316 SkScalar radius = shader.getEndRadius();
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000317 SkScalar invRadius = 1.f / radius;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000318
319 SkMatrix matrix;
320
321 matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
322 matrix.postScale(invRadius, invRadius);
323
324 SkPoint focalTrans;
325 matrix.mapPoints(&focalTrans, &focal, 1);
326 *focalX = focalTrans.length();
327
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000328 if (0.f != *focalX) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000329 SkScalar invFocalX = SkScalarInvert(*focalX);
330 SkMatrix rot;
331 rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY),
332 SkScalarMul(invFocalX, focalTrans.fX));
333 matrix.postConcat(rot);
334 }
335
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000336 matrix.postTranslate(-(*focalX), 0.f);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000337
338 // If the focal point is touching the edge of the circle it will
339 // cause a degenerate case that must be handled separately
egdaniel8405ef92014-06-09 11:57:28 -0700340 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
341 // stability trade off versus the linear approx used in the Edge Shader
342 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000343 return kEdge_ConicalType;
344 }
345
346 // Scale factor 1 / (1 - focalX * focalX)
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000347 SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX);
reed80ea19c2015-05-12 10:37:34 -0700348 SkScalar s = SkScalarInvert(oneMinusF2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000349
350
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000351 if (s >= 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000352 conicalType = kInside_ConicalType;
353 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
354 } else {
355 conicalType = kOutside_ConicalType;
356 matrix.postScale(s, s);
357 }
358
359 invLMatrix->postConcat(matrix);
360
361 return conicalType;
362}
363
364//////////////////////////////////////////////////////////////////////////////
365
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000366class FocalOutside2PtConicalEffect : public GrGradientEffect {
367public:
368
joshualittb0a8a372014-09-23 09:50:21 -0700369 static GrFragmentProcessor* Create(GrContext* ctx,
370 const SkTwoPointConicalGradient& shader,
371 const SkMatrix& matrix,
372 SkShader::TileMode tm,
373 SkScalar focalX) {
bsalomon4a339522015-10-06 08:40:50 -0700374 return new FocalOutside2PtConicalEffect(ctx, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000375 }
376
377 virtual ~FocalOutside2PtConicalEffect() { }
378
mtklein36352bf2015-03-25 18:17:31 -0700379 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800380 return "Two-Point Conical Gradient Focal Outside";
381 }
382
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000383 bool isFlipped() const { return fIsFlipped; }
384 SkScalar focal() const { return fFocalX; }
385
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000386private:
wangyixb1daa862015-08-18 11:29:31 -0700387 GrGLFragmentProcessor* onCreateGLInstance() const override;
388
wangyix4b3050b2015-08-04 07:59:37 -0700389 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
390
mtklein36352bf2015-03-25 18:17:31 -0700391 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700392 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000393 return (INHERITED::onIsEqual(sBase) &&
394 this->fFocalX == s.fFocalX &&
395 this->fIsFlipped == s.fIsFlipped);
396 }
397
398 FocalOutside2PtConicalEffect(GrContext* ctx,
399 const SkTwoPointConicalGradient& shader,
400 const SkMatrix& matrix,
401 SkShader::TileMode tm,
402 SkScalar focalX)
bsalomon4a339522015-10-06 08:40:50 -0700403 : INHERITED(ctx, shader, matrix, tm)
joshualittb2456052015-07-08 09:36:59 -0700404 , fFocalX(focalX)
405 , fIsFlipped(shader.isFlippedGrad()) {
joshualitteb2a6762014-12-04 11:35:33 -0800406 this->initClassID<FocalOutside2PtConicalEffect>();
407 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000408
joshualittb0a8a372014-09-23 09:50:21 -0700409 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000410
411 SkScalar fFocalX;
412 bool fIsFlipped;
413
414 typedef GrGradientEffect INHERITED;
415};
416
417class GLFocalOutside2PtConicalEffect : public GrGLGradientEffect {
418public:
joshualitteb2a6762014-12-04 11:35:33 -0800419 GLFocalOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000420 virtual ~GLFocalOutside2PtConicalEffect() { }
421
wangyix7c157a92015-07-22 15:08:53 -0700422 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000423
jvanverthcfc18862015-04-28 08:48:20 -0700424 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000425
426protected:
egdaniel018fb622015-10-28 07:26:40 -0700427 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700428
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000429 UniformHandle fParamUni;
430
431 const char* fVSVaryingName;
432 const char* fFSVaryingName;
433
434 bool fIsFlipped;
435
436 // @{
437 /// Values last uploaded as uniforms
438
439 SkScalar fCachedFocal;
440
441 // @}
442
443private:
444 typedef GrGLGradientEffect INHERITED;
445
446};
447
wangyix4b3050b2015-08-04 07:59:37 -0700448void FocalOutside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800449 GrProcessorKeyBuilder* b) const {
450 GLFocalOutside2PtConicalEffect::GenKey(*this, caps, b);
451}
452
wangyixb1daa862015-08-18 11:29:31 -0700453GrGLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700454 return new GLFocalOutside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000455}
456
joshualittb0a8a372014-09-23 09:50:21 -0700457GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000458
joshualitt01258472014-09-22 10:29:30 -0700459/*
460 * All Two point conical gradient test create functions may occasionally create edge case shaders
461 */
bsalomonc21b09e2015-08-28 18:46:56 -0700462const GrFragmentProcessor* FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700463 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000464 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000465 SkPoint center2;
466 SkScalar radius2;
467 do {
joshualitt0067ff52015-07-08 14:26:19 -0700468 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000469 // 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 +0000470 } while (center1 == center2);
471 SkPoint diff = center2 - center1;
472 SkScalar diffLen = diff.length();
473 // Below makes sure that the focal point is not contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700474 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000475
476 SkColor colors[kMaxRandomGradientColors];
477 SkScalar stopsArray[kMaxRandomGradientColors];
478 SkScalar* stops = stopsArray;
479 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700480 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000481 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
482 center2, radius2,
483 colors, stops, colorCount,
484 tm));
bsalomonc21b09e2015-08-28 18:46:56 -0700485 const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
bsalomon4a339522015-10-06 08:40:50 -0700486 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality);
bsalomonc21b09e2015-08-28 18:46:56 -0700487 GrAlwaysAssert(fp);
488 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000489}
490
joshualitteb2a6762014-12-04 11:35:33 -0800491GLFocalOutside2PtConicalEffect::GLFocalOutside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700492 : fVSVaryingName(nullptr)
493 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000494 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700495 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000496 fIsFlipped = data.isFlipped();
497}
498
wangyix7c157a92015-07-22 15:08:53 -0700499void GLFocalOutside2PtConicalEffect::emitCode(EmitArgs& args) {
500 const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
501 this->emitUniforms(args.fBuilder, ge);
502 fParamUni = args.fBuilder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800503 kFloat_GrSLType, kDefault_GrSLPrecision,
504 "Conical2FSParams", 2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000505 SkString tName("t");
506 SkString p0; // focalX
507 SkString p1; // 1 - focalX * focalX
508
wangyix7c157a92015-07-22 15:08:53 -0700509 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
510 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000511
512 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700513 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
514 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000515 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000516
517 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
518
519 // output will default to transparent black (we simply won't write anything
520 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -0700521 fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000522
joshualitt30ba4362014-08-21 20:18:45 -0700523 fsBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
524 fsBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
525 fsBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000526
527 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
528 // If so we must also flip sign on sqrt
529 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -0700530 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000531 coords2D, p0.c_str());
532 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700533 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000534 coords2D, p0.c_str());
535 }
536
joshualitt30ba4362014-08-21 20:18:45 -0700537 fsBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
538 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -0700539 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
540 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -0700541 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000542}
543
egdaniel018fb622015-10-28 07:26:40 -0700544void GLFocalOutside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
545 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700546 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700547 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000548 SkASSERT(data.isFlipped() == fIsFlipped);
549 SkScalar focal = data.focal();
550
551 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000552 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000553
554 float values[2] = {
555 SkScalarToFloat(focal),
556 SkScalarToFloat(oneMinus2F),
557 };
558
kkinnunen7510b222014-07-30 00:04:16 -0700559 pdman.set1fv(fParamUni, 2, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000560 fCachedFocal = focal;
561 }
562}
563
joshualittb0a8a372014-09-23 09:50:21 -0700564void GLFocalOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700565 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700566 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700567 key[0] = GenBaseGradientKey(processor);
568 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000569}
570
571//////////////////////////////////////////////////////////////////////////////
572
573class GLFocalInside2PtConicalEffect;
574
575class FocalInside2PtConicalEffect : public GrGradientEffect {
576public:
577
joshualittb0a8a372014-09-23 09:50:21 -0700578 static GrFragmentProcessor* Create(GrContext* ctx,
579 const SkTwoPointConicalGradient& shader,
580 const SkMatrix& matrix,
581 SkShader::TileMode tm,
582 SkScalar focalX) {
bsalomon4a339522015-10-06 08:40:50 -0700583 return new FocalInside2PtConicalEffect(ctx, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000584 }
585
586 virtual ~FocalInside2PtConicalEffect() {}
587
mtklein36352bf2015-03-25 18:17:31 -0700588 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800589 return "Two-Point Conical Gradient Focal Inside";
590 }
591
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000592 SkScalar focal() const { return fFocalX; }
593
joshualittb0a8a372014-09-23 09:50:21 -0700594 typedef GLFocalInside2PtConicalEffect GLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000595
596private:
wangyixb1daa862015-08-18 11:29:31 -0700597 GrGLFragmentProcessor* onCreateGLInstance() const override;
598
wangyix4b3050b2015-08-04 07:59:37 -0700599 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
600
mtklein36352bf2015-03-25 18:17:31 -0700601 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700602 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000603 return (INHERITED::onIsEqual(sBase) &&
604 this->fFocalX == s.fFocalX);
605 }
606
607 FocalInside2PtConicalEffect(GrContext* ctx,
608 const SkTwoPointConicalGradient& shader,
609 const SkMatrix& matrix,
610 SkShader::TileMode tm,
611 SkScalar focalX)
bsalomon4a339522015-10-06 08:40:50 -0700612 : INHERITED(ctx, shader, matrix, tm), fFocalX(focalX) {
joshualitteb2a6762014-12-04 11:35:33 -0800613 this->initClassID<FocalInside2PtConicalEffect>();
614 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000615
joshualittb0a8a372014-09-23 09:50:21 -0700616 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000617
618 SkScalar fFocalX;
619
620 typedef GrGradientEffect INHERITED;
621};
622
623class GLFocalInside2PtConicalEffect : public GrGLGradientEffect {
624public:
joshualitteb2a6762014-12-04 11:35:33 -0800625 GLFocalInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000626 virtual ~GLFocalInside2PtConicalEffect() {}
627
wangyix7c157a92015-07-22 15:08:53 -0700628 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000629
jvanverthcfc18862015-04-28 08:48:20 -0700630 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000631
632protected:
egdaniel018fb622015-10-28 07:26:40 -0700633 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700634
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000635 UniformHandle fFocalUni;
636
637 const char* fVSVaryingName;
638 const char* fFSVaryingName;
639
640 // @{
641 /// Values last uploaded as uniforms
642
643 SkScalar fCachedFocal;
644
645 // @}
646
647private:
648 typedef GrGLGradientEffect INHERITED;
649
650};
651
wangyix4b3050b2015-08-04 07:59:37 -0700652void FocalInside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800653 GrProcessorKeyBuilder* b) const {
654 GLFocalInside2PtConicalEffect::GenKey(*this, caps, b);
655}
656
wangyixb1daa862015-08-18 11:29:31 -0700657GrGLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700658 return new GLFocalInside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000659}
660
joshualittb0a8a372014-09-23 09:50:21 -0700661GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000662
joshualitt01258472014-09-22 10:29:30 -0700663/*
664 * All Two point conical gradient test create functions may occasionally create edge case shaders
665 */
bsalomonc21b09e2015-08-28 18:46:56 -0700666const GrFragmentProcessor* FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700667 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000668 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000669 SkPoint center2;
670 SkScalar radius2;
671 do {
joshualitt0067ff52015-07-08 14:26:19 -0700672 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000673 // Below makes sure radius2 is larger enouch such that the focal point
674 // is inside the end circle
joshualitt0067ff52015-07-08 14:26:19 -0700675 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000676 SkPoint diff = center2 - center1;
677 SkScalar diffLen = diff.length();
678 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000679 // If the circles are identical the factory will give us an empty shader.
680 } while (radius1 == radius2 && center1 == center2);
681
682 SkColor colors[kMaxRandomGradientColors];
683 SkScalar stopsArray[kMaxRandomGradientColors];
684 SkScalar* stops = stopsArray;
685 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700686 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000687 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
688 center2, radius2,
689 colors, stops, colorCount,
690 tm));
bsalomonc21b09e2015-08-28 18:46:56 -0700691 const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
bsalomon4a339522015-10-06 08:40:50 -0700692 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality);
bsalomonc21b09e2015-08-28 18:46:56 -0700693 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700694 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000695}
696
joshualitteb2a6762014-12-04 11:35:33 -0800697GLFocalInside2PtConicalEffect::GLFocalInside2PtConicalEffect(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700698 : fVSVaryingName(nullptr)
699 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000700 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000701
wangyix7c157a92015-07-22 15:08:53 -0700702void GLFocalInside2PtConicalEffect::emitCode(EmitArgs& args) {
703 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
704 this->emitUniforms(args.fBuilder, ge);
705 fFocalUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800706 kFloat_GrSLType, kDefault_GrSLPrecision,
707 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000708 SkString tName("t");
709
710 // this is the distance along x-axis from the end center to focal point in
711 // transformed coordinates
egdaniel0d3f0612015-10-21 10:45:48 -0700712 GrGLSLShaderVar focal = args.fBuilder->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000713
714 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700715 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
716 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000717 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000718
719 // t = p.x * focalX + length(p)
joshualitt30ba4362014-08-21 20:18:45 -0700720 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000721 coords2D, focal.c_str(), coords2D);
722
wangyix7c157a92015-07-22 15:08:53 -0700723 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
724 args.fSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000725}
726
egdaniel018fb622015-10-28 07:26:40 -0700727void GLFocalInside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
728 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700729 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700730 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000731 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000732
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000733 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700734 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000735 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000736 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000737}
738
joshualittb0a8a372014-09-23 09:50:21 -0700739void GLFocalInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700740 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700741 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000742}
743
744//////////////////////////////////////////////////////////////////////////////
745// Circle Conical Gradients
746//////////////////////////////////////////////////////////////////////////////
747
748struct CircleConicalInfo {
749 SkPoint fCenterEnd;
750 SkScalar fA;
751 SkScalar fB;
752 SkScalar fC;
753};
754
755// Returns focal distance along x-axis in transformed coords
756static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
757 SkMatrix* invLMatrix, CircleConicalInfo* info) {
758 // Inverse of the current local matrix is passed in then,
759 // translate and scale such that start circle is on the origin and has radius 1
760 const SkPoint& centerStart = shader.getStartCenter();
761 const SkPoint& centerEnd = shader.getEndCenter();
762 SkScalar radiusStart = shader.getStartRadius();
763 SkScalar radiusEnd = shader.getEndRadius();
764
765 SkMatrix matrix;
766
767 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
768
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000769 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000770 matrix.postScale(invStartRad, invStartRad);
771
772 radiusEnd /= radiusStart;
773
774 SkPoint centerEndTrans;
775 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
776
777 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
778 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
779
780 // Check to see if start circle is inside end circle with edges touching.
781 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700782 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
783 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
784 // still accurate.
785 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000786 return kEdge_ConicalType;
787 }
788
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000789 SkScalar C = 1.f / A;
790 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000791
792 matrix.postScale(C, C);
793
794 invLMatrix->postConcat(matrix);
795
796 info->fCenterEnd = centerEndTrans;
797 info->fA = A;
798 info->fB = B;
799 info->fC = C;
800
801 // 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 +0000802 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000803 return kInside_ConicalType;
804 }
805 return kOutside_ConicalType;
806}
807
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000808class CircleInside2PtConicalEffect : public GrGradientEffect {
809public:
810
joshualittb0a8a372014-09-23 09:50:21 -0700811 static GrFragmentProcessor* Create(GrContext* ctx,
812 const SkTwoPointConicalGradient& shader,
813 const SkMatrix& matrix,
814 SkShader::TileMode tm,
815 const CircleConicalInfo& info) {
bsalomon4a339522015-10-06 08:40:50 -0700816 return new CircleInside2PtConicalEffect(ctx, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000817 }
818
819 virtual ~CircleInside2PtConicalEffect() {}
820
mtklein36352bf2015-03-25 18:17:31 -0700821 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800822
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000823 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
824 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
825 SkScalar A() const { return fInfo.fA; }
826 SkScalar B() const { return fInfo.fB; }
827 SkScalar C() const { return fInfo.fC; }
828
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000829private:
wangyixb1daa862015-08-18 11:29:31 -0700830 GrGLFragmentProcessor* onCreateGLInstance() const override;
831
wangyix4b3050b2015-08-04 07:59:37 -0700832 virtual void onGetGLProcessorKey(const GrGLSLCaps& caps,
833 GrProcessorKeyBuilder* b) const override;
834
mtklein36352bf2015-03-25 18:17:31 -0700835 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700836 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000837 return (INHERITED::onIsEqual(sBase) &&
838 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
839 this->fInfo.fA == s.fInfo.fA &&
840 this->fInfo.fB == s.fInfo.fB &&
841 this->fInfo.fC == s.fInfo.fC);
842 }
843
844 CircleInside2PtConicalEffect(GrContext* ctx,
845 const SkTwoPointConicalGradient& shader,
846 const SkMatrix& matrix,
847 SkShader::TileMode tm,
848 const CircleConicalInfo& info)
bsalomon4a339522015-10-06 08:40:50 -0700849 : INHERITED(ctx, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800850 this->initClassID<CircleInside2PtConicalEffect>();
851 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000852
joshualittb0a8a372014-09-23 09:50:21 -0700853 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000854
855 const CircleConicalInfo fInfo;
856
857 typedef GrGradientEffect INHERITED;
858};
859
860class GLCircleInside2PtConicalEffect : public GrGLGradientEffect {
861public:
joshualitteb2a6762014-12-04 11:35:33 -0800862 GLCircleInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000863 virtual ~GLCircleInside2PtConicalEffect() {}
864
wangyix7c157a92015-07-22 15:08:53 -0700865 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000866
jvanverthcfc18862015-04-28 08:48:20 -0700867 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000868
869protected:
egdaniel018fb622015-10-28 07:26:40 -0700870 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700871
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000872 UniformHandle fCenterUni;
873 UniformHandle fParamUni;
874
875 const char* fVSVaryingName;
876 const char* fFSVaryingName;
877
878 // @{
879 /// Values last uploaded as uniforms
880
881 SkScalar fCachedCenterX;
882 SkScalar fCachedCenterY;
883 SkScalar fCachedA;
884 SkScalar fCachedB;
885 SkScalar fCachedC;
886
887 // @}
888
889private:
890 typedef GrGLGradientEffect INHERITED;
891
892};
893
wangyix4b3050b2015-08-04 07:59:37 -0700894void CircleInside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800895 GrProcessorKeyBuilder* b) const {
896 GLCircleInside2PtConicalEffect::GenKey(*this, caps, b);
897}
898
wangyixb1daa862015-08-18 11:29:31 -0700899GrGLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700900 return new GLCircleInside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000901}
902
joshualittb0a8a372014-09-23 09:50:21 -0700903GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000904
joshualitt01258472014-09-22 10:29:30 -0700905/*
906 * All Two point conical gradient test create functions may occasionally create edge case shaders
907 */
bsalomonc21b09e2015-08-28 18:46:56 -0700908const GrFragmentProcessor* CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700909 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
910 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000911 SkPoint center2;
912 SkScalar radius2;
913 do {
joshualitt0067ff52015-07-08 14:26:19 -0700914 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000915 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700916 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000917 SkPoint diff = center2 - center1;
918 SkScalar diffLen = diff.length();
919 radius2 = radius1 + diffLen + increase;
920 // If the circles are identical the factory will give us an empty shader.
921 } while (radius1 == radius2 && center1 == center2);
922
923 SkColor colors[kMaxRandomGradientColors];
924 SkScalar stopsArray[kMaxRandomGradientColors];
925 SkScalar* stops = stopsArray;
926 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700927 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000928 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
929 center2, radius2,
930 colors, stops, colorCount,
931 tm));
bsalomonc21b09e2015-08-28 18:46:56 -0700932 const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
bsalomon4a339522015-10-06 08:40:50 -0700933 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality);
bsalomonc21b09e2015-08-28 18:46:56 -0700934 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -0700935 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000936}
937
joshualitteb2a6762014-12-04 11:35:33 -0800938GLCircleInside2PtConicalEffect::GLCircleInside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700939 : fVSVaryingName(nullptr)
940 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000941 , fCachedCenterX(SK_ScalarMax)
942 , fCachedCenterY(SK_ScalarMax)
943 , fCachedA(SK_ScalarMax)
944 , fCachedB(SK_ScalarMax)
945 , fCachedC(SK_ScalarMax) {}
946
wangyix7c157a92015-07-22 15:08:53 -0700947void GLCircleInside2PtConicalEffect::emitCode(EmitArgs& args) {
948 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
949 this->emitUniforms(args.fBuilder, ge);
950 fCenterUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800951 kVec2f_GrSLType, kDefault_GrSLPrecision,
952 "Conical2FSCenter");
wangyix7c157a92015-07-22 15:08:53 -0700953 fParamUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800954 kVec3f_GrSLType, kDefault_GrSLPrecision,
955 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000956 SkString tName("t");
957
egdaniel0d3f0612015-10-21 10:45:48 -0700958 GrGLSLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000959 // params.x = A
960 // params.y = B
961 // params.z = C
egdaniel0d3f0612015-10-21 10:45:48 -0700962 GrGLSLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000963
964 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700965 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
966 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000967 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000968
969 // p = coords2D
970 // e = center end
971 // r = radius end
972 // A = dot(e, e) - r^2 + 2 * r - 1
973 // B = (r -1) / A
974 // C = 1 / A
975 // d = dot(e, p) + B
976 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
joshualitt30ba4362014-08-21 20:18:45 -0700977 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -0700978 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
979 params.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700980 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000981 tName.c_str(), params.c_str(), params.c_str());
982
wangyix7c157a92015-07-22 15:08:53 -0700983 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
984 args.fSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000985}
986
egdaniel018fb622015-10-28 07:26:40 -0700987void GLCircleInside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
988 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700989 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700990 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000991 SkScalar centerX = data.centerX();
992 SkScalar centerY = data.centerY();
993 SkScalar A = data.A();
994 SkScalar B = data.B();
995 SkScalar C = data.C();
996
997 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
998 fCachedA != A || fCachedB != B || fCachedC != C) {
999
kkinnunen7510b222014-07-30 00:04:16 -07001000 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1001 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001002
1003 fCachedCenterX = centerX;
1004 fCachedCenterY = centerY;
1005 fCachedA = A;
1006 fCachedB = B;
1007 fCachedC = C;
1008 }
1009}
1010
joshualittb0a8a372014-09-23 09:50:21 -07001011void GLCircleInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001012 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001013 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001014}
1015
1016//////////////////////////////////////////////////////////////////////////////
1017
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001018class CircleOutside2PtConicalEffect : public GrGradientEffect {
1019public:
1020
joshualittb0a8a372014-09-23 09:50:21 -07001021 static GrFragmentProcessor* Create(GrContext* ctx,
1022 const SkTwoPointConicalGradient& shader,
1023 const SkMatrix& matrix,
1024 SkShader::TileMode tm,
1025 const CircleConicalInfo& info) {
bsalomon4a339522015-10-06 08:40:50 -07001026 return new CircleOutside2PtConicalEffect(ctx, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001027 }
1028
1029 virtual ~CircleOutside2PtConicalEffect() {}
1030
mtklein36352bf2015-03-25 18:17:31 -07001031 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001032
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001033 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1034 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1035 SkScalar A() const { return fInfo.fA; }
1036 SkScalar B() const { return fInfo.fB; }
1037 SkScalar C() const { return fInfo.fC; }
1038 SkScalar tLimit() const { return fTLimit; }
1039 bool isFlipped() const { return fIsFlipped; }
1040
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001041private:
wangyixb1daa862015-08-18 11:29:31 -07001042 GrGLFragmentProcessor* onCreateGLInstance() const override;
1043
wangyix4b3050b2015-08-04 07:59:37 -07001044 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
1045
mtklein36352bf2015-03-25 18:17:31 -07001046 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001047 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001048 return (INHERITED::onIsEqual(sBase) &&
1049 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1050 this->fInfo.fA == s.fInfo.fA &&
1051 this->fInfo.fB == s.fInfo.fB &&
1052 this->fInfo.fC == s.fInfo.fC &&
1053 this->fTLimit == s.fTLimit &&
1054 this->fIsFlipped == s.fIsFlipped);
1055 }
1056
1057 CircleOutside2PtConicalEffect(GrContext* ctx,
1058 const SkTwoPointConicalGradient& shader,
1059 const SkMatrix& matrix,
1060 SkShader::TileMode tm,
1061 const CircleConicalInfo& info)
bsalomon4a339522015-10-06 08:40:50 -07001062 : INHERITED(ctx, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001063 this->initClassID<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001064 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001065 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001066 } else {
1067 fTLimit = SK_ScalarMin;
1068 }
1069
1070 fIsFlipped = shader.isFlippedGrad();
1071 }
1072
joshualittb0a8a372014-09-23 09:50:21 -07001073 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001074
1075 const CircleConicalInfo fInfo;
1076 SkScalar fTLimit;
1077 bool fIsFlipped;
1078
1079 typedef GrGradientEffect INHERITED;
1080};
1081
1082class GLCircleOutside2PtConicalEffect : public GrGLGradientEffect {
1083public:
joshualitteb2a6762014-12-04 11:35:33 -08001084 GLCircleOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001085 virtual ~GLCircleOutside2PtConicalEffect() {}
1086
wangyix7c157a92015-07-22 15:08:53 -07001087 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001088
jvanverthcfc18862015-04-28 08:48:20 -07001089 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001090
1091protected:
egdaniel018fb622015-10-28 07:26:40 -07001092 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001093
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001094 UniformHandle fCenterUni;
1095 UniformHandle fParamUni;
1096
1097 const char* fVSVaryingName;
1098 const char* fFSVaryingName;
1099
1100 bool fIsFlipped;
1101
1102 // @{
1103 /// Values last uploaded as uniforms
1104
1105 SkScalar fCachedCenterX;
1106 SkScalar fCachedCenterY;
1107 SkScalar fCachedA;
1108 SkScalar fCachedB;
1109 SkScalar fCachedC;
1110 SkScalar fCachedTLimit;
1111
1112 // @}
1113
1114private:
1115 typedef GrGLGradientEffect INHERITED;
1116
1117};
1118
wangyix4b3050b2015-08-04 07:59:37 -07001119void CircleOutside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001120 GrProcessorKeyBuilder* b) const {
1121 GLCircleOutside2PtConicalEffect::GenKey(*this, caps, b);
1122}
1123
wangyixb1daa862015-08-18 11:29:31 -07001124GrGLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001125 return new GLCircleOutside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001126}
1127
joshualittb0a8a372014-09-23 09:50:21 -07001128GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001129
joshualitt01258472014-09-22 10:29:30 -07001130/*
1131 * All Two point conical gradient test create functions may occasionally create edge case shaders
1132 */
bsalomonc21b09e2015-08-28 18:46:56 -07001133const GrFragmentProcessor* CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001134 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1135 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001136 SkPoint center2;
1137 SkScalar radius2;
1138 SkScalar diffLen;
1139 do {
joshualitt0067ff52015-07-08 14:26:19 -07001140 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001141 // If the circles share a center than we can't be in the outside case
1142 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001143 SkPoint diff = center2 - center1;
1144 diffLen = diff.length();
1145 // Below makes sure that circle one is not contained within circle two
1146 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001147 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001148
1149 SkColor colors[kMaxRandomGradientColors];
1150 SkScalar stopsArray[kMaxRandomGradientColors];
1151 SkScalar* stops = stopsArray;
1152 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -07001153 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001154 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
1155 center2, radius2,
1156 colors, stops, colorCount,
1157 tm));
bsalomonc21b09e2015-08-28 18:46:56 -07001158 const GrFragmentProcessor* fp = shader->asFragmentProcessor(
bsalomon4a339522015-10-06 08:40:50 -07001159 d->fContext,GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality);
bsalomonc21b09e2015-08-28 18:46:56 -07001160 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -07001161 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001162}
1163
joshualitteb2a6762014-12-04 11:35:33 -08001164GLCircleOutside2PtConicalEffect::GLCircleOutside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -07001165 : fVSVaryingName(nullptr)
1166 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001167 , fCachedCenterX(SK_ScalarMax)
1168 , fCachedCenterY(SK_ScalarMax)
1169 , fCachedA(SK_ScalarMax)
1170 , fCachedB(SK_ScalarMax)
1171 , fCachedC(SK_ScalarMax)
1172 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001173 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001174 fIsFlipped = data.isFlipped();
1175 }
1176
wangyix7c157a92015-07-22 15:08:53 -07001177void GLCircleOutside2PtConicalEffect::emitCode(EmitArgs& args) {
1178 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
1179 this->emitUniforms(args.fBuilder, ge);
1180 fCenterUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001181 kVec2f_GrSLType, kDefault_GrSLPrecision,
1182 "Conical2FSCenter");
wangyix7c157a92015-07-22 15:08:53 -07001183 fParamUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001184 kVec4f_GrSLType, kDefault_GrSLPrecision,
1185 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001186 SkString tName("t");
1187
egdaniel0d3f0612015-10-21 10:45:48 -07001188 GrGLSLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001189 // params.x = A
1190 // params.y = B
1191 // params.z = C
egdaniel0d3f0612015-10-21 10:45:48 -07001192 GrGLSLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001193
1194 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -07001195 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
1196 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001197 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001198
1199 // output will default to transparent black (we simply won't write anything
1200 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -07001201 fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001202
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001203 // p = coords2D
1204 // e = center end
1205 // r = radius end
1206 // A = dot(e, e) - r^2 + 2 * r - 1
1207 // B = (r -1) / A
1208 // C = 1 / A
1209 // d = dot(e, p) + B
1210 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001211
joshualitt30ba4362014-08-21 20:18:45 -07001212 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -07001213 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1214 params.c_str());
1215 fsBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1216 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001217
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001218 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1219 // If so we must also flip sign on sqrt
1220 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -07001221 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001222 } else {
joshualitt30ba4362014-08-21 20:18:45 -07001223 fsBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001224 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001225
joshualitt30ba4362014-08-21 20:18:45 -07001226 fsBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str());
1227 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -07001228 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
1229 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -07001230 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001231}
1232
egdaniel018fb622015-10-28 07:26:40 -07001233void GLCircleOutside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1234 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001235 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001236 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001237 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001238 SkScalar centerX = data.centerX();
1239 SkScalar centerY = data.centerY();
1240 SkScalar A = data.A();
1241 SkScalar B = data.B();
1242 SkScalar C = data.C();
1243 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001244
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001245 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1246 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001247
kkinnunen7510b222014-07-30 00:04:16 -07001248 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1249 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001250 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001251
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001252 fCachedCenterX = centerX;
1253 fCachedCenterY = centerY;
1254 fCachedA = A;
1255 fCachedB = B;
1256 fCachedC = C;
1257 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001258 }
1259}
1260
joshualittb0a8a372014-09-23 09:50:21 -07001261void GLCircleOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001262 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001263 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001264 key[0] = GenBaseGradientKey(processor);
1265 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001266}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001267
1268//////////////////////////////////////////////////////////////////////////////
1269
joshualittb0a8a372014-09-23 09:50:21 -07001270GrFragmentProcessor* Gr2PtConicalGradientEffect::Create(GrContext* ctx,
1271 const SkTwoPointConicalGradient& shader,
1272 SkShader::TileMode tm,
1273 const SkMatrix* localMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001274 SkMatrix matrix;
1275 if (!shader.getLocalMatrix().invert(&matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001276 return nullptr;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001277 }
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001278 if (localMatrix) {
1279 SkMatrix inv;
1280 if (!localMatrix->invert(&inv)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001281 return nullptr;
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001282 }
1283 matrix.postConcat(inv);
1284 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001285
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001286 if (shader.getStartRadius() < kErrorTol) {
1287 SkScalar focalX;
1288 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1289 if (type == kInside_ConicalType) {
bsalomon4a339522015-10-06 08:40:50 -07001290 return FocalInside2PtConicalEffect::Create(ctx, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001291 } else if(type == kEdge_ConicalType) {
1292 set_matrix_edge_conical(shader, &matrix);
bsalomon4a339522015-10-06 08:40:50 -07001293 return Edge2PtConicalEffect::Create(ctx, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001294 } else {
bsalomon4a339522015-10-06 08:40:50 -07001295 return FocalOutside2PtConicalEffect::Create(ctx, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001296 }
1297 }
1298
1299 CircleConicalInfo info;
1300 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1301
1302 if (type == kInside_ConicalType) {
bsalomon4a339522015-10-06 08:40:50 -07001303 return CircleInside2PtConicalEffect::Create(ctx, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001304 } else if (type == kEdge_ConicalType) {
1305 set_matrix_edge_conical(shader, &matrix);
bsalomon4a339522015-10-06 08:40:50 -07001306 return Edge2PtConicalEffect::Create(ctx, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001307 } else {
bsalomon4a339522015-10-06 08:40:50 -07001308 return CircleOutside2PtConicalEffect::Create(ctx, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001309 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001310}
1311
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001312#endif