blob: 9461f1377071b0e85eaf6b76e9eb6db09d4aaad8 [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"
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000016// For brevity
kkinnunen7510b222014-07-30 00:04:16 -070017typedef GrGLProgramDataManager::UniformHandle UniformHandle;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000018
commit-bot@chromium.org80894672014-04-22 21:24:22 +000019static const SkScalar kErrorTol = 0.00001f;
egdaniel8405ef92014-06-09 11:57:28 -070020static const SkScalar kEdgeErrorTol = 5.f * kErrorTol;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000021
22/**
23 * We have three general cases for 2pt conical gradients. First we always assume that
24 * the start radius <= end radius. Our first case (kInside_) is when the start circle
25 * is completely enclosed by the end circle. The second case (kOutside_) is the case
26 * when the start circle is either completely outside the end circle or the circles
27 * overlap. The final case (kEdge_) is when the start circle is inside the end one,
28 * but the two are just barely touching at 1 point along their edges.
29 */
30enum ConicalType {
31 kInside_ConicalType,
32 kOutside_ConicalType,
33 kEdge_ConicalType,
34};
35
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000036//////////////////////////////////////////////////////////////////////////////
37
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000038static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader,
39 SkMatrix* invLMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000040 // Inverse of the current local matrix is passed in then,
41 // translate to center1, rotate so center2 is on x axis.
42 const SkPoint& center1 = shader.getStartCenter();
43 const SkPoint& center2 = shader.getEndCenter();
44
45 invLMatrix->postTranslate(-center1.fX, -center1.fY);
46
47 SkPoint diff = center2 - center1;
48 SkScalar diffLen = diff.length();
49 if (0 != diffLen) {
50 SkScalar invDiffLen = SkScalarInvert(diffLen);
51 SkMatrix rot;
52 rot.setSinCos(-SkScalarMul(invDiffLen, diff.fY),
53 SkScalarMul(invDiffLen, diff.fX));
54 invLMatrix->postConcat(rot);
55 }
56}
57
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000058class Edge2PtConicalEffect : public GrGradientEffect {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000059public:
60
joshualittb0a8a372014-09-23 09:50:21 -070061 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -070062 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -070063 const SkTwoPointConicalGradient& shader,
64 const SkMatrix& matrix,
65 SkShader::TileMode tm) {
joshualitt9cc17752015-07-09 06:28:14 -070066 return SkNEW_ARGS(Edge2PtConicalEffect, (ctx, procDataManager, 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
jvanverthcfc18862015-04-28 08:48:20 -070075 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -080076
mtklein36352bf2015-03-25 18:17:31 -070077 GrGLFragmentProcessor* createGLInstance() const override;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000078
79 // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000080 SkScalar center() const { return fCenterX1; }
81 SkScalar diffRadius() const { return fDiffRadius; }
82 SkScalar radius() const { return fRadius0; }
83
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000084private:
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,
joshualitt9cc17752015-07-09 06:28:14 -070094 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000095 const SkTwoPointConicalGradient& shader,
96 const SkMatrix& matrix,
97 SkShader::TileMode tm)
joshualitt9cc17752015-07-09 06:28:14 -070098 : INHERITED(ctx, procDataManager, shader, matrix, tm),
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000099 fCenterX1(shader.getCenterX1()),
100 fRadius0(shader.getStartRadius()),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000101 fDiffRadius(shader.getDiffRadius()){
joshualitteb2a6762014-12-04 11:35:33 -0800102 this->initClassID<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000103 // We should only be calling this shader if we are degenerate case with touching circles
egdaniel8405ef92014-06-09 11:57:28 -0700104 // When deciding if we are in edge case, we scaled by the end radius for cases when the
joshualitt01258472014-09-22 10:29:30 -0700105 // start radius was close to zero, otherwise we scaled by the start radius. In addition
106 // Our test for the edge case in set_matrix_circle_conical has a higher tolerance so we
107 // need the sqrt value below
108 SkASSERT(SkScalarAbs(SkScalarAbs(fDiffRadius) - fCenterX1) <
109 (fRadius0 < kErrorTol ? shader.getEndRadius() * kEdgeErrorTol :
110 fRadius0 * sqrt(kEdgeErrorTol)));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000111
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000112 // We pass the linear part of the quadratic as a varying.
113 // float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
114 fBTransform = this->getCoordTransform();
115 SkMatrix& bMatrix = *fBTransform.accessMatrix();
116 SkScalar r0dr = SkScalarMul(fRadius0, fDiffRadius);
117 bMatrix[SkMatrix::kMScaleX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMScaleX]) +
118 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp0]));
119 bMatrix[SkMatrix::kMSkewX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMSkewX]) +
120 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp1]));
121 bMatrix[SkMatrix::kMTransX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMTransX]) +
122 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp2]));
123 this->addCoordTransform(&fBTransform);
124 }
125
joshualittb0a8a372014-09-23 09:50:21 -0700126 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000127
128 // @{
129 // Cache of values - these can change arbitrarily, EXCEPT
130 // we shouldn't change between degenerate and non-degenerate?!
131
132 GrCoordTransform fBTransform;
133 SkScalar fCenterX1;
134 SkScalar fRadius0;
135 SkScalar fDiffRadius;
136
137 // @}
138
139 typedef GrGradientEffect INHERITED;
140};
141
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000142class GLEdge2PtConicalEffect : public GrGLGradientEffect {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000143public:
joshualitteb2a6762014-12-04 11:35:33 -0800144 GLEdge2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000145 virtual ~GLEdge2PtConicalEffect() { }
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000146
wangyix7c157a92015-07-22 15:08:53 -0700147 virtual void emitCode(EmitArgs&) override;
mtklein36352bf2015-03-25 18:17:31 -0700148 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000149
jvanverthcfc18862015-04-28 08:48:20 -0700150 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000151
152protected:
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
jvanverthcfc18862015-04-28 08:48:20 -0700171void Edge2PtConicalEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800172 GrProcessorKeyBuilder* b) const {
173 GLEdge2PtConicalEffect::GenKey(*this, caps, b);
174}
175
176GrGLFragmentProcessor* Edge2PtConicalEffect::createGLInstance() const {
177 return SkNEW_ARGS(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 */
joshualitt0067ff52015-07-08 14:26:19 -0700185GrFragmentProcessor* Edge2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
186 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));
211 SkPaint paint;
joshualittb0a8a372014-09-23 09:50:21 -0700212 GrFragmentProcessor* fp;
bsalomon83d081a2014-07-08 09:56:10 -0700213 GrColor paintColor;
joshualitt0067ff52015-07-08 14:26:19 -0700214 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
215 GrTest::TestMatrix(d->fRandom), NULL,
joshualitt9cc17752015-07-09 06:28:14 -0700216 &paintColor, d->fProcDataManager, &fp));
joshualittb0a8a372014-09-23 09:50:21 -0700217 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000218}
219
joshualitteb2a6762014-12-04 11:35:33 -0800220GLEdge2PtConicalEffect::GLEdge2PtConicalEffect(const GrProcessor&)
221 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000222 , fFSVaryingName(NULL)
223 , fCachedRadius(-SK_ScalarMax)
224 , fCachedDiffRadius(-SK_ScalarMax) {}
225
wangyix7c157a92015-07-22 15:08:53 -0700226void GLEdge2PtConicalEffect::emitCode(EmitArgs& args) {
227 const Edge2PtConicalEffect& ge = args.fFp.cast<Edge2PtConicalEffect>();
228 this->emitUniforms(args.fBuilder, ge);
229 fParamUni = args.fBuilder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800230 kFloat_GrSLType, kDefault_GrSLPrecision,
231 "Conical2FSParams", 3);
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
wangyix7c157a92015-07-22 15:08:53 -0700239 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
240 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
241 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000242
243 // We interpolate the linear component in coords[1].
wangyix7c157a92015-07-22 15:08:53 -0700244 SkASSERT(args.fCoords[0].getType() == args.fCoords[1].getType());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000245 const char* coords2D;
246 SkString bVar;
wangyix7c157a92015-07-22 15:08:53 -0700247 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
248 if (kVec3f_GrSLType == args.fCoords[0].getType()) {
joshualitt30ba4362014-08-21 20:18:45 -0700249 fsBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
wangyix7c157a92015-07-22 15:08:53 -0700250 args.fCoords[0].c_str(), args.fCoords[0].c_str(),
251 args.fCoords[1].c_str(), args.fCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000252 coords2D = "interpolants.xy";
253 bVar = "interpolants.z";
254 } else {
wangyix7c157a92015-07-22 15:08:53 -0700255 coords2D = args.fCoords[0].c_str();
256 bVar.printf("%s.x", args.fCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000257 }
258
259 // output will default to transparent black (we simply won't write anything
260 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -0700261 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 +0000262
263 // c = (x^2)+(y^2) - params[1]
joshualitt30ba4362014-08-21 20:18:45 -0700264 fsBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000265 cName.c_str(), coords2D, coords2D, p1.c_str());
266
267 // linear case: t = -c/b
joshualitt30ba4362014-08-21 20:18:45 -0700268 fsBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000269 cName.c_str(), bVar.c_str());
270
271 // if r(t) > 0, then t will be the x coordinate
joshualitt30ba4362014-08-21 20:18:45 -0700272 fsBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000273 p2.c_str(), p0.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700274 fsBuilder->codeAppend("\t");
wangyix7c157a92015-07-22 15:08:53 -0700275 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
276 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -0700277 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000278}
279
kkinnunen7510b222014-07-30 00:04:16 -0700280void GLEdge2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700281 const GrProcessor& processor) {
282 INHERITED::setData(pdman, processor);
283 const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000284 SkScalar radius0 = data.radius();
285 SkScalar diffRadius = data.diffRadius();
286
287 if (fCachedRadius != radius0 ||
288 fCachedDiffRadius != diffRadius) {
289
290 float values[3] = {
291 SkScalarToFloat(radius0),
292 SkScalarToFloat(SkScalarMul(radius0, radius0)),
293 SkScalarToFloat(diffRadius)
294 };
295
kkinnunen7510b222014-07-30 00:04:16 -0700296 pdman.set1fv(fParamUni, 3, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000297 fCachedRadius = radius0;
298 fCachedDiffRadius = diffRadius;
299 }
300}
301
joshualittb0a8a372014-09-23 09:50:21 -0700302void GLEdge2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700303 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700304 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000305}
306
307//////////////////////////////////////////////////////////////////////////////
308// Focal Conical Gradients
309//////////////////////////////////////////////////////////////////////////////
310
311static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
312 SkMatrix* invLMatrix, SkScalar* focalX) {
313 // Inverse of the current local matrix is passed in then,
314 // translate, scale, and rotate such that endCircle is unit circle on x-axis,
315 // and focal point is at the origin.
316 ConicalType conicalType;
317 const SkPoint& focal = shader.getStartCenter();
318 const SkPoint& centerEnd = shader.getEndCenter();
319 SkScalar radius = shader.getEndRadius();
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000320 SkScalar invRadius = 1.f / radius;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000321
322 SkMatrix matrix;
323
324 matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
325 matrix.postScale(invRadius, invRadius);
326
327 SkPoint focalTrans;
328 matrix.mapPoints(&focalTrans, &focal, 1);
329 *focalX = focalTrans.length();
330
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000331 if (0.f != *focalX) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000332 SkScalar invFocalX = SkScalarInvert(*focalX);
333 SkMatrix rot;
334 rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY),
335 SkScalarMul(invFocalX, focalTrans.fX));
336 matrix.postConcat(rot);
337 }
338
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000339 matrix.postTranslate(-(*focalX), 0.f);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000340
341 // If the focal point is touching the edge of the circle it will
342 // cause a degenerate case that must be handled separately
egdaniel8405ef92014-06-09 11:57:28 -0700343 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
344 // stability trade off versus the linear approx used in the Edge Shader
345 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000346 return kEdge_ConicalType;
347 }
348
349 // Scale factor 1 / (1 - focalX * focalX)
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000350 SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX);
reed80ea19c2015-05-12 10:37:34 -0700351 SkScalar s = SkScalarInvert(oneMinusF2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000352
353
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000354 if (s >= 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000355 conicalType = kInside_ConicalType;
356 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
357 } else {
358 conicalType = kOutside_ConicalType;
359 matrix.postScale(s, s);
360 }
361
362 invLMatrix->postConcat(matrix);
363
364 return conicalType;
365}
366
367//////////////////////////////////////////////////////////////////////////////
368
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000369class FocalOutside2PtConicalEffect : public GrGradientEffect {
370public:
371
joshualittb0a8a372014-09-23 09:50:21 -0700372 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700373 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700374 const SkTwoPointConicalGradient& shader,
375 const SkMatrix& matrix,
376 SkShader::TileMode tm,
377 SkScalar focalX) {
joshualitt9cc17752015-07-09 06:28:14 -0700378 return SkNEW_ARGS(FocalOutside2PtConicalEffect, (ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -0700379 focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000380 }
381
382 virtual ~FocalOutside2PtConicalEffect() { }
383
mtklein36352bf2015-03-25 18:17:31 -0700384 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800385 return "Two-Point Conical Gradient Focal Outside";
386 }
387
jvanverthcfc18862015-04-28 08:48:20 -0700388 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800389
mtklein36352bf2015-03-25 18:17:31 -0700390 GrGLFragmentProcessor* createGLInstance() const override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000391
392 bool isFlipped() const { return fIsFlipped; }
393 SkScalar focal() const { return fFocalX; }
394
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000395private:
mtklein36352bf2015-03-25 18:17:31 -0700396 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700397 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000398 return (INHERITED::onIsEqual(sBase) &&
399 this->fFocalX == s.fFocalX &&
400 this->fIsFlipped == s.fIsFlipped);
401 }
402
403 FocalOutside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700404 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000405 const SkTwoPointConicalGradient& shader,
406 const SkMatrix& matrix,
407 SkShader::TileMode tm,
408 SkScalar focalX)
joshualitt9cc17752015-07-09 06:28:14 -0700409 : INHERITED(ctx, procDataManager, shader, matrix, tm)
joshualittb2456052015-07-08 09:36:59 -0700410 , fFocalX(focalX)
411 , fIsFlipped(shader.isFlippedGrad()) {
joshualitteb2a6762014-12-04 11:35:33 -0800412 this->initClassID<FocalOutside2PtConicalEffect>();
413 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000414
joshualittb0a8a372014-09-23 09:50:21 -0700415 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000416
417 SkScalar fFocalX;
418 bool fIsFlipped;
419
420 typedef GrGradientEffect INHERITED;
421};
422
423class GLFocalOutside2PtConicalEffect : public GrGLGradientEffect {
424public:
joshualitteb2a6762014-12-04 11:35:33 -0800425 GLFocalOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000426 virtual ~GLFocalOutside2PtConicalEffect() { }
427
wangyix7c157a92015-07-22 15:08:53 -0700428 virtual void emitCode(EmitArgs&) override;
mtklein36352bf2015-03-25 18:17:31 -0700429 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000430
jvanverthcfc18862015-04-28 08:48:20 -0700431 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000432
433protected:
434 UniformHandle fParamUni;
435
436 const char* fVSVaryingName;
437 const char* fFSVaryingName;
438
439 bool fIsFlipped;
440
441 // @{
442 /// Values last uploaded as uniforms
443
444 SkScalar fCachedFocal;
445
446 // @}
447
448private:
449 typedef GrGLGradientEffect INHERITED;
450
451};
452
jvanverthcfc18862015-04-28 08:48:20 -0700453void FocalOutside2PtConicalEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800454 GrProcessorKeyBuilder* b) const {
455 GLFocalOutside2PtConicalEffect::GenKey(*this, caps, b);
456}
457
458GrGLFragmentProcessor* FocalOutside2PtConicalEffect::createGLInstance() const {
459 return SkNEW_ARGS(GLFocalOutside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000460}
461
joshualittb0a8a372014-09-23 09:50:21 -0700462GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000463
joshualitt01258472014-09-22 10:29:30 -0700464/*
465 * All Two point conical gradient test create functions may occasionally create edge case shaders
466 */
joshualitt0067ff52015-07-08 14:26:19 -0700467GrFragmentProcessor* FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
468 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000469 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000470 SkPoint center2;
471 SkScalar radius2;
472 do {
joshualitt0067ff52015-07-08 14:26:19 -0700473 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000474 // 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 +0000475 } while (center1 == center2);
476 SkPoint diff = center2 - center1;
477 SkScalar diffLen = diff.length();
478 // Below makes sure that the focal point is not contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700479 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000480
481 SkColor colors[kMaxRandomGradientColors];
482 SkScalar stopsArray[kMaxRandomGradientColors];
483 SkScalar* stops = stopsArray;
484 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700485 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000486 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
487 center2, radius2,
488 colors, stops, colorCount,
489 tm));
490 SkPaint paint;
joshualittb0a8a372014-09-23 09:50:21 -0700491 GrFragmentProcessor* effect;
bsalomon83d081a2014-07-08 09:56:10 -0700492 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -0700493 GrPaint grPaint;
joshualitt0067ff52015-07-08 14:26:19 -0700494 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
495 GrTest::TestMatrix(d->fRandom), NULL,
joshualitt9cc17752015-07-09 06:28:14 -0700496 &paintColor, d->fProcDataManager,
joshualitt8ca93e72015-07-08 06:51:43 -0700497 &effect));
dandov9de5b512014-06-10 14:38:28 -0700498 return effect;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000499}
500
joshualitteb2a6762014-12-04 11:35:33 -0800501GLFocalOutside2PtConicalEffect::GLFocalOutside2PtConicalEffect(const GrProcessor& processor)
502 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000503 , fFSVaryingName(NULL)
504 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700505 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000506 fIsFlipped = data.isFlipped();
507}
508
wangyix7c157a92015-07-22 15:08:53 -0700509void GLFocalOutside2PtConicalEffect::emitCode(EmitArgs& args) {
510 const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
511 this->emitUniforms(args.fBuilder, ge);
512 fParamUni = args.fBuilder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800513 kFloat_GrSLType, kDefault_GrSLPrecision,
514 "Conical2FSParams", 2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000515 SkString tName("t");
516 SkString p0; // focalX
517 SkString p1; // 1 - focalX * focalX
518
wangyix7c157a92015-07-22 15:08:53 -0700519 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
520 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000521
522 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700523 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
524 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000525 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000526
527 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
528
529 // output will default to transparent black (we simply won't write anything
530 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -0700531 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 +0000532
joshualitt30ba4362014-08-21 20:18:45 -0700533 fsBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
534 fsBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
535 fsBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000536
537 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
538 // If so we must also flip sign on sqrt
539 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -0700540 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000541 coords2D, p0.c_str());
542 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700543 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000544 coords2D, p0.c_str());
545 }
546
joshualitt30ba4362014-08-21 20:18:45 -0700547 fsBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
548 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -0700549 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
550 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -0700551 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000552}
553
kkinnunen7510b222014-07-30 00:04:16 -0700554void GLFocalOutside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700555 const GrProcessor& processor) {
556 INHERITED::setData(pdman, processor);
557 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000558 SkASSERT(data.isFlipped() == fIsFlipped);
559 SkScalar focal = data.focal();
560
561 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000562 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000563
564 float values[2] = {
565 SkScalarToFloat(focal),
566 SkScalarToFloat(oneMinus2F),
567 };
568
kkinnunen7510b222014-07-30 00:04:16 -0700569 pdman.set1fv(fParamUni, 2, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000570 fCachedFocal = focal;
571 }
572}
573
joshualittb0a8a372014-09-23 09:50:21 -0700574void GLFocalOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700575 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700576 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700577 key[0] = GenBaseGradientKey(processor);
578 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000579}
580
581//////////////////////////////////////////////////////////////////////////////
582
583class GLFocalInside2PtConicalEffect;
584
585class FocalInside2PtConicalEffect : public GrGradientEffect {
586public:
587
joshualittb0a8a372014-09-23 09:50:21 -0700588 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700589 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700590 const SkTwoPointConicalGradient& shader,
591 const SkMatrix& matrix,
592 SkShader::TileMode tm,
593 SkScalar focalX) {
joshualitt9cc17752015-07-09 06:28:14 -0700594 return SkNEW_ARGS(FocalInside2PtConicalEffect, (ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -0700595 focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000596 }
597
598 virtual ~FocalInside2PtConicalEffect() {}
599
mtklein36352bf2015-03-25 18:17:31 -0700600 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800601 return "Two-Point Conical Gradient Focal Inside";
602 }
603
jvanverthcfc18862015-04-28 08:48:20 -0700604 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800605
mtklein36352bf2015-03-25 18:17:31 -0700606 GrGLFragmentProcessor* createGLInstance() const override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000607
608 SkScalar focal() const { return fFocalX; }
609
joshualittb0a8a372014-09-23 09:50:21 -0700610 typedef GLFocalInside2PtConicalEffect GLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000611
612private:
mtklein36352bf2015-03-25 18:17:31 -0700613 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700614 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000615 return (INHERITED::onIsEqual(sBase) &&
616 this->fFocalX == s.fFocalX);
617 }
618
619 FocalInside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700620 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000621 const SkTwoPointConicalGradient& shader,
622 const SkMatrix& matrix,
623 SkShader::TileMode tm,
624 SkScalar focalX)
joshualitt9cc17752015-07-09 06:28:14 -0700625 : INHERITED(ctx, procDataManager, shader, matrix, tm), fFocalX(focalX) {
joshualitteb2a6762014-12-04 11:35:33 -0800626 this->initClassID<FocalInside2PtConicalEffect>();
627 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000628
joshualittb0a8a372014-09-23 09:50:21 -0700629 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000630
631 SkScalar fFocalX;
632
633 typedef GrGradientEffect INHERITED;
634};
635
636class GLFocalInside2PtConicalEffect : public GrGLGradientEffect {
637public:
joshualitteb2a6762014-12-04 11:35:33 -0800638 GLFocalInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000639 virtual ~GLFocalInside2PtConicalEffect() {}
640
wangyix7c157a92015-07-22 15:08:53 -0700641 virtual void emitCode(EmitArgs&) override;
mtklein36352bf2015-03-25 18:17:31 -0700642 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000643
jvanverthcfc18862015-04-28 08:48:20 -0700644 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000645
646protected:
647 UniformHandle fFocalUni;
648
649 const char* fVSVaryingName;
650 const char* fFSVaryingName;
651
652 // @{
653 /// Values last uploaded as uniforms
654
655 SkScalar fCachedFocal;
656
657 // @}
658
659private:
660 typedef GrGLGradientEffect INHERITED;
661
662};
663
jvanverthcfc18862015-04-28 08:48:20 -0700664void FocalInside2PtConicalEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800665 GrProcessorKeyBuilder* b) const {
666 GLFocalInside2PtConicalEffect::GenKey(*this, caps, b);
667}
668
669GrGLFragmentProcessor* FocalInside2PtConicalEffect::createGLInstance() const {
670 return SkNEW_ARGS(GLFocalInside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000671}
672
joshualittb0a8a372014-09-23 09:50:21 -0700673GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000674
joshualitt01258472014-09-22 10:29:30 -0700675/*
676 * All Two point conical gradient test create functions may occasionally create edge case shaders
677 */
joshualitt0067ff52015-07-08 14:26:19 -0700678GrFragmentProcessor* FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
679 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000680 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000681 SkPoint center2;
682 SkScalar radius2;
683 do {
joshualitt0067ff52015-07-08 14:26:19 -0700684 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000685 // Below makes sure radius2 is larger enouch such that the focal point
686 // is inside the end circle
joshualitt0067ff52015-07-08 14:26:19 -0700687 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000688 SkPoint diff = center2 - center1;
689 SkScalar diffLen = diff.length();
690 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000691 // If the circles are identical the factory will give us an empty shader.
692 } while (radius1 == radius2 && center1 == center2);
693
694 SkColor colors[kMaxRandomGradientColors];
695 SkScalar stopsArray[kMaxRandomGradientColors];
696 SkScalar* stops = stopsArray;
697 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700698 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000699 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
700 center2, radius2,
701 colors, stops, colorCount,
702 tm));
703 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700704 GrColor paintColor;
joshualittb0a8a372014-09-23 09:50:21 -0700705 GrFragmentProcessor* fp;
joshualitt0067ff52015-07-08 14:26:19 -0700706 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
707 GrTest::TestMatrix(d->fRandom), NULL,
joshualitt9cc17752015-07-09 06:28:14 -0700708 &paintColor, d->fProcDataManager, &fp));
joshualittb0a8a372014-09-23 09:50:21 -0700709 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000710}
711
joshualitteb2a6762014-12-04 11:35:33 -0800712GLFocalInside2PtConicalEffect::GLFocalInside2PtConicalEffect(const GrProcessor&)
713 : fVSVaryingName(NULL)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000714 , fFSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000715 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000716
wangyix7c157a92015-07-22 15:08:53 -0700717void GLFocalInside2PtConicalEffect::emitCode(EmitArgs& args) {
718 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
719 this->emitUniforms(args.fBuilder, ge);
720 fFocalUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800721 kFloat_GrSLType, kDefault_GrSLPrecision,
722 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000723 SkString tName("t");
724
725 // this is the distance along x-axis from the end center to focal point in
726 // transformed coordinates
wangyix7c157a92015-07-22 15:08:53 -0700727 GrGLShaderVar focal = args.fBuilder->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000728
729 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700730 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
731 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000732 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000733
734 // t = p.x * focalX + length(p)
joshualitt30ba4362014-08-21 20:18:45 -0700735 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000736 coords2D, focal.c_str(), coords2D);
737
wangyix7c157a92015-07-22 15:08:53 -0700738 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
739 args.fSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000740}
741
kkinnunen7510b222014-07-30 00:04:16 -0700742void GLFocalInside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700743 const GrProcessor& processor) {
744 INHERITED::setData(pdman, processor);
745 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
joshualittb0a8a372014-09-23 09:50:21 -0700754void GLFocalInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700755 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700756 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000757}
758
759//////////////////////////////////////////////////////////////////////////////
760// Circle Conical Gradients
761//////////////////////////////////////////////////////////////////////////////
762
763struct CircleConicalInfo {
764 SkPoint fCenterEnd;
765 SkScalar fA;
766 SkScalar fB;
767 SkScalar fC;
768};
769
770// Returns focal distance along x-axis in transformed coords
771static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
772 SkMatrix* invLMatrix, CircleConicalInfo* info) {
773 // Inverse of the current local matrix is passed in then,
774 // translate and scale such that start circle is on the origin and has radius 1
775 const SkPoint& centerStart = shader.getStartCenter();
776 const SkPoint& centerEnd = shader.getEndCenter();
777 SkScalar radiusStart = shader.getStartRadius();
778 SkScalar radiusEnd = shader.getEndRadius();
779
780 SkMatrix matrix;
781
782 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
783
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000784 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000785 matrix.postScale(invStartRad, invStartRad);
786
787 radiusEnd /= radiusStart;
788
789 SkPoint centerEndTrans;
790 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
791
792 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
793 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
794
795 // Check to see if start circle is inside end circle with edges touching.
796 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700797 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
798 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
799 // still accurate.
800 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000801 return kEdge_ConicalType;
802 }
803
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000804 SkScalar C = 1.f / A;
805 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000806
807 matrix.postScale(C, C);
808
809 invLMatrix->postConcat(matrix);
810
811 info->fCenterEnd = centerEndTrans;
812 info->fA = A;
813 info->fB = B;
814 info->fC = C;
815
816 // 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 +0000817 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000818 return kInside_ConicalType;
819 }
820 return kOutside_ConicalType;
821}
822
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000823class CircleInside2PtConicalEffect : public GrGradientEffect {
824public:
825
joshualittb0a8a372014-09-23 09:50:21 -0700826 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700827 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700828 const SkTwoPointConicalGradient& shader,
829 const SkMatrix& matrix,
830 SkShader::TileMode tm,
831 const CircleConicalInfo& info) {
joshualitt9cc17752015-07-09 06:28:14 -0700832 return SkNEW_ARGS(CircleInside2PtConicalEffect, (ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -0700833 info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000834 }
835
836 virtual ~CircleInside2PtConicalEffect() {}
837
mtklein36352bf2015-03-25 18:17:31 -0700838 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800839
jvanverthcfc18862015-04-28 08:48:20 -0700840 virtual void getGLProcessorKey(const GrGLSLCaps& caps,
mtklein36352bf2015-03-25 18:17:31 -0700841 GrProcessorKeyBuilder* b) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800842
mtklein36352bf2015-03-25 18:17:31 -0700843 GrGLFragmentProcessor* createGLInstance() const override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000844
845 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
846 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
847 SkScalar A() const { return fInfo.fA; }
848 SkScalar B() const { return fInfo.fB; }
849 SkScalar C() const { return fInfo.fC; }
850
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000851private:
mtklein36352bf2015-03-25 18:17:31 -0700852 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700853 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000854 return (INHERITED::onIsEqual(sBase) &&
855 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
856 this->fInfo.fA == s.fInfo.fA &&
857 this->fInfo.fB == s.fInfo.fB &&
858 this->fInfo.fC == s.fInfo.fC);
859 }
860
861 CircleInside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700862 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000863 const SkTwoPointConicalGradient& shader,
864 const SkMatrix& matrix,
865 SkShader::TileMode tm,
866 const CircleConicalInfo& info)
joshualitt9cc17752015-07-09 06:28:14 -0700867 : INHERITED(ctx, procDataManager, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800868 this->initClassID<CircleInside2PtConicalEffect>();
869 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000870
joshualittb0a8a372014-09-23 09:50:21 -0700871 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000872
873 const CircleConicalInfo fInfo;
874
875 typedef GrGradientEffect INHERITED;
876};
877
878class GLCircleInside2PtConicalEffect : public GrGLGradientEffect {
879public:
joshualitteb2a6762014-12-04 11:35:33 -0800880 GLCircleInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000881 virtual ~GLCircleInside2PtConicalEffect() {}
882
wangyix7c157a92015-07-22 15:08:53 -0700883 virtual void emitCode(EmitArgs&) override;
mtklein36352bf2015-03-25 18:17:31 -0700884 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000885
jvanverthcfc18862015-04-28 08:48:20 -0700886 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000887
888protected:
889 UniformHandle fCenterUni;
890 UniformHandle fParamUni;
891
892 const char* fVSVaryingName;
893 const char* fFSVaryingName;
894
895 // @{
896 /// Values last uploaded as uniforms
897
898 SkScalar fCachedCenterX;
899 SkScalar fCachedCenterY;
900 SkScalar fCachedA;
901 SkScalar fCachedB;
902 SkScalar fCachedC;
903
904 // @}
905
906private:
907 typedef GrGLGradientEffect INHERITED;
908
909};
910
jvanverthcfc18862015-04-28 08:48:20 -0700911void CircleInside2PtConicalEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800912 GrProcessorKeyBuilder* b) const {
913 GLCircleInside2PtConicalEffect::GenKey(*this, caps, b);
914}
915
916GrGLFragmentProcessor* CircleInside2PtConicalEffect::createGLInstance() const {
917 return SkNEW_ARGS(GLCircleInside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000918}
919
joshualittb0a8a372014-09-23 09:50:21 -0700920GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000921
joshualitt01258472014-09-22 10:29:30 -0700922/*
923 * All Two point conical gradient test create functions may occasionally create edge case shaders
924 */
joshualitt0067ff52015-07-08 14:26:19 -0700925GrFragmentProcessor*
926CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
927 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
928 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000929 SkPoint center2;
930 SkScalar radius2;
931 do {
joshualitt0067ff52015-07-08 14:26:19 -0700932 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000933 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700934 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000935 SkPoint diff = center2 - center1;
936 SkScalar diffLen = diff.length();
937 radius2 = radius1 + diffLen + increase;
938 // If the circles are identical the factory will give us an empty shader.
939 } while (radius1 == radius2 && center1 == center2);
940
941 SkColor colors[kMaxRandomGradientColors];
942 SkScalar stopsArray[kMaxRandomGradientColors];
943 SkScalar* stops = stopsArray;
944 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700945 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000946 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
947 center2, radius2,
948 colors, stops, colorCount,
949 tm));
950 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700951 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -0700952 GrFragmentProcessor* fp;
joshualitt0067ff52015-07-08 14:26:19 -0700953 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
954 GrTest::TestMatrix(d->fRandom), NULL,
joshualitt9cc17752015-07-09 06:28:14 -0700955 &paintColor, d->fProcDataManager, &fp));
joshualitt8ca93e72015-07-08 06:51:43 -0700956 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000957}
958
joshualitteb2a6762014-12-04 11:35:33 -0800959GLCircleInside2PtConicalEffect::GLCircleInside2PtConicalEffect(const GrProcessor& processor)
960 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000961 , fFSVaryingName(NULL)
962 , fCachedCenterX(SK_ScalarMax)
963 , fCachedCenterY(SK_ScalarMax)
964 , fCachedA(SK_ScalarMax)
965 , fCachedB(SK_ScalarMax)
966 , fCachedC(SK_ScalarMax) {}
967
wangyix7c157a92015-07-22 15:08:53 -0700968void GLCircleInside2PtConicalEffect::emitCode(EmitArgs& args) {
969 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
970 this->emitUniforms(args.fBuilder, ge);
971 fCenterUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800972 kVec2f_GrSLType, kDefault_GrSLPrecision,
973 "Conical2FSCenter");
wangyix7c157a92015-07-22 15:08:53 -0700974 fParamUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800975 kVec3f_GrSLType, kDefault_GrSLPrecision,
976 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000977 SkString tName("t");
978
wangyix7c157a92015-07-22 15:08:53 -0700979 GrGLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000980 // params.x = A
981 // params.y = B
982 // params.z = C
wangyix7c157a92015-07-22 15:08:53 -0700983 GrGLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000984
985 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700986 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
987 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000988 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000989
990 // p = coords2D
991 // e = center end
992 // r = radius end
993 // A = dot(e, e) - r^2 + 2 * r - 1
994 // B = (r -1) / A
995 // C = 1 / A
996 // d = dot(e, p) + B
997 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
joshualitt30ba4362014-08-21 20:18:45 -0700998 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -0700999 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1000 params.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001001 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001002 tName.c_str(), params.c_str(), params.c_str());
1003
wangyix7c157a92015-07-22 15:08:53 -07001004 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
1005 args.fSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001006}
1007
kkinnunen7510b222014-07-30 00:04:16 -07001008void GLCircleInside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001009 const GrProcessor& processor) {
1010 INHERITED::setData(pdman, processor);
1011 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001012 SkScalar centerX = data.centerX();
1013 SkScalar centerY = data.centerY();
1014 SkScalar A = data.A();
1015 SkScalar B = data.B();
1016 SkScalar C = data.C();
1017
1018 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1019 fCachedA != A || fCachedB != B || fCachedC != C) {
1020
kkinnunen7510b222014-07-30 00:04:16 -07001021 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1022 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001023
1024 fCachedCenterX = centerX;
1025 fCachedCenterY = centerY;
1026 fCachedA = A;
1027 fCachedB = B;
1028 fCachedC = C;
1029 }
1030}
1031
joshualittb0a8a372014-09-23 09:50:21 -07001032void GLCircleInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001033 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001034 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001035}
1036
1037//////////////////////////////////////////////////////////////////////////////
1038
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001039class CircleOutside2PtConicalEffect : public GrGradientEffect {
1040public:
1041
joshualittb0a8a372014-09-23 09:50:21 -07001042 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -07001043 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -07001044 const SkTwoPointConicalGradient& shader,
1045 const SkMatrix& matrix,
1046 SkShader::TileMode tm,
1047 const CircleConicalInfo& info) {
joshualitt9cc17752015-07-09 06:28:14 -07001048 return SkNEW_ARGS(CircleOutside2PtConicalEffect, (ctx, procDataManager, shader, matrix,
joshualittb2456052015-07-08 09:36:59 -07001049 tm, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001050 }
1051
1052 virtual ~CircleOutside2PtConicalEffect() {}
1053
mtklein36352bf2015-03-25 18:17:31 -07001054 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001055
jvanverthcfc18862015-04-28 08:48:20 -07001056 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -08001057
mtklein36352bf2015-03-25 18:17:31 -07001058 GrGLFragmentProcessor* createGLInstance() const override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001059
1060 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1061 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1062 SkScalar A() const { return fInfo.fA; }
1063 SkScalar B() const { return fInfo.fB; }
1064 SkScalar C() const { return fInfo.fC; }
1065 SkScalar tLimit() const { return fTLimit; }
1066 bool isFlipped() const { return fIsFlipped; }
1067
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001068private:
mtklein36352bf2015-03-25 18:17:31 -07001069 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001070 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001071 return (INHERITED::onIsEqual(sBase) &&
1072 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1073 this->fInfo.fA == s.fInfo.fA &&
1074 this->fInfo.fB == s.fInfo.fB &&
1075 this->fInfo.fC == s.fInfo.fC &&
1076 this->fTLimit == s.fTLimit &&
1077 this->fIsFlipped == s.fIsFlipped);
1078 }
1079
1080 CircleOutside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -07001081 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001082 const SkTwoPointConicalGradient& shader,
1083 const SkMatrix& matrix,
1084 SkShader::TileMode tm,
1085 const CircleConicalInfo& info)
joshualitt9cc17752015-07-09 06:28:14 -07001086 : INHERITED(ctx, procDataManager, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001087 this->initClassID<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001088 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001089 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001090 } else {
1091 fTLimit = SK_ScalarMin;
1092 }
1093
1094 fIsFlipped = shader.isFlippedGrad();
1095 }
1096
joshualittb0a8a372014-09-23 09:50:21 -07001097 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001098
1099 const CircleConicalInfo fInfo;
1100 SkScalar fTLimit;
1101 bool fIsFlipped;
1102
1103 typedef GrGradientEffect INHERITED;
1104};
1105
1106class GLCircleOutside2PtConicalEffect : public GrGLGradientEffect {
1107public:
joshualitteb2a6762014-12-04 11:35:33 -08001108 GLCircleOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001109 virtual ~GLCircleOutside2PtConicalEffect() {}
1110
wangyix7c157a92015-07-22 15:08:53 -07001111 virtual void emitCode(EmitArgs&) override;
mtklein36352bf2015-03-25 18:17:31 -07001112 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001113
jvanverthcfc18862015-04-28 08:48:20 -07001114 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001115
1116protected:
1117 UniformHandle fCenterUni;
1118 UniformHandle fParamUni;
1119
1120 const char* fVSVaryingName;
1121 const char* fFSVaryingName;
1122
1123 bool fIsFlipped;
1124
1125 // @{
1126 /// Values last uploaded as uniforms
1127
1128 SkScalar fCachedCenterX;
1129 SkScalar fCachedCenterY;
1130 SkScalar fCachedA;
1131 SkScalar fCachedB;
1132 SkScalar fCachedC;
1133 SkScalar fCachedTLimit;
1134
1135 // @}
1136
1137private:
1138 typedef GrGLGradientEffect INHERITED;
1139
1140};
1141
jvanverthcfc18862015-04-28 08:48:20 -07001142void CircleOutside2PtConicalEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001143 GrProcessorKeyBuilder* b) const {
1144 GLCircleOutside2PtConicalEffect::GenKey(*this, caps, b);
1145}
1146
1147GrGLFragmentProcessor* CircleOutside2PtConicalEffect::createGLInstance() const {
1148 return SkNEW_ARGS(GLCircleOutside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001149}
1150
joshualittb0a8a372014-09-23 09:50:21 -07001151GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001152
joshualitt01258472014-09-22 10:29:30 -07001153/*
1154 * All Two point conical gradient test create functions may occasionally create edge case shaders
1155 */
joshualitt0067ff52015-07-08 14:26:19 -07001156GrFragmentProcessor* CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
1157 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1158 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001159 SkPoint center2;
1160 SkScalar radius2;
1161 SkScalar diffLen;
1162 do {
joshualitt0067ff52015-07-08 14:26:19 -07001163 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001164 // If the circles share a center than we can't be in the outside case
1165 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001166 SkPoint diff = center2 - center1;
1167 diffLen = diff.length();
1168 // Below makes sure that circle one is not contained within circle two
1169 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001170 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001171
1172 SkColor colors[kMaxRandomGradientColors];
1173 SkScalar stopsArray[kMaxRandomGradientColors];
1174 SkScalar* stops = stopsArray;
1175 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -07001176 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001177 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
1178 center2, radius2,
1179 colors, stops, colorCount,
1180 tm));
1181 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -07001182 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -07001183 GrFragmentProcessor* fp;
joshualitt0067ff52015-07-08 14:26:19 -07001184 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
1185 GrTest::TestMatrix(d->fRandom), NULL,
joshualitt9cc17752015-07-09 06:28:14 -07001186 &paintColor, d->fProcDataManager, &fp));
joshualitt8ca93e72015-07-08 06:51:43 -07001187 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001188}
1189
joshualitteb2a6762014-12-04 11:35:33 -08001190GLCircleOutside2PtConicalEffect::GLCircleOutside2PtConicalEffect(const GrProcessor& processor)
1191 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001192 , fFSVaryingName(NULL)
1193 , fCachedCenterX(SK_ScalarMax)
1194 , fCachedCenterY(SK_ScalarMax)
1195 , fCachedA(SK_ScalarMax)
1196 , fCachedB(SK_ScalarMax)
1197 , fCachedC(SK_ScalarMax)
1198 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001199 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001200 fIsFlipped = data.isFlipped();
1201 }
1202
wangyix7c157a92015-07-22 15:08:53 -07001203void GLCircleOutside2PtConicalEffect::emitCode(EmitArgs& args) {
1204 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
1205 this->emitUniforms(args.fBuilder, ge);
1206 fCenterUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001207 kVec2f_GrSLType, kDefault_GrSLPrecision,
1208 "Conical2FSCenter");
wangyix7c157a92015-07-22 15:08:53 -07001209 fParamUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001210 kVec4f_GrSLType, kDefault_GrSLPrecision,
1211 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001212 SkString tName("t");
1213
wangyix7c157a92015-07-22 15:08:53 -07001214 GrGLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001215 // params.x = A
1216 // params.y = B
1217 // params.z = C
wangyix7c157a92015-07-22 15:08:53 -07001218 GrGLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001219
1220 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -07001221 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
1222 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001223 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001224
1225 // output will default to transparent black (we simply won't write anything
1226 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -07001227 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 +00001228
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001229 // p = coords2D
1230 // e = center end
1231 // r = radius end
1232 // A = dot(e, e) - r^2 + 2 * r - 1
1233 // B = (r -1) / A
1234 // C = 1 / A
1235 // d = dot(e, p) + B
1236 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001237
joshualitt30ba4362014-08-21 20:18:45 -07001238 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -07001239 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1240 params.c_str());
1241 fsBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1242 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001243
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001244 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1245 // If so we must also flip sign on sqrt
1246 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -07001247 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001248 } else {
joshualitt30ba4362014-08-21 20:18:45 -07001249 fsBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001250 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001251
joshualitt30ba4362014-08-21 20:18:45 -07001252 fsBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str());
1253 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -07001254 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
1255 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -07001256 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001257}
1258
kkinnunen7510b222014-07-30 00:04:16 -07001259void GLCircleOutside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001260 const GrProcessor& processor) {
1261 INHERITED::setData(pdman, processor);
1262 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001263 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001264 SkScalar centerX = data.centerX();
1265 SkScalar centerY = data.centerY();
1266 SkScalar A = data.A();
1267 SkScalar B = data.B();
1268 SkScalar C = data.C();
1269 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001270
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001271 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1272 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001273
kkinnunen7510b222014-07-30 00:04:16 -07001274 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1275 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001276 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001277
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001278 fCachedCenterX = centerX;
1279 fCachedCenterY = centerY;
1280 fCachedA = A;
1281 fCachedB = B;
1282 fCachedC = C;
1283 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001284 }
1285}
1286
joshualittb0a8a372014-09-23 09:50:21 -07001287void GLCircleOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001288 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001289 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001290 key[0] = GenBaseGradientKey(processor);
1291 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001292}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001293
1294//////////////////////////////////////////////////////////////////////////////
1295
joshualittb0a8a372014-09-23 09:50:21 -07001296GrFragmentProcessor* Gr2PtConicalGradientEffect::Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -07001297 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -07001298 const SkTwoPointConicalGradient& shader,
1299 SkShader::TileMode tm,
1300 const SkMatrix* localMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001301 SkMatrix matrix;
1302 if (!shader.getLocalMatrix().invert(&matrix)) {
1303 return NULL;
1304 }
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001305 if (localMatrix) {
1306 SkMatrix inv;
1307 if (!localMatrix->invert(&inv)) {
1308 return NULL;
1309 }
1310 matrix.postConcat(inv);
1311 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001312
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001313 if (shader.getStartRadius() < kErrorTol) {
1314 SkScalar focalX;
1315 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1316 if (type == kInside_ConicalType) {
joshualitt9cc17752015-07-09 06:28:14 -07001317 return FocalInside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001318 focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001319 } else if(type == kEdge_ConicalType) {
1320 set_matrix_edge_conical(shader, &matrix);
joshualitt9cc17752015-07-09 06:28:14 -07001321 return Edge2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001322 } else {
joshualitt9cc17752015-07-09 06:28:14 -07001323 return FocalOutside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001324 focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001325 }
1326 }
1327
1328 CircleConicalInfo info;
1329 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1330
1331 if (type == kInside_ConicalType) {
joshualitt9cc17752015-07-09 06:28:14 -07001332 return CircleInside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001333 info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001334 } else if (type == kEdge_ConicalType) {
1335 set_matrix_edge_conical(shader, &matrix);
joshualitt9cc17752015-07-09 06:28:14 -07001336 return Edge2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001337 } else {
joshualitt9cc17752015-07-09 06:28:14 -07001338 return CircleOutside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001339 info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001340 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001341}
1342
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001343#endif