blob: dec3e96bdb704d21cd89e930ff68078153a48397 [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"
egdaniel2d721d32015-11-11 13:06:05 -080015#include "glsl/GrGLSLFragmentShaderBuilder.h"
16#include "glsl/GrGLSLProgramBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070017#include "glsl/GrGLSLProgramDataManager.h"
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000018// For brevity
egdaniel018fb622015-10-28 07:26:40 -070019typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000020
commit-bot@chromium.org80894672014-04-22 21:24:22 +000021static const SkScalar kErrorTol = 0.00001f;
egdaniel8405ef92014-06-09 11:57:28 -070022static const SkScalar kEdgeErrorTol = 5.f * kErrorTol;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000023
24/**
25 * We have three general cases for 2pt conical gradients. First we always assume that
26 * the start radius <= end radius. Our first case (kInside_) is when the start circle
27 * is completely enclosed by the end circle. The second case (kOutside_) is the case
28 * when the start circle is either completely outside the end circle or the circles
29 * overlap. The final case (kEdge_) is when the start circle is inside the end one,
30 * but the two are just barely touching at 1 point along their edges.
31 */
32enum ConicalType {
33 kInside_ConicalType,
34 kOutside_ConicalType,
35 kEdge_ConicalType,
36};
37
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000038//////////////////////////////////////////////////////////////////////////////
39
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000040static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader,
41 SkMatrix* invLMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000042 // Inverse of the current local matrix is passed in then,
43 // translate to center1, rotate so center2 is on x axis.
44 const SkPoint& center1 = shader.getStartCenter();
45 const SkPoint& center2 = shader.getEndCenter();
46
47 invLMatrix->postTranslate(-center1.fX, -center1.fY);
48
49 SkPoint diff = center2 - center1;
50 SkScalar diffLen = diff.length();
51 if (0 != diffLen) {
52 SkScalar invDiffLen = SkScalarInvert(diffLen);
53 SkMatrix rot;
54 rot.setSinCos(-SkScalarMul(invDiffLen, diff.fY),
55 SkScalarMul(invDiffLen, diff.fX));
56 invLMatrix->postConcat(rot);
57 }
58}
59
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000060class Edge2PtConicalEffect : public GrGradientEffect {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000061public:
62
joshualittb0a8a372014-09-23 09:50:21 -070063 static GrFragmentProcessor* Create(GrContext* ctx,
64 const SkTwoPointConicalGradient& shader,
65 const SkMatrix& matrix,
66 SkShader::TileMode tm) {
bsalomon4a339522015-10-06 08:40:50 -070067 return new Edge2PtConicalEffect(ctx, shader, matrix, tm);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000068 }
69
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000070 virtual ~Edge2PtConicalEffect() {}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000071
mtklein36352bf2015-03-25 18:17:31 -070072 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -080073 return "Two-Point Conical Gradient Edge Touching";
74 }
75
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000076 // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000077 SkScalar center() const { return fCenterX1; }
78 SkScalar diffRadius() const { return fDiffRadius; }
79 SkScalar radius() const { return fRadius0; }
80
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000081private:
wangyixb1daa862015-08-18 11:29:31 -070082 GrGLFragmentProcessor* onCreateGLInstance() const override;
83
wangyix4b3050b2015-08-04 07:59:37 -070084 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
85
mtklein36352bf2015-03-25 18:17:31 -070086 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -070087 const Edge2PtConicalEffect& s = sBase.cast<Edge2PtConicalEffect>();
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000088 return (INHERITED::onIsEqual(sBase) &&
89 this->fCenterX1 == s.fCenterX1 &&
90 this->fRadius0 == s.fRadius0 &&
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000091 this->fDiffRadius == s.fDiffRadius);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000092 }
93
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000094 Edge2PtConicalEffect(GrContext* ctx,
95 const SkTwoPointConicalGradient& shader,
96 const SkMatrix& matrix,
97 SkShader::TileMode tm)
bsalomon4a339522015-10-06 08:40:50 -070098 : INHERITED(ctx, 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:
egdaniel018fb622015-10-28 07:26:40 -0700152 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700153
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,
egdaniel2d721d32015-11-11 13:06:05 -0800173 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800174 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 */
bsalomonc21b09e2015-08-28 18:46:56 -0700186const GrFragmentProcessor* Edge2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700187 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));
bsalomonc21b09e2015-08-28 18:46:56 -0700212 const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
bsalomon4a339522015-10-06 08:40:50 -0700213 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality);
bsalomonc21b09e2015-08-28 18:46:56 -0700214 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700215 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000216}
217
joshualitteb2a6762014-12-04 11:35:33 -0800218GLEdge2PtConicalEffect::GLEdge2PtConicalEffect(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700219 : fVSVaryingName(nullptr)
220 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000221 , fCachedRadius(-SK_ScalarMax)
222 , fCachedDiffRadius(-SK_ScalarMax) {}
223
wangyix7c157a92015-07-22 15:08:53 -0700224void GLEdge2PtConicalEffect::emitCode(EmitArgs& args) {
225 const Edge2PtConicalEffect& ge = args.fFp.cast<Edge2PtConicalEffect>();
226 this->emitUniforms(args.fBuilder, ge);
egdaniel2d721d32015-11-11 13:06:05 -0800227 fParamUni = args.fBuilder->addUniformArray(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800228 kFloat_GrSLType, kDefault_GrSLPrecision,
229 "Conical2FSParams", 3);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000230
231 SkString cName("c");
232 SkString tName("t");
233 SkString p0; // start radius
234 SkString p1; // start radius squared
235 SkString p2; // difference in radii (r1 - r0)
236
wangyix7c157a92015-07-22 15:08:53 -0700237 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
238 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
239 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000240
241 // We interpolate the linear component in coords[1].
wangyix7c157a92015-07-22 15:08:53 -0700242 SkASSERT(args.fCoords[0].getType() == args.fCoords[1].getType());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000243 const char* coords2D;
244 SkString bVar;
egdaniel2d721d32015-11-11 13:06:05 -0800245 GrGLSLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
wangyix7c157a92015-07-22 15:08:53 -0700246 if (kVec3f_GrSLType == args.fCoords[0].getType()) {
joshualitt30ba4362014-08-21 20:18:45 -0700247 fsBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
wangyix7c157a92015-07-22 15:08:53 -0700248 args.fCoords[0].c_str(), args.fCoords[0].c_str(),
249 args.fCoords[1].c_str(), args.fCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000250 coords2D = "interpolants.xy";
251 bVar = "interpolants.z";
252 } else {
wangyix7c157a92015-07-22 15:08:53 -0700253 coords2D = args.fCoords[0].c_str();
254 bVar.printf("%s.x", args.fCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000255 }
256
257 // output will default to transparent black (we simply won't write anything
258 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -0700259 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 +0000260
261 // c = (x^2)+(y^2) - params[1]
joshualitt30ba4362014-08-21 20:18:45 -0700262 fsBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000263 cName.c_str(), coords2D, coords2D, p1.c_str());
264
265 // linear case: t = -c/b
joshualitt30ba4362014-08-21 20:18:45 -0700266 fsBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000267 cName.c_str(), bVar.c_str());
268
269 // if r(t) > 0, then t will be the x coordinate
joshualitt30ba4362014-08-21 20:18:45 -0700270 fsBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000271 p2.c_str(), p0.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700272 fsBuilder->codeAppend("\t");
wangyix7c157a92015-07-22 15:08:53 -0700273 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
274 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -0700275 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000276}
277
egdaniel018fb622015-10-28 07:26:40 -0700278void GLEdge2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
279 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700280 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700281 const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000282 SkScalar radius0 = data.radius();
283 SkScalar diffRadius = data.diffRadius();
284
285 if (fCachedRadius != radius0 ||
286 fCachedDiffRadius != diffRadius) {
287
288 float values[3] = {
289 SkScalarToFloat(radius0),
290 SkScalarToFloat(SkScalarMul(radius0, radius0)),
291 SkScalarToFloat(diffRadius)
292 };
293
kkinnunen7510b222014-07-30 00:04:16 -0700294 pdman.set1fv(fParamUni, 3, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000295 fCachedRadius = radius0;
296 fCachedDiffRadius = diffRadius;
297 }
298}
299
joshualittb0a8a372014-09-23 09:50:21 -0700300void GLEdge2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700301 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700302 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000303}
304
305//////////////////////////////////////////////////////////////////////////////
306// Focal Conical Gradients
307//////////////////////////////////////////////////////////////////////////////
308
309static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
310 SkMatrix* invLMatrix, SkScalar* focalX) {
311 // Inverse of the current local matrix is passed in then,
312 // translate, scale, and rotate such that endCircle is unit circle on x-axis,
313 // and focal point is at the origin.
314 ConicalType conicalType;
315 const SkPoint& focal = shader.getStartCenter();
316 const SkPoint& centerEnd = shader.getEndCenter();
317 SkScalar radius = shader.getEndRadius();
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000318 SkScalar invRadius = 1.f / radius;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000319
320 SkMatrix matrix;
321
322 matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
323 matrix.postScale(invRadius, invRadius);
324
325 SkPoint focalTrans;
326 matrix.mapPoints(&focalTrans, &focal, 1);
327 *focalX = focalTrans.length();
328
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000329 if (0.f != *focalX) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000330 SkScalar invFocalX = SkScalarInvert(*focalX);
331 SkMatrix rot;
332 rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY),
333 SkScalarMul(invFocalX, focalTrans.fX));
334 matrix.postConcat(rot);
335 }
336
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000337 matrix.postTranslate(-(*focalX), 0.f);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000338
339 // If the focal point is touching the edge of the circle it will
340 // cause a degenerate case that must be handled separately
egdaniel8405ef92014-06-09 11:57:28 -0700341 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
342 // stability trade off versus the linear approx used in the Edge Shader
343 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000344 return kEdge_ConicalType;
345 }
346
347 // Scale factor 1 / (1 - focalX * focalX)
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000348 SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX);
reed80ea19c2015-05-12 10:37:34 -0700349 SkScalar s = SkScalarInvert(oneMinusF2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000350
351
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000352 if (s >= 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000353 conicalType = kInside_ConicalType;
354 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
355 } else {
356 conicalType = kOutside_ConicalType;
357 matrix.postScale(s, s);
358 }
359
360 invLMatrix->postConcat(matrix);
361
362 return conicalType;
363}
364
365//////////////////////////////////////////////////////////////////////////////
366
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000367class FocalOutside2PtConicalEffect : public GrGradientEffect {
368public:
369
joshualittb0a8a372014-09-23 09:50:21 -0700370 static GrFragmentProcessor* Create(GrContext* ctx,
371 const SkTwoPointConicalGradient& shader,
372 const SkMatrix& matrix,
373 SkShader::TileMode tm,
374 SkScalar focalX) {
bsalomon4a339522015-10-06 08:40:50 -0700375 return new FocalOutside2PtConicalEffect(ctx, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000376 }
377
378 virtual ~FocalOutside2PtConicalEffect() { }
379
mtklein36352bf2015-03-25 18:17:31 -0700380 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800381 return "Two-Point Conical Gradient Focal Outside";
382 }
383
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000384 bool isFlipped() const { return fIsFlipped; }
385 SkScalar focal() const { return fFocalX; }
386
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000387private:
wangyixb1daa862015-08-18 11:29:31 -0700388 GrGLFragmentProcessor* onCreateGLInstance() const override;
389
wangyix4b3050b2015-08-04 07:59:37 -0700390 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
391
mtklein36352bf2015-03-25 18:17:31 -0700392 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700393 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000394 return (INHERITED::onIsEqual(sBase) &&
395 this->fFocalX == s.fFocalX &&
396 this->fIsFlipped == s.fIsFlipped);
397 }
398
399 FocalOutside2PtConicalEffect(GrContext* ctx,
400 const SkTwoPointConicalGradient& shader,
401 const SkMatrix& matrix,
402 SkShader::TileMode tm,
403 SkScalar focalX)
bsalomon4a339522015-10-06 08:40:50 -0700404 : INHERITED(ctx, shader, matrix, tm)
joshualittb2456052015-07-08 09:36:59 -0700405 , fFocalX(focalX)
406 , fIsFlipped(shader.isFlippedGrad()) {
joshualitteb2a6762014-12-04 11:35:33 -0800407 this->initClassID<FocalOutside2PtConicalEffect>();
408 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000409
joshualittb0a8a372014-09-23 09:50:21 -0700410 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000411
412 SkScalar fFocalX;
413 bool fIsFlipped;
414
415 typedef GrGradientEffect INHERITED;
416};
417
418class GLFocalOutside2PtConicalEffect : public GrGLGradientEffect {
419public:
joshualitteb2a6762014-12-04 11:35:33 -0800420 GLFocalOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000421 virtual ~GLFocalOutside2PtConicalEffect() { }
422
wangyix7c157a92015-07-22 15:08:53 -0700423 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000424
jvanverthcfc18862015-04-28 08:48:20 -0700425 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000426
427protected:
egdaniel018fb622015-10-28 07:26:40 -0700428 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700429
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000430 UniformHandle fParamUni;
431
432 const char* fVSVaryingName;
433 const char* fFSVaryingName;
434
435 bool fIsFlipped;
436
437 // @{
438 /// Values last uploaded as uniforms
439
440 SkScalar fCachedFocal;
441
442 // @}
443
444private:
445 typedef GrGLGradientEffect INHERITED;
446
447};
448
wangyix4b3050b2015-08-04 07:59:37 -0700449void FocalOutside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
egdaniel2d721d32015-11-11 13:06:05 -0800450 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800451 GLFocalOutside2PtConicalEffect::GenKey(*this, caps, b);
452}
453
wangyixb1daa862015-08-18 11:29:31 -0700454GrGLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700455 return new GLFocalOutside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000456}
457
joshualittb0a8a372014-09-23 09:50:21 -0700458GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000459
joshualitt01258472014-09-22 10:29:30 -0700460/*
461 * All Two point conical gradient test create functions may occasionally create edge case shaders
462 */
bsalomonc21b09e2015-08-28 18:46:56 -0700463const GrFragmentProcessor* FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700464 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000465 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000466 SkPoint center2;
467 SkScalar radius2;
468 do {
joshualitt0067ff52015-07-08 14:26:19 -0700469 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000470 // 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 +0000471 } while (center1 == center2);
472 SkPoint diff = center2 - center1;
473 SkScalar diffLen = diff.length();
474 // Below makes sure that the focal point is not contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700475 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000476
477 SkColor colors[kMaxRandomGradientColors];
478 SkScalar stopsArray[kMaxRandomGradientColors];
479 SkScalar* stops = stopsArray;
480 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700481 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000482 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
483 center2, radius2,
484 colors, stops, colorCount,
485 tm));
bsalomonc21b09e2015-08-28 18:46:56 -0700486 const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
bsalomon4a339522015-10-06 08:40:50 -0700487 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality);
bsalomonc21b09e2015-08-28 18:46:56 -0700488 GrAlwaysAssert(fp);
489 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000490}
491
joshualitteb2a6762014-12-04 11:35:33 -0800492GLFocalOutside2PtConicalEffect::GLFocalOutside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700493 : fVSVaryingName(nullptr)
494 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000495 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700496 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000497 fIsFlipped = data.isFlipped();
498}
499
wangyix7c157a92015-07-22 15:08:53 -0700500void GLFocalOutside2PtConicalEffect::emitCode(EmitArgs& args) {
501 const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
502 this->emitUniforms(args.fBuilder, ge);
egdaniel2d721d32015-11-11 13:06:05 -0800503 fParamUni = args.fBuilder->addUniformArray(GrGLSLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800504 kFloat_GrSLType, kDefault_GrSLPrecision,
505 "Conical2FSParams", 2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000506 SkString tName("t");
507 SkString p0; // focalX
508 SkString p1; // 1 - focalX * focalX
509
wangyix7c157a92015-07-22 15:08:53 -0700510 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
511 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000512
513 // if we have a vec3 from being in perspective, convert it to a vec2 first
egdaniel2d721d32015-11-11 13:06:05 -0800514 GrGLSLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
wangyix7c157a92015-07-22 15:08:53 -0700515 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000516 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000517
518 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
519
520 // output will default to transparent black (we simply won't write anything
521 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -0700522 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 +0000523
joshualitt30ba4362014-08-21 20:18:45 -0700524 fsBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
525 fsBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
526 fsBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000527
528 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
529 // If so we must also flip sign on sqrt
530 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -0700531 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000532 coords2D, p0.c_str());
533 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700534 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000535 coords2D, p0.c_str());
536 }
537
joshualitt30ba4362014-08-21 20:18:45 -0700538 fsBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
539 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -0700540 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
541 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -0700542 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000543}
544
egdaniel018fb622015-10-28 07:26:40 -0700545void GLFocalOutside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
546 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700547 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700548 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000549 SkASSERT(data.isFlipped() == fIsFlipped);
550 SkScalar focal = data.focal();
551
552 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000553 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000554
555 float values[2] = {
556 SkScalarToFloat(focal),
557 SkScalarToFloat(oneMinus2F),
558 };
559
kkinnunen7510b222014-07-30 00:04:16 -0700560 pdman.set1fv(fParamUni, 2, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000561 fCachedFocal = focal;
562 }
563}
564
joshualittb0a8a372014-09-23 09:50:21 -0700565void GLFocalOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700566 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700567 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700568 key[0] = GenBaseGradientKey(processor);
569 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000570}
571
572//////////////////////////////////////////////////////////////////////////////
573
574class GLFocalInside2PtConicalEffect;
575
576class FocalInside2PtConicalEffect : public GrGradientEffect {
577public:
578
joshualittb0a8a372014-09-23 09:50:21 -0700579 static GrFragmentProcessor* Create(GrContext* ctx,
580 const SkTwoPointConicalGradient& shader,
581 const SkMatrix& matrix,
582 SkShader::TileMode tm,
583 SkScalar focalX) {
bsalomon4a339522015-10-06 08:40:50 -0700584 return new FocalInside2PtConicalEffect(ctx, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000585 }
586
587 virtual ~FocalInside2PtConicalEffect() {}
588
mtklein36352bf2015-03-25 18:17:31 -0700589 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800590 return "Two-Point Conical Gradient Focal Inside";
591 }
592
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000593 SkScalar focal() const { return fFocalX; }
594
joshualittb0a8a372014-09-23 09:50:21 -0700595 typedef GLFocalInside2PtConicalEffect GLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000596
597private:
wangyixb1daa862015-08-18 11:29:31 -0700598 GrGLFragmentProcessor* onCreateGLInstance() const override;
599
wangyix4b3050b2015-08-04 07:59:37 -0700600 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
601
mtklein36352bf2015-03-25 18:17:31 -0700602 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700603 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000604 return (INHERITED::onIsEqual(sBase) &&
605 this->fFocalX == s.fFocalX);
606 }
607
608 FocalInside2PtConicalEffect(GrContext* ctx,
609 const SkTwoPointConicalGradient& shader,
610 const SkMatrix& matrix,
611 SkShader::TileMode tm,
612 SkScalar focalX)
bsalomon4a339522015-10-06 08:40:50 -0700613 : INHERITED(ctx, shader, matrix, tm), fFocalX(focalX) {
joshualitteb2a6762014-12-04 11:35:33 -0800614 this->initClassID<FocalInside2PtConicalEffect>();
615 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000616
joshualittb0a8a372014-09-23 09:50:21 -0700617 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000618
619 SkScalar fFocalX;
620
621 typedef GrGradientEffect INHERITED;
622};
623
624class GLFocalInside2PtConicalEffect : public GrGLGradientEffect {
625public:
joshualitteb2a6762014-12-04 11:35:33 -0800626 GLFocalInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000627 virtual ~GLFocalInside2PtConicalEffect() {}
628
wangyix7c157a92015-07-22 15:08:53 -0700629 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000630
jvanverthcfc18862015-04-28 08:48:20 -0700631 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000632
633protected:
egdaniel018fb622015-10-28 07:26:40 -0700634 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700635
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000636 UniformHandle fFocalUni;
637
638 const char* fVSVaryingName;
639 const char* fFSVaryingName;
640
641 // @{
642 /// Values last uploaded as uniforms
643
644 SkScalar fCachedFocal;
645
646 // @}
647
648private:
649 typedef GrGLGradientEffect INHERITED;
650
651};
652
wangyix4b3050b2015-08-04 07:59:37 -0700653void FocalInside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
egdaniel2d721d32015-11-11 13:06:05 -0800654 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800655 GLFocalInside2PtConicalEffect::GenKey(*this, caps, b);
656}
657
wangyixb1daa862015-08-18 11:29:31 -0700658GrGLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700659 return new GLFocalInside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000660}
661
joshualittb0a8a372014-09-23 09:50:21 -0700662GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000663
joshualitt01258472014-09-22 10:29:30 -0700664/*
665 * All Two point conical gradient test create functions may occasionally create edge case shaders
666 */
bsalomonc21b09e2015-08-28 18:46:56 -0700667const GrFragmentProcessor* FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700668 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000669 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000670 SkPoint center2;
671 SkScalar radius2;
672 do {
joshualitt0067ff52015-07-08 14:26:19 -0700673 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000674 // Below makes sure radius2 is larger enouch such that the focal point
675 // is inside the end circle
joshualitt0067ff52015-07-08 14:26:19 -0700676 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000677 SkPoint diff = center2 - center1;
678 SkScalar diffLen = diff.length();
679 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000680 // If the circles are identical the factory will give us an empty shader.
681 } while (radius1 == radius2 && center1 == center2);
682
683 SkColor colors[kMaxRandomGradientColors];
684 SkScalar stopsArray[kMaxRandomGradientColors];
685 SkScalar* stops = stopsArray;
686 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700687 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000688 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
689 center2, radius2,
690 colors, stops, colorCount,
691 tm));
bsalomonc21b09e2015-08-28 18:46:56 -0700692 const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
bsalomon4a339522015-10-06 08:40:50 -0700693 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality);
bsalomonc21b09e2015-08-28 18:46:56 -0700694 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700695 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000696}
697
joshualitteb2a6762014-12-04 11:35:33 -0800698GLFocalInside2PtConicalEffect::GLFocalInside2PtConicalEffect(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700699 : fVSVaryingName(nullptr)
700 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000701 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000702
wangyix7c157a92015-07-22 15:08:53 -0700703void GLFocalInside2PtConicalEffect::emitCode(EmitArgs& args) {
704 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
705 this->emitUniforms(args.fBuilder, ge);
egdaniel2d721d32015-11-11 13:06:05 -0800706 fFocalUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
707 kFloat_GrSLType, kDefault_GrSLPrecision,
708 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000709 SkString tName("t");
710
711 // this is the distance along x-axis from the end center to focal point in
712 // transformed coordinates
egdaniel0d3f0612015-10-21 10:45:48 -0700713 GrGLSLShaderVar focal = args.fBuilder->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000714
715 // if we have a vec3 from being in perspective, convert it to a vec2 first
egdaniel2d721d32015-11-11 13:06:05 -0800716 GrGLSLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
wangyix7c157a92015-07-22 15:08:53 -0700717 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000718 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000719
720 // t = p.x * focalX + length(p)
joshualitt30ba4362014-08-21 20:18:45 -0700721 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000722 coords2D, focal.c_str(), coords2D);
723
wangyix7c157a92015-07-22 15:08:53 -0700724 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
725 args.fSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000726}
727
egdaniel018fb622015-10-28 07:26:40 -0700728void GLFocalInside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
729 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700730 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700731 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000732 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000733
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000734 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700735 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000736 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000737 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000738}
739
joshualittb0a8a372014-09-23 09:50:21 -0700740void GLFocalInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700741 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700742 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000743}
744
745//////////////////////////////////////////////////////////////////////////////
746// Circle Conical Gradients
747//////////////////////////////////////////////////////////////////////////////
748
749struct CircleConicalInfo {
750 SkPoint fCenterEnd;
751 SkScalar fA;
752 SkScalar fB;
753 SkScalar fC;
754};
755
756// Returns focal distance along x-axis in transformed coords
757static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
758 SkMatrix* invLMatrix, CircleConicalInfo* info) {
759 // Inverse of the current local matrix is passed in then,
760 // translate and scale such that start circle is on the origin and has radius 1
761 const SkPoint& centerStart = shader.getStartCenter();
762 const SkPoint& centerEnd = shader.getEndCenter();
763 SkScalar radiusStart = shader.getStartRadius();
764 SkScalar radiusEnd = shader.getEndRadius();
765
766 SkMatrix matrix;
767
768 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
769
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000770 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000771 matrix.postScale(invStartRad, invStartRad);
772
773 radiusEnd /= radiusStart;
774
775 SkPoint centerEndTrans;
776 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
777
778 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
779 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
780
781 // Check to see if start circle is inside end circle with edges touching.
782 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700783 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
784 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
785 // still accurate.
786 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000787 return kEdge_ConicalType;
788 }
789
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000790 SkScalar C = 1.f / A;
791 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000792
793 matrix.postScale(C, C);
794
795 invLMatrix->postConcat(matrix);
796
797 info->fCenterEnd = centerEndTrans;
798 info->fA = A;
799 info->fB = B;
800 info->fC = C;
801
802 // 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 +0000803 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000804 return kInside_ConicalType;
805 }
806 return kOutside_ConicalType;
807}
808
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000809class CircleInside2PtConicalEffect : public GrGradientEffect {
810public:
811
joshualittb0a8a372014-09-23 09:50:21 -0700812 static GrFragmentProcessor* Create(GrContext* ctx,
813 const SkTwoPointConicalGradient& shader,
814 const SkMatrix& matrix,
815 SkShader::TileMode tm,
816 const CircleConicalInfo& info) {
bsalomon4a339522015-10-06 08:40:50 -0700817 return new CircleInside2PtConicalEffect(ctx, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000818 }
819
820 virtual ~CircleInside2PtConicalEffect() {}
821
mtklein36352bf2015-03-25 18:17:31 -0700822 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800823
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000824 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
825 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
826 SkScalar A() const { return fInfo.fA; }
827 SkScalar B() const { return fInfo.fB; }
828 SkScalar C() const { return fInfo.fC; }
829
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000830private:
wangyixb1daa862015-08-18 11:29:31 -0700831 GrGLFragmentProcessor* onCreateGLInstance() const override;
832
wangyix4b3050b2015-08-04 07:59:37 -0700833 virtual void onGetGLProcessorKey(const GrGLSLCaps& caps,
834 GrProcessorKeyBuilder* b) const override;
835
mtklein36352bf2015-03-25 18:17:31 -0700836 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700837 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000838 return (INHERITED::onIsEqual(sBase) &&
839 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
840 this->fInfo.fA == s.fInfo.fA &&
841 this->fInfo.fB == s.fInfo.fB &&
842 this->fInfo.fC == s.fInfo.fC);
843 }
844
845 CircleInside2PtConicalEffect(GrContext* ctx,
846 const SkTwoPointConicalGradient& shader,
847 const SkMatrix& matrix,
848 SkShader::TileMode tm,
849 const CircleConicalInfo& info)
bsalomon4a339522015-10-06 08:40:50 -0700850 : INHERITED(ctx, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800851 this->initClassID<CircleInside2PtConicalEffect>();
852 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000853
joshualittb0a8a372014-09-23 09:50:21 -0700854 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000855
856 const CircleConicalInfo fInfo;
857
858 typedef GrGradientEffect INHERITED;
859};
860
861class GLCircleInside2PtConicalEffect : public GrGLGradientEffect {
862public:
joshualitteb2a6762014-12-04 11:35:33 -0800863 GLCircleInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000864 virtual ~GLCircleInside2PtConicalEffect() {}
865
wangyix7c157a92015-07-22 15:08:53 -0700866 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000867
jvanverthcfc18862015-04-28 08:48:20 -0700868 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000869
870protected:
egdaniel018fb622015-10-28 07:26:40 -0700871 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700872
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000873 UniformHandle fCenterUni;
874 UniformHandle fParamUni;
875
876 const char* fVSVaryingName;
877 const char* fFSVaryingName;
878
879 // @{
880 /// Values last uploaded as uniforms
881
882 SkScalar fCachedCenterX;
883 SkScalar fCachedCenterY;
884 SkScalar fCachedA;
885 SkScalar fCachedB;
886 SkScalar fCachedC;
887
888 // @}
889
890private:
891 typedef GrGLGradientEffect INHERITED;
892
893};
894
wangyix4b3050b2015-08-04 07:59:37 -0700895void CircleInside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
egdaniel2d721d32015-11-11 13:06:05 -0800896 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800897 GLCircleInside2PtConicalEffect::GenKey(*this, caps, b);
898}
899
wangyixb1daa862015-08-18 11:29:31 -0700900GrGLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700901 return new GLCircleInside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000902}
903
joshualittb0a8a372014-09-23 09:50:21 -0700904GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000905
joshualitt01258472014-09-22 10:29:30 -0700906/*
907 * All Two point conical gradient test create functions may occasionally create edge case shaders
908 */
bsalomonc21b09e2015-08-28 18:46:56 -0700909const GrFragmentProcessor* CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700910 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
911 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000912 SkPoint center2;
913 SkScalar radius2;
914 do {
joshualitt0067ff52015-07-08 14:26:19 -0700915 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000916 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700917 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000918 SkPoint diff = center2 - center1;
919 SkScalar diffLen = diff.length();
920 radius2 = radius1 + diffLen + increase;
921 // If the circles are identical the factory will give us an empty shader.
922 } while (radius1 == radius2 && center1 == center2);
923
924 SkColor colors[kMaxRandomGradientColors];
925 SkScalar stopsArray[kMaxRandomGradientColors];
926 SkScalar* stops = stopsArray;
927 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700928 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000929 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
930 center2, radius2,
931 colors, stops, colorCount,
932 tm));
bsalomonc21b09e2015-08-28 18:46:56 -0700933 const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
bsalomon4a339522015-10-06 08:40:50 -0700934 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality);
bsalomonc21b09e2015-08-28 18:46:56 -0700935 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -0700936 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000937}
938
joshualitteb2a6762014-12-04 11:35:33 -0800939GLCircleInside2PtConicalEffect::GLCircleInside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700940 : fVSVaryingName(nullptr)
941 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000942 , fCachedCenterX(SK_ScalarMax)
943 , fCachedCenterY(SK_ScalarMax)
944 , fCachedA(SK_ScalarMax)
945 , fCachedB(SK_ScalarMax)
946 , fCachedC(SK_ScalarMax) {}
947
wangyix7c157a92015-07-22 15:08:53 -0700948void GLCircleInside2PtConicalEffect::emitCode(EmitArgs& args) {
949 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
950 this->emitUniforms(args.fBuilder, ge);
egdaniel2d721d32015-11-11 13:06:05 -0800951 fCenterUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
952 kVec2f_GrSLType, kDefault_GrSLPrecision,
953 "Conical2FSCenter");
954 fParamUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
955 kVec3f_GrSLType, kDefault_GrSLPrecision,
956 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000957 SkString tName("t");
958
egdaniel0d3f0612015-10-21 10:45:48 -0700959 GrGLSLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000960 // params.x = A
961 // params.y = B
962 // params.z = C
egdaniel0d3f0612015-10-21 10:45:48 -0700963 GrGLSLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000964
965 // if we have a vec3 from being in perspective, convert it to a vec2 first
egdaniel2d721d32015-11-11 13:06:05 -0800966 GrGLSLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
wangyix7c157a92015-07-22 15:08:53 -0700967 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000968 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000969
970 // p = coords2D
971 // e = center end
972 // r = radius end
973 // A = dot(e, e) - r^2 + 2 * r - 1
974 // B = (r -1) / A
975 // C = 1 / A
976 // d = dot(e, p) + B
977 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
joshualitt30ba4362014-08-21 20:18:45 -0700978 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -0700979 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
980 params.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700981 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000982 tName.c_str(), params.c_str(), params.c_str());
983
wangyix7c157a92015-07-22 15:08:53 -0700984 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
985 args.fSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000986}
987
egdaniel018fb622015-10-28 07:26:40 -0700988void GLCircleInside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
989 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700990 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700991 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000992 SkScalar centerX = data.centerX();
993 SkScalar centerY = data.centerY();
994 SkScalar A = data.A();
995 SkScalar B = data.B();
996 SkScalar C = data.C();
997
998 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
999 fCachedA != A || fCachedB != B || fCachedC != C) {
1000
kkinnunen7510b222014-07-30 00:04:16 -07001001 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1002 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001003
1004 fCachedCenterX = centerX;
1005 fCachedCenterY = centerY;
1006 fCachedA = A;
1007 fCachedB = B;
1008 fCachedC = C;
1009 }
1010}
1011
joshualittb0a8a372014-09-23 09:50:21 -07001012void GLCircleInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001013 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001014 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001015}
1016
1017//////////////////////////////////////////////////////////////////////////////
1018
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001019class CircleOutside2PtConicalEffect : public GrGradientEffect {
1020public:
1021
joshualittb0a8a372014-09-23 09:50:21 -07001022 static GrFragmentProcessor* Create(GrContext* ctx,
1023 const SkTwoPointConicalGradient& shader,
1024 const SkMatrix& matrix,
1025 SkShader::TileMode tm,
1026 const CircleConicalInfo& info) {
bsalomon4a339522015-10-06 08:40:50 -07001027 return new CircleOutside2PtConicalEffect(ctx, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001028 }
1029
1030 virtual ~CircleOutside2PtConicalEffect() {}
1031
mtklein36352bf2015-03-25 18:17:31 -07001032 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001033
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001034 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1035 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1036 SkScalar A() const { return fInfo.fA; }
1037 SkScalar B() const { return fInfo.fB; }
1038 SkScalar C() const { return fInfo.fC; }
1039 SkScalar tLimit() const { return fTLimit; }
1040 bool isFlipped() const { return fIsFlipped; }
1041
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001042private:
wangyixb1daa862015-08-18 11:29:31 -07001043 GrGLFragmentProcessor* onCreateGLInstance() const override;
1044
wangyix4b3050b2015-08-04 07:59:37 -07001045 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
1046
mtklein36352bf2015-03-25 18:17:31 -07001047 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001048 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001049 return (INHERITED::onIsEqual(sBase) &&
1050 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1051 this->fInfo.fA == s.fInfo.fA &&
1052 this->fInfo.fB == s.fInfo.fB &&
1053 this->fInfo.fC == s.fInfo.fC &&
1054 this->fTLimit == s.fTLimit &&
1055 this->fIsFlipped == s.fIsFlipped);
1056 }
1057
1058 CircleOutside2PtConicalEffect(GrContext* ctx,
1059 const SkTwoPointConicalGradient& shader,
1060 const SkMatrix& matrix,
1061 SkShader::TileMode tm,
1062 const CircleConicalInfo& info)
bsalomon4a339522015-10-06 08:40:50 -07001063 : INHERITED(ctx, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001064 this->initClassID<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001065 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001066 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001067 } else {
1068 fTLimit = SK_ScalarMin;
1069 }
1070
1071 fIsFlipped = shader.isFlippedGrad();
1072 }
1073
joshualittb0a8a372014-09-23 09:50:21 -07001074 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001075
1076 const CircleConicalInfo fInfo;
1077 SkScalar fTLimit;
1078 bool fIsFlipped;
1079
1080 typedef GrGradientEffect INHERITED;
1081};
1082
1083class GLCircleOutside2PtConicalEffect : public GrGLGradientEffect {
1084public:
joshualitteb2a6762014-12-04 11:35:33 -08001085 GLCircleOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001086 virtual ~GLCircleOutside2PtConicalEffect() {}
1087
wangyix7c157a92015-07-22 15:08:53 -07001088 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001089
jvanverthcfc18862015-04-28 08:48:20 -07001090 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001091
1092protected:
egdaniel018fb622015-10-28 07:26:40 -07001093 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001094
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001095 UniformHandle fCenterUni;
1096 UniformHandle fParamUni;
1097
1098 const char* fVSVaryingName;
1099 const char* fFSVaryingName;
1100
1101 bool fIsFlipped;
1102
1103 // @{
1104 /// Values last uploaded as uniforms
1105
1106 SkScalar fCachedCenterX;
1107 SkScalar fCachedCenterY;
1108 SkScalar fCachedA;
1109 SkScalar fCachedB;
1110 SkScalar fCachedC;
1111 SkScalar fCachedTLimit;
1112
1113 // @}
1114
1115private:
1116 typedef GrGLGradientEffect INHERITED;
1117
1118};
1119
wangyix4b3050b2015-08-04 07:59:37 -07001120void CircleOutside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
egdaniel2d721d32015-11-11 13:06:05 -08001121 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001122 GLCircleOutside2PtConicalEffect::GenKey(*this, caps, b);
1123}
1124
wangyixb1daa862015-08-18 11:29:31 -07001125GrGLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001126 return new GLCircleOutside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001127}
1128
joshualittb0a8a372014-09-23 09:50:21 -07001129GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001130
joshualitt01258472014-09-22 10:29:30 -07001131/*
1132 * All Two point conical gradient test create functions may occasionally create edge case shaders
1133 */
bsalomonc21b09e2015-08-28 18:46:56 -07001134const GrFragmentProcessor* CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001135 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1136 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001137 SkPoint center2;
1138 SkScalar radius2;
1139 SkScalar diffLen;
1140 do {
joshualitt0067ff52015-07-08 14:26:19 -07001141 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001142 // If the circles share a center than we can't be in the outside case
1143 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001144 SkPoint diff = center2 - center1;
1145 diffLen = diff.length();
1146 // Below makes sure that circle one is not contained within circle two
1147 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001148 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001149
1150 SkColor colors[kMaxRandomGradientColors];
1151 SkScalar stopsArray[kMaxRandomGradientColors];
1152 SkScalar* stops = stopsArray;
1153 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -07001154 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001155 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
1156 center2, radius2,
1157 colors, stops, colorCount,
1158 tm));
bsalomonc21b09e2015-08-28 18:46:56 -07001159 const GrFragmentProcessor* fp = shader->asFragmentProcessor(
bsalomon4a339522015-10-06 08:40:50 -07001160 d->fContext,GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality);
bsalomonc21b09e2015-08-28 18:46:56 -07001161 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -07001162 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001163}
1164
joshualitteb2a6762014-12-04 11:35:33 -08001165GLCircleOutside2PtConicalEffect::GLCircleOutside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -07001166 : fVSVaryingName(nullptr)
1167 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001168 , fCachedCenterX(SK_ScalarMax)
1169 , fCachedCenterY(SK_ScalarMax)
1170 , fCachedA(SK_ScalarMax)
1171 , fCachedB(SK_ScalarMax)
1172 , fCachedC(SK_ScalarMax)
1173 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001174 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001175 fIsFlipped = data.isFlipped();
1176 }
1177
wangyix7c157a92015-07-22 15:08:53 -07001178void GLCircleOutside2PtConicalEffect::emitCode(EmitArgs& args) {
1179 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
1180 this->emitUniforms(args.fBuilder, ge);
egdaniel2d721d32015-11-11 13:06:05 -08001181 fCenterUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
1182 kVec2f_GrSLType, kDefault_GrSLPrecision,
1183 "Conical2FSCenter");
1184 fParamUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
1185 kVec4f_GrSLType, kDefault_GrSLPrecision,
1186 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001187 SkString tName("t");
1188
egdaniel0d3f0612015-10-21 10:45:48 -07001189 GrGLSLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001190 // params.x = A
1191 // params.y = B
1192 // params.z = C
egdaniel0d3f0612015-10-21 10:45:48 -07001193 GrGLSLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001194
1195 // if we have a vec3 from being in perspective, convert it to a vec2 first
egdaniel2d721d32015-11-11 13:06:05 -08001196 GrGLSLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
wangyix7c157a92015-07-22 15:08:53 -07001197 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001198 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001199
1200 // output will default to transparent black (we simply won't write anything
1201 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -07001202 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 +00001203
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001204 // p = coords2D
1205 // e = center end
1206 // r = radius end
1207 // A = dot(e, e) - r^2 + 2 * r - 1
1208 // B = (r -1) / A
1209 // C = 1 / A
1210 // d = dot(e, p) + B
1211 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001212
joshualitt30ba4362014-08-21 20:18:45 -07001213 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -07001214 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1215 params.c_str());
1216 fsBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1217 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001218
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001219 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1220 // If so we must also flip sign on sqrt
1221 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -07001222 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001223 } else {
joshualitt30ba4362014-08-21 20:18:45 -07001224 fsBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001225 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001226
joshualitt30ba4362014-08-21 20:18:45 -07001227 fsBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str());
1228 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -07001229 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
1230 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -07001231 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001232}
1233
egdaniel018fb622015-10-28 07:26:40 -07001234void GLCircleOutside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1235 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001236 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001237 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001238 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001239 SkScalar centerX = data.centerX();
1240 SkScalar centerY = data.centerY();
1241 SkScalar A = data.A();
1242 SkScalar B = data.B();
1243 SkScalar C = data.C();
1244 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001245
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001246 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1247 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001248
kkinnunen7510b222014-07-30 00:04:16 -07001249 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1250 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001251 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001252
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001253 fCachedCenterX = centerX;
1254 fCachedCenterY = centerY;
1255 fCachedA = A;
1256 fCachedB = B;
1257 fCachedC = C;
1258 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001259 }
1260}
1261
joshualittb0a8a372014-09-23 09:50:21 -07001262void GLCircleOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001263 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001264 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001265 key[0] = GenBaseGradientKey(processor);
1266 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001267}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001268
1269//////////////////////////////////////////////////////////////////////////////
1270
joshualittb0a8a372014-09-23 09:50:21 -07001271GrFragmentProcessor* Gr2PtConicalGradientEffect::Create(GrContext* ctx,
1272 const SkTwoPointConicalGradient& shader,
1273 SkShader::TileMode tm,
1274 const SkMatrix* localMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001275 SkMatrix matrix;
1276 if (!shader.getLocalMatrix().invert(&matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001277 return nullptr;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001278 }
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001279 if (localMatrix) {
1280 SkMatrix inv;
1281 if (!localMatrix->invert(&inv)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001282 return nullptr;
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001283 }
1284 matrix.postConcat(inv);
1285 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001286
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001287 if (shader.getStartRadius() < kErrorTol) {
1288 SkScalar focalX;
1289 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1290 if (type == kInside_ConicalType) {
bsalomon4a339522015-10-06 08:40:50 -07001291 return FocalInside2PtConicalEffect::Create(ctx, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001292 } else if(type == kEdge_ConicalType) {
1293 set_matrix_edge_conical(shader, &matrix);
bsalomon4a339522015-10-06 08:40:50 -07001294 return Edge2PtConicalEffect::Create(ctx, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001295 } else {
bsalomon4a339522015-10-06 08:40:50 -07001296 return FocalOutside2PtConicalEffect::Create(ctx, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001297 }
1298 }
1299
1300 CircleConicalInfo info;
1301 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1302
1303 if (type == kInside_ConicalType) {
bsalomon4a339522015-10-06 08:40:50 -07001304 return CircleInside2PtConicalEffect::Create(ctx, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001305 } else if (type == kEdge_ConicalType) {
1306 set_matrix_edge_conical(shader, &matrix);
bsalomon4a339522015-10-06 08:40:50 -07001307 return Edge2PtConicalEffect::Create(ctx, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001308 } else {
bsalomon4a339522015-10-06 08:40:50 -07001309 return CircleOutside2PtConicalEffect::Create(ctx, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001310 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001311}
1312
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001313#endif