blob: 07722e972477a9093809a73a97ea80f1a361f6f6 [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,
joshualittb2456052015-07-08 09:36:59 -070062 GrShaderDataManager* shaderDataManager,
joshualittb0a8a372014-09-23 09:50:21 -070063 const SkTwoPointConicalGradient& shader,
64 const SkMatrix& matrix,
65 SkShader::TileMode tm) {
joshualittb2456052015-07-08 09:36:59 -070066 return SkNEW_ARGS(Edge2PtConicalEffect, (ctx, shaderDataManager, shader, matrix, tm));
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000067 }
68
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000069 virtual ~Edge2PtConicalEffect() {}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000070
mtklein36352bf2015-03-25 18:17:31 -070071 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -080072 return "Two-Point Conical Gradient Edge Touching";
73 }
74
jvanverthcfc18862015-04-28 08:48:20 -070075 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -080076
mtklein36352bf2015-03-25 18:17:31 -070077 GrGLFragmentProcessor* createGLInstance() const override;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000078
79 // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000080 SkScalar center() const { return fCenterX1; }
81 SkScalar diffRadius() const { return fDiffRadius; }
82 SkScalar radius() const { return fRadius0; }
83
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000084private:
mtklein36352bf2015-03-25 18:17:31 -070085 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -070086 const Edge2PtConicalEffect& s = sBase.cast<Edge2PtConicalEffect>();
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000087 return (INHERITED::onIsEqual(sBase) &&
88 this->fCenterX1 == s.fCenterX1 &&
89 this->fRadius0 == s.fRadius0 &&
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000090 this->fDiffRadius == s.fDiffRadius);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000091 }
92
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000093 Edge2PtConicalEffect(GrContext* ctx,
joshualittb2456052015-07-08 09:36:59 -070094 GrShaderDataManager* shaderDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000095 const SkTwoPointConicalGradient& shader,
96 const SkMatrix& matrix,
97 SkShader::TileMode tm)
joshualittb2456052015-07-08 09:36:59 -070098 : INHERITED(ctx, shaderDataManager, 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
joshualitt15988992014-10-09 15:04:05 -0700147 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -0700148 const GrFragmentProcessor&,
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000149 const char* outputColor,
150 const char* inputColor,
151 const TransformedCoordsArray&,
mtklein36352bf2015-03-25 18:17:31 -0700152 const TextureSamplerArray&) override;
153 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000154
jvanverthcfc18862015-04-28 08:48:20 -0700155 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000156
157protected:
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000158 UniformHandle fParamUni;
159
160 const char* fVSVaryingName;
161 const char* fFSVaryingName;
162
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000163 // @{
164 /// Values last uploaded as uniforms
165
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000166 SkScalar fCachedRadius;
167 SkScalar fCachedDiffRadius;
168
169 // @}
170
171private:
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000172 typedef GrGLGradientEffect INHERITED;
173
174};
175
jvanverthcfc18862015-04-28 08:48:20 -0700176void Edge2PtConicalEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800177 GrProcessorKeyBuilder* b) const {
178 GLEdge2PtConicalEffect::GenKey(*this, caps, b);
179}
180
181GrGLFragmentProcessor* Edge2PtConicalEffect::createGLInstance() const {
182 return SkNEW_ARGS(GLEdge2PtConicalEffect, (*this));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000183}
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000184
joshualittb0a8a372014-09-23 09:50:21 -0700185GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Edge2PtConicalEffect);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000186
joshualitt01258472014-09-22 10:29:30 -0700187/*
188 * All Two point conical gradient test create functions may occasionally create edge case shaders
189 */
joshualittb0a8a372014-09-23 09:50:21 -0700190GrFragmentProcessor* Edge2PtConicalEffect::TestCreate(SkRandom* random,
191 GrContext* context,
bsalomon4b91f762015-05-19 09:29:46 -0700192 const GrCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700193 GrTexture**) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000194 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
195 SkScalar radius1 = random->nextUScalar1();
196 SkPoint center2;
197 SkScalar radius2;
198 do {
199 center2.set(random->nextUScalar1(), random->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000200 // If the circles are identical the factory will give us an empty shader.
201 // This will happen if we pick identical centers
202 } while (center1 == center2);
203
204 // Below makes sure that circle one is contained within circle two
205 // and both circles are touching on an edge
206 SkPoint diff = center2 - center1;
207 SkScalar diffLen = diff.length();
208 radius2 = radius1 + diffLen;
209
210 SkColor colors[kMaxRandomGradientColors];
211 SkScalar stopsArray[kMaxRandomGradientColors];
212 SkScalar* stops = stopsArray;
213 SkShader::TileMode tm;
214 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
215 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
216 center2, radius2,
217 colors, stops, colorCount,
218 tm));
219 SkPaint paint;
joshualittb0a8a372014-09-23 09:50:21 -0700220 GrFragmentProcessor* fp;
bsalomon83d081a2014-07-08 09:56:10 -0700221 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -0700222 GrPaint grPaint;
joshualitt5531d512014-12-17 15:50:11 -0800223 SkAssertResult(shader->asFragmentProcessor(context, paint,
joshualitt4eaf9ce2015-04-28 13:31:18 -0700224 GrTest::TestMatrix(random), NULL,
joshualitt8ca93e72015-07-08 06:51:43 -0700225 &paintColor, grPaint.getShaderDataManager(), &fp));
joshualittb0a8a372014-09-23 09:50:21 -0700226 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000227}
228
joshualitteb2a6762014-12-04 11:35:33 -0800229GLEdge2PtConicalEffect::GLEdge2PtConicalEffect(const GrProcessor&)
230 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000231 , fFSVaryingName(NULL)
232 , fCachedRadius(-SK_ScalarMax)
233 , fCachedDiffRadius(-SK_ScalarMax) {}
234
joshualitt15988992014-10-09 15:04:05 -0700235void GLEdge2PtConicalEffect::emitCode(GrGLFPBuilder* builder,
joshualitt60030bc2014-11-25 14:21:55 -0800236 const GrFragmentProcessor& fp,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000237 const char* outputColor,
238 const char* inputColor,
239 const TransformedCoordsArray& coords,
240 const TextureSamplerArray& samplers) {
joshualitteb2a6762014-12-04 11:35:33 -0800241 const Edge2PtConicalEffect& ge = fp.cast<Edge2PtConicalEffect>();
joshualitt60030bc2014-11-25 14:21:55 -0800242 this->emitUniforms(builder, ge);
joshualitt30ba4362014-08-21 20:18:45 -0700243 fParamUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800244 kFloat_GrSLType, kDefault_GrSLPrecision,
245 "Conical2FSParams", 3);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000246
247 SkString cName("c");
248 SkString tName("t");
249 SkString p0; // start radius
250 SkString p1; // start radius squared
251 SkString p2; // difference in radii (r1 - r0)
252
253 builder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
254 builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
255 builder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
256
257 // We interpolate the linear component in coords[1].
joshualitt23e280d2014-09-18 12:26:38 -0700258 SkASSERT(coords[0].getType() == coords[1].getType());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000259 const char* coords2D;
260 SkString bVar;
egdaniel29bee0f2015-04-29 11:54:42 -0700261 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt23e280d2014-09-18 12:26:38 -0700262 if (kVec3f_GrSLType == coords[0].getType()) {
joshualitt30ba4362014-08-21 20:18:45 -0700263 fsBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
joshualitt49586be2014-09-16 08:21:41 -0700264 coords[0].c_str(), coords[0].c_str(), coords[1].c_str(),
265 coords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000266 coords2D = "interpolants.xy";
267 bVar = "interpolants.z";
268 } else {
269 coords2D = coords[0].c_str();
270 bVar.printf("%s.x", coords[1].c_str());
271 }
272
273 // output will default to transparent black (we simply won't write anything
274 // else to it if invalid, instead of discarding or returning prematurely)
joshualitt30ba4362014-08-21 20:18:45 -0700275 fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000276
277 // c = (x^2)+(y^2) - params[1]
joshualitt30ba4362014-08-21 20:18:45 -0700278 fsBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000279 cName.c_str(), coords2D, coords2D, p1.c_str());
280
281 // linear case: t = -c/b
joshualitt30ba4362014-08-21 20:18:45 -0700282 fsBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000283 cName.c_str(), bVar.c_str());
284
285 // if r(t) > 0, then t will be the x coordinate
joshualitt30ba4362014-08-21 20:18:45 -0700286 fsBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000287 p2.c_str(), p0.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700288 fsBuilder->codeAppend("\t");
joshualitt60030bc2014-11-25 14:21:55 -0800289 this->emitColor(builder, ge, tName.c_str(), outputColor, inputColor, samplers);
joshualitt30ba4362014-08-21 20:18:45 -0700290 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000291}
292
kkinnunen7510b222014-07-30 00:04:16 -0700293void GLEdge2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700294 const GrProcessor& processor) {
295 INHERITED::setData(pdman, processor);
296 const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000297 SkScalar radius0 = data.radius();
298 SkScalar diffRadius = data.diffRadius();
299
300 if (fCachedRadius != radius0 ||
301 fCachedDiffRadius != diffRadius) {
302
303 float values[3] = {
304 SkScalarToFloat(radius0),
305 SkScalarToFloat(SkScalarMul(radius0, radius0)),
306 SkScalarToFloat(diffRadius)
307 };
308
kkinnunen7510b222014-07-30 00:04:16 -0700309 pdman.set1fv(fParamUni, 3, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000310 fCachedRadius = radius0;
311 fCachedDiffRadius = diffRadius;
312 }
313}
314
joshualittb0a8a372014-09-23 09:50:21 -0700315void GLEdge2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700316 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700317 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000318}
319
320//////////////////////////////////////////////////////////////////////////////
321// Focal Conical Gradients
322//////////////////////////////////////////////////////////////////////////////
323
324static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
325 SkMatrix* invLMatrix, SkScalar* focalX) {
326 // Inverse of the current local matrix is passed in then,
327 // translate, scale, and rotate such that endCircle is unit circle on x-axis,
328 // and focal point is at the origin.
329 ConicalType conicalType;
330 const SkPoint& focal = shader.getStartCenter();
331 const SkPoint& centerEnd = shader.getEndCenter();
332 SkScalar radius = shader.getEndRadius();
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000333 SkScalar invRadius = 1.f / radius;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000334
335 SkMatrix matrix;
336
337 matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
338 matrix.postScale(invRadius, invRadius);
339
340 SkPoint focalTrans;
341 matrix.mapPoints(&focalTrans, &focal, 1);
342 *focalX = focalTrans.length();
343
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000344 if (0.f != *focalX) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000345 SkScalar invFocalX = SkScalarInvert(*focalX);
346 SkMatrix rot;
347 rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY),
348 SkScalarMul(invFocalX, focalTrans.fX));
349 matrix.postConcat(rot);
350 }
351
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000352 matrix.postTranslate(-(*focalX), 0.f);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000353
354 // If the focal point is touching the edge of the circle it will
355 // cause a degenerate case that must be handled separately
egdaniel8405ef92014-06-09 11:57:28 -0700356 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
357 // stability trade off versus the linear approx used in the Edge Shader
358 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000359 return kEdge_ConicalType;
360 }
361
362 // Scale factor 1 / (1 - focalX * focalX)
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000363 SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX);
reed80ea19c2015-05-12 10:37:34 -0700364 SkScalar s = SkScalarInvert(oneMinusF2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000365
366
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000367 if (s >= 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000368 conicalType = kInside_ConicalType;
369 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
370 } else {
371 conicalType = kOutside_ConicalType;
372 matrix.postScale(s, s);
373 }
374
375 invLMatrix->postConcat(matrix);
376
377 return conicalType;
378}
379
380//////////////////////////////////////////////////////////////////////////////
381
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000382class FocalOutside2PtConicalEffect : public GrGradientEffect {
383public:
384
joshualittb0a8a372014-09-23 09:50:21 -0700385 static GrFragmentProcessor* Create(GrContext* ctx,
joshualittb2456052015-07-08 09:36:59 -0700386 GrShaderDataManager* shaderDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700387 const SkTwoPointConicalGradient& shader,
388 const SkMatrix& matrix,
389 SkShader::TileMode tm,
390 SkScalar focalX) {
joshualittb2456052015-07-08 09:36:59 -0700391 return SkNEW_ARGS(FocalOutside2PtConicalEffect, (ctx, shaderDataManager, shader, matrix, tm,
392 focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000393 }
394
395 virtual ~FocalOutside2PtConicalEffect() { }
396
mtklein36352bf2015-03-25 18:17:31 -0700397 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800398 return "Two-Point Conical Gradient Focal Outside";
399 }
400
jvanverthcfc18862015-04-28 08:48:20 -0700401 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800402
mtklein36352bf2015-03-25 18:17:31 -0700403 GrGLFragmentProcessor* createGLInstance() const override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000404
405 bool isFlipped() const { return fIsFlipped; }
406 SkScalar focal() const { return fFocalX; }
407
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000408private:
mtklein36352bf2015-03-25 18:17:31 -0700409 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700410 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000411 return (INHERITED::onIsEqual(sBase) &&
412 this->fFocalX == s.fFocalX &&
413 this->fIsFlipped == s.fIsFlipped);
414 }
415
416 FocalOutside2PtConicalEffect(GrContext* ctx,
joshualittb2456052015-07-08 09:36:59 -0700417 GrShaderDataManager* shaderDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000418 const SkTwoPointConicalGradient& shader,
419 const SkMatrix& matrix,
420 SkShader::TileMode tm,
421 SkScalar focalX)
joshualittb2456052015-07-08 09:36:59 -0700422 : INHERITED(ctx, shaderDataManager, shader, matrix, tm)
423 , fFocalX(focalX)
424 , fIsFlipped(shader.isFlippedGrad()) {
joshualitteb2a6762014-12-04 11:35:33 -0800425 this->initClassID<FocalOutside2PtConicalEffect>();
426 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000427
joshualittb0a8a372014-09-23 09:50:21 -0700428 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000429
430 SkScalar fFocalX;
431 bool fIsFlipped;
432
433 typedef GrGradientEffect INHERITED;
434};
435
436class GLFocalOutside2PtConicalEffect : public GrGLGradientEffect {
437public:
joshualitteb2a6762014-12-04 11:35:33 -0800438 GLFocalOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000439 virtual ~GLFocalOutside2PtConicalEffect() { }
440
joshualitt15988992014-10-09 15:04:05 -0700441 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -0700442 const GrFragmentProcessor&,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000443 const char* outputColor,
444 const char* inputColor,
445 const TransformedCoordsArray&,
mtklein36352bf2015-03-25 18:17:31 -0700446 const TextureSamplerArray&) override;
447 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000448
jvanverthcfc18862015-04-28 08:48:20 -0700449 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000450
451protected:
452 UniformHandle fParamUni;
453
454 const char* fVSVaryingName;
455 const char* fFSVaryingName;
456
457 bool fIsFlipped;
458
459 // @{
460 /// Values last uploaded as uniforms
461
462 SkScalar fCachedFocal;
463
464 // @}
465
466private:
467 typedef GrGLGradientEffect INHERITED;
468
469};
470
jvanverthcfc18862015-04-28 08:48:20 -0700471void FocalOutside2PtConicalEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800472 GrProcessorKeyBuilder* b) const {
473 GLFocalOutside2PtConicalEffect::GenKey(*this, caps, b);
474}
475
476GrGLFragmentProcessor* FocalOutside2PtConicalEffect::createGLInstance() const {
477 return SkNEW_ARGS(GLFocalOutside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000478}
479
joshualittb0a8a372014-09-23 09:50:21 -0700480GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000481
joshualitt01258472014-09-22 10:29:30 -0700482/*
483 * All Two point conical gradient test create functions may occasionally create edge case shaders
484 */
joshualittb0a8a372014-09-23 09:50:21 -0700485GrFragmentProcessor* FocalOutside2PtConicalEffect::TestCreate(SkRandom* random,
486 GrContext* context,
bsalomon4b91f762015-05-19 09:29:46 -0700487 const GrCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700488 GrTexture**) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000489 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000490 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000491 SkPoint center2;
492 SkScalar radius2;
493 do {
494 center2.set(random->nextUScalar1(), random->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000495 // 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 +0000496 } while (center1 == center2);
497 SkPoint diff = center2 - center1;
498 SkScalar diffLen = diff.length();
499 // Below makes sure that the focal point is not contained within circle two
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000500 radius2 = random->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000501
502 SkColor colors[kMaxRandomGradientColors];
503 SkScalar stopsArray[kMaxRandomGradientColors];
504 SkScalar* stops = stopsArray;
505 SkShader::TileMode tm;
506 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
507 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
508 center2, radius2,
509 colors, stops, colorCount,
510 tm));
511 SkPaint paint;
joshualittb0a8a372014-09-23 09:50:21 -0700512 GrFragmentProcessor* effect;
bsalomon83d081a2014-07-08 09:56:10 -0700513 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -0700514 GrPaint grPaint;
joshualitt5531d512014-12-17 15:50:11 -0800515 SkAssertResult(shader->asFragmentProcessor(context, paint,
joshualitt4eaf9ce2015-04-28 13:31:18 -0700516 GrTest::TestMatrix(random), NULL,
joshualitt8ca93e72015-07-08 06:51:43 -0700517 &paintColor, grPaint.getShaderDataManager(),
518 &effect));
dandov9de5b512014-06-10 14:38:28 -0700519 return effect;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000520}
521
joshualitteb2a6762014-12-04 11:35:33 -0800522GLFocalOutside2PtConicalEffect::GLFocalOutside2PtConicalEffect(const GrProcessor& processor)
523 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000524 , fFSVaryingName(NULL)
525 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700526 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000527 fIsFlipped = data.isFlipped();
528}
529
joshualitt15988992014-10-09 15:04:05 -0700530void GLFocalOutside2PtConicalEffect::emitCode(GrGLFPBuilder* builder,
joshualitt60030bc2014-11-25 14:21:55 -0800531 const GrFragmentProcessor& fp,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000532 const char* outputColor,
533 const char* inputColor,
534 const TransformedCoordsArray& coords,
535 const TextureSamplerArray& samplers) {
joshualitteb2a6762014-12-04 11:35:33 -0800536 const FocalOutside2PtConicalEffect& ge = fp.cast<FocalOutside2PtConicalEffect>();
joshualitt60030bc2014-11-25 14:21:55 -0800537 this->emitUniforms(builder, ge);
joshualitt30ba4362014-08-21 20:18:45 -0700538 fParamUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800539 kFloat_GrSLType, kDefault_GrSLPrecision,
540 "Conical2FSParams", 2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000541 SkString tName("t");
542 SkString p0; // focalX
543 SkString p1; // 1 - focalX * focalX
544
545 builder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
546 builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
547
548 // if we have a vec3 from being in perspective, convert it to a vec2 first
egdaniel29bee0f2015-04-29 11:54:42 -0700549 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -0700550 SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000551 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000552
553 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
554
555 // output will default to transparent black (we simply won't write anything
556 // else to it if invalid, instead of discarding or returning prematurely)
joshualitt30ba4362014-08-21 20:18:45 -0700557 fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000558
joshualitt30ba4362014-08-21 20:18:45 -0700559 fsBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
560 fsBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
561 fsBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000562
563 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
564 // If so we must also flip sign on sqrt
565 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -0700566 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000567 coords2D, p0.c_str());
568 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700569 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000570 coords2D, p0.c_str());
571 }
572
joshualitt30ba4362014-08-21 20:18:45 -0700573 fsBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
574 fsBuilder->codeAppend("\t\t");
joshualitt60030bc2014-11-25 14:21:55 -0800575 this->emitColor(builder, ge, tName.c_str(), outputColor, inputColor, samplers);
joshualitt30ba4362014-08-21 20:18:45 -0700576 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000577}
578
kkinnunen7510b222014-07-30 00:04:16 -0700579void GLFocalOutside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700580 const GrProcessor& processor) {
581 INHERITED::setData(pdman, processor);
582 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000583 SkASSERT(data.isFlipped() == fIsFlipped);
584 SkScalar focal = data.focal();
585
586 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000587 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000588
589 float values[2] = {
590 SkScalarToFloat(focal),
591 SkScalarToFloat(oneMinus2F),
592 };
593
kkinnunen7510b222014-07-30 00:04:16 -0700594 pdman.set1fv(fParamUni, 2, values);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000595 fCachedFocal = focal;
596 }
597}
598
joshualittb0a8a372014-09-23 09:50:21 -0700599void GLFocalOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700600 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700601 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700602 key[0] = GenBaseGradientKey(processor);
603 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000604}
605
606//////////////////////////////////////////////////////////////////////////////
607
608class GLFocalInside2PtConicalEffect;
609
610class FocalInside2PtConicalEffect : public GrGradientEffect {
611public:
612
joshualittb0a8a372014-09-23 09:50:21 -0700613 static GrFragmentProcessor* Create(GrContext* ctx,
joshualittb2456052015-07-08 09:36:59 -0700614 GrShaderDataManager* shaderDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700615 const SkTwoPointConicalGradient& shader,
616 const SkMatrix& matrix,
617 SkShader::TileMode tm,
618 SkScalar focalX) {
joshualittb2456052015-07-08 09:36:59 -0700619 return SkNEW_ARGS(FocalInside2PtConicalEffect, (ctx, shaderDataManager, shader, matrix, tm,
620 focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000621 }
622
623 virtual ~FocalInside2PtConicalEffect() {}
624
mtklein36352bf2015-03-25 18:17:31 -0700625 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800626 return "Two-Point Conical Gradient Focal Inside";
627 }
628
jvanverthcfc18862015-04-28 08:48:20 -0700629 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800630
mtklein36352bf2015-03-25 18:17:31 -0700631 GrGLFragmentProcessor* createGLInstance() const override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000632
633 SkScalar focal() const { return fFocalX; }
634
joshualittb0a8a372014-09-23 09:50:21 -0700635 typedef GLFocalInside2PtConicalEffect GLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000636
637private:
mtklein36352bf2015-03-25 18:17:31 -0700638 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700639 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000640 return (INHERITED::onIsEqual(sBase) &&
641 this->fFocalX == s.fFocalX);
642 }
643
644 FocalInside2PtConicalEffect(GrContext* ctx,
joshualittb2456052015-07-08 09:36:59 -0700645 GrShaderDataManager* shaderDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000646 const SkTwoPointConicalGradient& shader,
647 const SkMatrix& matrix,
648 SkShader::TileMode tm,
649 SkScalar focalX)
joshualittb2456052015-07-08 09:36:59 -0700650 : INHERITED(ctx, shaderDataManager, shader, matrix, tm), fFocalX(focalX) {
joshualitteb2a6762014-12-04 11:35:33 -0800651 this->initClassID<FocalInside2PtConicalEffect>();
652 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000653
joshualittb0a8a372014-09-23 09:50:21 -0700654 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000655
656 SkScalar fFocalX;
657
658 typedef GrGradientEffect INHERITED;
659};
660
661class GLFocalInside2PtConicalEffect : public GrGLGradientEffect {
662public:
joshualitteb2a6762014-12-04 11:35:33 -0800663 GLFocalInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000664 virtual ~GLFocalInside2PtConicalEffect() {}
665
joshualitt15988992014-10-09 15:04:05 -0700666 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -0700667 const GrFragmentProcessor&,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000668 const char* outputColor,
669 const char* inputColor,
670 const TransformedCoordsArray&,
mtklein36352bf2015-03-25 18:17:31 -0700671 const TextureSamplerArray&) override;
672 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000673
jvanverthcfc18862015-04-28 08:48:20 -0700674 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000675
676protected:
677 UniformHandle fFocalUni;
678
679 const char* fVSVaryingName;
680 const char* fFSVaryingName;
681
682 // @{
683 /// Values last uploaded as uniforms
684
685 SkScalar fCachedFocal;
686
687 // @}
688
689private:
690 typedef GrGLGradientEffect INHERITED;
691
692};
693
jvanverthcfc18862015-04-28 08:48:20 -0700694void FocalInside2PtConicalEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800695 GrProcessorKeyBuilder* b) const {
696 GLFocalInside2PtConicalEffect::GenKey(*this, caps, b);
697}
698
699GrGLFragmentProcessor* FocalInside2PtConicalEffect::createGLInstance() const {
700 return SkNEW_ARGS(GLFocalInside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000701}
702
joshualittb0a8a372014-09-23 09:50:21 -0700703GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000704
joshualitt01258472014-09-22 10:29:30 -0700705/*
706 * All Two point conical gradient test create functions may occasionally create edge case shaders
707 */
joshualittb0a8a372014-09-23 09:50:21 -0700708GrFragmentProcessor* FocalInside2PtConicalEffect::TestCreate(SkRandom* random,
709 GrContext* context,
bsalomon4b91f762015-05-19 09:29:46 -0700710 const GrCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700711 GrTexture**) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000712 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000713 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000714 SkPoint center2;
715 SkScalar radius2;
716 do {
717 center2.set(random->nextUScalar1(), random->nextUScalar1());
718 // Below makes sure radius2 is larger enouch such that the focal point
719 // is inside the end circle
720 SkScalar increase = random->nextUScalar1();
721 SkPoint diff = center2 - center1;
722 SkScalar diffLen = diff.length();
723 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000724 // If the circles are identical the factory will give us an empty shader.
725 } while (radius1 == radius2 && center1 == center2);
726
727 SkColor colors[kMaxRandomGradientColors];
728 SkScalar stopsArray[kMaxRandomGradientColors];
729 SkScalar* stops = stopsArray;
730 SkShader::TileMode tm;
731 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
732 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
733 center2, radius2,
734 colors, stops, colorCount,
735 tm));
736 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700737 GrColor paintColor;
joshualittb0a8a372014-09-23 09:50:21 -0700738 GrFragmentProcessor* fp;
joshualitt8ca93e72015-07-08 06:51:43 -0700739 GrPaint grPaint;
joshualitt5531d512014-12-17 15:50:11 -0800740 SkAssertResult(shader->asFragmentProcessor(context, paint,
joshualitt4eaf9ce2015-04-28 13:31:18 -0700741 GrTest::TestMatrix(random), NULL,
joshualitt8ca93e72015-07-08 06:51:43 -0700742 &paintColor, grPaint.getShaderDataManager(), &fp));
joshualittb0a8a372014-09-23 09:50:21 -0700743 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000744}
745
joshualitteb2a6762014-12-04 11:35:33 -0800746GLFocalInside2PtConicalEffect::GLFocalInside2PtConicalEffect(const GrProcessor&)
747 : fVSVaryingName(NULL)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000748 , fFSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000749 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000750
joshualitt15988992014-10-09 15:04:05 -0700751void GLFocalInside2PtConicalEffect::emitCode(GrGLFPBuilder* builder,
joshualitt60030bc2014-11-25 14:21:55 -0800752 const GrFragmentProcessor& fp,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000753 const char* outputColor,
754 const char* inputColor,
755 const TransformedCoordsArray& coords,
756 const TextureSamplerArray& samplers) {
joshualitteb2a6762014-12-04 11:35:33 -0800757 const FocalInside2PtConicalEffect& ge = fp.cast<FocalInside2PtConicalEffect>();
joshualitt60030bc2014-11-25 14:21:55 -0800758 this->emitUniforms(builder, ge);
joshualitt30ba4362014-08-21 20:18:45 -0700759 fFocalUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800760 kFloat_GrSLType, kDefault_GrSLPrecision,
761 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000762 SkString tName("t");
763
764 // this is the distance along x-axis from the end center to focal point in
765 // transformed coordinates
766 GrGLShaderVar focal = builder->getUniformVariable(fFocalUni);
767
768 // if we have a vec3 from being in perspective, convert it to a vec2 first
egdaniel29bee0f2015-04-29 11:54:42 -0700769 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -0700770 SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000771 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000772
773 // t = p.x * focalX + length(p)
joshualitt30ba4362014-08-21 20:18:45 -0700774 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000775 coords2D, focal.c_str(), coords2D);
776
joshualitt60030bc2014-11-25 14:21:55 -0800777 this->emitColor(builder, ge, tName.c_str(), outputColor, inputColor, samplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000778}
779
kkinnunen7510b222014-07-30 00:04:16 -0700780void GLFocalInside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -0700781 const GrProcessor& processor) {
782 INHERITED::setData(pdman, processor);
783 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000784 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000785
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000786 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700787 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000788 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000789 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000790}
791
joshualittb0a8a372014-09-23 09:50:21 -0700792void GLFocalInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700793 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700794 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000795}
796
797//////////////////////////////////////////////////////////////////////////////
798// Circle Conical Gradients
799//////////////////////////////////////////////////////////////////////////////
800
801struct CircleConicalInfo {
802 SkPoint fCenterEnd;
803 SkScalar fA;
804 SkScalar fB;
805 SkScalar fC;
806};
807
808// Returns focal distance along x-axis in transformed coords
809static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
810 SkMatrix* invLMatrix, CircleConicalInfo* info) {
811 // Inverse of the current local matrix is passed in then,
812 // translate and scale such that start circle is on the origin and has radius 1
813 const SkPoint& centerStart = shader.getStartCenter();
814 const SkPoint& centerEnd = shader.getEndCenter();
815 SkScalar radiusStart = shader.getStartRadius();
816 SkScalar radiusEnd = shader.getEndRadius();
817
818 SkMatrix matrix;
819
820 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
821
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000822 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000823 matrix.postScale(invStartRad, invStartRad);
824
825 radiusEnd /= radiusStart;
826
827 SkPoint centerEndTrans;
828 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
829
830 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
831 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
832
833 // Check to see if start circle is inside end circle with edges touching.
834 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700835 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
836 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
837 // still accurate.
838 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000839 return kEdge_ConicalType;
840 }
841
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000842 SkScalar C = 1.f / A;
843 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000844
845 matrix.postScale(C, C);
846
847 invLMatrix->postConcat(matrix);
848
849 info->fCenterEnd = centerEndTrans;
850 info->fA = A;
851 info->fB = B;
852 info->fC = C;
853
854 // 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 +0000855 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000856 return kInside_ConicalType;
857 }
858 return kOutside_ConicalType;
859}
860
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000861class CircleInside2PtConicalEffect : public GrGradientEffect {
862public:
863
joshualittb0a8a372014-09-23 09:50:21 -0700864 static GrFragmentProcessor* Create(GrContext* ctx,
joshualittb2456052015-07-08 09:36:59 -0700865 GrShaderDataManager* shaderDataManager,
joshualittb0a8a372014-09-23 09:50:21 -0700866 const SkTwoPointConicalGradient& shader,
867 const SkMatrix& matrix,
868 SkShader::TileMode tm,
869 const CircleConicalInfo& info) {
joshualittb2456052015-07-08 09:36:59 -0700870 return SkNEW_ARGS(CircleInside2PtConicalEffect, (ctx, shaderDataManager, shader, matrix, tm,
871 info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000872 }
873
874 virtual ~CircleInside2PtConicalEffect() {}
875
mtklein36352bf2015-03-25 18:17:31 -0700876 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800877
jvanverthcfc18862015-04-28 08:48:20 -0700878 virtual void getGLProcessorKey(const GrGLSLCaps& caps,
mtklein36352bf2015-03-25 18:17:31 -0700879 GrProcessorKeyBuilder* b) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800880
mtklein36352bf2015-03-25 18:17:31 -0700881 GrGLFragmentProcessor* createGLInstance() const override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000882
883 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
884 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
885 SkScalar A() const { return fInfo.fA; }
886 SkScalar B() const { return fInfo.fB; }
887 SkScalar C() const { return fInfo.fC; }
888
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000889private:
mtklein36352bf2015-03-25 18:17:31 -0700890 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700891 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000892 return (INHERITED::onIsEqual(sBase) &&
893 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
894 this->fInfo.fA == s.fInfo.fA &&
895 this->fInfo.fB == s.fInfo.fB &&
896 this->fInfo.fC == s.fInfo.fC);
897 }
898
899 CircleInside2PtConicalEffect(GrContext* ctx,
joshualittb2456052015-07-08 09:36:59 -0700900 GrShaderDataManager* shaderDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000901 const SkTwoPointConicalGradient& shader,
902 const SkMatrix& matrix,
903 SkShader::TileMode tm,
904 const CircleConicalInfo& info)
joshualittb2456052015-07-08 09:36:59 -0700905 : INHERITED(ctx, shaderDataManager, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800906 this->initClassID<CircleInside2PtConicalEffect>();
907 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000908
joshualittb0a8a372014-09-23 09:50:21 -0700909 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000910
911 const CircleConicalInfo fInfo;
912
913 typedef GrGradientEffect INHERITED;
914};
915
916class GLCircleInside2PtConicalEffect : public GrGLGradientEffect {
917public:
joshualitteb2a6762014-12-04 11:35:33 -0800918 GLCircleInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000919 virtual ~GLCircleInside2PtConicalEffect() {}
920
joshualitt15988992014-10-09 15:04:05 -0700921 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -0700922 const GrFragmentProcessor&,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000923 const char* outputColor,
924 const char* inputColor,
925 const TransformedCoordsArray&,
mtklein36352bf2015-03-25 18:17:31 -0700926 const TextureSamplerArray&) override;
927 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000928
jvanverthcfc18862015-04-28 08:48:20 -0700929 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000930
931protected:
932 UniformHandle fCenterUni;
933 UniformHandle fParamUni;
934
935 const char* fVSVaryingName;
936 const char* fFSVaryingName;
937
938 // @{
939 /// Values last uploaded as uniforms
940
941 SkScalar fCachedCenterX;
942 SkScalar fCachedCenterY;
943 SkScalar fCachedA;
944 SkScalar fCachedB;
945 SkScalar fCachedC;
946
947 // @}
948
949private:
950 typedef GrGLGradientEffect INHERITED;
951
952};
953
jvanverthcfc18862015-04-28 08:48:20 -0700954void CircleInside2PtConicalEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800955 GrProcessorKeyBuilder* b) const {
956 GLCircleInside2PtConicalEffect::GenKey(*this, caps, b);
957}
958
959GrGLFragmentProcessor* CircleInside2PtConicalEffect::createGLInstance() const {
960 return SkNEW_ARGS(GLCircleInside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000961}
962
joshualittb0a8a372014-09-23 09:50:21 -0700963GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000964
joshualitt01258472014-09-22 10:29:30 -0700965/*
966 * All Two point conical gradient test create functions may occasionally create edge case shaders
967 */
joshualittb0a8a372014-09-23 09:50:21 -0700968GrFragmentProcessor* CircleInside2PtConicalEffect::TestCreate(SkRandom* random,
969 GrContext* context,
bsalomon4b91f762015-05-19 09:29:46 -0700970 const GrCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700971 GrTexture**) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000972 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000973 SkScalar radius1 = random->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000974 SkPoint center2;
975 SkScalar radius2;
976 do {
977 center2.set(random->nextUScalar1(), random->nextUScalar1());
978 // Below makes sure that circle one is contained within circle two
979 SkScalar increase = random->nextUScalar1();
980 SkPoint diff = center2 - center1;
981 SkScalar diffLen = diff.length();
982 radius2 = radius1 + diffLen + increase;
983 // If the circles are identical the factory will give us an empty shader.
984 } while (radius1 == radius2 && center1 == center2);
985
986 SkColor colors[kMaxRandomGradientColors];
987 SkScalar stopsArray[kMaxRandomGradientColors];
988 SkScalar* stops = stopsArray;
989 SkShader::TileMode tm;
990 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
991 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
992 center2, radius2,
993 colors, stops, colorCount,
994 tm));
995 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700996 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -0700997 GrFragmentProcessor* fp;
998 GrPaint grPaint;
joshualitt5531d512014-12-17 15:50:11 -0800999 SkAssertResult(shader->asFragmentProcessor(context, paint,
joshualitt4eaf9ce2015-04-28 13:31:18 -07001000 GrTest::TestMatrix(random), NULL,
joshualitt8ca93e72015-07-08 06:51:43 -07001001 &paintColor, grPaint.getShaderDataManager(), &fp));
1002 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001003}
1004
joshualitteb2a6762014-12-04 11:35:33 -08001005GLCircleInside2PtConicalEffect::GLCircleInside2PtConicalEffect(const GrProcessor& processor)
1006 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001007 , fFSVaryingName(NULL)
1008 , fCachedCenterX(SK_ScalarMax)
1009 , fCachedCenterY(SK_ScalarMax)
1010 , fCachedA(SK_ScalarMax)
1011 , fCachedB(SK_ScalarMax)
1012 , fCachedC(SK_ScalarMax) {}
1013
joshualitt15988992014-10-09 15:04:05 -07001014void GLCircleInside2PtConicalEffect::emitCode(GrGLFPBuilder* builder,
joshualitt60030bc2014-11-25 14:21:55 -08001015 const GrFragmentProcessor& fp,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001016 const char* outputColor,
1017 const char* inputColor,
1018 const TransformedCoordsArray& coords,
1019 const TextureSamplerArray& samplers) {
joshualitteb2a6762014-12-04 11:35:33 -08001020 const CircleInside2PtConicalEffect& ge = fp.cast<CircleInside2PtConicalEffect>();
joshualitt60030bc2014-11-25 14:21:55 -08001021 this->emitUniforms(builder, ge);
joshualitt30ba4362014-08-21 20:18:45 -07001022 fCenterUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001023 kVec2f_GrSLType, kDefault_GrSLPrecision,
1024 "Conical2FSCenter");
joshualitt30ba4362014-08-21 20:18:45 -07001025 fParamUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001026 kVec3f_GrSLType, kDefault_GrSLPrecision,
1027 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001028 SkString tName("t");
1029
1030 GrGLShaderVar center = builder->getUniformVariable(fCenterUni);
1031 // params.x = A
1032 // params.y = B
1033 // params.z = C
1034 GrGLShaderVar params = builder->getUniformVariable(fParamUni);
1035
1036 // if we have a vec3 from being in perspective, convert it to a vec2 first
egdaniel29bee0f2015-04-29 11:54:42 -07001037 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001038 SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001039 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001040
1041 // p = coords2D
1042 // e = center end
1043 // r = radius end
1044 // A = dot(e, e) - r^2 + 2 * r - 1
1045 // B = (r -1) / A
1046 // C = 1 / A
1047 // d = dot(e, p) + B
1048 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
joshualitt30ba4362014-08-21 20:18:45 -07001049 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -07001050 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1051 params.c_str());
joshualitt30ba4362014-08-21 20:18:45 -07001052 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001053 tName.c_str(), params.c_str(), params.c_str());
1054
joshualitt60030bc2014-11-25 14:21:55 -08001055 this->emitColor(builder, ge, tName.c_str(), outputColor, inputColor, samplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001056}
1057
kkinnunen7510b222014-07-30 00:04:16 -07001058void GLCircleInside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001059 const GrProcessor& processor) {
1060 INHERITED::setData(pdman, processor);
1061 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001062 SkScalar centerX = data.centerX();
1063 SkScalar centerY = data.centerY();
1064 SkScalar A = data.A();
1065 SkScalar B = data.B();
1066 SkScalar C = data.C();
1067
1068 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1069 fCachedA != A || fCachedB != B || fCachedC != C) {
1070
kkinnunen7510b222014-07-30 00:04:16 -07001071 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1072 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001073
1074 fCachedCenterX = centerX;
1075 fCachedCenterY = centerY;
1076 fCachedA = A;
1077 fCachedB = B;
1078 fCachedC = C;
1079 }
1080}
1081
joshualittb0a8a372014-09-23 09:50:21 -07001082void GLCircleInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001083 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001084 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001085}
1086
1087//////////////////////////////////////////////////////////////////////////////
1088
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001089class CircleOutside2PtConicalEffect : public GrGradientEffect {
1090public:
1091
joshualittb0a8a372014-09-23 09:50:21 -07001092 static GrFragmentProcessor* Create(GrContext* ctx,
joshualittb2456052015-07-08 09:36:59 -07001093 GrShaderDataManager* shaderDataManager,
joshualittb0a8a372014-09-23 09:50:21 -07001094 const SkTwoPointConicalGradient& shader,
1095 const SkMatrix& matrix,
1096 SkShader::TileMode tm,
1097 const CircleConicalInfo& info) {
joshualittb2456052015-07-08 09:36:59 -07001098 return SkNEW_ARGS(CircleOutside2PtConicalEffect, (ctx, shaderDataManager, shader, matrix,
1099 tm, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001100 }
1101
1102 virtual ~CircleOutside2PtConicalEffect() {}
1103
mtklein36352bf2015-03-25 18:17:31 -07001104 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001105
jvanverthcfc18862015-04-28 08:48:20 -07001106 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -08001107
mtklein36352bf2015-03-25 18:17:31 -07001108 GrGLFragmentProcessor* createGLInstance() const override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001109
1110 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1111 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1112 SkScalar A() const { return fInfo.fA; }
1113 SkScalar B() const { return fInfo.fB; }
1114 SkScalar C() const { return fInfo.fC; }
1115 SkScalar tLimit() const { return fTLimit; }
1116 bool isFlipped() const { return fIsFlipped; }
1117
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001118private:
mtklein36352bf2015-03-25 18:17:31 -07001119 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001120 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001121 return (INHERITED::onIsEqual(sBase) &&
1122 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1123 this->fInfo.fA == s.fInfo.fA &&
1124 this->fInfo.fB == s.fInfo.fB &&
1125 this->fInfo.fC == s.fInfo.fC &&
1126 this->fTLimit == s.fTLimit &&
1127 this->fIsFlipped == s.fIsFlipped);
1128 }
1129
1130 CircleOutside2PtConicalEffect(GrContext* ctx,
joshualittb2456052015-07-08 09:36:59 -07001131 GrShaderDataManager* shaderDataManager,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001132 const SkTwoPointConicalGradient& shader,
1133 const SkMatrix& matrix,
1134 SkShader::TileMode tm,
1135 const CircleConicalInfo& info)
joshualittb2456052015-07-08 09:36:59 -07001136 : INHERITED(ctx, shaderDataManager, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001137 this->initClassID<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001138 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001139 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001140 } else {
1141 fTLimit = SK_ScalarMin;
1142 }
1143
1144 fIsFlipped = shader.isFlippedGrad();
1145 }
1146
joshualittb0a8a372014-09-23 09:50:21 -07001147 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001148
1149 const CircleConicalInfo fInfo;
1150 SkScalar fTLimit;
1151 bool fIsFlipped;
1152
1153 typedef GrGradientEffect INHERITED;
1154};
1155
1156class GLCircleOutside2PtConicalEffect : public GrGLGradientEffect {
1157public:
joshualitteb2a6762014-12-04 11:35:33 -08001158 GLCircleOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001159 virtual ~GLCircleOutside2PtConicalEffect() {}
1160
joshualitt15988992014-10-09 15:04:05 -07001161 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -07001162 const GrFragmentProcessor&,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001163 const char* outputColor,
1164 const char* inputColor,
1165 const TransformedCoordsArray&,
mtklein36352bf2015-03-25 18:17:31 -07001166 const TextureSamplerArray&) override;
1167 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001168
jvanverthcfc18862015-04-28 08:48:20 -07001169 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001170
1171protected:
1172 UniformHandle fCenterUni;
1173 UniformHandle fParamUni;
1174
1175 const char* fVSVaryingName;
1176 const char* fFSVaryingName;
1177
1178 bool fIsFlipped;
1179
1180 // @{
1181 /// Values last uploaded as uniforms
1182
1183 SkScalar fCachedCenterX;
1184 SkScalar fCachedCenterY;
1185 SkScalar fCachedA;
1186 SkScalar fCachedB;
1187 SkScalar fCachedC;
1188 SkScalar fCachedTLimit;
1189
1190 // @}
1191
1192private:
1193 typedef GrGLGradientEffect INHERITED;
1194
1195};
1196
jvanverthcfc18862015-04-28 08:48:20 -07001197void CircleOutside2PtConicalEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -08001198 GrProcessorKeyBuilder* b) const {
1199 GLCircleOutside2PtConicalEffect::GenKey(*this, caps, b);
1200}
1201
1202GrGLFragmentProcessor* CircleOutside2PtConicalEffect::createGLInstance() const {
1203 return SkNEW_ARGS(GLCircleOutside2PtConicalEffect, (*this));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001204}
1205
joshualittb0a8a372014-09-23 09:50:21 -07001206GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001207
joshualitt01258472014-09-22 10:29:30 -07001208/*
1209 * All Two point conical gradient test create functions may occasionally create edge case shaders
1210 */
joshualittb0a8a372014-09-23 09:50:21 -07001211GrFragmentProcessor* CircleOutside2PtConicalEffect::TestCreate(SkRandom* random,
1212 GrContext* context,
bsalomon4b91f762015-05-19 09:29:46 -07001213 const GrCaps&,
joshualittb0a8a372014-09-23 09:50:21 -07001214 GrTexture**) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001215 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +00001216 SkScalar radius1 = random->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001217 SkPoint center2;
1218 SkScalar radius2;
1219 SkScalar diffLen;
1220 do {
1221 center2.set(random->nextUScalar1(), random->nextUScalar1());
1222 // If the circles share a center than we can't be in the outside case
1223 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001224 SkPoint diff = center2 - center1;
1225 diffLen = diff.length();
1226 // Below makes sure that circle one is not contained within circle two
1227 // and have radius2 >= radius to match sorting on cpu side
1228 radius2 = radius1 + random->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001229
1230 SkColor colors[kMaxRandomGradientColors];
1231 SkScalar stopsArray[kMaxRandomGradientColors];
1232 SkScalar* stops = stopsArray;
1233 SkShader::TileMode tm;
1234 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
1235 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
1236 center2, radius2,
1237 colors, stops, colorCount,
1238 tm));
1239 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -07001240 GrColor paintColor;
joshualitt8ca93e72015-07-08 06:51:43 -07001241 GrFragmentProcessor* fp;
1242 GrPaint grPaint;
joshualitt5531d512014-12-17 15:50:11 -08001243 SkAssertResult(shader->asFragmentProcessor(context, paint,
joshualitt4eaf9ce2015-04-28 13:31:18 -07001244 GrTest::TestMatrix(random), NULL,
joshualitt8ca93e72015-07-08 06:51:43 -07001245 &paintColor, grPaint.getShaderDataManager(), &fp));
1246 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001247}
1248
joshualitteb2a6762014-12-04 11:35:33 -08001249GLCircleOutside2PtConicalEffect::GLCircleOutside2PtConicalEffect(const GrProcessor& processor)
1250 : fVSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001251 , fFSVaryingName(NULL)
1252 , fCachedCenterX(SK_ScalarMax)
1253 , fCachedCenterY(SK_ScalarMax)
1254 , fCachedA(SK_ScalarMax)
1255 , fCachedB(SK_ScalarMax)
1256 , fCachedC(SK_ScalarMax)
1257 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001258 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001259 fIsFlipped = data.isFlipped();
1260 }
1261
joshualitt15988992014-10-09 15:04:05 -07001262void GLCircleOutside2PtConicalEffect::emitCode(GrGLFPBuilder* builder,
joshualitt60030bc2014-11-25 14:21:55 -08001263 const GrFragmentProcessor& fp,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001264 const char* outputColor,
1265 const char* inputColor,
1266 const TransformedCoordsArray& coords,
1267 const TextureSamplerArray& samplers) {
joshualitteb2a6762014-12-04 11:35:33 -08001268 const CircleOutside2PtConicalEffect& ge = fp.cast<CircleOutside2PtConicalEffect>();
joshualitt60030bc2014-11-25 14:21:55 -08001269 this->emitUniforms(builder, ge);
joshualitt30ba4362014-08-21 20:18:45 -07001270 fCenterUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001271 kVec2f_GrSLType, kDefault_GrSLPrecision,
1272 "Conical2FSCenter");
joshualitt30ba4362014-08-21 20:18:45 -07001273 fParamUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -08001274 kVec4f_GrSLType, kDefault_GrSLPrecision,
1275 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001276 SkString tName("t");
1277
1278 GrGLShaderVar center = builder->getUniformVariable(fCenterUni);
1279 // params.x = A
1280 // params.y = B
1281 // params.z = C
1282 GrGLShaderVar params = builder->getUniformVariable(fParamUni);
1283
1284 // if we have a vec3 from being in perspective, convert it to a vec2 first
egdaniel29bee0f2015-04-29 11:54:42 -07001285 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -07001286 SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001287 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001288
1289 // output will default to transparent black (we simply won't write anything
1290 // else to it if invalid, instead of discarding or returning prematurely)
joshualitt30ba4362014-08-21 20:18:45 -07001291 fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001292
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001293 // p = coords2D
1294 // e = center end
1295 // r = radius end
1296 // A = dot(e, e) - r^2 + 2 * r - 1
1297 // B = (r -1) / A
1298 // C = 1 / A
1299 // d = dot(e, p) + B
1300 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001301
joshualitt30ba4362014-08-21 20:18:45 -07001302 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -07001303 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1304 params.c_str());
1305 fsBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1306 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001307
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001308 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1309 // If so we must also flip sign on sqrt
1310 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -07001311 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001312 } else {
joshualitt30ba4362014-08-21 20:18:45 -07001313 fsBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001314 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001315
joshualitt30ba4362014-08-21 20:18:45 -07001316 fsBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str());
1317 fsBuilder->codeAppend("\t\t");
joshualitt60030bc2014-11-25 14:21:55 -08001318 this->emitColor(builder, ge, tName.c_str(), outputColor, inputColor, samplers);
joshualitt30ba4362014-08-21 20:18:45 -07001319 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001320}
1321
kkinnunen7510b222014-07-30 00:04:16 -07001322void GLCircleOutside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualittb0a8a372014-09-23 09:50:21 -07001323 const GrProcessor& processor) {
1324 INHERITED::setData(pdman, processor);
1325 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001326 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001327 SkScalar centerX = data.centerX();
1328 SkScalar centerY = data.centerY();
1329 SkScalar A = data.A();
1330 SkScalar B = data.B();
1331 SkScalar C = data.C();
1332 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001333
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001334 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1335 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001336
kkinnunen7510b222014-07-30 00:04:16 -07001337 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1338 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001339 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001340
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001341 fCachedCenterX = centerX;
1342 fCachedCenterY = centerY;
1343 fCachedA = A;
1344 fCachedB = B;
1345 fCachedC = C;
1346 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001347 }
1348}
1349
joshualittb0a8a372014-09-23 09:50:21 -07001350void GLCircleOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001351 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001352 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001353 key[0] = GenBaseGradientKey(processor);
1354 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001355}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001356
1357//////////////////////////////////////////////////////////////////////////////
1358
joshualittb0a8a372014-09-23 09:50:21 -07001359GrFragmentProcessor* Gr2PtConicalGradientEffect::Create(GrContext* ctx,
joshualittb2456052015-07-08 09:36:59 -07001360 GrShaderDataManager* shaderDataManager,
joshualittb0a8a372014-09-23 09:50:21 -07001361 const SkTwoPointConicalGradient& shader,
1362 SkShader::TileMode tm,
1363 const SkMatrix* localMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001364 SkMatrix matrix;
1365 if (!shader.getLocalMatrix().invert(&matrix)) {
1366 return NULL;
1367 }
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001368 if (localMatrix) {
1369 SkMatrix inv;
1370 if (!localMatrix->invert(&inv)) {
1371 return NULL;
1372 }
1373 matrix.postConcat(inv);
1374 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001375
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001376 if (shader.getStartRadius() < kErrorTol) {
1377 SkScalar focalX;
1378 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1379 if (type == kInside_ConicalType) {
joshualittb2456052015-07-08 09:36:59 -07001380 return FocalInside2PtConicalEffect::Create(ctx, shaderDataManager, shader, matrix, tm,
1381 focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001382 } else if(type == kEdge_ConicalType) {
1383 set_matrix_edge_conical(shader, &matrix);
joshualittb2456052015-07-08 09:36:59 -07001384 return Edge2PtConicalEffect::Create(ctx, shaderDataManager, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001385 } else {
joshualittb2456052015-07-08 09:36:59 -07001386 return FocalOutside2PtConicalEffect::Create(ctx, shaderDataManager, shader, matrix, tm,
1387 focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001388 }
1389 }
1390
1391 CircleConicalInfo info;
1392 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1393
1394 if (type == kInside_ConicalType) {
joshualittb2456052015-07-08 09:36:59 -07001395 return CircleInside2PtConicalEffect::Create(ctx, shaderDataManager, shader, matrix, tm,
1396 info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001397 } else if (type == kEdge_ConicalType) {
1398 set_matrix_edge_conical(shader, &matrix);
joshualittb2456052015-07-08 09:36:59 -07001399 return Edge2PtConicalEffect::Create(ctx, shaderDataManager, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001400 } else {
joshualittb2456052015-07-08 09:36:59 -07001401 return CircleOutside2PtConicalEffect::Create(ctx, shaderDataManager, shader, matrix, tm,
1402 info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001403 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001404}
1405
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001406#endif