blob: 4c474b28dc3631bffba0b0282ca6674ce4d6a750 [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
commit-bot@chromium.org7f434932014-04-10 16:03:06 +000014#include "GrTBackendEffectFactory.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 GLEdge2PtConicalEffect;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000059
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000060class Edge2PtConicalEffect : public GrGradientEffect {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000061public:
62
bsalomon83d081a2014-07-08 09:56:10 -070063 static GrEffect* Create(GrContext* ctx,
64 const SkTwoPointConicalGradient& shader,
65 const SkMatrix& matrix,
66 SkShader::TileMode tm) {
bsalomon55fad7a2014-07-08 07:34:20 -070067 return SkNEW_ARGS(Edge2PtConicalEffect, (ctx, shader, matrix, tm));
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000068 }
69
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000070 virtual ~Edge2PtConicalEffect() {}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000071
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000072 static const char* Name() { return "Two-Point Conical Gradient Edge Touching"; }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000073 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
74
75 // 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.orgc8379d72014-04-22 20:56:37 +000080 typedef GLEdge2PtConicalEffect GLEffect;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000081
82private:
83 virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
joshualitt49586be2014-09-16 08:21:41 -070084 const Edge2PtConicalEffect& s = sBase.cast<Edge2PtConicalEffect>();
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000085 return (INHERITED::onIsEqual(sBase) &&
86 this->fCenterX1 == s.fCenterX1 &&
87 this->fRadius0 == s.fRadius0 &&
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000088 this->fDiffRadius == s.fDiffRadius);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000089 }
90
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000091 Edge2PtConicalEffect(GrContext* ctx,
92 const SkTwoPointConicalGradient& shader,
93 const SkMatrix& matrix,
94 SkShader::TileMode tm)
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000095 : INHERITED(ctx, shader, matrix, tm),
96 fCenterX1(shader.getCenterX1()),
97 fRadius0(shader.getStartRadius()),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000098 fDiffRadius(shader.getDiffRadius()){
99 // We should only be calling this shader if we are degenerate case with touching circles
egdaniel8405ef92014-06-09 11:57:28 -0700100 // When deciding if we are in edge case, we scaled by the end radius for cases when the
101 // start radius was close to zero, otherwise we scaled by the start radius
102 SkASSERT(SkScalarAbs(SkScalarAbs(fDiffRadius) - SkScalarAbs(fCenterX1)) <
103 kEdgeErrorTol * (fRadius0 < kErrorTol ? shader.getEndRadius() : fRadius0));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000104
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000105 // We pass the linear part of the quadratic as a varying.
106 // float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
107 fBTransform = this->getCoordTransform();
108 SkMatrix& bMatrix = *fBTransform.accessMatrix();
109 SkScalar r0dr = SkScalarMul(fRadius0, fDiffRadius);
110 bMatrix[SkMatrix::kMScaleX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMScaleX]) +
111 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp0]));
112 bMatrix[SkMatrix::kMSkewX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMSkewX]) +
113 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp1]));
114 bMatrix[SkMatrix::kMTransX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMTransX]) +
115 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp2]));
116 this->addCoordTransform(&fBTransform);
117 }
118
119 GR_DECLARE_EFFECT_TEST;
120
121 // @{
122 // Cache of values - these can change arbitrarily, EXCEPT
123 // we shouldn't change between degenerate and non-degenerate?!
124
125 GrCoordTransform fBTransform;
126 SkScalar fCenterX1;
127 SkScalar fRadius0;
128 SkScalar fDiffRadius;
129
130 // @}
131
132 typedef GrGradientEffect INHERITED;
133};
134
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000135class GLEdge2PtConicalEffect : public GrGLGradientEffect {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000136public:
joshualitt49586be2014-09-16 08:21:41 -0700137 GLEdge2PtConicalEffect(const GrBackendEffectFactory& factory, const GrEffect&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000138 virtual ~GLEdge2PtConicalEffect() { }
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000139
joshualitt30ba4362014-08-21 20:18:45 -0700140 virtual void emitCode(GrGLProgramBuilder*,
joshualitt49586be2014-09-16 08:21:41 -0700141 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700142 const GrEffectKey&,
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000143 const char* outputColor,
144 const char* inputColor,
145 const TransformedCoordsArray&,
146 const TextureSamplerArray&) SK_OVERRIDE;
joshualitt49586be2014-09-16 08:21:41 -0700147 virtual void setData(const GrGLProgramDataManager&, const GrEffect&) SK_OVERRIDE;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000148
joshualitt49586be2014-09-16 08:21:41 -0700149 static void GenKey(const GrEffect&, const GrGLCaps& caps, GrEffectKeyBuilder* b);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000150
151protected:
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000152 UniformHandle fParamUni;
153
154 const char* fVSVaryingName;
155 const char* fFSVaryingName;
156
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000157 // @{
158 /// Values last uploaded as uniforms
159
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000160 SkScalar fCachedRadius;
161 SkScalar fCachedDiffRadius;
162
163 // @}
164
165private:
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000166 typedef GrGLGradientEffect INHERITED;
167
168};
169
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000170const GrBackendEffectFactory& Edge2PtConicalEffect::getFactory() const {
171 return GrTBackendEffectFactory<Edge2PtConicalEffect>::getInstance();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000172}
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000173
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000174GR_DEFINE_EFFECT_TEST(Edge2PtConicalEffect);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000175
bsalomon83d081a2014-07-08 09:56:10 -0700176GrEffect* Edge2PtConicalEffect::TestCreate(SkRandom* random,
177 GrContext* context,
178 const GrDrawTargetCaps&,
179 GrTexture**) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000180 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
181 SkScalar radius1 = random->nextUScalar1();
182 SkPoint center2;
183 SkScalar radius2;
184 do {
185 center2.set(random->nextUScalar1(), random->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000186 // If the circles are identical the factory will give us an empty shader.
187 // This will happen if we pick identical centers
188 } while (center1 == center2);
189
190 // Below makes sure that circle one is contained within circle two
191 // and both circles are touching on an edge
192 SkPoint diff = center2 - center1;
193 SkScalar diffLen = diff.length();
194 radius2 = radius1 + diffLen;
195
196 SkColor colors[kMaxRandomGradientColors];
197 SkScalar stopsArray[kMaxRandomGradientColors];
198 SkScalar* stops = stopsArray;
199 SkShader::TileMode tm;
200 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
201 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
202 center2, radius2,
203 colors, stops, colorCount,
204 tm));
205 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700206 GrEffect* effect;
207 GrColor paintColor;
208 SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect));
dandov9de5b512014-06-10 14:38:28 -0700209 return effect;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000210}
211
212GLEdge2PtConicalEffect::GLEdge2PtConicalEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -0700213 const GrEffect& effect)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000214 : INHERITED(factory)
215 , fVSVaryingName(NULL)
216 , fFSVaryingName(NULL)
217 , fCachedRadius(-SK_ScalarMax)
218 , fCachedDiffRadius(-SK_ScalarMax) {}
219
joshualitt30ba4362014-08-21 20:18:45 -0700220void GLEdge2PtConicalEffect::emitCode(GrGLProgramBuilder* builder,
joshualitt49586be2014-09-16 08:21:41 -0700221 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700222 const GrEffectKey& key,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000223 const char* outputColor,
224 const char* inputColor,
225 const TransformedCoordsArray& coords,
226 const TextureSamplerArray& samplers) {
bsalomon63e99f72014-07-21 08:03:14 -0700227 uint32_t baseKey = key.get32(0);
228 this->emitUniforms(builder, baseKey);
joshualitt30ba4362014-08-21 20:18:45 -0700229 fParamUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000230 kFloat_GrSLType, "Conical2FSParams", 3);
231
232 SkString cName("c");
233 SkString tName("t");
234 SkString p0; // start radius
235 SkString p1; // start radius squared
236 SkString p2; // difference in radii (r1 - r0)
237
238 builder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
239 builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
240 builder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
241
242 // We interpolate the linear component in coords[1].
243 SkASSERT(coords[0].type() == coords[1].type());
244 const char* coords2D;
245 SkString bVar;
joshualitt30ba4362014-08-21 20:18:45 -0700246 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000247 if (kVec3f_GrSLType == coords[0].type()) {
joshualitt30ba4362014-08-21 20:18:45 -0700248 fsBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
joshualitt49586be2014-09-16 08:21:41 -0700249 coords[0].c_str(), coords[0].c_str(), coords[1].c_str(),
250 coords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000251 coords2D = "interpolants.xy";
252 bVar = "interpolants.z";
253 } else {
254 coords2D = coords[0].c_str();
255 bVar.printf("%s.x", coords[1].c_str());
256 }
257
258 // output will default to transparent black (we simply won't write anything
259 // else to it if invalid, instead of discarding or returning prematurely)
joshualitt30ba4362014-08-21 20:18:45 -0700260 fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000261
262 // c = (x^2)+(y^2) - params[1]
joshualitt30ba4362014-08-21 20:18:45 -0700263 fsBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000264 cName.c_str(), coords2D, coords2D, p1.c_str());
265
266 // linear case: t = -c/b
joshualitt30ba4362014-08-21 20:18:45 -0700267 fsBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000268 cName.c_str(), bVar.c_str());
269
270 // if r(t) > 0, then t will be the x coordinate
joshualitt30ba4362014-08-21 20:18:45 -0700271 fsBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000272 p2.c_str(), p0.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700273 fsBuilder->codeAppend("\t");
bsalomon63e99f72014-07-21 08:03:14 -0700274 this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
joshualitt30ba4362014-08-21 20:18:45 -0700275 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000276}
277
kkinnunen7510b222014-07-30 00:04:16 -0700278void GLEdge2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualitt49586be2014-09-16 08:21:41 -0700279 const GrEffect& effect) {
280 INHERITED::setData(pdman, effect);
281 const Edge2PtConicalEffect& data = effect.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
joshualitt49586be2014-09-16 08:21:41 -0700300void GLEdge2PtConicalEffect::GenKey(const GrEffect& effect,
bsalomon63e99f72014-07-21 08:03:14 -0700301 const GrGLCaps&, GrEffectKeyBuilder* b) {
joshualitt49586be2014-09-16 08:21:41 -0700302 b->add32(GenBaseGradientKey(effect));
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);
349 SkScalar s = SkScalarDiv(1.f, 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
367class GLFocalOutside2PtConicalEffect;
368
369class FocalOutside2PtConicalEffect : public GrGradientEffect {
370public:
371
bsalomon83d081a2014-07-08 09:56:10 -0700372 static GrEffect* Create(GrContext* ctx,
373 const SkTwoPointConicalGradient& shader,
374 const SkMatrix& matrix,
375 SkShader::TileMode tm,
376 SkScalar focalX) {
bsalomon55fad7a2014-07-08 07:34:20 -0700377 return SkNEW_ARGS(FocalOutside2PtConicalEffect, (ctx, shader, matrix, tm, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000378 }
379
380 virtual ~FocalOutside2PtConicalEffect() { }
381
382 static const char* Name() { return "Two-Point Conical Gradient Focal Outside"; }
383 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
384
385 bool isFlipped() const { return fIsFlipped; }
386 SkScalar focal() const { return fFocalX; }
387
388 typedef GLFocalOutside2PtConicalEffect GLEffect;
389
390private:
391 virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
joshualitt49586be2014-09-16 08:21:41 -0700392 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000393 return (INHERITED::onIsEqual(sBase) &&
394 this->fFocalX == s.fFocalX &&
395 this->fIsFlipped == s.fIsFlipped);
396 }
397
398 FocalOutside2PtConicalEffect(GrContext* ctx,
399 const SkTwoPointConicalGradient& shader,
400 const SkMatrix& matrix,
401 SkShader::TileMode tm,
402 SkScalar focalX)
403 : INHERITED(ctx, shader, matrix, tm), fFocalX(focalX), fIsFlipped(shader.isFlippedGrad()) {}
404
405 GR_DECLARE_EFFECT_TEST;
406
407 SkScalar fFocalX;
408 bool fIsFlipped;
409
410 typedef GrGradientEffect INHERITED;
411};
412
413class GLFocalOutside2PtConicalEffect : public GrGLGradientEffect {
414public:
joshualitt49586be2014-09-16 08:21:41 -0700415 GLFocalOutside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrEffect&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000416 virtual ~GLFocalOutside2PtConicalEffect() { }
417
joshualitt30ba4362014-08-21 20:18:45 -0700418 virtual void emitCode(GrGLProgramBuilder*,
joshualitt49586be2014-09-16 08:21:41 -0700419 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700420 const GrEffectKey&,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000421 const char* outputColor,
422 const char* inputColor,
423 const TransformedCoordsArray&,
424 const TextureSamplerArray&) SK_OVERRIDE;
joshualitt49586be2014-09-16 08:21:41 -0700425 virtual void setData(const GrGLProgramDataManager&, const GrEffect&) SK_OVERRIDE;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000426
joshualitt49586be2014-09-16 08:21:41 -0700427 static void GenKey(const GrEffect&, const GrGLCaps& caps, GrEffectKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000428
429protected:
430 UniformHandle fParamUni;
431
432 const char* fVSVaryingName;
433 const char* fFSVaryingName;
434
435 bool fIsFlipped;
436
437 // @{
438 /// Values last uploaded as uniforms
439
440 SkScalar fCachedFocal;
441
442 // @}
443
444private:
445 typedef GrGLGradientEffect INHERITED;
446
447};
448
449const GrBackendEffectFactory& FocalOutside2PtConicalEffect::getFactory() const {
450 return GrTBackendEffectFactory<FocalOutside2PtConicalEffect>::getInstance();
451}
452
453GR_DEFINE_EFFECT_TEST(FocalOutside2PtConicalEffect);
454
bsalomon83d081a2014-07-08 09:56:10 -0700455GrEffect* FocalOutside2PtConicalEffect::TestCreate(SkRandom* random,
456 GrContext* context,
457 const GrDrawTargetCaps&,
458 GrTexture**) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000459 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000460 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000461 SkPoint center2;
462 SkScalar radius2;
463 do {
464 center2.set(random->nextUScalar1(), random->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000465 // 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 +0000466 } while (center1 == center2);
467 SkPoint diff = center2 - center1;
468 SkScalar diffLen = diff.length();
469 // Below makes sure that the focal point is not contained within circle two
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000470 radius2 = random->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000471
472 SkColor colors[kMaxRandomGradientColors];
473 SkScalar stopsArray[kMaxRandomGradientColors];
474 SkScalar* stops = stopsArray;
475 SkShader::TileMode tm;
476 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
477 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
478 center2, radius2,
479 colors, stops, colorCount,
480 tm));
481 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700482 GrEffect* effect;
483 GrColor paintColor;
484 SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect));
dandov9de5b512014-06-10 14:38:28 -0700485 return effect;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000486}
487
488GLFocalOutside2PtConicalEffect::GLFocalOutside2PtConicalEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -0700489 const GrEffect& effect)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000490 : INHERITED(factory)
491 , fVSVaryingName(NULL)
492 , fFSVaryingName(NULL)
493 , fCachedFocal(SK_ScalarMax) {
joshualitt49586be2014-09-16 08:21:41 -0700494 const FocalOutside2PtConicalEffect& data = effect.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000495 fIsFlipped = data.isFlipped();
496}
497
joshualitt30ba4362014-08-21 20:18:45 -0700498void GLFocalOutside2PtConicalEffect::emitCode(GrGLProgramBuilder* builder,
joshualitt49586be2014-09-16 08:21:41 -0700499 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700500 const GrEffectKey& key,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000501 const char* outputColor,
502 const char* inputColor,
503 const TransformedCoordsArray& coords,
504 const TextureSamplerArray& samplers) {
bsalomon63e99f72014-07-21 08:03:14 -0700505 uint32_t baseKey = key.get32(0);
506 this->emitUniforms(builder, baseKey);
joshualitt30ba4362014-08-21 20:18:45 -0700507 fParamUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000508 kFloat_GrSLType, "Conical2FSParams", 2);
509 SkString tName("t");
510 SkString p0; // focalX
511 SkString p1; // 1 - focalX * focalX
512
513 builder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
514 builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
515
516 // if we have a vec3 from being in perspective, convert it to a vec2 first
joshualitt30ba4362014-08-21 20:18:45 -0700517 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
518 SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000519 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000520
521 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
522
523 // output will default to transparent black (we simply won't write anything
524 // else to it if invalid, instead of discarding or returning prematurely)
joshualitt30ba4362014-08-21 20:18:45 -0700525 fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000526
joshualitt30ba4362014-08-21 20:18:45 -0700527 fsBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
528 fsBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
529 fsBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000530
531 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
532 // If so we must also flip sign on sqrt
533 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -0700534 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000535 coords2D, p0.c_str());
536 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700537 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000538 coords2D, p0.c_str());
539 }
540
joshualitt30ba4362014-08-21 20:18:45 -0700541 fsBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
542 fsBuilder->codeAppend("\t\t");
bsalomon63e99f72014-07-21 08:03:14 -0700543 this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
joshualitt30ba4362014-08-21 20:18:45 -0700544 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000545}
546
kkinnunen7510b222014-07-30 00:04:16 -0700547void GLFocalOutside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualitt49586be2014-09-16 08:21:41 -0700548 const GrEffect& effect) {
549 INHERITED::setData(pdman, effect);
550 const FocalOutside2PtConicalEffect& data = effect.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
joshualitt49586be2014-09-16 08:21:41 -0700567void GLFocalOutside2PtConicalEffect::GenKey(const GrEffect& effect,
bsalomon63e99f72014-07-21 08:03:14 -0700568 const GrGLCaps&, GrEffectKeyBuilder* b) {
569 uint32_t* key = b->add32n(2);
joshualitt49586be2014-09-16 08:21:41 -0700570 key[0] = GenBaseGradientKey(effect);
571 key[1] = effect.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
bsalomon83d081a2014-07-08 09:56:10 -0700581 static GrEffect* Create(GrContext* ctx,
582 const SkTwoPointConicalGradient& shader,
583 const SkMatrix& matrix,
584 SkShader::TileMode tm,
585 SkScalar focalX) {
bsalomon55fad7a2014-07-08 07:34:20 -0700586 return SkNEW_ARGS(FocalInside2PtConicalEffect, (ctx, shader, matrix, tm, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000587 }
588
589 virtual ~FocalInside2PtConicalEffect() {}
590
591 static const char* Name() { return "Two-Point Conical Gradient Focal Inside"; }
592 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
593
594 SkScalar focal() const { return fFocalX; }
595
596 typedef GLFocalInside2PtConicalEffect GLEffect;
597
598private:
599 virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
joshualitt49586be2014-09-16 08:21:41 -0700600 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000601 return (INHERITED::onIsEqual(sBase) &&
602 this->fFocalX == s.fFocalX);
603 }
604
605 FocalInside2PtConicalEffect(GrContext* ctx,
606 const SkTwoPointConicalGradient& shader,
607 const SkMatrix& matrix,
608 SkShader::TileMode tm,
609 SkScalar focalX)
610 : INHERITED(ctx, shader, matrix, tm), fFocalX(focalX) {}
611
612 GR_DECLARE_EFFECT_TEST;
613
614 SkScalar fFocalX;
615
616 typedef GrGradientEffect INHERITED;
617};
618
619class GLFocalInside2PtConicalEffect : public GrGLGradientEffect {
620public:
joshualitt49586be2014-09-16 08:21:41 -0700621 GLFocalInside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrEffect&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000622 virtual ~GLFocalInside2PtConicalEffect() {}
623
joshualitt30ba4362014-08-21 20:18:45 -0700624 virtual void emitCode(GrGLProgramBuilder*,
joshualitt49586be2014-09-16 08:21:41 -0700625 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700626 const GrEffectKey&,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000627 const char* outputColor,
628 const char* inputColor,
629 const TransformedCoordsArray&,
630 const TextureSamplerArray&) SK_OVERRIDE;
joshualitt49586be2014-09-16 08:21:41 -0700631 virtual void setData(const GrGLProgramDataManager&, const GrEffect&) SK_OVERRIDE;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000632
joshualitt49586be2014-09-16 08:21:41 -0700633 static void GenKey(const GrEffect&, const GrGLCaps& caps, GrEffectKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000634
635protected:
636 UniformHandle fFocalUni;
637
638 const char* fVSVaryingName;
639 const char* fFSVaryingName;
640
641 // @{
642 /// Values last uploaded as uniforms
643
644 SkScalar fCachedFocal;
645
646 // @}
647
648private:
649 typedef GrGLGradientEffect INHERITED;
650
651};
652
653const GrBackendEffectFactory& FocalInside2PtConicalEffect::getFactory() const {
654 return GrTBackendEffectFactory<FocalInside2PtConicalEffect>::getInstance();
655}
656
657GR_DEFINE_EFFECT_TEST(FocalInside2PtConicalEffect);
658
bsalomon83d081a2014-07-08 09:56:10 -0700659GrEffect* FocalInside2PtConicalEffect::TestCreate(SkRandom* random,
660 GrContext* context,
661 const GrDrawTargetCaps&,
662 GrTexture**) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000663 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000664 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000665 SkPoint center2;
666 SkScalar radius2;
667 do {
668 center2.set(random->nextUScalar1(), random->nextUScalar1());
669 // Below makes sure radius2 is larger enouch such that the focal point
670 // is inside the end circle
671 SkScalar increase = random->nextUScalar1();
672 SkPoint diff = center2 - center1;
673 SkScalar diffLen = diff.length();
674 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000675 // If the circles are identical the factory will give us an empty shader.
676 } while (radius1 == radius2 && center1 == center2);
677
678 SkColor colors[kMaxRandomGradientColors];
679 SkScalar stopsArray[kMaxRandomGradientColors];
680 SkScalar* stops = stopsArray;
681 SkShader::TileMode tm;
682 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
683 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
684 center2, radius2,
685 colors, stops, colorCount,
686 tm));
687 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700688 GrColor paintColor;
689 GrEffect* effect;
690 SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect));
691 return effect;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000692}
693
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000694GLFocalInside2PtConicalEffect::GLFocalInside2PtConicalEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -0700695 const GrEffect& effect)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000696 : INHERITED(factory)
697 , fVSVaryingName(NULL)
698 , fFSVaryingName(NULL)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000699 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000700
joshualitt30ba4362014-08-21 20:18:45 -0700701void GLFocalInside2PtConicalEffect::emitCode(GrGLProgramBuilder* builder,
joshualitt49586be2014-09-16 08:21:41 -0700702 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700703 const GrEffectKey& key,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000704 const char* outputColor,
705 const char* inputColor,
706 const TransformedCoordsArray& coords,
707 const TextureSamplerArray& samplers) {
bsalomon63e99f72014-07-21 08:03:14 -0700708 uint32_t baseKey = key.get32(0);
709 this->emitUniforms(builder, baseKey);
joshualitt30ba4362014-08-21 20:18:45 -0700710 fFocalUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000711 kFloat_GrSLType, "Conical2FSParams");
712 SkString tName("t");
713
714 // this is the distance along x-axis from the end center to focal point in
715 // transformed coordinates
716 GrGLShaderVar focal = builder->getUniformVariable(fFocalUni);
717
718 // if we have a vec3 from being in perspective, convert it to a vec2 first
joshualitt30ba4362014-08-21 20:18:45 -0700719 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
720 SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000721 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000722
723 // t = p.x * focalX + length(p)
joshualitt30ba4362014-08-21 20:18:45 -0700724 fsBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000725 coords2D, focal.c_str(), coords2D);
726
bsalomon63e99f72014-07-21 08:03:14 -0700727 this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000728}
729
kkinnunen7510b222014-07-30 00:04:16 -0700730void GLFocalInside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualitt49586be2014-09-16 08:21:41 -0700731 const GrEffect& effect) {
732 INHERITED::setData(pdman, effect);
733 const FocalInside2PtConicalEffect& data = effect.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000734 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000735
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000736 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700737 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000738 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000739 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000740}
741
joshualitt49586be2014-09-16 08:21:41 -0700742void GLFocalInside2PtConicalEffect::GenKey(const GrEffect& effect,
bsalomon63e99f72014-07-21 08:03:14 -0700743 const GrGLCaps&, GrEffectKeyBuilder* b) {
joshualitt49586be2014-09-16 08:21:41 -0700744 b->add32(GenBaseGradientKey(effect));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000745}
746
747//////////////////////////////////////////////////////////////////////////////
748// Circle Conical Gradients
749//////////////////////////////////////////////////////////////////////////////
750
751struct CircleConicalInfo {
752 SkPoint fCenterEnd;
753 SkScalar fA;
754 SkScalar fB;
755 SkScalar fC;
756};
757
758// Returns focal distance along x-axis in transformed coords
759static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
760 SkMatrix* invLMatrix, CircleConicalInfo* info) {
761 // Inverse of the current local matrix is passed in then,
762 // translate and scale such that start circle is on the origin and has radius 1
763 const SkPoint& centerStart = shader.getStartCenter();
764 const SkPoint& centerEnd = shader.getEndCenter();
765 SkScalar radiusStart = shader.getStartRadius();
766 SkScalar radiusEnd = shader.getEndRadius();
767
768 SkMatrix matrix;
769
770 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
771
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000772 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000773 matrix.postScale(invStartRad, invStartRad);
774
775 radiusEnd /= radiusStart;
776
777 SkPoint centerEndTrans;
778 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
779
780 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
781 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
782
783 // Check to see if start circle is inside end circle with edges touching.
784 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700785 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
786 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
787 // still accurate.
788 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000789 return kEdge_ConicalType;
790 }
791
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000792 SkScalar C = 1.f / A;
793 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000794
795 matrix.postScale(C, C);
796
797 invLMatrix->postConcat(matrix);
798
799 info->fCenterEnd = centerEndTrans;
800 info->fA = A;
801 info->fB = B;
802 info->fC = C;
803
804 // 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 +0000805 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000806 return kInside_ConicalType;
807 }
808 return kOutside_ConicalType;
809}
810
811class GLCircleInside2PtConicalEffect;
812
813class CircleInside2PtConicalEffect : public GrGradientEffect {
814public:
815
bsalomon83d081a2014-07-08 09:56:10 -0700816 static GrEffect* Create(GrContext* ctx,
817 const SkTwoPointConicalGradient& shader,
818 const SkMatrix& matrix,
819 SkShader::TileMode tm,
820 const CircleConicalInfo& info) {
bsalomon55fad7a2014-07-08 07:34:20 -0700821 return SkNEW_ARGS(CircleInside2PtConicalEffect, (ctx, shader, matrix, tm, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000822 }
823
824 virtual ~CircleInside2PtConicalEffect() {}
825
826 static const char* Name() { return "Two-Point Conical Gradient Inside"; }
827 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
828
829 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
835 typedef GLCircleInside2PtConicalEffect GLEffect;
836
837private:
838 virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
joshualitt49586be2014-09-16 08:21:41 -0700839 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000840 return (INHERITED::onIsEqual(sBase) &&
841 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
842 this->fInfo.fA == s.fInfo.fA &&
843 this->fInfo.fB == s.fInfo.fB &&
844 this->fInfo.fC == s.fInfo.fC);
845 }
846
847 CircleInside2PtConicalEffect(GrContext* ctx,
848 const SkTwoPointConicalGradient& shader,
849 const SkMatrix& matrix,
850 SkShader::TileMode tm,
851 const CircleConicalInfo& info)
852 : INHERITED(ctx, shader, matrix, tm), fInfo(info) {}
853
854 GR_DECLARE_EFFECT_TEST;
855
856 const CircleConicalInfo fInfo;
857
858 typedef GrGradientEffect INHERITED;
859};
860
861class GLCircleInside2PtConicalEffect : public GrGLGradientEffect {
862public:
joshualitt49586be2014-09-16 08:21:41 -0700863 GLCircleInside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrEffect&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000864 virtual ~GLCircleInside2PtConicalEffect() {}
865
joshualitt30ba4362014-08-21 20:18:45 -0700866 virtual void emitCode(GrGLProgramBuilder*,
joshualitt49586be2014-09-16 08:21:41 -0700867 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700868 const GrEffectKey&,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000869 const char* outputColor,
870 const char* inputColor,
871 const TransformedCoordsArray&,
872 const TextureSamplerArray&) SK_OVERRIDE;
joshualitt49586be2014-09-16 08:21:41 -0700873 virtual void setData(const GrGLProgramDataManager&, const GrEffect&) SK_OVERRIDE;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000874
joshualitt49586be2014-09-16 08:21:41 -0700875 static void GenKey(const GrEffect&, const GrGLCaps& caps, GrEffectKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000876
877protected:
878 UniformHandle fCenterUni;
879 UniformHandle fParamUni;
880
881 const char* fVSVaryingName;
882 const char* fFSVaryingName;
883
884 // @{
885 /// Values last uploaded as uniforms
886
887 SkScalar fCachedCenterX;
888 SkScalar fCachedCenterY;
889 SkScalar fCachedA;
890 SkScalar fCachedB;
891 SkScalar fCachedC;
892
893 // @}
894
895private:
896 typedef GrGLGradientEffect INHERITED;
897
898};
899
900const GrBackendEffectFactory& CircleInside2PtConicalEffect::getFactory() const {
901 return GrTBackendEffectFactory<CircleInside2PtConicalEffect>::getInstance();
902}
903
904GR_DEFINE_EFFECT_TEST(CircleInside2PtConicalEffect);
905
bsalomon83d081a2014-07-08 09:56:10 -0700906GrEffect* CircleInside2PtConicalEffect::TestCreate(SkRandom* random,
907 GrContext* context,
908 const GrDrawTargetCaps&,
909 GrTexture**) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000910 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000911 SkScalar radius1 = random->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000912 SkPoint center2;
913 SkScalar radius2;
914 do {
915 center2.set(random->nextUScalar1(), random->nextUScalar1());
916 // Below makes sure that circle one is contained within circle two
917 SkScalar increase = random->nextUScalar1();
918 SkPoint diff = center2 - center1;
919 SkScalar diffLen = diff.length();
920 radius2 = radius1 + diffLen + increase;
921 // If the circles are identical the factory will give us an empty shader.
922 } while (radius1 == radius2 && center1 == center2);
923
924 SkColor colors[kMaxRandomGradientColors];
925 SkScalar stopsArray[kMaxRandomGradientColors];
926 SkScalar* stops = stopsArray;
927 SkShader::TileMode tm;
928 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
929 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
930 center2, radius2,
931 colors, stops, colorCount,
932 tm));
933 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -0700934 GrColor paintColor;
935 GrEffect* effect;
936 SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect));
937 return effect;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000938}
939
940GLCircleInside2PtConicalEffect::GLCircleInside2PtConicalEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -0700941 const GrEffect& effect)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000942 : INHERITED(factory)
943 , fVSVaryingName(NULL)
944 , fFSVaryingName(NULL)
945 , fCachedCenterX(SK_ScalarMax)
946 , fCachedCenterY(SK_ScalarMax)
947 , fCachedA(SK_ScalarMax)
948 , fCachedB(SK_ScalarMax)
949 , fCachedC(SK_ScalarMax) {}
950
joshualitt30ba4362014-08-21 20:18:45 -0700951void GLCircleInside2PtConicalEffect::emitCode(GrGLProgramBuilder* builder,
joshualitt49586be2014-09-16 08:21:41 -0700952 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -0700953 const GrEffectKey& key,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000954 const char* outputColor,
955 const char* inputColor,
956 const TransformedCoordsArray& coords,
957 const TextureSamplerArray& samplers) {
bsalomon63e99f72014-07-21 08:03:14 -0700958 uint32_t baseKey = key.get32(0);
959 this->emitUniforms(builder, baseKey);
joshualitt30ba4362014-08-21 20:18:45 -0700960 fCenterUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000961 kVec2f_GrSLType, "Conical2FSCenter");
joshualitt30ba4362014-08-21 20:18:45 -0700962 fParamUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000963 kVec3f_GrSLType, "Conical2FSParams");
964 SkString tName("t");
965
966 GrGLShaderVar center = builder->getUniformVariable(fCenterUni);
967 // params.x = A
968 // params.y = B
969 // params.z = C
970 GrGLShaderVar params = builder->getUniformVariable(fParamUni);
971
972 // if we have a vec3 from being in perspective, convert it to a vec2 first
joshualitt30ba4362014-08-21 20:18:45 -0700973 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
974 SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000975 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000976
977 // p = coords2D
978 // e = center end
979 // r = radius end
980 // A = dot(e, e) - r^2 + 2 * r - 1
981 // B = (r -1) / A
982 // C = 1 / A
983 // d = dot(e, p) + B
984 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
joshualitt30ba4362014-08-21 20:18:45 -0700985 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -0700986 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
987 params.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700988 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000989 tName.c_str(), params.c_str(), params.c_str());
990
bsalomon63e99f72014-07-21 08:03:14 -0700991 this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000992}
993
kkinnunen7510b222014-07-30 00:04:16 -0700994void GLCircleInside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualitt49586be2014-09-16 08:21:41 -0700995 const GrEffect& effect) {
996 INHERITED::setData(pdman, effect);
997 const CircleInside2PtConicalEffect& data = effect.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
joshualitt49586be2014-09-16 08:21:41 -07001018void GLCircleInside2PtConicalEffect::GenKey(const GrEffect& effect,
bsalomon63e99f72014-07-21 08:03:14 -07001019 const GrGLCaps&, GrEffectKeyBuilder* b) {
joshualitt49586be2014-09-16 08:21:41 -07001020 b->add32(GenBaseGradientKey(effect));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001021}
1022
1023//////////////////////////////////////////////////////////////////////////////
1024
1025class GLCircleOutside2PtConicalEffect;
1026
1027class CircleOutside2PtConicalEffect : public GrGradientEffect {
1028public:
1029
bsalomon83d081a2014-07-08 09:56:10 -07001030 static GrEffect* Create(GrContext* ctx,
1031 const SkTwoPointConicalGradient& shader,
1032 const SkMatrix& matrix,
1033 SkShader::TileMode tm,
1034 const CircleConicalInfo& info) {
bsalomon55fad7a2014-07-08 07:34:20 -07001035 return SkNEW_ARGS(CircleOutside2PtConicalEffect, (ctx, shader, matrix, tm, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001036 }
1037
1038 virtual ~CircleOutside2PtConicalEffect() {}
1039
1040 static const char* Name() { return "Two-Point Conical Gradient Outside"; }
1041 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
1042
1043 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1044 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1045 SkScalar A() const { return fInfo.fA; }
1046 SkScalar B() const { return fInfo.fB; }
1047 SkScalar C() const { return fInfo.fC; }
1048 SkScalar tLimit() const { return fTLimit; }
1049 bool isFlipped() const { return fIsFlipped; }
1050
1051 typedef GLCircleOutside2PtConicalEffect GLEffect;
1052
1053private:
1054 virtual bool onIsEqual(const GrEffect& sBase) const SK_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,
1066 const SkTwoPointConicalGradient& shader,
1067 const SkMatrix& matrix,
1068 SkShader::TileMode tm,
1069 const CircleConicalInfo& info)
1070 : INHERITED(ctx, shader, matrix, tm), fInfo(info) {
1071 if (shader.getStartRadius() != shader.getEndRadius()) {
joshualitt49586be2014-09-16 08:21:41 -07001072 fTLimit = SkScalarDiv(shader.getStartRadius(),
1073 (shader.getStartRadius() - shader.getEndRadius()));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001074 } else {
1075 fTLimit = SK_ScalarMin;
1076 }
1077
1078 fIsFlipped = shader.isFlippedGrad();
1079 }
1080
1081 GR_DECLARE_EFFECT_TEST;
1082
1083 const CircleConicalInfo fInfo;
1084 SkScalar fTLimit;
1085 bool fIsFlipped;
1086
1087 typedef GrGradientEffect INHERITED;
1088};
1089
1090class GLCircleOutside2PtConicalEffect : public GrGLGradientEffect {
1091public:
joshualitt49586be2014-09-16 08:21:41 -07001092 GLCircleOutside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrEffect&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001093 virtual ~GLCircleOutside2PtConicalEffect() {}
1094
joshualitt30ba4362014-08-21 20:18:45 -07001095 virtual void emitCode(GrGLProgramBuilder*,
joshualitt49586be2014-09-16 08:21:41 -07001096 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -07001097 const GrEffectKey&,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001098 const char* outputColor,
1099 const char* inputColor,
1100 const TransformedCoordsArray&,
1101 const TextureSamplerArray&) SK_OVERRIDE;
joshualitt49586be2014-09-16 08:21:41 -07001102 virtual void setData(const GrGLProgramDataManager&, const GrEffect&) SK_OVERRIDE;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001103
joshualitt49586be2014-09-16 08:21:41 -07001104 static void GenKey(const GrEffect&, const GrGLCaps& caps, GrEffectKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001105
1106protected:
1107 UniformHandle fCenterUni;
1108 UniformHandle fParamUni;
1109
1110 const char* fVSVaryingName;
1111 const char* fFSVaryingName;
1112
1113 bool fIsFlipped;
1114
1115 // @{
1116 /// Values last uploaded as uniforms
1117
1118 SkScalar fCachedCenterX;
1119 SkScalar fCachedCenterY;
1120 SkScalar fCachedA;
1121 SkScalar fCachedB;
1122 SkScalar fCachedC;
1123 SkScalar fCachedTLimit;
1124
1125 // @}
1126
1127private:
1128 typedef GrGLGradientEffect INHERITED;
1129
1130};
1131
1132const GrBackendEffectFactory& CircleOutside2PtConicalEffect::getFactory() const {
1133 return GrTBackendEffectFactory<CircleOutside2PtConicalEffect>::getInstance();
1134}
1135
1136GR_DEFINE_EFFECT_TEST(CircleOutside2PtConicalEffect);
1137
bsalomon83d081a2014-07-08 09:56:10 -07001138GrEffect* CircleOutside2PtConicalEffect::TestCreate(SkRandom* random,
1139 GrContext* context,
1140 const GrDrawTargetCaps&,
1141 GrTexture**) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001142 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +00001143 SkScalar radius1 = random->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001144 SkPoint center2;
1145 SkScalar radius2;
1146 SkScalar diffLen;
1147 do {
1148 center2.set(random->nextUScalar1(), random->nextUScalar1());
1149 // If the circles share a center than we can't be in the outside case
1150 } while (center1 == center2);
1151 SkPoint diff = center2 - center1;
1152 diffLen = diff.length();
1153 // Below makes sure that circle one is not contained within circle two
1154 // and have radius2 >= radius to match sorting on cpu side
commit-bot@chromium.org80894672014-04-22 21:24:22 +00001155 radius2 = radius1 + random->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001156
1157 SkColor colors[kMaxRandomGradientColors];
1158 SkScalar stopsArray[kMaxRandomGradientColors];
1159 SkScalar* stops = stopsArray;
1160 SkShader::TileMode tm;
1161 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
1162 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
1163 center2, radius2,
1164 colors, stops, colorCount,
1165 tm));
1166 SkPaint paint;
bsalomon83d081a2014-07-08 09:56:10 -07001167 GrColor paintColor;
1168 GrEffect* effect;
1169 SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect));
1170 return effect;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001171}
1172
1173GLCircleOutside2PtConicalEffect::GLCircleOutside2PtConicalEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -07001174 const GrEffect& effect)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001175 : INHERITED(factory)
1176 , fVSVaryingName(NULL)
1177 , fFSVaryingName(NULL)
1178 , fCachedCenterX(SK_ScalarMax)
1179 , fCachedCenterY(SK_ScalarMax)
1180 , fCachedA(SK_ScalarMax)
1181 , fCachedB(SK_ScalarMax)
1182 , fCachedC(SK_ScalarMax)
1183 , fCachedTLimit(SK_ScalarMax) {
joshualitt49586be2014-09-16 08:21:41 -07001184 const CircleOutside2PtConicalEffect& data = effect.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001185 fIsFlipped = data.isFlipped();
1186 }
1187
joshualitt30ba4362014-08-21 20:18:45 -07001188void GLCircleOutside2PtConicalEffect::emitCode(GrGLProgramBuilder* builder,
joshualitt49586be2014-09-16 08:21:41 -07001189 const GrEffect&,
bsalomon63e99f72014-07-21 08:03:14 -07001190 const GrEffectKey& key,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001191 const char* outputColor,
1192 const char* inputColor,
1193 const TransformedCoordsArray& coords,
1194 const TextureSamplerArray& samplers) {
bsalomon63e99f72014-07-21 08:03:14 -07001195 uint32_t baseKey = key.get32(0);
1196 this->emitUniforms(builder, baseKey);
joshualitt30ba4362014-08-21 20:18:45 -07001197 fCenterUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001198 kVec2f_GrSLType, "Conical2FSCenter");
joshualitt30ba4362014-08-21 20:18:45 -07001199 fParamUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001200 kVec4f_GrSLType, "Conical2FSParams");
1201 SkString tName("t");
1202
1203 GrGLShaderVar center = builder->getUniformVariable(fCenterUni);
1204 // params.x = A
1205 // params.y = B
1206 // params.z = C
1207 GrGLShaderVar params = builder->getUniformVariable(fParamUni);
1208
1209 // if we have a vec3 from being in perspective, convert it to a vec2 first
joshualitt30ba4362014-08-21 20:18:45 -07001210 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1211 SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001212 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001213
1214 // output will default to transparent black (we simply won't write anything
1215 // else to it if invalid, instead of discarding or returning prematurely)
joshualitt30ba4362014-08-21 20:18:45 -07001216 fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001217
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001218 // p = coords2D
1219 // e = center end
1220 // r = radius end
1221 // A = dot(e, e) - r^2 + 2 * r - 1
1222 // B = (r -1) / A
1223 // C = 1 / A
1224 // d = dot(e, p) + B
1225 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001226
joshualitt30ba4362014-08-21 20:18:45 -07001227 fsBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
joshualitt49586be2014-09-16 08:21:41 -07001228 fsBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1229 params.c_str());
1230 fsBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1231 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001232
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001233 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1234 // If so we must also flip sign on sqrt
1235 if (!fIsFlipped) {
joshualitt30ba4362014-08-21 20:18:45 -07001236 fsBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001237 } else {
joshualitt30ba4362014-08-21 20:18:45 -07001238 fsBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001239 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001240
joshualitt30ba4362014-08-21 20:18:45 -07001241 fsBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str());
1242 fsBuilder->codeAppend("\t\t");
bsalomon63e99f72014-07-21 08:03:14 -07001243 this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
joshualitt30ba4362014-08-21 20:18:45 -07001244 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001245}
1246
kkinnunen7510b222014-07-30 00:04:16 -07001247void GLCircleOutside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
joshualitt49586be2014-09-16 08:21:41 -07001248 const GrEffect& effect) {
1249 INHERITED::setData(pdman, effect);
1250 const CircleOutside2PtConicalEffect& data = effect.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001251 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001252 SkScalar centerX = data.centerX();
1253 SkScalar centerY = data.centerY();
1254 SkScalar A = data.A();
1255 SkScalar B = data.B();
1256 SkScalar C = data.C();
1257 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001258
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001259 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1260 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001261
kkinnunen7510b222014-07-30 00:04:16 -07001262 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1263 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001264 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001265
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001266 fCachedCenterX = centerX;
1267 fCachedCenterY = centerY;
1268 fCachedA = A;
1269 fCachedB = B;
1270 fCachedC = C;
1271 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001272 }
1273}
1274
joshualitt49586be2014-09-16 08:21:41 -07001275void GLCircleOutside2PtConicalEffect::GenKey(const GrEffect& effect,
bsalomon63e99f72014-07-21 08:03:14 -07001276 const GrGLCaps&, GrEffectKeyBuilder* b) {
1277 uint32_t* key = b->add32n(2);
joshualitt49586be2014-09-16 08:21:41 -07001278 key[0] = GenBaseGradientKey(effect);
1279 key[1] = effect.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001280}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001281
1282//////////////////////////////////////////////////////////////////////////////
1283
bsalomon83d081a2014-07-08 09:56:10 -07001284GrEffect* Gr2PtConicalGradientEffect::Create(GrContext* ctx,
1285 const SkTwoPointConicalGradient& shader,
1286 SkShader::TileMode tm,
1287 const SkMatrix* localMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001288 SkMatrix matrix;
1289 if (!shader.getLocalMatrix().invert(&matrix)) {
1290 return NULL;
1291 }
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001292 if (localMatrix) {
1293 SkMatrix inv;
1294 if (!localMatrix->invert(&inv)) {
1295 return NULL;
1296 }
1297 matrix.postConcat(inv);
1298 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001299
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001300 if (shader.getStartRadius() < kErrorTol) {
1301 SkScalar focalX;
1302 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1303 if (type == kInside_ConicalType) {
1304 return FocalInside2PtConicalEffect::Create(ctx, shader, matrix, tm, focalX);
1305 } else if(type == kEdge_ConicalType) {
1306 set_matrix_edge_conical(shader, &matrix);
1307 return Edge2PtConicalEffect::Create(ctx, shader, matrix, tm);
1308 } else {
1309 return FocalOutside2PtConicalEffect::Create(ctx, shader, matrix, tm, focalX);
1310 }
1311 }
1312
1313 CircleConicalInfo info;
1314 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1315
1316 if (type == kInside_ConicalType) {
1317 return CircleInside2PtConicalEffect::Create(ctx, shader, matrix, tm, info);
1318 } else if (type == kEdge_ConicalType) {
1319 set_matrix_edge_conical(shader, &matrix);
1320 return Edge2PtConicalEffect::Create(ctx, shader, matrix, tm);
1321 } else {
1322 return CircleOutside2PtConicalEffect::Create(ctx, shader, matrix, tm, info);
1323 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001324}
1325
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001326#endif