blob: c88e75692c609c567a8baf0aa33448e2747cddc6 [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 */
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,
213 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality, d->fProcDataManager);
214 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);
227 fParamUni = args.fBuilder->addUniformArray(GrGLProgramBuilder::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;
wangyix7c157a92015-07-22 15:08:53 -0700245 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
246 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
wangyixb1daa862015-08-18 11:29:31 -0700278void GLEdge2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700279 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,
joshualitt9cc17752015-07-09 06:28:14 -0700371 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700372 const SkTwoPointConicalGradient& shader,
373 const SkMatrix& matrix,
374 SkShader::TileMode tm,
375 SkScalar focalX) {
halcanary385fe4d2015-08-26 13:07:48 -0700376 return new FocalOutside2PtConicalEffect(ctx, procDataManager, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000377 }
378
379 virtual ~FocalOutside2PtConicalEffect() { }
380
mtklein36352bf2015-03-25 18:17:31 -0700381 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800382 return "Two-Point Conical Gradient Focal Outside";
383 }
384
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000385 bool isFlipped() const { return fIsFlipped; }
386 SkScalar focal() const { return fFocalX; }
387
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000388private:
wangyixb1daa862015-08-18 11:29:31 -0700389 GrGLFragmentProcessor* onCreateGLInstance() const override;
390
wangyix4b3050b2015-08-04 07:59:37 -0700391 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
392
mtklein36352bf2015-03-25 18:17:31 -0700393 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700394 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000395 return (INHERITED::onIsEqual(sBase) &&
396 this->fFocalX == s.fFocalX &&
397 this->fIsFlipped == s.fIsFlipped);
398 }
399
400 FocalOutside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700401 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000402 const SkTwoPointConicalGradient& shader,
403 const SkMatrix& matrix,
404 SkShader::TileMode tm,
405 SkScalar focalX)
joshualitt9cc17752015-07-09 06:28:14 -0700406 : INHERITED(ctx, procDataManager, shader, matrix, tm)
joshualittb2456052015-07-08 09:36:59 -0700407 , fFocalX(focalX)
408 , fIsFlipped(shader.isFlippedGrad()) {
joshualitteb2a6762014-12-04 11:35:33 -0800409 this->initClassID<FocalOutside2PtConicalEffect>();
410 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000411
joshualittb0a8a372014-09-23 09:50:21 -0700412 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000413
414 SkScalar fFocalX;
415 bool fIsFlipped;
416
417 typedef GrGradientEffect INHERITED;
418};
419
420class GLFocalOutside2PtConicalEffect : public GrGLGradientEffect {
421public:
joshualitteb2a6762014-12-04 11:35:33 -0800422 GLFocalOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000423 virtual ~GLFocalOutside2PtConicalEffect() { }
424
wangyix7c157a92015-07-22 15:08:53 -0700425 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000426
jvanverthcfc18862015-04-28 08:48:20 -0700427 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000428
429protected:
wangyixb1daa862015-08-18 11:29:31 -0700430 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
431
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000432 UniformHandle fParamUni;
433
434 const char* fVSVaryingName;
435 const char* fFSVaryingName;
436
437 bool fIsFlipped;
438
439 // @{
440 /// Values last uploaded as uniforms
441
442 SkScalar fCachedFocal;
443
444 // @}
445
446private:
447 typedef GrGLGradientEffect INHERITED;
448
449};
450
wangyix4b3050b2015-08-04 07:59:37 -0700451void FocalOutside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800452 GrProcessorKeyBuilder* b) const {
453 GLFocalOutside2PtConicalEffect::GenKey(*this, caps, b);
454}
455
wangyixb1daa862015-08-18 11:29:31 -0700456GrGLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700457 return new GLFocalOutside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000458}
459
joshualittb0a8a372014-09-23 09:50:21 -0700460GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000461
joshualitt01258472014-09-22 10:29:30 -0700462/*
463 * All Two point conical gradient test create functions may occasionally create edge case shaders
464 */
bsalomonc21b09e2015-08-28 18:46:56 -0700465const GrFragmentProcessor* FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700466 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000467 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000468 SkPoint center2;
469 SkScalar radius2;
470 do {
joshualitt0067ff52015-07-08 14:26:19 -0700471 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000472 // 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 +0000473 } while (center1 == center2);
474 SkPoint diff = center2 - center1;
475 SkScalar diffLen = diff.length();
476 // Below makes sure that the focal point is not contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700477 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000478
479 SkColor colors[kMaxRandomGradientColors];
480 SkScalar stopsArray[kMaxRandomGradientColors];
481 SkScalar* stops = stopsArray;
482 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700483 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000484 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
485 center2, radius2,
486 colors, stops, colorCount,
487 tm));
bsalomonc21b09e2015-08-28 18:46:56 -0700488 const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
489 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality, d->fProcDataManager);
490 GrAlwaysAssert(fp);
491 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000492}
493
joshualitteb2a6762014-12-04 11:35:33 -0800494GLFocalOutside2PtConicalEffect::GLFocalOutside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700495 : fVSVaryingName(nullptr)
496 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000497 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700498 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000499 fIsFlipped = data.isFlipped();
500}
501
wangyix7c157a92015-07-22 15:08:53 -0700502void GLFocalOutside2PtConicalEffect::emitCode(EmitArgs& args) {
503 const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
504 this->emitUniforms(args.fBuilder, ge);
505 fParamUni = args.fBuilder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800506 kFloat_GrSLType, kDefault_GrSLPrecision,
507 "Conical2FSParams", 2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000508 SkString tName("t");
509 SkString p0; // focalX
510 SkString p1; // 1 - focalX * focalX
511
wangyix7c157a92015-07-22 15:08:53 -0700512 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
513 args.fBuilder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000514
515 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700516 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
517 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000518 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000519
520 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
521
522 // output will default to transparent black (we simply won't write anything
523 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -0700524 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 +0000525
joshualitt30ba4362014-08-21 20:18:45 -0700526 fsBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
527 fsBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
528 fsBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000529
530 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
531 // If so we must also flip sign on sqrt
532 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -0700533 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000534 coords2D, p0.c_str());
535 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700536 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000537 coords2D, p0.c_str());
538 }
539
joshualitt30ba4362014-08-21 20:18:45 -0700540 fsBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
541 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -0700542 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
543 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -0700544 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000545}
546
wangyixb1daa862015-08-18 11:29:31 -0700547void GLFocalOutside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700548 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700549 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700550 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000551 SkASSERT(data.isFlipped() == fIsFlipped);
552 SkScalar focal = data.focal();
553
554 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000555 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000556
557 float values[2] = {
558 SkScalarToFloat(focal),
559 SkScalarToFloat(oneMinus2F),
560 };
561
kkinnunen7510b222014-07-30 00:04:16 -0700562 pdman.set1fv(fParamUni, 2, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000563 fCachedFocal = focal;
564 }
565}
566
joshualittb0a8a372014-09-23 09:50:21 -0700567void GLFocalOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700568 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700569 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700570 key[0] = GenBaseGradientKey(processor);
571 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000572}
573
574//////////////////////////////////////////////////////////////////////////////
575
576class GLFocalInside2PtConicalEffect;
577
578class FocalInside2PtConicalEffect : public GrGradientEffect {
579public:
580
joshualittb0a8a372014-09-23 09:50:21 -0700581 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700582 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700583 const SkTwoPointConicalGradient& shader,
584 const SkMatrix& matrix,
585 SkShader::TileMode tm,
586 SkScalar focalX) {
halcanary385fe4d2015-08-26 13:07:48 -0700587 return new FocalInside2PtConicalEffect(ctx, procDataManager, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000588 }
589
590 virtual ~FocalInside2PtConicalEffect() {}
591
mtklein36352bf2015-03-25 18:17:31 -0700592 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800593 return "Two-Point Conical Gradient Focal Inside";
594 }
595
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000596 SkScalar focal() const { return fFocalX; }
597
joshualittb0a8a372014-09-23 09:50:21 -0700598 typedef GLFocalInside2PtConicalEffect GLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000599
600private:
wangyixb1daa862015-08-18 11:29:31 -0700601 GrGLFragmentProcessor* onCreateGLInstance() const override;
602
wangyix4b3050b2015-08-04 07:59:37 -0700603 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
604
mtklein36352bf2015-03-25 18:17:31 -0700605 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700606 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000607 return (INHERITED::onIsEqual(sBase) &&
608 this->fFocalX == s.fFocalX);
609 }
610
611 FocalInside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700612 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000613 const SkTwoPointConicalGradient& shader,
614 const SkMatrix& matrix,
615 SkShader::TileMode tm,
616 SkScalar focalX)
joshualitt9cc17752015-07-09 06:28:14 -0700617 : INHERITED(ctx, procDataManager, shader, matrix, tm), fFocalX(focalX) {
joshualitteb2a6762014-12-04 11:35:33 -0800618 this->initClassID<FocalInside2PtConicalEffect>();
619 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000620
joshualittb0a8a372014-09-23 09:50:21 -0700621 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000622
623 SkScalar fFocalX;
624
625 typedef GrGradientEffect INHERITED;
626};
627
628class GLFocalInside2PtConicalEffect : public GrGLGradientEffect {
629public:
joshualitteb2a6762014-12-04 11:35:33 -0800630 GLFocalInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000631 virtual ~GLFocalInside2PtConicalEffect() {}
632
wangyix7c157a92015-07-22 15:08:53 -0700633 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000634
jvanverthcfc18862015-04-28 08:48:20 -0700635 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000636
637protected:
wangyixb1daa862015-08-18 11:29:31 -0700638 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
639
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000640 UniformHandle fFocalUni;
641
642 const char* fVSVaryingName;
643 const char* fFSVaryingName;
644
645 // @{
646 /// Values last uploaded as uniforms
647
648 SkScalar fCachedFocal;
649
650 // @}
651
652private:
653 typedef GrGLGradientEffect INHERITED;
654
655};
656
wangyix4b3050b2015-08-04 07:59:37 -0700657void FocalInside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800658 GrProcessorKeyBuilder* b) const {
659 GLFocalInside2PtConicalEffect::GenKey(*this, caps, b);
660}
661
wangyixb1daa862015-08-18 11:29:31 -0700662GrGLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700663 return new GLFocalInside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000664}
665
joshualittb0a8a372014-09-23 09:50:21 -0700666GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000667
joshualitt01258472014-09-22 10:29:30 -0700668/*
669 * All Two point conical gradient test create functions may occasionally create edge case shaders
670 */
bsalomonc21b09e2015-08-28 18:46:56 -0700671const GrFragmentProcessor* FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700672 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000673 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000674 SkPoint center2;
675 SkScalar radius2;
676 do {
joshualitt0067ff52015-07-08 14:26:19 -0700677 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000678 // Below makes sure radius2 is larger enouch such that the focal point
679 // is inside the end circle
joshualitt0067ff52015-07-08 14:26:19 -0700680 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000681 SkPoint diff = center2 - center1;
682 SkScalar diffLen = diff.length();
683 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000684 // If the circles are identical the factory will give us an empty shader.
685 } while (radius1 == radius2 && center1 == center2);
686
687 SkColor colors[kMaxRandomGradientColors];
688 SkScalar stopsArray[kMaxRandomGradientColors];
689 SkScalar* stops = stopsArray;
690 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700691 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000692 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
693 center2, radius2,
694 colors, stops, colorCount,
695 tm));
bsalomonc21b09e2015-08-28 18:46:56 -0700696 const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
697 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality, d->fProcDataManager);
698 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700699 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000700}
701
joshualitteb2a6762014-12-04 11:35:33 -0800702GLFocalInside2PtConicalEffect::GLFocalInside2PtConicalEffect(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700703 : fVSVaryingName(nullptr)
704 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000705 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000706
wangyix7c157a92015-07-22 15:08:53 -0700707void GLFocalInside2PtConicalEffect::emitCode(EmitArgs& args) {
708 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
709 this->emitUniforms(args.fBuilder, ge);
710 fFocalUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800711 kFloat_GrSLType, kDefault_GrSLPrecision,
712 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000713 SkString tName("t");
714
715 // this is the distance along x-axis from the end center to focal point in
716 // transformed coordinates
wangyix7c157a92015-07-22 15:08:53 -0700717 GrGLShaderVar focal = args.fBuilder->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000718
719 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700720 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
721 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000722 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000723
724 // t = p.x * focalX + length(p)
joshualitt30ba4362014-08-21 20:18:45 -0700725 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000726 coords2D, focal.c_str(), coords2D);
727
wangyix7c157a92015-07-22 15:08:53 -0700728 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
729 args.fSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000730}
731
wangyixb1daa862015-08-18 11:29:31 -0700732void GLFocalInside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700733 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700734 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700735 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000736 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000737
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000738 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700739 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000740 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000741 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000742}
743
joshualittb0a8a372014-09-23 09:50:21 -0700744void GLFocalInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700745 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700746 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000747}
748
749//////////////////////////////////////////////////////////////////////////////
750// Circle Conical Gradients
751//////////////////////////////////////////////////////////////////////////////
752
753struct CircleConicalInfo {
754 SkPoint fCenterEnd;
755 SkScalar fA;
756 SkScalar fB;
757 SkScalar fC;
758};
759
760// Returns focal distance along x-axis in transformed coords
761static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
762 SkMatrix* invLMatrix, CircleConicalInfo* info) {
763 // Inverse of the current local matrix is passed in then,
764 // translate and scale such that start circle is on the origin and has radius 1
765 const SkPoint& centerStart = shader.getStartCenter();
766 const SkPoint& centerEnd = shader.getEndCenter();
767 SkScalar radiusStart = shader.getStartRadius();
768 SkScalar radiusEnd = shader.getEndRadius();
769
770 SkMatrix matrix;
771
772 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
773
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000774 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000775 matrix.postScale(invStartRad, invStartRad);
776
777 radiusEnd /= radiusStart;
778
779 SkPoint centerEndTrans;
780 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
781
782 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
783 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
784
785 // Check to see if start circle is inside end circle with edges touching.
786 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700787 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
788 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
789 // still accurate.
790 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000791 return kEdge_ConicalType;
792 }
793
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000794 SkScalar C = 1.f / A;
795 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000796
797 matrix.postScale(C, C);
798
799 invLMatrix->postConcat(matrix);
800
801 info->fCenterEnd = centerEndTrans;
802 info->fA = A;
803 info->fB = B;
804 info->fC = C;
805
806 // 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 +0000807 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000808 return kInside_ConicalType;
809 }
810 return kOutside_ConicalType;
811}
812
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000813class CircleInside2PtConicalEffect : public GrGradientEffect {
814public:
815
joshualittb0a8a372014-09-23 09:50:21 -0700816 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700817 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700818 const SkTwoPointConicalGradient& shader,
819 const SkMatrix& matrix,
820 SkShader::TileMode tm,
821 const CircleConicalInfo& info) {
halcanary385fe4d2015-08-26 13:07:48 -0700822 return new CircleInside2PtConicalEffect(ctx, procDataManager, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000823 }
824
825 virtual ~CircleInside2PtConicalEffect() {}
826
mtklein36352bf2015-03-25 18:17:31 -0700827 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800828
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000829 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
830 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
831 SkScalar A() const { return fInfo.fA; }
832 SkScalar B() const { return fInfo.fB; }
833 SkScalar C() const { return fInfo.fC; }
834
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000835private:
wangyixb1daa862015-08-18 11:29:31 -0700836 GrGLFragmentProcessor* onCreateGLInstance() const override;
837
wangyix4b3050b2015-08-04 07:59:37 -0700838 virtual void onGetGLProcessorKey(const GrGLSLCaps& caps,
839 GrProcessorKeyBuilder* b) const override;
840
mtklein36352bf2015-03-25 18:17:31 -0700841 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700842 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000843 return (INHERITED::onIsEqual(sBase) &&
844 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
845 this->fInfo.fA == s.fInfo.fA &&
846 this->fInfo.fB == s.fInfo.fB &&
847 this->fInfo.fC == s.fInfo.fC);
848 }
849
850 CircleInside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -0700851 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000852 const SkTwoPointConicalGradient& shader,
853 const SkMatrix& matrix,
854 SkShader::TileMode tm,
855 const CircleConicalInfo& info)
joshualitt9cc17752015-07-09 06:28:14 -0700856 : INHERITED(ctx, procDataManager, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800857 this->initClassID<CircleInside2PtConicalEffect>();
858 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000859
joshualittb0a8a372014-09-23 09:50:21 -0700860 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000861
862 const CircleConicalInfo fInfo;
863
864 typedef GrGradientEffect INHERITED;
865};
866
867class GLCircleInside2PtConicalEffect : public GrGLGradientEffect {
868public:
joshualitteb2a6762014-12-04 11:35:33 -0800869 GLCircleInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000870 virtual ~GLCircleInside2PtConicalEffect() {}
871
wangyix7c157a92015-07-22 15:08:53 -0700872 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000873
jvanverthcfc18862015-04-28 08:48:20 -0700874 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000875
876protected:
wangyixb1daa862015-08-18 11:29:31 -0700877 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
878
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000879 UniformHandle fCenterUni;
880 UniformHandle fParamUni;
881
882 const char* fVSVaryingName;
883 const char* fFSVaryingName;
884
885 // @{
886 /// Values last uploaded as uniforms
887
888 SkScalar fCachedCenterX;
889 SkScalar fCachedCenterY;
890 SkScalar fCachedA;
891 SkScalar fCachedB;
892 SkScalar fCachedC;
893
894 // @}
895
896private:
897 typedef GrGLGradientEffect INHERITED;
898
899};
900
wangyix4b3050b2015-08-04 07:59:37 -0700901void CircleInside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800902 GrProcessorKeyBuilder* b) const {
903 GLCircleInside2PtConicalEffect::GenKey(*this, caps, b);
904}
905
wangyixb1daa862015-08-18 11:29:31 -0700906GrGLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700907 return new GLCircleInside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000908}
909
joshualittb0a8a372014-09-23 09:50:21 -0700910GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000911
joshualitt01258472014-09-22 10:29:30 -0700912/*
913 * All Two point conical gradient test create functions may occasionally create edge case shaders
914 */
bsalomonc21b09e2015-08-28 18:46:56 -0700915const GrFragmentProcessor* CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700916 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
917 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000918 SkPoint center2;
919 SkScalar radius2;
920 do {
joshualitt0067ff52015-07-08 14:26:19 -0700921 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000922 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700923 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000924 SkPoint diff = center2 - center1;
925 SkScalar diffLen = diff.length();
926 radius2 = radius1 + diffLen + increase;
927 // If the circles are identical the factory will give us an empty shader.
928 } while (radius1 == radius2 && center1 == center2);
929
930 SkColor colors[kMaxRandomGradientColors];
931 SkScalar stopsArray[kMaxRandomGradientColors];
932 SkScalar* stops = stopsArray;
933 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700934 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000935 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
936 center2, radius2,
937 colors, stops, colorCount,
938 tm));
bsalomonc21b09e2015-08-28 18:46:56 -0700939 const GrFragmentProcessor* fp = shader->asFragmentProcessor(d->fContext,
940 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality, d->fProcDataManager);
941 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -0700942 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000943}
944
joshualitteb2a6762014-12-04 11:35:33 -0800945GLCircleInside2PtConicalEffect::GLCircleInside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700946 : fVSVaryingName(nullptr)
947 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000948 , fCachedCenterX(SK_ScalarMax)
949 , fCachedCenterY(SK_ScalarMax)
950 , fCachedA(SK_ScalarMax)
951 , fCachedB(SK_ScalarMax)
952 , fCachedC(SK_ScalarMax) {}
953
wangyix7c157a92015-07-22 15:08:53 -0700954void GLCircleInside2PtConicalEffect::emitCode(EmitArgs& args) {
955 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
956 this->emitUniforms(args.fBuilder, ge);
957 fCenterUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800958 kVec2f_GrSLType, kDefault_GrSLPrecision,
959 "Conical2FSCenter");
wangyix7c157a92015-07-22 15:08:53 -0700960 fParamUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800961 kVec3f_GrSLType, kDefault_GrSLPrecision,
962 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000963 SkString tName("t");
964
wangyix7c157a92015-07-22 15:08:53 -0700965 GrGLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000966 // params.x = A
967 // params.y = B
968 // params.z = C
wangyix7c157a92015-07-22 15:08:53 -0700969 GrGLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000970
971 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -0700972 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
973 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000974 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000975
976 // p = coords2D
977 // e = center end
978 // r = radius end
979 // A = dot(e, e) - r^2 + 2 * r - 1
980 // B = (r -1) / A
981 // C = 1 / A
982 // d = dot(e, p) + B
983 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
joshualitt30ba4362014-08-21 20:18:45 -0700984 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -0700985 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
986 params.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700987 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000988 tName.c_str(), params.c_str(), params.c_str());
989
wangyix7c157a92015-07-22 15:08:53 -0700990 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
991 args.fSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000992}
993
wangyixb1daa862015-08-18 11:29:31 -0700994void GLCircleInside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700995 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700996 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700997 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000998 SkScalar centerX = data.centerX();
999 SkScalar centerY = data.centerY();
1000 SkScalar A = data.A();
1001 SkScalar B = data.B();
1002 SkScalar C = data.C();
1003
1004 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1005 fCachedA != A || fCachedB != B || fCachedC != C) {
1006
kkinnunen7510b222014-07-30 00:04:16 -07001007 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1008 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001009
1010 fCachedCenterX = centerX;
1011 fCachedCenterY = centerY;
1012 fCachedA = A;
1013 fCachedB = B;
1014 fCachedC = C;
1015 }
1016}
1017
joshualittb0a8a372014-09-23 09:50:21 -07001018void GLCircleInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001019 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001020 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001021}
1022
1023//////////////////////////////////////////////////////////////////////////////
1024
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001025class CircleOutside2PtConicalEffect : public GrGradientEffect {
1026public:
1027
joshualittb0a8a372014-09-23 09:50:21 -07001028 static GrFragmentProcessor* Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -07001029 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -07001030 const SkTwoPointConicalGradient& shader,
1031 const SkMatrix& matrix,
1032 SkShader::TileMode tm,
1033 const CircleConicalInfo& info) {
halcanary385fe4d2015-08-26 13:07:48 -07001034 return new CircleOutside2PtConicalEffect(ctx, procDataManager, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001035 }
1036
1037 virtual ~CircleOutside2PtConicalEffect() {}
1038
mtklein36352bf2015-03-25 18:17:31 -07001039 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001040
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001041 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1042 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1043 SkScalar A() const { return fInfo.fA; }
1044 SkScalar B() const { return fInfo.fB; }
1045 SkScalar C() const { return fInfo.fC; }
1046 SkScalar tLimit() const { return fTLimit; }
1047 bool isFlipped() const { return fIsFlipped; }
1048
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001049private:
wangyixb1daa862015-08-18 11:29:31 -07001050 GrGLFragmentProcessor* onCreateGLInstance() const override;
1051
wangyix4b3050b2015-08-04 07:59:37 -07001052 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
1053
mtklein36352bf2015-03-25 18:17:31 -07001054 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001055 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001056 return (INHERITED::onIsEqual(sBase) &&
1057 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1058 this->fInfo.fA == s.fInfo.fA &&
1059 this->fInfo.fB == s.fInfo.fB &&
1060 this->fInfo.fC == s.fInfo.fC &&
1061 this->fTLimit == s.fTLimit &&
1062 this->fIsFlipped == s.fIsFlipped);
1063 }
1064
1065 CircleOutside2PtConicalEffect(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -07001066 GrProcessorDataManager* procDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001067 const SkTwoPointConicalGradient& shader,
1068 const SkMatrix& matrix,
1069 SkShader::TileMode tm,
1070 const CircleConicalInfo& info)
joshualitt9cc17752015-07-09 06:28:14 -07001071 : INHERITED(ctx, procDataManager, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001072 this->initClassID<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001073 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001074 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001075 } else {
1076 fTLimit = SK_ScalarMin;
1077 }
1078
1079 fIsFlipped = shader.isFlippedGrad();
1080 }
1081
joshualittb0a8a372014-09-23 09:50:21 -07001082 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001083
1084 const CircleConicalInfo fInfo;
1085 SkScalar fTLimit;
1086 bool fIsFlipped;
1087
1088 typedef GrGradientEffect INHERITED;
1089};
1090
1091class GLCircleOutside2PtConicalEffect : public GrGLGradientEffect {
1092public:
joshualitteb2a6762014-12-04 11:35:33 -08001093 GLCircleOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001094 virtual ~GLCircleOutside2PtConicalEffect() {}
1095
wangyix7c157a92015-07-22 15:08:53 -07001096 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001097
jvanverthcfc18862015-04-28 08:48:20 -07001098 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001099
1100protected:
wangyixb1daa862015-08-18 11:29:31 -07001101 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
1102
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001103 UniformHandle fCenterUni;
1104 UniformHandle fParamUni;
1105
1106 const char* fVSVaryingName;
1107 const char* fFSVaryingName;
1108
1109 bool fIsFlipped;
1110
1111 // @{
1112 /// Values last uploaded as uniforms
1113
1114 SkScalar fCachedCenterX;
1115 SkScalar fCachedCenterY;
1116 SkScalar fCachedA;
1117 SkScalar fCachedB;
1118 SkScalar fCachedC;
1119 SkScalar fCachedTLimit;
1120
1121 // @}
1122
1123private:
1124 typedef GrGLGradientEffect INHERITED;
1125
1126};
1127
wangyix4b3050b2015-08-04 07:59:37 -07001128void CircleOutside2PtConicalEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001129 GrProcessorKeyBuilder* b) const {
1130 GLCircleOutside2PtConicalEffect::GenKey(*this, caps, b);
1131}
1132
wangyixb1daa862015-08-18 11:29:31 -07001133GrGLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001134 return new GLCircleOutside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001135}
1136
joshualittb0a8a372014-09-23 09:50:21 -07001137GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001138
joshualitt01258472014-09-22 10:29:30 -07001139/*
1140 * All Two point conical gradient test create functions may occasionally create edge case shaders
1141 */
bsalomonc21b09e2015-08-28 18:46:56 -07001142const GrFragmentProcessor* CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001143 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1144 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001145 SkPoint center2;
1146 SkScalar radius2;
1147 SkScalar diffLen;
1148 do {
joshualitt0067ff52015-07-08 14:26:19 -07001149 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001150 // If the circles share a center than we can't be in the outside case
1151 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001152 SkPoint diff = center2 - center1;
1153 diffLen = diff.length();
1154 // Below makes sure that circle one is not contained within circle two
1155 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001156 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001157
1158 SkColor colors[kMaxRandomGradientColors];
1159 SkScalar stopsArray[kMaxRandomGradientColors];
1160 SkScalar* stops = stopsArray;
1161 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -07001162 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001163 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
1164 center2, radius2,
1165 colors, stops, colorCount,
1166 tm));
bsalomonc21b09e2015-08-28 18:46:56 -07001167 const GrFragmentProcessor* fp = shader->asFragmentProcessor(
1168 d->fContext,GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality,
1169 d->fProcDataManager);
1170 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -07001171 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001172}
1173
joshualitteb2a6762014-12-04 11:35:33 -08001174GLCircleOutside2PtConicalEffect::GLCircleOutside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -07001175 : fVSVaryingName(nullptr)
1176 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001177 , fCachedCenterX(SK_ScalarMax)
1178 , fCachedCenterY(SK_ScalarMax)
1179 , fCachedA(SK_ScalarMax)
1180 , fCachedB(SK_ScalarMax)
1181 , fCachedC(SK_ScalarMax)
1182 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001183 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001184 fIsFlipped = data.isFlipped();
1185 }
1186
wangyix7c157a92015-07-22 15:08:53 -07001187void GLCircleOutside2PtConicalEffect::emitCode(EmitArgs& args) {
1188 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
1189 this->emitUniforms(args.fBuilder, ge);
1190 fCenterUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001191 kVec2f_GrSLType, kDefault_GrSLPrecision,
1192 "Conical2FSCenter");
wangyix7c157a92015-07-22 15:08:53 -07001193 fParamUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001194 kVec4f_GrSLType, kDefault_GrSLPrecision,
1195 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001196 SkString tName("t");
1197
wangyix7c157a92015-07-22 15:08:53 -07001198 GrGLShaderVar center = args.fBuilder->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001199 // params.x = A
1200 // params.y = B
1201 // params.z = C
wangyix7c157a92015-07-22 15:08:53 -07001202 GrGLShaderVar params = args.fBuilder->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001203
1204 // if we have a vec3 from being in perspective, convert it to a vec2 first
wangyix7c157a92015-07-22 15:08:53 -07001205 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
1206 SkString coords2DString = fsBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001207 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001208
1209 // output will default to transparent black (we simply won't write anything
1210 // else to it if invalid, instead of discarding or returning prematurely)
wangyix7c157a92015-07-22 15:08:53 -07001211 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 +00001212
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001213 // p = coords2D
1214 // e = center end
1215 // r = radius end
1216 // A = dot(e, e) - r^2 + 2 * r - 1
1217 // B = (r -1) / A
1218 // C = 1 / A
1219 // d = dot(e, p) + B
1220 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001221
joshualitt30ba4362014-08-21 20:18:45 -07001222 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -07001223 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1224 params.c_str());
1225 fsBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1226 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001227
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001228 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1229 // If so we must also flip sign on sqrt
1230 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -07001231 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001232 } else {
joshualitt30ba4362014-08-21 20:18:45 -07001233 fsBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001234 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001235
joshualitt30ba4362014-08-21 20:18:45 -07001236 fsBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str());
1237 fsBuilder->codeAppend("\t\t");
wangyix7c157a92015-07-22 15:08:53 -07001238 this->emitColor(args.fBuilder, ge, tName.c_str(), args.fOutputColor, args.fInputColor,
1239 args.fSamplers);
joshualitt30ba4362014-08-21 20:18:45 -07001240 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001241}
1242
wangyixb1daa862015-08-18 11:29:31 -07001243void GLCircleOutside2PtConicalEffect::onSetData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001244 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001245 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001246 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001247 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001248 SkScalar centerX = data.centerX();
1249 SkScalar centerY = data.centerY();
1250 SkScalar A = data.A();
1251 SkScalar B = data.B();
1252 SkScalar C = data.C();
1253 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001254
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001255 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1256 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001257
kkinnunen7510b222014-07-30 00:04:16 -07001258 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1259 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001260 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001261
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001262 fCachedCenterX = centerX;
1263 fCachedCenterY = centerY;
1264 fCachedA = A;
1265 fCachedB = B;
1266 fCachedC = C;
1267 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001268 }
1269}
1270
joshualittb0a8a372014-09-23 09:50:21 -07001271void GLCircleOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001272 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001273 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001274 key[0] = GenBaseGradientKey(processor);
1275 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001276}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001277
1278//////////////////////////////////////////////////////////////////////////////
1279
joshualittb0a8a372014-09-23 09:50:21 -07001280GrFragmentProcessor* Gr2PtConicalGradientEffect::Create(GrContext* ctx,
joshualitt9cc17752015-07-09 06:28:14 -07001281 GrProcessorDataManager* procDataManager,
joshualittb0a8a372014-09-23 09:50:21 -07001282 const SkTwoPointConicalGradient& shader,
1283 SkShader::TileMode tm,
1284 const SkMatrix* localMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001285 SkMatrix matrix;
1286 if (!shader.getLocalMatrix().invert(&matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001287 return nullptr;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001288 }
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001289 if (localMatrix) {
1290 SkMatrix inv;
1291 if (!localMatrix->invert(&inv)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001292 return nullptr;
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001293 }
1294 matrix.postConcat(inv);
1295 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001296
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001297 if (shader.getStartRadius() < kErrorTol) {
1298 SkScalar focalX;
1299 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1300 if (type == kInside_ConicalType) {
joshualitt9cc17752015-07-09 06:28:14 -07001301 return FocalInside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001302 focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001303 } else if(type == kEdge_ConicalType) {
1304 set_matrix_edge_conical(shader, &matrix);
joshualitt9cc17752015-07-09 06:28:14 -07001305 return Edge2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001306 } else {
joshualitt9cc17752015-07-09 06:28:14 -07001307 return FocalOutside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001308 focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001309 }
1310 }
1311
1312 CircleConicalInfo info;
1313 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1314
1315 if (type == kInside_ConicalType) {
joshualitt9cc17752015-07-09 06:28:14 -07001316 return CircleInside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001317 info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001318 } else if (type == kEdge_ConicalType) {
1319 set_matrix_edge_conical(shader, &matrix);
joshualitt9cc17752015-07-09 06:28:14 -07001320 return Edge2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001321 } else {
joshualitt9cc17752015-07-09 06:28:14 -07001322 return CircleOutside2PtConicalEffect::Create(ctx, procDataManager, shader, matrix, tm,
joshualittb2456052015-07-08 09:36:59 -07001323 info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001324 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001325}
1326
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001327#endif