blob: 6f6048251be87ce10913e148a089cecf3df820c0 [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
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,
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;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000148
jvanverthcfc18862015-04-28 08:48:20 -0700149 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000150
151protected:
wangyixb1daa862015-08-18 11:29:31 -0700152 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
153
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000154 UniformHandle fParamUni;
155
156 const char* fVSVaryingName;
157 const char* fFSVaryingName;
158
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000159 // @{
160 /// Values last uploaded as uniforms
161
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000162 SkScalar fCachedRadius;
163 SkScalar fCachedDiffRadius;
164
165 // @}
166
167private:
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000168 typedef GrGLGradientEffect INHERITED;
169
170};
171
wangyix4b3050b2015-08-04 07:59:37 -0700172void Edge2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800173 GrProcessorKeyBuilder* b) const {
174 GLEdge2PtConicalEffect::GenKey(*this, caps, b);
175}
176
wangyixb1daa862015-08-18 11:29:31 -0700177GrGLFragmentProcessor* Edge2PtConicalEffect::onCreateGLInstance() const {
joshualitteb2a6762014-12-04 11:35:33 -0800178 return SkNEW_ARGS(GLEdge2PtConicalEffect, (*this));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000179}
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000180
joshualittb0a8a372014-09-23 09:50:21 -0700181GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Edge2PtConicalEffect);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000182
joshualitt01258472014-09-22 10:29:30 -0700183/*
184 * All Two point conical gradient test create functions may occasionally create edge case shaders
185 */
joshualitt0067ff52015-07-08 14:26:19 -0700186GrFragmentProcessor* Edge2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
187 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
188 SkScalar radius1 = d->fRandom->nextUScalar1();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000189 SkPoint center2;
190 SkScalar radius2;
191 do {
joshualitt0067ff52015-07-08 14:26:19 -0700192 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000193 // If the circles are identical the factory will give us an empty shader.
194 // This will happen if we pick identical centers
195 } while (center1 == center2);
196
197 // Below makes sure that circle one is contained within circle two
198 // and both circles are touching on an edge
199 SkPoint diff = center2 - center1;
200 SkScalar diffLen = diff.length();
201 radius2 = radius1 + diffLen;
202
203 SkColor colors[kMaxRandomGradientColors];
204 SkScalar stopsArray[kMaxRandomGradientColors];
205 SkScalar* stops = stopsArray;
206 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700207 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000208 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
209 center2, radius2,
210 colors, stops, colorCount,
211 tm));
212 SkPaint paint;
joshualittb0a8a372014-09-23 09:50:21 -0700213 GrFragmentProcessor* fp;
bsalomon83d081a2014-07-08 09:56:10 -0700214 GrColor paintColor;
joshualitt0067ff52015-07-08 14:26:19 -0700215 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
216 GrTest::TestMatrix(d->fRandom), NULL,
joshualitt9cc17752015-07-09 06:28:14 -0700217 &paintColor, d->fProcDataManager, &fp));
joshualittb0a8a372014-09-23 09:50:21 -0700218 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000219}
220
joshualitteb2a6762014-12-04 11:35:33 -0800221GLEdge2PtConicalEffect::GLEdge2PtConicalEffect(const GrProcessor&)
222 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000223 , fFSVaryingName(NULL)
224 , fCachedRadius(-SK_ScalarMax)
225 , fCachedDiffRadius(-SK_ScalarMax) {}
226
wangyix7c157a92015-07-22 15:08:53 -0700227void GLEdge2PtConicalEffect::emitCode(EmitArgs& args) {
228 const Edge2PtConicalEffect& ge = args.fFp.cast<Edge2PtConicalEffect>();
229 this->emitUniforms(args.fBuilder, ge);
230 fParamUni = args.fBuilder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800231 kFloat_GrSLType, kDefault_GrSLPrecision,
232 "Conical2FSParams", 3);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000233
234 SkString cName("c");
235 SkString tName("t");
236 SkString p0; // start radius
237 SkString p1; // start radius squared
238 SkString p2; // difference in radii (r1 - r0)
239
wangyix7c157a92015-07-22 15:08:53 -0700240 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
241 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
242 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000243
244 // We interpolate the linear component in coords[1].
wangyix7c157a92015-07-22 15:08:53 -0700245 SkASSERT(args.fCoords[0].getType() == args.fCoords[1].getType());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000246 const char* coords2D;
247 SkString bVar;
wangyix7c157a92015-07-22 15:08:53 -0700248 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
249 if (kVec3f_GrSLType == args.fCoords[0].getType()) {
joshualitt30ba4362014-08-21 20:18:45 -0700250 fsBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
wangyix7c157a92015-07-22 15:08:53 -0700251 args.fCoords[0].c_str(), args.fCoords[0].c_str(),
252 args.fCoords[1].c_str(), args.fCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000253 coords2D = "interpolants.xy";
254 bVar = "interpolants.z";
255 } else {
wangyix7c157a92015-07-22 15:08:53 -0700256 coords2D = args.fCoords[0].c_str();
257 bVar.printf("%s.x", args.fCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000258 }
259
260 // output will default to transparent black (we simply won't write anything
261 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -0700262 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 +0000263
264 // c = (x^2)+(y^2) - params[1]
joshualitt30ba4362014-08-21 20:18:45 -0700265 fsBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000266 cName.c_str(), coords2D, coords2D, p1.c_str());
267
268 // linear case: t = -c/b
joshualitt30ba4362014-08-21 20:18:45 -0700269 fsBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000270 cName.c_str(), bVar.c_str());
271
272 // if r(t) > 0, then t will be the x coordinate
joshualitt30ba4362014-08-21 20:18:45 -0700273 fsBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000274 p2.c_str(), p0.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700275 fsBuilder->codeAppend("\t");
wangyix7c157a92015-07-22 15:08:53 -0700276 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
277 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -0700278 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000279}
280
wangyixb1daa862015-08-18 11:29:31 -0700281void GLEdge2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700282 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700283 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700284 const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000285 SkScalar radius0 = data.radius();
286 SkScalar diffRadius = data.diffRadius();
287
288 if (fCachedRadius != radius0 ||
289 fCachedDiffRadius != diffRadius) {
290
291 float values[3] = {
292 SkScalarToFloat(radius0),
293 SkScalarToFloat(SkScalarMul(radius0, radius0)),
294 SkScalarToFloat(diffRadius)
295 };
296
kkinnunen7510b222014-07-30 00:04:16 -0700297 pdman.set1fv(fParamUni, 3, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000298 fCachedRadius = radius0;
299 fCachedDiffRadius = diffRadius;
300 }
301}
302
joshualittb0a8a372014-09-23 09:50:21 -0700303void GLEdge2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700304 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700305 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000306}
307
308//////////////////////////////////////////////////////////////////////////////
309// Focal Conical Gradients
310//////////////////////////////////////////////////////////////////////////////
311
312static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
313 SkMatrix* invLMatrix, SkScalar* focalX) {
314 // Inverse of the current local matrix is passed in then,
315 // translate, scale, and rotate such that endCircle is unit circle on x-axis,
316 // and focal point is at the origin.
317 ConicalType conicalType;
318 const SkPoint& focal = shader.getStartCenter();
319 const SkPoint& centerEnd = shader.getEndCenter();
320 SkScalar radius = shader.getEndRadius();
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000321 SkScalar invRadius = 1.f / radius;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000322
323 SkMatrix matrix;
324
325 matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
326 matrix.postScale(invRadius, invRadius);
327
328 SkPoint focalTrans;
329 matrix.mapPoints(&focalTrans, &focal, 1);
330 *focalX = focalTrans.length();
331
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000332 if (0.f != *focalX) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000333 SkScalar invFocalX = SkScalarInvert(*focalX);
334 SkMatrix rot;
335 rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY),
336 SkScalarMul(invFocalX, focalTrans.fX));
337 matrix.postConcat(rot);
338 }
339
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000340 matrix.postTranslate(-(*focalX), 0.f);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000341
342 // If the focal point is touching the edge of the circle it will
343 // cause a degenerate case that must be handled separately
egdaniel8405ef92014-06-09 11:57:28 -0700344 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
345 // stability trade off versus the linear approx used in the Edge Shader
346 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000347 return kEdge_ConicalType;
348 }
349
350 // Scale factor 1 / (1 - focalX * focalX)
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000351 SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX);
reed80ea19c2015-05-12 10:37:34 -0700352 SkScalar s = SkScalarInvert(oneMinusF2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000353
354
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000355 if (s >= 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000356 conicalType = kInside_ConicalType;
357 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
358 } else {
359 conicalType = kOutside_ConicalType;
360 matrix.postScale(s, s);
361 }
362
363 invLMatrix->postConcat(matrix);
364
365 return conicalType;
366}
367
368//////////////////////////////////////////////////////////////////////////////
369
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000370class FocalOutside2PtConicalEffect : public GrGradientEffect {
371public:
372
joshualittb0a8a372014-09-23 09:50:21 -0700373 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700374 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700375 const SkTwoPointConicalGradient& shader,
376 const SkMatrix& matrix,
377 SkShader::TileMode tm,
378 SkScalar focalX) {
joshualitt9cc17752015-07-09 06:28:14 -0700379 return SkNEW_ARGS(FocalOutside2PtConicalEffect, (ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -0700380 focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000381 }
382
383 virtual ~FocalOutside2PtConicalEffect() { }
384
mtklein36352bf2015-03-25 18:17:31 -0700385 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800386 return "Two-Point Conical Gradient Focal Outside";
387 }
388
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000389 bool isFlipped() const { return fIsFlipped; }
390 SkScalar focal() const { return fFocalX; }
391
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000392private:
wangyixb1daa862015-08-18 11:29:31 -0700393 GrGLFragmentProcessor* onCreateGLInstance() const override;
394
wangyix4b3050b2015-08-04 07:59:37 -0700395 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
396
mtklein36352bf2015-03-25 18:17:31 -0700397 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700398 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000399 return (INHERITED::onIsEqual(sBase) &&
400 this->fFocalX == s.fFocalX &&
401 this->fIsFlipped == s.fIsFlipped);
402 }
403
404 FocalOutside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700405 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000406 const SkTwoPointConicalGradient& shader,
407 const SkMatrix& matrix,
408 SkShader::TileMode tm,
409 SkScalar focalX)
joshualitt9cc17752015-07-09 06:28:14 -0700410 : INHERITED(ctx, procDataManager, shader, matrix, tm)
joshualittb2456052015-07-08 09:36:59 -0700411 , fFocalX(focalX)
412 , fIsFlipped(shader.isFlippedGrad()) {
joshualitteb2a6762014-12-04 11:35:33 -0800413 this->initClassID<FocalOutside2PtConicalEffect>();
414 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000415
joshualittb0a8a372014-09-23 09:50:21 -0700416 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000417
418 SkScalar fFocalX;
419 bool fIsFlipped;
420
421 typedef GrGradientEffect INHERITED;
422};
423
424class GLFocalOutside2PtConicalEffect : public GrGLGradientEffect {
425public:
joshualitteb2a6762014-12-04 11:35:33 -0800426 GLFocalOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000427 virtual ~GLFocalOutside2PtConicalEffect() { }
428
wangyix7c157a92015-07-22 15:08:53 -0700429 virtual void emitCode(EmitArgs&) 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:
wangyixb1daa862015-08-18 11:29:31 -0700434 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
435
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000436 UniformHandle fParamUni;
437
438 const char* fVSVaryingName;
439 const char* fFSVaryingName;
440
441 bool fIsFlipped;
442
443 // @{
444 /// Values last uploaded as uniforms
445
446 SkScalar fCachedFocal;
447
448 // @}
449
450private:
451 typedef GrGLGradientEffect INHERITED;
452
453};
454
wangyix4b3050b2015-08-04 07:59:37 -0700455void FocalOutside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800456 GrProcessorKeyBuilder* b) const {
457 GLFocalOutside2PtConicalEffect::GenKey(*this, caps, b);
458}
459
wangyixb1daa862015-08-18 11:29:31 -0700460GrGLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLInstance() const {
joshualitteb2a6762014-12-04 11:35:33 -0800461 return SkNEW_ARGS(GLFocalOutside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000462}
463
joshualittb0a8a372014-09-23 09:50:21 -0700464GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000465
joshualitt01258472014-09-22 10:29:30 -0700466/*
467 * All Two point conical gradient test create functions may occasionally create edge case shaders
468 */
joshualitt0067ff52015-07-08 14:26:19 -0700469GrFragmentProcessor* FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
470 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000471 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000472 SkPoint center2;
473 SkScalar radius2;
474 do {
joshualitt0067ff52015-07-08 14:26:19 -0700475 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000476 // 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 +0000477 } while (center1 == center2);
478 SkPoint diff = center2 - center1;
479 SkScalar diffLen = diff.length();
480 // Below makes sure that the focal point is not contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700481 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000482
483 SkColor colors[kMaxRandomGradientColors];
484 SkScalar stopsArray[kMaxRandomGradientColors];
485 SkScalar* stops = stopsArray;
486 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700487 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000488 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
489 center2, radius2,
490 colors, stops, colorCount,
491 tm));
492 SkPaint paint;
joshualittb0a8a372014-09-23 09:50:21 -0700493 GrFragmentProcessor* effect;
bsalomon83d081a2014-07-08 09:56:10 -0700494 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -0700495 GrPaint grPaint;
joshualitt0067ff52015-07-08 14:26:19 -0700496 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
497 GrTest::TestMatrix(d->fRandom), NULL,
joshualitt9cc17752015-07-09 06:28:14 -0700498 &paintColor, d->fProcDataManager,
joshualitt8ca93e72015-07-08 06:51:43 -0700499 &effect));
dandov9de5b512014-06-10 14:38:28 -0700500 return effect;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000501}
502
joshualitteb2a6762014-12-04 11:35:33 -0800503GLFocalOutside2PtConicalEffect::GLFocalOutside2PtConicalEffect(const GrProcessor& processor)
504 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000505 , fFSVaryingName(NULL)
506 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700507 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000508 fIsFlipped = data.isFlipped();
509}
510
wangyix7c157a92015-07-22 15:08:53 -0700511void GLFocalOutside2PtConicalEffect::emitCode(EmitArgs& args) {
512 const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
513 this->emitUniforms(args.fBuilder, ge);
514 fParamUni = args.fBuilder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800515 kFloat_GrSLType, kDefault_GrSLPrecision,
516 "Conical2FSParams", 2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000517 SkString tName("t");
518 SkString p0; // focalX
519 SkString p1; // 1 - focalX * focalX
520
wangyix7c157a92015-07-22 15:08:53 -0700521 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
522 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000523
524 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700525 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
526 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000527 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000528
529 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
530
531 // output will default to transparent black (we simply won't write anything
532 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -0700533 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 +0000534
joshualitt30ba4362014-08-21 20:18:45 -0700535 fsBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
536 fsBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
537 fsBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000538
539 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
540 // If so we must also flip sign on sqrt
541 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -0700542 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000543 coords2D, p0.c_str());
544 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700545 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000546 coords2D, p0.c_str());
547 }
548
joshualitt30ba4362014-08-21 20:18:45 -0700549 fsBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
550 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -0700551 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
552 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -0700553 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000554}
555
wangyixb1daa862015-08-18 11:29:31 -0700556void GLFocalOutside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700557 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700558 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700559 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000560 SkASSERT(data.isFlipped() == fIsFlipped);
561 SkScalar focal = data.focal();
562
563 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000564 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000565
566 float values[2] = {
567 SkScalarToFloat(focal),
568 SkScalarToFloat(oneMinus2F),
569 };
570
kkinnunen7510b222014-07-30 00:04:16 -0700571 pdman.set1fv(fParamUni, 2, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000572 fCachedFocal = focal;
573 }
574}
575
joshualittb0a8a372014-09-23 09:50:21 -0700576void GLFocalOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700577 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700578 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700579 key[0] = GenBaseGradientKey(processor);
580 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000581}
582
583//////////////////////////////////////////////////////////////////////////////
584
585class GLFocalInside2PtConicalEffect;
586
587class FocalInside2PtConicalEffect : public GrGradientEffect {
588public:
589
joshualittb0a8a372014-09-23 09:50:21 -0700590 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700591 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700592 const SkTwoPointConicalGradient& shader,
593 const SkMatrix& matrix,
594 SkShader::TileMode tm,
595 SkScalar focalX) {
joshualitt9cc17752015-07-09 06:28:14 -0700596 return SkNEW_ARGS(FocalInside2PtConicalEffect, (ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -0700597 focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000598 }
599
600 virtual ~FocalInside2PtConicalEffect() {}
601
mtklein36352bf2015-03-25 18:17:31 -0700602 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800603 return "Two-Point Conical Gradient Focal Inside";
604 }
605
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000606 SkScalar focal() const { return fFocalX; }
607
joshualittb0a8a372014-09-23 09:50:21 -0700608 typedef GLFocalInside2PtConicalEffect GLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000609
610private:
wangyixb1daa862015-08-18 11:29:31 -0700611 GrGLFragmentProcessor* onCreateGLInstance() const override;
612
wangyix4b3050b2015-08-04 07:59:37 -0700613 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
614
mtklein36352bf2015-03-25 18:17:31 -0700615 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700616 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000617 return (INHERITED::onIsEqual(sBase) &&
618 this->fFocalX == s.fFocalX);
619 }
620
621 FocalInside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700622 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000623 const SkTwoPointConicalGradient& shader,
624 const SkMatrix& matrix,
625 SkShader::TileMode tm,
626 SkScalar focalX)
joshualitt9cc17752015-07-09 06:28:14 -0700627 : INHERITED(ctx, procDataManager, shader, matrix, tm), fFocalX(focalX) {
joshualitteb2a6762014-12-04 11:35:33 -0800628 this->initClassID<FocalInside2PtConicalEffect>();
629 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000630
joshualittb0a8a372014-09-23 09:50:21 -0700631 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000632
633 SkScalar fFocalX;
634
635 typedef GrGradientEffect INHERITED;
636};
637
638class GLFocalInside2PtConicalEffect : public GrGLGradientEffect {
639public:
joshualitteb2a6762014-12-04 11:35:33 -0800640 GLFocalInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000641 virtual ~GLFocalInside2PtConicalEffect() {}
642
wangyix7c157a92015-07-22 15:08:53 -0700643 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000644
jvanverthcfc18862015-04-28 08:48:20 -0700645 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000646
647protected:
wangyixb1daa862015-08-18 11:29:31 -0700648 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
649
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000650 UniformHandle fFocalUni;
651
652 const char* fVSVaryingName;
653 const char* fFSVaryingName;
654
655 // @{
656 /// Values last uploaded as uniforms
657
658 SkScalar fCachedFocal;
659
660 // @}
661
662private:
663 typedef GrGLGradientEffect INHERITED;
664
665};
666
wangyix4b3050b2015-08-04 07:59:37 -0700667void FocalInside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800668 GrProcessorKeyBuilder* b) const {
669 GLFocalInside2PtConicalEffect::GenKey(*this, caps, b);
670}
671
wangyixb1daa862015-08-18 11:29:31 -0700672GrGLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLInstance() const {
joshualitteb2a6762014-12-04 11:35:33 -0800673 return SkNEW_ARGS(GLFocalInside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000674}
675
joshualittb0a8a372014-09-23 09:50:21 -0700676GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000677
joshualitt01258472014-09-22 10:29:30 -0700678/*
679 * All Two point conical gradient test create functions may occasionally create edge case shaders
680 */
joshualitt0067ff52015-07-08 14:26:19 -0700681GrFragmentProcessor* FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
682 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000683 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000684 SkPoint center2;
685 SkScalar radius2;
686 do {
joshualitt0067ff52015-07-08 14:26:19 -0700687 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000688 // Below makes sure radius2 is larger enouch such that the focal point
689 // is inside the end circle
joshualitt0067ff52015-07-08 14:26:19 -0700690 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000691 SkPoint diff = center2 - center1;
692 SkScalar diffLen = diff.length();
693 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000694 // If the circles are identical the factory will give us an empty shader.
695 } while (radius1 == radius2 && center1 == center2);
696
697 SkColor colors[kMaxRandomGradientColors];
698 SkScalar stopsArray[kMaxRandomGradientColors];
699 SkScalar* stops = stopsArray;
700 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700701 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000702 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
703 center2, radius2,
704 colors, stops, colorCount,
705 tm));
706 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700707 GrColor paintColor;
joshualittb0a8a372014-09-23 09:50:21 -0700708 GrFragmentProcessor* fp;
joshualitt0067ff52015-07-08 14:26:19 -0700709 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
710 GrTest::TestMatrix(d->fRandom), NULL,
joshualitt9cc17752015-07-09 06:28:14 -0700711 &paintColor, d->fProcDataManager, &fp));
joshualittb0a8a372014-09-23 09:50:21 -0700712 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000713}
714
joshualitteb2a6762014-12-04 11:35:33 -0800715GLFocalInside2PtConicalEffect::GLFocalInside2PtConicalEffect(const GrProcessor&)
716 : fVSVaryingName(NULL)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000717 , fFSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000718 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000719
wangyix7c157a92015-07-22 15:08:53 -0700720void GLFocalInside2PtConicalEffect::emitCode(EmitArgs& args) {
721 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
722 this->emitUniforms(args.fBuilder, ge);
723 fFocalUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800724 kFloat_GrSLType, kDefault_GrSLPrecision,
725 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000726 SkString tName("t");
727
728 // this is the distance along x-axis from the end center to focal point in
729 // transformed coordinates
wangyix7c157a92015-07-22 15:08:53 -0700730 GrGLShaderVar focal = args.fBuilder->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000731
732 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700733 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
734 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000735 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000736
737 // t = p.x * focalX + length(p)
joshualitt30ba4362014-08-21 20:18:45 -0700738 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000739 coords2D, focal.c_str(), coords2D);
740
wangyix7c157a92015-07-22 15:08:53 -0700741 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
742 args.fSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000743}
744
wangyixb1daa862015-08-18 11:29:31 -0700745void GLFocalInside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700746 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700747 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700748 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000749 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000750
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000751 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700752 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000753 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000754 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000755}
756
joshualittb0a8a372014-09-23 09:50:21 -0700757void GLFocalInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700758 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700759 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000760}
761
762//////////////////////////////////////////////////////////////////////////////
763// Circle Conical Gradients
764//////////////////////////////////////////////////////////////////////////////
765
766struct CircleConicalInfo {
767 SkPoint fCenterEnd;
768 SkScalar fA;
769 SkScalar fB;
770 SkScalar fC;
771};
772
773// Returns focal distance along x-axis in transformed coords
774static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
775 SkMatrix* invLMatrix, CircleConicalInfo* info) {
776 // Inverse of the current local matrix is passed in then,
777 // translate and scale such that start circle is on the origin and has radius 1
778 const SkPoint& centerStart = shader.getStartCenter();
779 const SkPoint& centerEnd = shader.getEndCenter();
780 SkScalar radiusStart = shader.getStartRadius();
781 SkScalar radiusEnd = shader.getEndRadius();
782
783 SkMatrix matrix;
784
785 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
786
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000787 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000788 matrix.postScale(invStartRad, invStartRad);
789
790 radiusEnd /= radiusStart;
791
792 SkPoint centerEndTrans;
793 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
794
795 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
796 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
797
798 // Check to see if start circle is inside end circle with edges touching.
799 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700800 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
801 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
802 // still accurate.
803 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000804 return kEdge_ConicalType;
805 }
806
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000807 SkScalar C = 1.f / A;
808 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000809
810 matrix.postScale(C, C);
811
812 invLMatrix->postConcat(matrix);
813
814 info->fCenterEnd = centerEndTrans;
815 info->fA = A;
816 info->fB = B;
817 info->fC = C;
818
819 // if A ends up being negative, the start circle is contained completely inside the end cirlce
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000820 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000821 return kInside_ConicalType;
822 }
823 return kOutside_ConicalType;
824}
825
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000826class CircleInside2PtConicalEffect : public GrGradientEffect {
827public:
828
joshualittb0a8a372014-09-23 09:50:21 -0700829 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700830 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700831 const SkTwoPointConicalGradient& shader,
832 const SkMatrix& matrix,
833 SkShader::TileMode tm,
834 const CircleConicalInfo& info) {
joshualitt9cc17752015-07-09 06:28:14 -0700835 return SkNEW_ARGS(CircleInside2PtConicalEffect, (ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -0700836 info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000837 }
838
839 virtual ~CircleInside2PtConicalEffect() {}
840
mtklein36352bf2015-03-25 18:17:31 -0700841 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800842
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000843 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
844 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
845 SkScalar A() const { return fInfo.fA; }
846 SkScalar B() const { return fInfo.fB; }
847 SkScalar C() const { return fInfo.fC; }
848
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000849private:
wangyixb1daa862015-08-18 11:29:31 -0700850 GrGLFragmentProcessor* onCreateGLInstance() const override;
851
wangyix4b3050b2015-08-04 07:59:37 -0700852 virtual void onGetGLProcessorKey(const GrGLSLCaps& caps,
853 GrProcessorKeyBuilder* b) const override;
854
mtklein36352bf2015-03-25 18:17:31 -0700855 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700856 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000857 return (INHERITED::onIsEqual(sBase) &&
858 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
859 this->fInfo.fA == s.fInfo.fA &&
860 this->fInfo.fB == s.fInfo.fB &&
861 this->fInfo.fC == s.fInfo.fC);
862 }
863
864 CircleInside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700865 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000866 const SkTwoPointConicalGradient& shader,
867 const SkMatrix& matrix,
868 SkShader::TileMode tm,
869 const CircleConicalInfo& info)
joshualitt9cc17752015-07-09 06:28:14 -0700870 : INHERITED(ctx, procDataManager, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800871 this->initClassID<CircleInside2PtConicalEffect>();
872 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000873
joshualittb0a8a372014-09-23 09:50:21 -0700874 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000875
876 const CircleConicalInfo fInfo;
877
878 typedef GrGradientEffect INHERITED;
879};
880
881class GLCircleInside2PtConicalEffect : public GrGLGradientEffect {
882public:
joshualitteb2a6762014-12-04 11:35:33 -0800883 GLCircleInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000884 virtual ~GLCircleInside2PtConicalEffect() {}
885
wangyix7c157a92015-07-22 15:08:53 -0700886 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000887
jvanverthcfc18862015-04-28 08:48:20 -0700888 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000889
890protected:
wangyixb1daa862015-08-18 11:29:31 -0700891 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
892
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000893 UniformHandle fCenterUni;
894 UniformHandle fParamUni;
895
896 const char* fVSVaryingName;
897 const char* fFSVaryingName;
898
899 // @{
900 /// Values last uploaded as uniforms
901
902 SkScalar fCachedCenterX;
903 SkScalar fCachedCenterY;
904 SkScalar fCachedA;
905 SkScalar fCachedB;
906 SkScalar fCachedC;
907
908 // @}
909
910private:
911 typedef GrGLGradientEffect INHERITED;
912
913};
914
wangyix4b3050b2015-08-04 07:59:37 -0700915void CircleInside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800916 GrProcessorKeyBuilder* b) const {
917 GLCircleInside2PtConicalEffect::GenKey(*this, caps, b);
918}
919
wangyixb1daa862015-08-18 11:29:31 -0700920GrGLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLInstance() const {
joshualitteb2a6762014-12-04 11:35:33 -0800921 return SkNEW_ARGS(GLCircleInside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000922}
923
joshualittb0a8a372014-09-23 09:50:21 -0700924GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000925
joshualitt01258472014-09-22 10:29:30 -0700926/*
927 * All Two point conical gradient test create functions may occasionally create edge case shaders
928 */
joshualitt0067ff52015-07-08 14:26:19 -0700929GrFragmentProcessor*
930CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
931 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
932 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000933 SkPoint center2;
934 SkScalar radius2;
935 do {
joshualitt0067ff52015-07-08 14:26:19 -0700936 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000937 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700938 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000939 SkPoint diff = center2 - center1;
940 SkScalar diffLen = diff.length();
941 radius2 = radius1 + diffLen + increase;
942 // If the circles are identical the factory will give us an empty shader.
943 } while (radius1 == radius2 && center1 == center2);
944
945 SkColor colors[kMaxRandomGradientColors];
946 SkScalar stopsArray[kMaxRandomGradientColors];
947 SkScalar* stops = stopsArray;
948 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700949 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000950 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
951 center2, radius2,
952 colors, stops, colorCount,
953 tm));
954 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700955 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -0700956 GrFragmentProcessor* fp;
joshualitt0067ff52015-07-08 14:26:19 -0700957 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
958 GrTest::TestMatrix(d->fRandom), NULL,
joshualitt9cc17752015-07-09 06:28:14 -0700959 &paintColor, d->fProcDataManager, &fp));
joshualitt8ca93e72015-07-08 06:51:43 -0700960 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000961}
962
joshualitteb2a6762014-12-04 11:35:33 -0800963GLCircleInside2PtConicalEffect::GLCircleInside2PtConicalEffect(const GrProcessor& processor)
964 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000965 , fFSVaryingName(NULL)
966 , fCachedCenterX(SK_ScalarMax)
967 , fCachedCenterY(SK_ScalarMax)
968 , fCachedA(SK_ScalarMax)
969 , fCachedB(SK_ScalarMax)
970 , fCachedC(SK_ScalarMax) {}
971
wangyix7c157a92015-07-22 15:08:53 -0700972void GLCircleInside2PtConicalEffect::emitCode(EmitArgs& args) {
973 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
974 this->emitUniforms(args.fBuilder, ge);
975 fCenterUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800976 kVec2f_GrSLType, kDefault_GrSLPrecision,
977 "Conical2FSCenter");
wangyix7c157a92015-07-22 15:08:53 -0700978 fParamUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800979 kVec3f_GrSLType, kDefault_GrSLPrecision,
980 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000981 SkString tName("t");
982
wangyix7c157a92015-07-22 15:08:53 -0700983 GrGLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000984 // params.x = A
985 // params.y = B
986 // params.z = C
wangyix7c157a92015-07-22 15:08:53 -0700987 GrGLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000988
989 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700990 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
991 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000992 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000993
994 // p = coords2D
995 // e = center end
996 // r = radius end
997 // A = dot(e, e) - r^2 + 2 * r - 1
998 // B = (r -1) / A
999 // C = 1 / A
1000 // d = dot(e, p) + B
1001 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
joshualitt30ba4362014-08-21 20:18:45 -07001002 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -07001003 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1004 params.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001005 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001006 tName.c_str(), params.c_str(), params.c_str());
1007
wangyix7c157a92015-07-22 15:08:53 -07001008 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
1009 args.fSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001010}
1011
wangyixb1daa862015-08-18 11:29:31 -07001012void GLCircleInside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001013 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001014 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001015 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001016 SkScalar centerX = data.centerX();
1017 SkScalar centerY = data.centerY();
1018 SkScalar A = data.A();
1019 SkScalar B = data.B();
1020 SkScalar C = data.C();
1021
1022 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1023 fCachedA != A || fCachedB != B || fCachedC != C) {
1024
kkinnunen7510b222014-07-30 00:04:16 -07001025 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1026 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001027
1028 fCachedCenterX = centerX;
1029 fCachedCenterY = centerY;
1030 fCachedA = A;
1031 fCachedB = B;
1032 fCachedC = C;
1033 }
1034}
1035
joshualittb0a8a372014-09-23 09:50:21 -07001036void GLCircleInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001037 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001038 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001039}
1040
1041//////////////////////////////////////////////////////////////////////////////
1042
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001043class CircleOutside2PtConicalEffect : public GrGradientEffect {
1044public:
1045
joshualittb0a8a372014-09-23 09:50:21 -07001046 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -07001047 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -07001048 const SkTwoPointConicalGradient& shader,
1049 const SkMatrix& matrix,
1050 SkShader::TileMode tm,
1051 const CircleConicalInfo& info) {
joshualitt9cc17752015-07-09 06:28:14 -07001052 return SkNEW_ARGS(CircleOutside2PtConicalEffect, (ctx, procDataManager, shader, matrix,
joshualittb2456052015-07-08 09:36:59 -07001053 tm, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001054 }
1055
1056 virtual ~CircleOutside2PtConicalEffect() {}
1057
mtklein36352bf2015-03-25 18:17:31 -07001058 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001059
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001060 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:
wangyixb1daa862015-08-18 11:29:31 -07001069 GrGLFragmentProcessor* onCreateGLInstance() const override;
1070
wangyix4b3050b2015-08-04 07:59:37 -07001071 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
1072
mtklein36352bf2015-03-25 18:17:31 -07001073 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001074 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001075 return (INHERITED::onIsEqual(sBase) &&
1076 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1077 this->fInfo.fA == s.fInfo.fA &&
1078 this->fInfo.fB == s.fInfo.fB &&
1079 this->fInfo.fC == s.fInfo.fC &&
1080 this->fTLimit == s.fTLimit &&
1081 this->fIsFlipped == s.fIsFlipped);
1082 }
1083
1084 CircleOutside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -07001085 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001086 const SkTwoPointConicalGradient& shader,
1087 const SkMatrix& matrix,
1088 SkShader::TileMode tm,
1089 const CircleConicalInfo& info)
joshualitt9cc17752015-07-09 06:28:14 -07001090 : INHERITED(ctx, procDataManager, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001091 this->initClassID<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001092 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001093 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001094 } else {
1095 fTLimit = SK_ScalarMin;
1096 }
1097
1098 fIsFlipped = shader.isFlippedGrad();
1099 }
1100
joshualittb0a8a372014-09-23 09:50:21 -07001101 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001102
1103 const CircleConicalInfo fInfo;
1104 SkScalar fTLimit;
1105 bool fIsFlipped;
1106
1107 typedef GrGradientEffect INHERITED;
1108};
1109
1110class GLCircleOutside2PtConicalEffect : public GrGLGradientEffect {
1111public:
joshualitteb2a6762014-12-04 11:35:33 -08001112 GLCircleOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001113 virtual ~GLCircleOutside2PtConicalEffect() {}
1114
wangyix7c157a92015-07-22 15:08:53 -07001115 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001116
jvanverthcfc18862015-04-28 08:48:20 -07001117 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001118
1119protected:
wangyixb1daa862015-08-18 11:29:31 -07001120 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
1121
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001122 UniformHandle fCenterUni;
1123 UniformHandle fParamUni;
1124
1125 const char* fVSVaryingName;
1126 const char* fFSVaryingName;
1127
1128 bool fIsFlipped;
1129
1130 // @{
1131 /// Values last uploaded as uniforms
1132
1133 SkScalar fCachedCenterX;
1134 SkScalar fCachedCenterY;
1135 SkScalar fCachedA;
1136 SkScalar fCachedB;
1137 SkScalar fCachedC;
1138 SkScalar fCachedTLimit;
1139
1140 // @}
1141
1142private:
1143 typedef GrGLGradientEffect INHERITED;
1144
1145};
1146
wangyix4b3050b2015-08-04 07:59:37 -07001147void CircleOutside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001148 GrProcessorKeyBuilder* b) const {
1149 GLCircleOutside2PtConicalEffect::GenKey(*this, caps, b);
1150}
1151
wangyixb1daa862015-08-18 11:29:31 -07001152GrGLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLInstance() const {
joshualitteb2a6762014-12-04 11:35:33 -08001153 return SkNEW_ARGS(GLCircleOutside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001154}
1155
joshualittb0a8a372014-09-23 09:50:21 -07001156GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001157
joshualitt01258472014-09-22 10:29:30 -07001158/*
1159 * All Two point conical gradient test create functions may occasionally create edge case shaders
1160 */
joshualitt0067ff52015-07-08 14:26:19 -07001161GrFragmentProcessor* CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
1162 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1163 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001164 SkPoint center2;
1165 SkScalar radius2;
1166 SkScalar diffLen;
1167 do {
joshualitt0067ff52015-07-08 14:26:19 -07001168 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001169 // If the circles share a center than we can't be in the outside case
1170 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001171 SkPoint diff = center2 - center1;
1172 diffLen = diff.length();
1173 // Below makes sure that circle one is not contained within circle two
1174 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001175 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001176
1177 SkColor colors[kMaxRandomGradientColors];
1178 SkScalar stopsArray[kMaxRandomGradientColors];
1179 SkScalar* stops = stopsArray;
1180 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -07001181 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001182 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
1183 center2, radius2,
1184 colors, stops, colorCount,
1185 tm));
1186 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -07001187 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -07001188 GrFragmentProcessor* fp;
joshualitt0067ff52015-07-08 14:26:19 -07001189 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
1190 GrTest::TestMatrix(d->fRandom), NULL,
joshualitt9cc17752015-07-09 06:28:14 -07001191 &paintColor, d->fProcDataManager, &fp));
joshualitt8ca93e72015-07-08 06:51:43 -07001192 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001193}
1194
joshualitteb2a6762014-12-04 11:35:33 -08001195GLCircleOutside2PtConicalEffect::GLCircleOutside2PtConicalEffect(const GrProcessor& processor)
1196 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001197 , fFSVaryingName(NULL)
1198 , fCachedCenterX(SK_ScalarMax)
1199 , fCachedCenterY(SK_ScalarMax)
1200 , fCachedA(SK_ScalarMax)
1201 , fCachedB(SK_ScalarMax)
1202 , fCachedC(SK_ScalarMax)
1203 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001204 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001205 fIsFlipped = data.isFlipped();
1206 }
1207
wangyix7c157a92015-07-22 15:08:53 -07001208void GLCircleOutside2PtConicalEffect::emitCode(EmitArgs& args) {
1209 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
1210 this->emitUniforms(args.fBuilder, ge);
1211 fCenterUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001212 kVec2f_GrSLType, kDefault_GrSLPrecision,
1213 "Conical2FSCenter");
wangyix7c157a92015-07-22 15:08:53 -07001214 fParamUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001215 kVec4f_GrSLType, kDefault_GrSLPrecision,
1216 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001217 SkString tName("t");
1218
wangyix7c157a92015-07-22 15:08:53 -07001219 GrGLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001220 // params.x = A
1221 // params.y = B
1222 // params.z = C
wangyix7c157a92015-07-22 15:08:53 -07001223 GrGLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001224
1225 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -07001226 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
1227 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001228 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001229
1230 // output will default to transparent black (we simply won't write anything
1231 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -07001232 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 +00001233
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001234 // p = coords2D
1235 // e = center end
1236 // r = radius end
1237 // A = dot(e, e) - r^2 + 2 * r - 1
1238 // B = (r -1) / A
1239 // C = 1 / A
1240 // d = dot(e, p) + B
1241 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001242
joshualitt30ba4362014-08-21 20:18:45 -07001243 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -07001244 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1245 params.c_str());
1246 fsBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1247 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001248
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001249 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1250 // If so we must also flip sign on sqrt
1251 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -07001252 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001253 } else {
joshualitt30ba4362014-08-21 20:18:45 -07001254 fsBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001255 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001256
joshualitt30ba4362014-08-21 20:18:45 -07001257 fsBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str());
1258 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -07001259 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
1260 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -07001261 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001262}
1263
wangyixb1daa862015-08-18 11:29:31 -07001264void GLCircleOutside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001265 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001266 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001267 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001268 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001269 SkScalar centerX = data.centerX();
1270 SkScalar centerY = data.centerY();
1271 SkScalar A = data.A();
1272 SkScalar B = data.B();
1273 SkScalar C = data.C();
1274 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001275
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001276 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1277 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001278
kkinnunen7510b222014-07-30 00:04:16 -07001279 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1280 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001281 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001282
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001283 fCachedCenterX = centerX;
1284 fCachedCenterY = centerY;
1285 fCachedA = A;
1286 fCachedB = B;
1287 fCachedC = C;
1288 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001289 }
1290}
1291
joshualittb0a8a372014-09-23 09:50:21 -07001292void GLCircleOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001293 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001294 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001295 key[0] = GenBaseGradientKey(processor);
1296 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001297}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001298
1299//////////////////////////////////////////////////////////////////////////////
1300
joshualittb0a8a372014-09-23 09:50:21 -07001301GrFragmentProcessor* Gr2PtConicalGradientEffect::Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -07001302 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -07001303 const SkTwoPointConicalGradient& shader,
1304 SkShader::TileMode tm,
1305 const SkMatrix* localMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001306 SkMatrix matrix;
1307 if (!shader.getLocalMatrix().invert(&matrix)) {
1308 return NULL;
1309 }
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001310 if (localMatrix) {
1311 SkMatrix inv;
1312 if (!localMatrix->invert(&inv)) {
1313 return NULL;
1314 }
1315 matrix.postConcat(inv);
1316 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001317
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001318 if (shader.getStartRadius() < kErrorTol) {
1319 SkScalar focalX;
1320 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1321 if (type == kInside_ConicalType) {
joshualitt9cc17752015-07-09 06:28:14 -07001322 return FocalInside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001323 focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001324 } else if(type == kEdge_ConicalType) {
1325 set_matrix_edge_conical(shader, &matrix);
joshualitt9cc17752015-07-09 06:28:14 -07001326 return Edge2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001327 } else {
joshualitt9cc17752015-07-09 06:28:14 -07001328 return FocalOutside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001329 focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001330 }
1331 }
1332
1333 CircleConicalInfo info;
1334 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1335
1336 if (type == kInside_ConicalType) {
joshualitt9cc17752015-07-09 06:28:14 -07001337 return CircleInside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001338 info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001339 } else if (type == kEdge_ConicalType) {
1340 set_matrix_edge_conical(shader, &matrix);
joshualitt9cc17752015-07-09 06:28:14 -07001341 return Edge2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001342 } else {
joshualitt9cc17752015-07-09 06:28:14 -07001343 return CircleOutside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001344 info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001345 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001346}
1347
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001348#endif