blob: 30f0fdf6a1fae5e369f3fd716f8b658ac7a79461 [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) {
halcanary385fe4d2015-08-26 13:07:48 -070066 return new 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 {
halcanary385fe4d2015-08-26 13:07:48 -0700178 return new 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,
halcanary96fcdcc2015-08-27 07:41:13 -0700216 GrTest::TestMatrix(d->fRandom), nullptr,
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&)
halcanary96fcdcc2015-08-27 07:41:13 -0700222 : fVSVaryingName(nullptr)
223 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000224 , 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) {
halcanary385fe4d2015-08-26 13:07:48 -0700379 return new FocalOutside2PtConicalEffect(ctx, procDataManager, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000380 }
381
382 virtual ~FocalOutside2PtConicalEffect() { }
383
mtklein36352bf2015-03-25 18:17:31 -0700384 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800385 return "Two-Point Conical Gradient Focal Outside";
386 }
387
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000388 bool isFlipped() const { return fIsFlipped; }
389 SkScalar focal() const { return fFocalX; }
390
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000391private:
wangyixb1daa862015-08-18 11:29:31 -0700392 GrGLFragmentProcessor* onCreateGLInstance() const override;
393
wangyix4b3050b2015-08-04 07:59:37 -0700394 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
395
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;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000429
jvanverthcfc18862015-04-28 08:48:20 -0700430 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000431
432protected:
wangyixb1daa862015-08-18 11:29:31 -0700433 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
434
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000435 UniformHandle fParamUni;
436
437 const char* fVSVaryingName;
438 const char* fFSVaryingName;
439
440 bool fIsFlipped;
441
442 // @{
443 /// Values last uploaded as uniforms
444
445 SkScalar fCachedFocal;
446
447 // @}
448
449private:
450 typedef GrGLGradientEffect INHERITED;
451
452};
453
wangyix4b3050b2015-08-04 07:59:37 -0700454void FocalOutside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800455 GrProcessorKeyBuilder* b) const {
456 GLFocalOutside2PtConicalEffect::GenKey(*this, caps, b);
457}
458
wangyixb1daa862015-08-18 11:29:31 -0700459GrGLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700460 return new GLFocalOutside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000461}
462
joshualittb0a8a372014-09-23 09:50:21 -0700463GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000464
joshualitt01258472014-09-22 10:29:30 -0700465/*
466 * All Two point conical gradient test create functions may occasionally create edge case shaders
467 */
joshualitt0067ff52015-07-08 14:26:19 -0700468GrFragmentProcessor* FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
469 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000470 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000471 SkPoint center2;
472 SkScalar radius2;
473 do {
joshualitt0067ff52015-07-08 14:26:19 -0700474 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000475 // 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 +0000476 } while (center1 == center2);
477 SkPoint diff = center2 - center1;
478 SkScalar diffLen = diff.length();
479 // Below makes sure that the focal point is not contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700480 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000481
482 SkColor colors[kMaxRandomGradientColors];
483 SkScalar stopsArray[kMaxRandomGradientColors];
484 SkScalar* stops = stopsArray;
485 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700486 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000487 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
488 center2, radius2,
489 colors, stops, colorCount,
490 tm));
491 SkPaint paint;
joshualittb0a8a372014-09-23 09:50:21 -0700492 GrFragmentProcessor* effect;
bsalomon83d081a2014-07-08 09:56:10 -0700493 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -0700494 GrPaint grPaint;
joshualitt0067ff52015-07-08 14:26:19 -0700495 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
halcanary96fcdcc2015-08-27 07:41:13 -0700496 GrTest::TestMatrix(d->fRandom), nullptr,
joshualitt9cc17752015-07-09 06:28:14 -0700497 &paintColor, d->fProcDataManager,
joshualitt8ca93e72015-07-08 06:51:43 -0700498 &effect));
dandov9de5b512014-06-10 14:38:28 -0700499 return effect;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000500}
501
joshualitteb2a6762014-12-04 11:35:33 -0800502GLFocalOutside2PtConicalEffect::GLFocalOutside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700503 : fVSVaryingName(nullptr)
504 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000505 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700506 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000507 fIsFlipped = data.isFlipped();
508}
509
wangyix7c157a92015-07-22 15:08:53 -0700510void GLFocalOutside2PtConicalEffect::emitCode(EmitArgs& args) {
511 const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
512 this->emitUniforms(args.fBuilder, ge);
513 fParamUni = args.fBuilder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800514 kFloat_GrSLType, kDefault_GrSLPrecision,
515 "Conical2FSParams", 2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000516 SkString tName("t");
517 SkString p0; // focalX
518 SkString p1; // 1 - focalX * focalX
519
wangyix7c157a92015-07-22 15:08:53 -0700520 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
521 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000522
523 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700524 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
525 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000526 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000527
528 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
529
530 // output will default to transparent black (we simply won't write anything
531 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -0700532 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 +0000533
joshualitt30ba4362014-08-21 20:18:45 -0700534 fsBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
535 fsBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
536 fsBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000537
538 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
539 // If so we must also flip sign on sqrt
540 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -0700541 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000542 coords2D, p0.c_str());
543 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700544 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000545 coords2D, p0.c_str());
546 }
547
joshualitt30ba4362014-08-21 20:18:45 -0700548 fsBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
549 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -0700550 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
551 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -0700552 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000553}
554
wangyixb1daa862015-08-18 11:29:31 -0700555void GLFocalOutside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700556 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700557 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700558 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000559 SkASSERT(data.isFlipped() == fIsFlipped);
560 SkScalar focal = data.focal();
561
562 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000563 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000564
565 float values[2] = {
566 SkScalarToFloat(focal),
567 SkScalarToFloat(oneMinus2F),
568 };
569
kkinnunen7510b222014-07-30 00:04:16 -0700570 pdman.set1fv(fParamUni, 2, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000571 fCachedFocal = focal;
572 }
573}
574
joshualittb0a8a372014-09-23 09:50:21 -0700575void GLFocalOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700576 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700577 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700578 key[0] = GenBaseGradientKey(processor);
579 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000580}
581
582//////////////////////////////////////////////////////////////////////////////
583
584class GLFocalInside2PtConicalEffect;
585
586class FocalInside2PtConicalEffect : public GrGradientEffect {
587public:
588
joshualittb0a8a372014-09-23 09:50:21 -0700589 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700590 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700591 const SkTwoPointConicalGradient& shader,
592 const SkMatrix& matrix,
593 SkShader::TileMode tm,
594 SkScalar focalX) {
halcanary385fe4d2015-08-26 13:07:48 -0700595 return new FocalInside2PtConicalEffect(ctx, procDataManager, shader, matrix, tm, 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
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000604 SkScalar focal() const { return fFocalX; }
605
joshualittb0a8a372014-09-23 09:50:21 -0700606 typedef GLFocalInside2PtConicalEffect GLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000607
608private:
wangyixb1daa862015-08-18 11:29:31 -0700609 GrGLFragmentProcessor* onCreateGLInstance() const override;
610
wangyix4b3050b2015-08-04 07:59:37 -0700611 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
612
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;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000642
jvanverthcfc18862015-04-28 08:48:20 -0700643 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000644
645protected:
wangyixb1daa862015-08-18 11:29:31 -0700646 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
647
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000648 UniformHandle fFocalUni;
649
650 const char* fVSVaryingName;
651 const char* fFSVaryingName;
652
653 // @{
654 /// Values last uploaded as uniforms
655
656 SkScalar fCachedFocal;
657
658 // @}
659
660private:
661 typedef GrGLGradientEffect INHERITED;
662
663};
664
wangyix4b3050b2015-08-04 07:59:37 -0700665void FocalInside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800666 GrProcessorKeyBuilder* b) const {
667 GLFocalInside2PtConicalEffect::GenKey(*this, caps, b);
668}
669
wangyixb1daa862015-08-18 11:29:31 -0700670GrGLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700671 return new GLFocalInside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000672}
673
joshualittb0a8a372014-09-23 09:50:21 -0700674GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000675
joshualitt01258472014-09-22 10:29:30 -0700676/*
677 * All Two point conical gradient test create functions may occasionally create edge case shaders
678 */
joshualitt0067ff52015-07-08 14:26:19 -0700679GrFragmentProcessor* FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
680 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000681 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000682 SkPoint center2;
683 SkScalar radius2;
684 do {
joshualitt0067ff52015-07-08 14:26:19 -0700685 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000686 // Below makes sure radius2 is larger enouch such that the focal point
687 // is inside the end circle
joshualitt0067ff52015-07-08 14:26:19 -0700688 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000689 SkPoint diff = center2 - center1;
690 SkScalar diffLen = diff.length();
691 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000692 // If the circles are identical the factory will give us an empty shader.
693 } while (radius1 == radius2 && center1 == center2);
694
695 SkColor colors[kMaxRandomGradientColors];
696 SkScalar stopsArray[kMaxRandomGradientColors];
697 SkScalar* stops = stopsArray;
698 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700699 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000700 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
701 center2, radius2,
702 colors, stops, colorCount,
703 tm));
704 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700705 GrColor paintColor;
joshualittb0a8a372014-09-23 09:50:21 -0700706 GrFragmentProcessor* fp;
joshualitt0067ff52015-07-08 14:26:19 -0700707 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
halcanary96fcdcc2015-08-27 07:41:13 -0700708 GrTest::TestMatrix(d->fRandom), nullptr,
joshualitt9cc17752015-07-09 06:28:14 -0700709 &paintColor, d->fProcDataManager, &fp));
joshualittb0a8a372014-09-23 09:50:21 -0700710 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000711}
712
joshualitteb2a6762014-12-04 11:35:33 -0800713GLFocalInside2PtConicalEffect::GLFocalInside2PtConicalEffect(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700714 : fVSVaryingName(nullptr)
715 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000716 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000717
wangyix7c157a92015-07-22 15:08:53 -0700718void GLFocalInside2PtConicalEffect::emitCode(EmitArgs& args) {
719 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
720 this->emitUniforms(args.fBuilder, ge);
721 fFocalUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800722 kFloat_GrSLType, kDefault_GrSLPrecision,
723 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000724 SkString tName("t");
725
726 // this is the distance along x-axis from the end center to focal point in
727 // transformed coordinates
wangyix7c157a92015-07-22 15:08:53 -0700728 GrGLShaderVar focal = args.fBuilder->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000729
730 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700731 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
732 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000733 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000734
735 // t = p.x * focalX + length(p)
joshualitt30ba4362014-08-21 20:18:45 -0700736 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000737 coords2D, focal.c_str(), coords2D);
738
wangyix7c157a92015-07-22 15:08:53 -0700739 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
740 args.fSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000741}
742
wangyixb1daa862015-08-18 11:29:31 -0700743void GLFocalInside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700744 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700745 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700746 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000747 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000748
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000749 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700750 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000751 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000752 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000753}
754
joshualittb0a8a372014-09-23 09:50:21 -0700755void GLFocalInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700756 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700757 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000758}
759
760//////////////////////////////////////////////////////////////////////////////
761// Circle Conical Gradients
762//////////////////////////////////////////////////////////////////////////////
763
764struct CircleConicalInfo {
765 SkPoint fCenterEnd;
766 SkScalar fA;
767 SkScalar fB;
768 SkScalar fC;
769};
770
771// Returns focal distance along x-axis in transformed coords
772static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
773 SkMatrix* invLMatrix, CircleConicalInfo* info) {
774 // Inverse of the current local matrix is passed in then,
775 // translate and scale such that start circle is on the origin and has radius 1
776 const SkPoint& centerStart = shader.getStartCenter();
777 const SkPoint& centerEnd = shader.getEndCenter();
778 SkScalar radiusStart = shader.getStartRadius();
779 SkScalar radiusEnd = shader.getEndRadius();
780
781 SkMatrix matrix;
782
783 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
784
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000785 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000786 matrix.postScale(invStartRad, invStartRad);
787
788 radiusEnd /= radiusStart;
789
790 SkPoint centerEndTrans;
791 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
792
793 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
794 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
795
796 // Check to see if start circle is inside end circle with edges touching.
797 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700798 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
799 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
800 // still accurate.
801 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000802 return kEdge_ConicalType;
803 }
804
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000805 SkScalar C = 1.f / A;
806 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000807
808 matrix.postScale(C, C);
809
810 invLMatrix->postConcat(matrix);
811
812 info->fCenterEnd = centerEndTrans;
813 info->fA = A;
814 info->fB = B;
815 info->fC = C;
816
817 // if A ends up being negative, the start circle is contained completely inside the end cirlce
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000818 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000819 return kInside_ConicalType;
820 }
821 return kOutside_ConicalType;
822}
823
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000824class CircleInside2PtConicalEffect : public GrGradientEffect {
825public:
826
joshualittb0a8a372014-09-23 09:50:21 -0700827 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700828 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700829 const SkTwoPointConicalGradient& shader,
830 const SkMatrix& matrix,
831 SkShader::TileMode tm,
832 const CircleConicalInfo& info) {
halcanary385fe4d2015-08-26 13:07:48 -0700833 return new CircleInside2PtConicalEffect(ctx, procDataManager, shader, matrix, tm, 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
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000840 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
841 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
842 SkScalar A() const { return fInfo.fA; }
843 SkScalar B() const { return fInfo.fB; }
844 SkScalar C() const { return fInfo.fC; }
845
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000846private:
wangyixb1daa862015-08-18 11:29:31 -0700847 GrGLFragmentProcessor* onCreateGLInstance() const override;
848
wangyix4b3050b2015-08-04 07:59:37 -0700849 virtual void onGetGLProcessorKey(const GrGLSLCaps& caps,
850 GrProcessorKeyBuilder* b) const override;
851
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;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000884
jvanverthcfc18862015-04-28 08:48:20 -0700885 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000886
887protected:
wangyixb1daa862015-08-18 11:29:31 -0700888 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
889
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000890 UniformHandle fCenterUni;
891 UniformHandle fParamUni;
892
893 const char* fVSVaryingName;
894 const char* fFSVaryingName;
895
896 // @{
897 /// Values last uploaded as uniforms
898
899 SkScalar fCachedCenterX;
900 SkScalar fCachedCenterY;
901 SkScalar fCachedA;
902 SkScalar fCachedB;
903 SkScalar fCachedC;
904
905 // @}
906
907private:
908 typedef GrGLGradientEffect INHERITED;
909
910};
911
wangyix4b3050b2015-08-04 07:59:37 -0700912void CircleInside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800913 GrProcessorKeyBuilder* b) const {
914 GLCircleInside2PtConicalEffect::GenKey(*this, caps, b);
915}
916
wangyixb1daa862015-08-18 11:29:31 -0700917GrGLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700918 return new GLCircleInside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000919}
920
joshualittb0a8a372014-09-23 09:50:21 -0700921GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000922
joshualitt01258472014-09-22 10:29:30 -0700923/*
924 * All Two point conical gradient test create functions may occasionally create edge case shaders
925 */
joshualitt0067ff52015-07-08 14:26:19 -0700926GrFragmentProcessor*
927CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
928 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
929 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000930 SkPoint center2;
931 SkScalar radius2;
932 do {
joshualitt0067ff52015-07-08 14:26:19 -0700933 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000934 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700935 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000936 SkPoint diff = center2 - center1;
937 SkScalar diffLen = diff.length();
938 radius2 = radius1 + diffLen + increase;
939 // If the circles are identical the factory will give us an empty shader.
940 } while (radius1 == radius2 && center1 == center2);
941
942 SkColor colors[kMaxRandomGradientColors];
943 SkScalar stopsArray[kMaxRandomGradientColors];
944 SkScalar* stops = stopsArray;
945 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700946 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000947 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
948 center2, radius2,
949 colors, stops, colorCount,
950 tm));
951 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700952 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -0700953 GrFragmentProcessor* fp;
joshualitt0067ff52015-07-08 14:26:19 -0700954 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
halcanary96fcdcc2015-08-27 07:41:13 -0700955 GrTest::TestMatrix(d->fRandom), nullptr,
joshualitt9cc17752015-07-09 06:28:14 -0700956 &paintColor, d->fProcDataManager, &fp));
joshualitt8ca93e72015-07-08 06:51:43 -0700957 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000958}
959
joshualitteb2a6762014-12-04 11:35:33 -0800960GLCircleInside2PtConicalEffect::GLCircleInside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700961 : fVSVaryingName(nullptr)
962 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000963 , fCachedCenterX(SK_ScalarMax)
964 , fCachedCenterY(SK_ScalarMax)
965 , fCachedA(SK_ScalarMax)
966 , fCachedB(SK_ScalarMax)
967 , fCachedC(SK_ScalarMax) {}
968
wangyix7c157a92015-07-22 15:08:53 -0700969void GLCircleInside2PtConicalEffect::emitCode(EmitArgs& args) {
970 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
971 this->emitUniforms(args.fBuilder, ge);
972 fCenterUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800973 kVec2f_GrSLType, kDefault_GrSLPrecision,
974 "Conical2FSCenter");
wangyix7c157a92015-07-22 15:08:53 -0700975 fParamUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800976 kVec3f_GrSLType, kDefault_GrSLPrecision,
977 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000978 SkString tName("t");
979
wangyix7c157a92015-07-22 15:08:53 -0700980 GrGLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000981 // params.x = A
982 // params.y = B
983 // params.z = C
wangyix7c157a92015-07-22 15:08:53 -0700984 GrGLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000985
986 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700987 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
988 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000989 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000990
991 // p = coords2D
992 // e = center end
993 // r = radius end
994 // A = dot(e, e) - r^2 + 2 * r - 1
995 // B = (r -1) / A
996 // C = 1 / A
997 // d = dot(e, p) + B
998 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
joshualitt30ba4362014-08-21 20:18:45 -0700999 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -07001000 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1001 params.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001002 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001003 tName.c_str(), params.c_str(), params.c_str());
1004
wangyix7c157a92015-07-22 15:08:53 -07001005 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
1006 args.fSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001007}
1008
wangyixb1daa862015-08-18 11:29:31 -07001009void GLCircleInside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001010 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001011 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001012 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001013 SkScalar centerX = data.centerX();
1014 SkScalar centerY = data.centerY();
1015 SkScalar A = data.A();
1016 SkScalar B = data.B();
1017 SkScalar C = data.C();
1018
1019 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1020 fCachedA != A || fCachedB != B || fCachedC != C) {
1021
kkinnunen7510b222014-07-30 00:04:16 -07001022 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1023 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001024
1025 fCachedCenterX = centerX;
1026 fCachedCenterY = centerY;
1027 fCachedA = A;
1028 fCachedB = B;
1029 fCachedC = C;
1030 }
1031}
1032
joshualittb0a8a372014-09-23 09:50:21 -07001033void GLCircleInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001034 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001035 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001036}
1037
1038//////////////////////////////////////////////////////////////////////////////
1039
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001040class CircleOutside2PtConicalEffect : public GrGradientEffect {
1041public:
1042
joshualittb0a8a372014-09-23 09:50:21 -07001043 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -07001044 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -07001045 const SkTwoPointConicalGradient& shader,
1046 const SkMatrix& matrix,
1047 SkShader::TileMode tm,
1048 const CircleConicalInfo& info) {
halcanary385fe4d2015-08-26 13:07:48 -07001049 return new CircleOutside2PtConicalEffect(ctx, procDataManager, shader, matrix, 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
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001056 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1057 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1058 SkScalar A() const { return fInfo.fA; }
1059 SkScalar B() const { return fInfo.fB; }
1060 SkScalar C() const { return fInfo.fC; }
1061 SkScalar tLimit() const { return fTLimit; }
1062 bool isFlipped() const { return fIsFlipped; }
1063
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001064private:
wangyixb1daa862015-08-18 11:29:31 -07001065 GrGLFragmentProcessor* onCreateGLInstance() const override;
1066
wangyix4b3050b2015-08-04 07:59:37 -07001067 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
1068
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;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001112
jvanverthcfc18862015-04-28 08:48:20 -07001113 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001114
1115protected:
wangyixb1daa862015-08-18 11:29:31 -07001116 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
1117
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001118 UniformHandle fCenterUni;
1119 UniformHandle fParamUni;
1120
1121 const char* fVSVaryingName;
1122 const char* fFSVaryingName;
1123
1124 bool fIsFlipped;
1125
1126 // @{
1127 /// Values last uploaded as uniforms
1128
1129 SkScalar fCachedCenterX;
1130 SkScalar fCachedCenterY;
1131 SkScalar fCachedA;
1132 SkScalar fCachedB;
1133 SkScalar fCachedC;
1134 SkScalar fCachedTLimit;
1135
1136 // @}
1137
1138private:
1139 typedef GrGLGradientEffect INHERITED;
1140
1141};
1142
wangyix4b3050b2015-08-04 07:59:37 -07001143void CircleOutside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001144 GrProcessorKeyBuilder* b) const {
1145 GLCircleOutside2PtConicalEffect::GenKey(*this, caps, b);
1146}
1147
wangyixb1daa862015-08-18 11:29:31 -07001148GrGLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001149 return new GLCircleOutside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001150}
1151
joshualittb0a8a372014-09-23 09:50:21 -07001152GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001153
joshualitt01258472014-09-22 10:29:30 -07001154/*
1155 * All Two point conical gradient test create functions may occasionally create edge case shaders
1156 */
joshualitt0067ff52015-07-08 14:26:19 -07001157GrFragmentProcessor* CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
1158 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1159 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001160 SkPoint center2;
1161 SkScalar radius2;
1162 SkScalar diffLen;
1163 do {
joshualitt0067ff52015-07-08 14:26:19 -07001164 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001165 // If the circles share a center than we can't be in the outside case
1166 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001167 SkPoint diff = center2 - center1;
1168 diffLen = diff.length();
1169 // Below makes sure that circle one is not contained within circle two
1170 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001171 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001172
1173 SkColor colors[kMaxRandomGradientColors];
1174 SkScalar stopsArray[kMaxRandomGradientColors];
1175 SkScalar* stops = stopsArray;
1176 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -07001177 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001178 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
1179 center2, radius2,
1180 colors, stops, colorCount,
1181 tm));
1182 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -07001183 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -07001184 GrFragmentProcessor* fp;
joshualitt0067ff52015-07-08 14:26:19 -07001185 SkAssertResult(shader->asFragmentProcessor(d->fContext, paint,
halcanary96fcdcc2015-08-27 07:41:13 -07001186 GrTest::TestMatrix(d->fRandom), nullptr,
joshualitt9cc17752015-07-09 06:28:14 -07001187 &paintColor, d->fProcDataManager, &fp));
joshualitt8ca93e72015-07-08 06:51:43 -07001188 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001189}
1190
joshualitteb2a6762014-12-04 11:35:33 -08001191GLCircleOutside2PtConicalEffect::GLCircleOutside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -07001192 : fVSVaryingName(nullptr)
1193 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001194 , fCachedCenterX(SK_ScalarMax)
1195 , fCachedCenterY(SK_ScalarMax)
1196 , fCachedA(SK_ScalarMax)
1197 , fCachedB(SK_ScalarMax)
1198 , fCachedC(SK_ScalarMax)
1199 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001200 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001201 fIsFlipped = data.isFlipped();
1202 }
1203
wangyix7c157a92015-07-22 15:08:53 -07001204void GLCircleOutside2PtConicalEffect::emitCode(EmitArgs& args) {
1205 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
1206 this->emitUniforms(args.fBuilder, ge);
1207 fCenterUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001208 kVec2f_GrSLType, kDefault_GrSLPrecision,
1209 "Conical2FSCenter");
wangyix7c157a92015-07-22 15:08:53 -07001210 fParamUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001211 kVec4f_GrSLType, kDefault_GrSLPrecision,
1212 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001213 SkString tName("t");
1214
wangyix7c157a92015-07-22 15:08:53 -07001215 GrGLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001216 // params.x = A
1217 // params.y = B
1218 // params.z = C
wangyix7c157a92015-07-22 15:08:53 -07001219 GrGLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001220
1221 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -07001222 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
1223 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001224 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001225
1226 // output will default to transparent black (we simply won't write anything
1227 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -07001228 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 +00001229
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001230 // p = coords2D
1231 // e = center end
1232 // r = radius end
1233 // A = dot(e, e) - r^2 + 2 * r - 1
1234 // B = (r -1) / A
1235 // C = 1 / A
1236 // d = dot(e, p) + B
1237 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001238
joshualitt30ba4362014-08-21 20:18:45 -07001239 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -07001240 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1241 params.c_str());
1242 fsBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1243 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001244
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001245 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1246 // If so we must also flip sign on sqrt
1247 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -07001248 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001249 } else {
joshualitt30ba4362014-08-21 20:18:45 -07001250 fsBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001251 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001252
joshualitt30ba4362014-08-21 20:18:45 -07001253 fsBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str());
1254 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -07001255 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
1256 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -07001257 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001258}
1259
wangyixb1daa862015-08-18 11:29:31 -07001260void GLCircleOutside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001261 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001262 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001263 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001264 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001265 SkScalar centerX = data.centerX();
1266 SkScalar centerY = data.centerY();
1267 SkScalar A = data.A();
1268 SkScalar B = data.B();
1269 SkScalar C = data.C();
1270 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001271
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001272 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1273 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001274
kkinnunen7510b222014-07-30 00:04:16 -07001275 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1276 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001277 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001278
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001279 fCachedCenterX = centerX;
1280 fCachedCenterY = centerY;
1281 fCachedA = A;
1282 fCachedB = B;
1283 fCachedC = C;
1284 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001285 }
1286}
1287
joshualittb0a8a372014-09-23 09:50:21 -07001288void GLCircleOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001289 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001290 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001291 key[0] = GenBaseGradientKey(processor);
1292 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001293}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001294
1295//////////////////////////////////////////////////////////////////////////////
1296
joshualittb0a8a372014-09-23 09:50:21 -07001297GrFragmentProcessor* Gr2PtConicalGradientEffect::Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -07001298 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -07001299 const SkTwoPointConicalGradient& shader,
1300 SkShader::TileMode tm,
1301 const SkMatrix* localMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001302 SkMatrix matrix;
1303 if (!shader.getLocalMatrix().invert(&matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001304 return nullptr;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001305 }
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001306 if (localMatrix) {
1307 SkMatrix inv;
1308 if (!localMatrix->invert(&inv)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001309 return nullptr;
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001310 }
1311 matrix.postConcat(inv);
1312 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001313
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001314 if (shader.getStartRadius() < kErrorTol) {
1315 SkScalar focalX;
1316 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1317 if (type == kInside_ConicalType) {
joshualitt9cc17752015-07-09 06:28:14 -07001318 return FocalInside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001319 focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001320 } else if(type == kEdge_ConicalType) {
1321 set_matrix_edge_conical(shader, &matrix);
joshualitt9cc17752015-07-09 06:28:14 -07001322 return Edge2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001323 } else {
joshualitt9cc17752015-07-09 06:28:14 -07001324 return FocalOutside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001325 focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001326 }
1327 }
1328
1329 CircleConicalInfo info;
1330 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1331
1332 if (type == kInside_ConicalType) {
joshualitt9cc17752015-07-09 06:28:14 -07001333 return CircleInside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001334 info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001335 } else if (type == kEdge_ConicalType) {
1336 set_matrix_edge_conical(shader, &matrix);
joshualitt9cc17752015-07-09 06:28:14 -07001337 return Edge2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001338 } else {
joshualitt9cc17752015-07-09 06:28:14 -07001339 return CircleOutside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001340 info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001341 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001342}
1343
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001344#endif