3 * Copyright 2014 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
9 #include "SkTwoPointConicalGradient_gpu.h"
11 #include "SkTwoPointConicalGradient.h"
14 #include "GrTBackendEffectFactory.h"
15 #include "gl/GrGLShaderBuilder.h"
17 typedef GrGLProgramDataManager::UniformHandle UniformHandle;
19 static const SkScalar kErrorTol = 0.00001f;
20 static const SkScalar kEdgeErrorTol = 5.f * kErrorTol;
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.
36 //////////////////////////////////////////////////////////////////////////////
38 static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader,
39 SkMatrix* invLMatrix) {
40 // 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();
45 invLMatrix->postTranslate(-center1.fX, -center1.fY);
47 SkPoint diff = center2 - center1;
48 SkScalar diffLen = diff.length();
50 SkScalar invDiffLen = SkScalarInvert(diffLen);
52 rot.setSinCos(-SkScalarMul(invDiffLen, diff.fY),
53 SkScalarMul(invDiffLen, diff.fX));
54 invLMatrix->postConcat(rot);
58 class GLEdge2PtConicalEffect;
60 class Edge2PtConicalEffect : public GrGradientEffect {
63 static GrEffect* Create(GrContext* ctx,
64 const SkTwoPointConicalGradient& shader,
65 const SkMatrix& matrix,
66 SkShader::TileMode tm) {
67 return SkNEW_ARGS(Edge2PtConicalEffect, (ctx, shader, matrix, tm));
70 virtual ~Edge2PtConicalEffect() {}
72 static const char* Name() { return "Two-Point Conical Gradient Edge Touching"; }
73 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
75 // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
76 SkScalar center() const { return fCenterX1; }
77 SkScalar diffRadius() const { return fDiffRadius; }
78 SkScalar radius() const { return fRadius0; }
80 typedef GLEdge2PtConicalEffect GLEffect;
83 virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
84 const Edge2PtConicalEffect& s = CastEffect<Edge2PtConicalEffect>(sBase);
85 return (INHERITED::onIsEqual(sBase) &&
86 this->fCenterX1 == s.fCenterX1 &&
87 this->fRadius0 == s.fRadius0 &&
88 this->fDiffRadius == s.fDiffRadius);
91 Edge2PtConicalEffect(GrContext* ctx,
92 const SkTwoPointConicalGradient& shader,
93 const SkMatrix& matrix,
94 SkShader::TileMode tm)
95 : INHERITED(ctx, shader, matrix, tm),
96 fCenterX1(shader.getCenterX1()),
97 fRadius0(shader.getStartRadius()),
98 fDiffRadius(shader.getDiffRadius()){
99 // We should only be calling this shader if we are degenerate case with touching circles
100 // 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));
105 // 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);
119 GR_DECLARE_EFFECT_TEST;
122 // Cache of values - these can change arbitrarily, EXCEPT
123 // we shouldn't change between degenerate and non-degenerate?!
125 GrCoordTransform fBTransform;
128 SkScalar fDiffRadius;
132 typedef GrGradientEffect INHERITED;
135 class GLEdge2PtConicalEffect : public GrGLGradientEffect {
137 GLEdge2PtConicalEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&);
138 virtual ~GLEdge2PtConicalEffect() { }
140 virtual void emitCode(GrGLShaderBuilder*,
143 const char* outputColor,
144 const char* inputColor,
145 const TransformedCoordsArray&,
146 const TextureSamplerArray&) SK_OVERRIDE;
147 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
149 static void GenKey(const GrDrawEffect&, const GrGLCaps& caps, GrEffectKeyBuilder* b);
152 UniformHandle fParamUni;
154 const char* fVSVaryingName;
155 const char* fFSVaryingName;
158 /// Values last uploaded as uniforms
160 SkScalar fCachedRadius;
161 SkScalar fCachedDiffRadius;
166 typedef GrGLGradientEffect INHERITED;
170 const GrBackendEffectFactory& Edge2PtConicalEffect::getFactory() const {
171 return GrTBackendEffectFactory<Edge2PtConicalEffect>::getInstance();
174 GR_DEFINE_EFFECT_TEST(Edge2PtConicalEffect);
176 GrEffect* Edge2PtConicalEffect::TestCreate(SkRandom* random,
178 const GrDrawTargetCaps&,
180 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
181 SkScalar radius1 = random->nextUScalar1();
185 center2.set(random->nextUScalar1(), random->nextUScalar1());
186 // 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);
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;
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,
203 colors, stops, colorCount,
208 SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect));
212 GLEdge2PtConicalEffect::GLEdge2PtConicalEffect(const GrBackendEffectFactory& factory,
213 const GrDrawEffect& drawEffect)
215 , fVSVaryingName(NULL)
216 , fFSVaryingName(NULL)
217 , fCachedRadius(-SK_ScalarMax)
218 , fCachedDiffRadius(-SK_ScalarMax) {}
220 void GLEdge2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
222 const GrEffectKey& key,
223 const char* outputColor,
224 const char* inputColor,
225 const TransformedCoordsArray& coords,
226 const TextureSamplerArray& samplers) {
227 uint32_t baseKey = key.get32(0);
228 this->emitUniforms(builder, baseKey);
229 fParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
230 kFloat_GrSLType, "Conical2FSParams", 3);
234 SkString p0; // start radius
235 SkString p1; // start radius squared
236 SkString p2; // difference in radii (r1 - r0)
238 builder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
239 builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
240 builder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
242 // We interpolate the linear component in coords[1].
243 SkASSERT(coords[0].type() == coords[1].type());
244 const char* coords2D;
246 if (kVec3f_GrSLType == coords[0].type()) {
247 builder->fsCodeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
248 coords[0].c_str(), coords[0].c_str(), coords[1].c_str(), coords[1].c_str());
249 coords2D = "interpolants.xy";
250 bVar = "interpolants.z";
252 coords2D = coords[0].c_str();
253 bVar.printf("%s.x", coords[1].c_str());
256 // output will default to transparent black (we simply won't write anything
257 // else to it if invalid, instead of discarding or returning prematurely)
258 builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
260 // c = (x^2)+(y^2) - params[1]
261 builder->fsCodeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
262 cName.c_str(), coords2D, coords2D, p1.c_str());
264 // linear case: t = -c/b
265 builder->fsCodeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
266 cName.c_str(), bVar.c_str());
268 // if r(t) > 0, then t will be the x coordinate
269 builder->fsCodeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
270 p2.c_str(), p0.c_str());
271 builder->fsCodeAppend("\t");
272 this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
273 builder->fsCodeAppend("\t}\n");
276 void GLEdge2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
277 const GrDrawEffect& drawEffect) {
278 INHERITED::setData(pdman, drawEffect);
279 const Edge2PtConicalEffect& data = drawEffect.castEffect<Edge2PtConicalEffect>();
280 SkScalar radius0 = data.radius();
281 SkScalar diffRadius = data.diffRadius();
283 if (fCachedRadius != radius0 ||
284 fCachedDiffRadius != diffRadius) {
287 SkScalarToFloat(radius0),
288 SkScalarToFloat(SkScalarMul(radius0, radius0)),
289 SkScalarToFloat(diffRadius)
292 pdman.set1fv(fParamUni, 3, values);
293 fCachedRadius = radius0;
294 fCachedDiffRadius = diffRadius;
298 void GLEdge2PtConicalEffect::GenKey(const GrDrawEffect& drawEffect,
299 const GrGLCaps&, GrEffectKeyBuilder* b) {
300 b->add32(GenBaseGradientKey(drawEffect));
303 //////////////////////////////////////////////////////////////////////////////
304 // Focal Conical Gradients
305 //////////////////////////////////////////////////////////////////////////////
307 static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
308 SkMatrix* invLMatrix, SkScalar* focalX) {
309 // Inverse of the current local matrix is passed in then,
310 // translate, scale, and rotate such that endCircle is unit circle on x-axis,
311 // and focal point is at the origin.
312 ConicalType conicalType;
313 const SkPoint& focal = shader.getStartCenter();
314 const SkPoint& centerEnd = shader.getEndCenter();
315 SkScalar radius = shader.getEndRadius();
316 SkScalar invRadius = 1.f / radius;
320 matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
321 matrix.postScale(invRadius, invRadius);
324 matrix.mapPoints(&focalTrans, &focal, 1);
325 *focalX = focalTrans.length();
327 if (0.f != *focalX) {
328 SkScalar invFocalX = SkScalarInvert(*focalX);
330 rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY),
331 SkScalarMul(invFocalX, focalTrans.fX));
332 matrix.postConcat(rot);
335 matrix.postTranslate(-(*focalX), 0.f);
337 // If the focal point is touching the edge of the circle it will
338 // cause a degenerate case that must be handled separately
339 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
340 // stability trade off versus the linear approx used in the Edge Shader
341 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
342 return kEdge_ConicalType;
345 // Scale factor 1 / (1 - focalX * focalX)
346 SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX);
347 SkScalar s = SkScalarDiv(1.f, oneMinusF2);
351 conicalType = kInside_ConicalType;
352 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
354 conicalType = kOutside_ConicalType;
355 matrix.postScale(s, s);
358 invLMatrix->postConcat(matrix);
363 //////////////////////////////////////////////////////////////////////////////
365 class GLFocalOutside2PtConicalEffect;
367 class FocalOutside2PtConicalEffect : public GrGradientEffect {
370 static GrEffect* Create(GrContext* ctx,
371 const SkTwoPointConicalGradient& shader,
372 const SkMatrix& matrix,
373 SkShader::TileMode tm,
375 return SkNEW_ARGS(FocalOutside2PtConicalEffect, (ctx, shader, matrix, tm, focalX));
378 virtual ~FocalOutside2PtConicalEffect() { }
380 static const char* Name() { return "Two-Point Conical Gradient Focal Outside"; }
381 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
383 bool isFlipped() const { return fIsFlipped; }
384 SkScalar focal() const { return fFocalX; }
386 typedef GLFocalOutside2PtConicalEffect GLEffect;
389 virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
390 const FocalOutside2PtConicalEffect& s = CastEffect<FocalOutside2PtConicalEffect>(sBase);
391 return (INHERITED::onIsEqual(sBase) &&
392 this->fFocalX == s.fFocalX &&
393 this->fIsFlipped == s.fIsFlipped);
396 FocalOutside2PtConicalEffect(GrContext* ctx,
397 const SkTwoPointConicalGradient& shader,
398 const SkMatrix& matrix,
399 SkShader::TileMode tm,
401 : INHERITED(ctx, shader, matrix, tm), fFocalX(focalX), fIsFlipped(shader.isFlippedGrad()) {}
403 GR_DECLARE_EFFECT_TEST;
408 typedef GrGradientEffect INHERITED;
411 class GLFocalOutside2PtConicalEffect : public GrGLGradientEffect {
413 GLFocalOutside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&);
414 virtual ~GLFocalOutside2PtConicalEffect() { }
416 virtual void emitCode(GrGLShaderBuilder*,
419 const char* outputColor,
420 const char* inputColor,
421 const TransformedCoordsArray&,
422 const TextureSamplerArray&) SK_OVERRIDE;
423 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
425 static void GenKey(const GrDrawEffect&, const GrGLCaps& caps, GrEffectKeyBuilder* b);
428 UniformHandle fParamUni;
430 const char* fVSVaryingName;
431 const char* fFSVaryingName;
436 /// Values last uploaded as uniforms
438 SkScalar fCachedFocal;
443 typedef GrGLGradientEffect INHERITED;
447 const GrBackendEffectFactory& FocalOutside2PtConicalEffect::getFactory() const {
448 return GrTBackendEffectFactory<FocalOutside2PtConicalEffect>::getInstance();
451 GR_DEFINE_EFFECT_TEST(FocalOutside2PtConicalEffect);
453 GrEffect* FocalOutside2PtConicalEffect::TestCreate(SkRandom* random,
455 const GrDrawTargetCaps&,
457 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
458 SkScalar radius1 = 0.f;
462 center2.set(random->nextUScalar1(), random->nextUScalar1());
463 // Need to make sure the centers are not the same or else focal point will be inside
464 } while (center1 == center2);
465 SkPoint diff = center2 - center1;
466 SkScalar diffLen = diff.length();
467 // Below makes sure that the focal point is not contained within circle two
468 radius2 = random->nextRangeF(0.f, diffLen);
470 SkColor colors[kMaxRandomGradientColors];
471 SkScalar stopsArray[kMaxRandomGradientColors];
472 SkScalar* stops = stopsArray;
473 SkShader::TileMode tm;
474 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
475 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
477 colors, stops, colorCount,
482 SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect));
486 GLFocalOutside2PtConicalEffect::GLFocalOutside2PtConicalEffect(const GrBackendEffectFactory& factory,
487 const GrDrawEffect& drawEffect)
489 , fVSVaryingName(NULL)
490 , fFSVaryingName(NULL)
491 , fCachedFocal(SK_ScalarMax) {
492 const FocalOutside2PtConicalEffect& data = drawEffect.castEffect<FocalOutside2PtConicalEffect>();
493 fIsFlipped = data.isFlipped();
496 void GLFocalOutside2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
498 const GrEffectKey& key,
499 const char* outputColor,
500 const char* inputColor,
501 const TransformedCoordsArray& coords,
502 const TextureSamplerArray& samplers) {
503 uint32_t baseKey = key.get32(0);
504 this->emitUniforms(builder, baseKey);
505 fParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
506 kFloat_GrSLType, "Conical2FSParams", 2);
508 SkString p0; // focalX
509 SkString p1; // 1 - focalX * focalX
511 builder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
512 builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
514 // if we have a vec3 from being in perspective, convert it to a vec2 first
515 SkString coords2DString = builder->ensureFSCoords2D(coords, 0);
516 const char* coords2D = coords2DString.c_str();
518 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
520 // output will default to transparent black (we simply won't write anything
521 // else to it if invalid, instead of discarding or returning prematurely)
522 builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
524 builder->fsCodeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
525 builder->fsCodeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
526 builder->fsCodeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
528 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
529 // If so we must also flip sign on sqrt
531 builder->fsCodeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
532 coords2D, p0.c_str());
534 builder->fsCodeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
535 coords2D, p0.c_str());
538 builder->fsCodeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
539 builder->fsCodeAppend("\t\t");
540 this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
541 builder->fsCodeAppend("\t}\n");
544 void GLFocalOutside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
545 const GrDrawEffect& drawEffect) {
546 INHERITED::setData(pdman, drawEffect);
547 const FocalOutside2PtConicalEffect& data = drawEffect.castEffect<FocalOutside2PtConicalEffect>();
548 SkASSERT(data.isFlipped() == fIsFlipped);
549 SkScalar focal = data.focal();
551 if (fCachedFocal != focal) {
552 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
555 SkScalarToFloat(focal),
556 SkScalarToFloat(oneMinus2F),
559 pdman.set1fv(fParamUni, 2, values);
560 fCachedFocal = focal;
564 void GLFocalOutside2PtConicalEffect::GenKey(const GrDrawEffect& drawEffect,
565 const GrGLCaps&, GrEffectKeyBuilder* b) {
566 uint32_t* key = b->add32n(2);
567 key[0] = GenBaseGradientKey(drawEffect);
568 key[1] = drawEffect.castEffect<FocalOutside2PtConicalEffect>().isFlipped();
571 //////////////////////////////////////////////////////////////////////////////
573 class GLFocalInside2PtConicalEffect;
575 class FocalInside2PtConicalEffect : public GrGradientEffect {
578 static GrEffect* Create(GrContext* ctx,
579 const SkTwoPointConicalGradient& shader,
580 const SkMatrix& matrix,
581 SkShader::TileMode tm,
583 return SkNEW_ARGS(FocalInside2PtConicalEffect, (ctx, shader, matrix, tm, focalX));
586 virtual ~FocalInside2PtConicalEffect() {}
588 static const char* Name() { return "Two-Point Conical Gradient Focal Inside"; }
589 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
591 SkScalar focal() const { return fFocalX; }
593 typedef GLFocalInside2PtConicalEffect GLEffect;
596 virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
597 const FocalInside2PtConicalEffect& s = CastEffect<FocalInside2PtConicalEffect>(sBase);
598 return (INHERITED::onIsEqual(sBase) &&
599 this->fFocalX == s.fFocalX);
602 FocalInside2PtConicalEffect(GrContext* ctx,
603 const SkTwoPointConicalGradient& shader,
604 const SkMatrix& matrix,
605 SkShader::TileMode tm,
607 : INHERITED(ctx, shader, matrix, tm), fFocalX(focalX) {}
609 GR_DECLARE_EFFECT_TEST;
613 typedef GrGradientEffect INHERITED;
616 class GLFocalInside2PtConicalEffect : public GrGLGradientEffect {
618 GLFocalInside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&);
619 virtual ~GLFocalInside2PtConicalEffect() {}
621 virtual void emitCode(GrGLShaderBuilder*,
624 const char* outputColor,
625 const char* inputColor,
626 const TransformedCoordsArray&,
627 const TextureSamplerArray&) SK_OVERRIDE;
628 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
630 static void GenKey(const GrDrawEffect&, const GrGLCaps& caps, GrEffectKeyBuilder* b);
633 UniformHandle fFocalUni;
635 const char* fVSVaryingName;
636 const char* fFSVaryingName;
639 /// Values last uploaded as uniforms
641 SkScalar fCachedFocal;
646 typedef GrGLGradientEffect INHERITED;
650 const GrBackendEffectFactory& FocalInside2PtConicalEffect::getFactory() const {
651 return GrTBackendEffectFactory<FocalInside2PtConicalEffect>::getInstance();
654 GR_DEFINE_EFFECT_TEST(FocalInside2PtConicalEffect);
656 GrEffect* FocalInside2PtConicalEffect::TestCreate(SkRandom* random,
658 const GrDrawTargetCaps&,
660 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
661 SkScalar radius1 = 0.f;
665 center2.set(random->nextUScalar1(), random->nextUScalar1());
666 // Below makes sure radius2 is larger enouch such that the focal point
667 // is inside the end circle
668 SkScalar increase = random->nextUScalar1();
669 SkPoint diff = center2 - center1;
670 SkScalar diffLen = diff.length();
671 radius2 = diffLen + increase;
672 // If the circles are identical the factory will give us an empty shader.
673 } while (radius1 == radius2 && center1 == center2);
675 SkColor colors[kMaxRandomGradientColors];
676 SkScalar stopsArray[kMaxRandomGradientColors];
677 SkScalar* stops = stopsArray;
678 SkShader::TileMode tm;
679 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
680 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
682 colors, stops, colorCount,
687 SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect));
691 GLFocalInside2PtConicalEffect::GLFocalInside2PtConicalEffect(const GrBackendEffectFactory& factory,
692 const GrDrawEffect& drawEffect)
694 , fVSVaryingName(NULL)
695 , fFSVaryingName(NULL)
696 , fCachedFocal(SK_ScalarMax) {}
698 void GLFocalInside2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
700 const GrEffectKey& key,
701 const char* outputColor,
702 const char* inputColor,
703 const TransformedCoordsArray& coords,
704 const TextureSamplerArray& samplers) {
705 uint32_t baseKey = key.get32(0);
706 this->emitUniforms(builder, baseKey);
707 fFocalUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
708 kFloat_GrSLType, "Conical2FSParams");
711 // this is the distance along x-axis from the end center to focal point in
712 // transformed coordinates
713 GrGLShaderVar focal = builder->getUniformVariable(fFocalUni);
715 // if we have a vec3 from being in perspective, convert it to a vec2 first
716 SkString coords2DString = builder->ensureFSCoords2D(coords, 0);
717 const char* coords2D = coords2DString.c_str();
719 // t = p.x * focalX + length(p)
720 builder->fsCodeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
721 coords2D, focal.c_str(), coords2D);
723 this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
726 void GLFocalInside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
727 const GrDrawEffect& drawEffect) {
728 INHERITED::setData(pdman, drawEffect);
729 const FocalInside2PtConicalEffect& data = drawEffect.castEffect<FocalInside2PtConicalEffect>();
730 SkScalar focal = data.focal();
732 if (fCachedFocal != focal) {
733 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
734 fCachedFocal = focal;
738 void GLFocalInside2PtConicalEffect::GenKey(const GrDrawEffect& drawEffect,
739 const GrGLCaps&, GrEffectKeyBuilder* b) {
740 b->add32(GenBaseGradientKey(drawEffect));
743 //////////////////////////////////////////////////////////////////////////////
744 // Circle Conical Gradients
745 //////////////////////////////////////////////////////////////////////////////
747 struct CircleConicalInfo {
754 // Returns focal distance along x-axis in transformed coords
755 static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
756 SkMatrix* invLMatrix, CircleConicalInfo* info) {
757 // Inverse of the current local matrix is passed in then,
758 // translate and scale such that start circle is on the origin and has radius 1
759 const SkPoint& centerStart = shader.getStartCenter();
760 const SkPoint& centerEnd = shader.getEndCenter();
761 SkScalar radiusStart = shader.getStartRadius();
762 SkScalar radiusEnd = shader.getEndRadius();
766 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
768 SkScalar invStartRad = 1.f / radiusStart;
769 matrix.postScale(invStartRad, invStartRad);
771 radiusEnd /= radiusStart;
773 SkPoint centerEndTrans;
774 matrix.mapPoints(¢erEndTrans, ¢erEnd, 1);
776 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
777 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
779 // Check to see if start circle is inside end circle with edges touching.
780 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
781 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
782 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
784 if (SkScalarAbs(A) < kEdgeErrorTol) {
785 return kEdge_ConicalType;
788 SkScalar C = 1.f / A;
789 SkScalar B = (radiusEnd - 1.f) * C;
791 matrix.postScale(C, C);
793 invLMatrix->postConcat(matrix);
795 info->fCenterEnd = centerEndTrans;
800 // if A ends up being negative, the start circle is contained completely inside the end cirlce
802 return kInside_ConicalType;
804 return kOutside_ConicalType;
807 class GLCircleInside2PtConicalEffect;
809 class CircleInside2PtConicalEffect : public GrGradientEffect {
812 static GrEffect* Create(GrContext* ctx,
813 const SkTwoPointConicalGradient& shader,
814 const SkMatrix& matrix,
815 SkShader::TileMode tm,
816 const CircleConicalInfo& info) {
817 return SkNEW_ARGS(CircleInside2PtConicalEffect, (ctx, shader, matrix, tm, info));
820 virtual ~CircleInside2PtConicalEffect() {}
822 static const char* Name() { return "Two-Point Conical Gradient Inside"; }
823 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
825 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
826 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
827 SkScalar A() const { return fInfo.fA; }
828 SkScalar B() const { return fInfo.fB; }
829 SkScalar C() const { return fInfo.fC; }
831 typedef GLCircleInside2PtConicalEffect GLEffect;
834 virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
835 const CircleInside2PtConicalEffect& s = CastEffect<CircleInside2PtConicalEffect>(sBase);
836 return (INHERITED::onIsEqual(sBase) &&
837 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
838 this->fInfo.fA == s.fInfo.fA &&
839 this->fInfo.fB == s.fInfo.fB &&
840 this->fInfo.fC == s.fInfo.fC);
843 CircleInside2PtConicalEffect(GrContext* ctx,
844 const SkTwoPointConicalGradient& shader,
845 const SkMatrix& matrix,
846 SkShader::TileMode tm,
847 const CircleConicalInfo& info)
848 : INHERITED(ctx, shader, matrix, tm), fInfo(info) {}
850 GR_DECLARE_EFFECT_TEST;
852 const CircleConicalInfo fInfo;
854 typedef GrGradientEffect INHERITED;
857 class GLCircleInside2PtConicalEffect : public GrGLGradientEffect {
859 GLCircleInside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&);
860 virtual ~GLCircleInside2PtConicalEffect() {}
862 virtual void emitCode(GrGLShaderBuilder*,
865 const char* outputColor,
866 const char* inputColor,
867 const TransformedCoordsArray&,
868 const TextureSamplerArray&) SK_OVERRIDE;
869 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
871 static void GenKey(const GrDrawEffect&, const GrGLCaps& caps, GrEffectKeyBuilder* b);
874 UniformHandle fCenterUni;
875 UniformHandle fParamUni;
877 const char* fVSVaryingName;
878 const char* fFSVaryingName;
881 /// Values last uploaded as uniforms
883 SkScalar fCachedCenterX;
884 SkScalar fCachedCenterY;
892 typedef GrGLGradientEffect INHERITED;
896 const GrBackendEffectFactory& CircleInside2PtConicalEffect::getFactory() const {
897 return GrTBackendEffectFactory<CircleInside2PtConicalEffect>::getInstance();
900 GR_DEFINE_EFFECT_TEST(CircleInside2PtConicalEffect);
902 GrEffect* CircleInside2PtConicalEffect::TestCreate(SkRandom* random,
904 const GrDrawTargetCaps&,
906 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
907 SkScalar radius1 = random->nextUScalar1() + 0.0001f; // make sure radius1 != 0
911 center2.set(random->nextUScalar1(), random->nextUScalar1());
912 // Below makes sure that circle one is contained within circle two
913 SkScalar increase = random->nextUScalar1();
914 SkPoint diff = center2 - center1;
915 SkScalar diffLen = diff.length();
916 radius2 = radius1 + diffLen + increase;
917 // If the circles are identical the factory will give us an empty shader.
918 } while (radius1 == radius2 && center1 == center2);
920 SkColor colors[kMaxRandomGradientColors];
921 SkScalar stopsArray[kMaxRandomGradientColors];
922 SkScalar* stops = stopsArray;
923 SkShader::TileMode tm;
924 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
925 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
927 colors, stops, colorCount,
932 SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect));
936 GLCircleInside2PtConicalEffect::GLCircleInside2PtConicalEffect(const GrBackendEffectFactory& factory,
937 const GrDrawEffect& drawEffect)
939 , fVSVaryingName(NULL)
940 , fFSVaryingName(NULL)
941 , fCachedCenterX(SK_ScalarMax)
942 , fCachedCenterY(SK_ScalarMax)
943 , fCachedA(SK_ScalarMax)
944 , fCachedB(SK_ScalarMax)
945 , fCachedC(SK_ScalarMax) {}
947 void GLCircleInside2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
949 const GrEffectKey& key,
950 const char* outputColor,
951 const char* inputColor,
952 const TransformedCoordsArray& coords,
953 const TextureSamplerArray& samplers) {
954 uint32_t baseKey = key.get32(0);
955 this->emitUniforms(builder, baseKey);
956 fCenterUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
957 kVec2f_GrSLType, "Conical2FSCenter");
958 fParamUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
959 kVec3f_GrSLType, "Conical2FSParams");
962 GrGLShaderVar center = builder->getUniformVariable(fCenterUni);
966 GrGLShaderVar params = builder->getUniformVariable(fParamUni);
968 // if we have a vec3 from being in perspective, convert it to a vec2 first
969 SkString coords2DString = builder->ensureFSCoords2D(coords, 0);
970 const char* coords2D = coords2DString.c_str();
975 // A = dot(e, e) - r^2 + 2 * r - 1
979 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
980 builder->fsCodeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
981 builder->fsCodeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(), params.c_str());
982 builder->fsCodeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
983 tName.c_str(), params.c_str(), params.c_str());
985 this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
988 void GLCircleInside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
989 const GrDrawEffect& drawEffect) {
990 INHERITED::setData(pdman, drawEffect);
991 const CircleInside2PtConicalEffect& data = drawEffect.castEffect<CircleInside2PtConicalEffect>();
992 SkScalar centerX = data.centerX();
993 SkScalar centerY = data.centerY();
994 SkScalar A = data.A();
995 SkScalar B = data.B();
996 SkScalar C = data.C();
998 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
999 fCachedA != A || fCachedB != B || fCachedC != C) {
1001 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1002 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
1004 fCachedCenterX = centerX;
1005 fCachedCenterY = centerY;
1012 void GLCircleInside2PtConicalEffect::GenKey(const GrDrawEffect& drawEffect,
1013 const GrGLCaps&, GrEffectKeyBuilder* b) {
1014 b->add32(GenBaseGradientKey(drawEffect));
1017 //////////////////////////////////////////////////////////////////////////////
1019 class GLCircleOutside2PtConicalEffect;
1021 class CircleOutside2PtConicalEffect : public GrGradientEffect {
1024 static GrEffect* Create(GrContext* ctx,
1025 const SkTwoPointConicalGradient& shader,
1026 const SkMatrix& matrix,
1027 SkShader::TileMode tm,
1028 const CircleConicalInfo& info) {
1029 return SkNEW_ARGS(CircleOutside2PtConicalEffect, (ctx, shader, matrix, tm, info));
1032 virtual ~CircleOutside2PtConicalEffect() {}
1034 static const char* Name() { return "Two-Point Conical Gradient Outside"; }
1035 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
1037 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1038 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1039 SkScalar A() const { return fInfo.fA; }
1040 SkScalar B() const { return fInfo.fB; }
1041 SkScalar C() const { return fInfo.fC; }
1042 SkScalar tLimit() const { return fTLimit; }
1043 bool isFlipped() const { return fIsFlipped; }
1045 typedef GLCircleOutside2PtConicalEffect GLEffect;
1048 virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
1049 const CircleOutside2PtConicalEffect& s = CastEffect<CircleOutside2PtConicalEffect>(sBase);
1050 return (INHERITED::onIsEqual(sBase) &&
1051 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1052 this->fInfo.fA == s.fInfo.fA &&
1053 this->fInfo.fB == s.fInfo.fB &&
1054 this->fInfo.fC == s.fInfo.fC &&
1055 this->fTLimit == s.fTLimit &&
1056 this->fIsFlipped == s.fIsFlipped);
1059 CircleOutside2PtConicalEffect(GrContext* ctx,
1060 const SkTwoPointConicalGradient& shader,
1061 const SkMatrix& matrix,
1062 SkShader::TileMode tm,
1063 const CircleConicalInfo& info)
1064 : INHERITED(ctx, shader, matrix, tm), fInfo(info) {
1065 if (shader.getStartRadius() != shader.getEndRadius()) {
1066 fTLimit = SkScalarDiv(shader.getStartRadius(), (shader.getStartRadius() - shader.getEndRadius()));
1068 fTLimit = SK_ScalarMin;
1071 fIsFlipped = shader.isFlippedGrad();
1074 GR_DECLARE_EFFECT_TEST;
1076 const CircleConicalInfo fInfo;
1080 typedef GrGradientEffect INHERITED;
1083 class GLCircleOutside2PtConicalEffect : public GrGLGradientEffect {
1085 GLCircleOutside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&);
1086 virtual ~GLCircleOutside2PtConicalEffect() {}
1088 virtual void emitCode(GrGLShaderBuilder*,
1089 const GrDrawEffect&,
1091 const char* outputColor,
1092 const char* inputColor,
1093 const TransformedCoordsArray&,
1094 const TextureSamplerArray&) SK_OVERRIDE;
1095 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
1097 static void GenKey(const GrDrawEffect&, const GrGLCaps& caps, GrEffectKeyBuilder* b);
1100 UniformHandle fCenterUni;
1101 UniformHandle fParamUni;
1103 const char* fVSVaryingName;
1104 const char* fFSVaryingName;
1109 /// Values last uploaded as uniforms
1111 SkScalar fCachedCenterX;
1112 SkScalar fCachedCenterY;
1116 SkScalar fCachedTLimit;
1121 typedef GrGLGradientEffect INHERITED;
1125 const GrBackendEffectFactory& CircleOutside2PtConicalEffect::getFactory() const {
1126 return GrTBackendEffectFactory<CircleOutside2PtConicalEffect>::getInstance();
1129 GR_DEFINE_EFFECT_TEST(CircleOutside2PtConicalEffect);
1131 GrEffect* CircleOutside2PtConicalEffect::TestCreate(SkRandom* random,
1133 const GrDrawTargetCaps&,
1135 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
1136 SkScalar radius1 = random->nextUScalar1() + 0.0001f; // make sure radius1 != 0
1141 center2.set(random->nextUScalar1(), random->nextUScalar1());
1142 // If the circles share a center than we can't be in the outside case
1143 } while (center1 == center2);
1144 SkPoint diff = center2 - center1;
1145 diffLen = diff.length();
1146 // Below makes sure that circle one is not contained within circle two
1147 // and have radius2 >= radius to match sorting on cpu side
1148 radius2 = radius1 + random->nextRangeF(0.f, diffLen);
1150 SkColor colors[kMaxRandomGradientColors];
1151 SkScalar stopsArray[kMaxRandomGradientColors];
1152 SkScalar* stops = stopsArray;
1153 SkShader::TileMode tm;
1154 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
1155 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
1157 colors, stops, colorCount,
1162 SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect));
1166 GLCircleOutside2PtConicalEffect::GLCircleOutside2PtConicalEffect(const GrBackendEffectFactory& factory,
1167 const GrDrawEffect& drawEffect)
1168 : INHERITED(factory)
1169 , fVSVaryingName(NULL)
1170 , fFSVaryingName(NULL)
1171 , fCachedCenterX(SK_ScalarMax)
1172 , fCachedCenterY(SK_ScalarMax)
1173 , fCachedA(SK_ScalarMax)
1174 , fCachedB(SK_ScalarMax)
1175 , fCachedC(SK_ScalarMax)
1176 , fCachedTLimit(SK_ScalarMax) {
1177 const CircleOutside2PtConicalEffect& data = drawEffect.castEffect<CircleOutside2PtConicalEffect>();
1178 fIsFlipped = data.isFlipped();
1181 void GLCircleOutside2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
1182 const GrDrawEffect&,
1183 const GrEffectKey& key,
1184 const char* outputColor,
1185 const char* inputColor,
1186 const TransformedCoordsArray& coords,
1187 const TextureSamplerArray& samplers) {
1188 uint32_t baseKey = key.get32(0);
1189 this->emitUniforms(builder, baseKey);
1190 fCenterUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1191 kVec2f_GrSLType, "Conical2FSCenter");
1192 fParamUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1193 kVec4f_GrSLType, "Conical2FSParams");
1194 SkString tName("t");
1196 GrGLShaderVar center = builder->getUniformVariable(fCenterUni);
1200 GrGLShaderVar params = builder->getUniformVariable(fParamUni);
1202 // if we have a vec3 from being in perspective, convert it to a vec2 first
1203 SkString coords2DString = builder->ensureFSCoords2D(coords, 0);
1204 const char* coords2D = coords2DString.c_str();
1206 // output will default to transparent black (we simply won't write anything
1207 // else to it if invalid, instead of discarding or returning prematurely)
1208 builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
1213 // A = dot(e, e) - r^2 + 2 * r - 1
1216 // d = dot(e, p) + B
1217 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
1219 builder->fsCodeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
1220 builder->fsCodeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(), params.c_str());
1221 builder->fsCodeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(), params.c_str());
1223 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1224 // If so we must also flip sign on sqrt
1226 builder->fsCodeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
1228 builder->fsCodeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
1231 builder->fsCodeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str());
1232 builder->fsCodeAppend("\t\t");
1233 this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
1234 builder->fsCodeAppend("\t}\n");
1237 void GLCircleOutside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
1238 const GrDrawEffect& drawEffect) {
1239 INHERITED::setData(pdman, drawEffect);
1240 const CircleOutside2PtConicalEffect& data = drawEffect.castEffect<CircleOutside2PtConicalEffect>();
1241 SkASSERT(data.isFlipped() == fIsFlipped);
1242 SkScalar centerX = data.centerX();
1243 SkScalar centerY = data.centerY();
1244 SkScalar A = data.A();
1245 SkScalar B = data.B();
1246 SkScalar C = data.C();
1247 SkScalar tLimit = data.tLimit();
1249 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1250 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
1252 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1253 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
1254 SkScalarToFloat(tLimit));
1256 fCachedCenterX = centerX;
1257 fCachedCenterY = centerY;
1261 fCachedTLimit = tLimit;
1265 void GLCircleOutside2PtConicalEffect::GenKey(const GrDrawEffect& drawEffect,
1266 const GrGLCaps&, GrEffectKeyBuilder* b) {
1267 uint32_t* key = b->add32n(2);
1268 key[0] = GenBaseGradientKey(drawEffect);
1269 key[1] = drawEffect.castEffect<CircleOutside2PtConicalEffect>().isFlipped();
1272 //////////////////////////////////////////////////////////////////////////////
1274 GrEffect* Gr2PtConicalGradientEffect::Create(GrContext* ctx,
1275 const SkTwoPointConicalGradient& shader,
1276 SkShader::TileMode tm,
1277 const SkMatrix* localMatrix) {
1279 if (!shader.getLocalMatrix().invert(&matrix)) {
1284 if (!localMatrix->invert(&inv)) {
1287 matrix.postConcat(inv);
1290 if (shader.getStartRadius() < kErrorTol) {
1292 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1293 if (type == kInside_ConicalType) {
1294 return FocalInside2PtConicalEffect::Create(ctx, shader, matrix, tm, focalX);
1295 } else if(type == kEdge_ConicalType) {
1296 set_matrix_edge_conical(shader, &matrix);
1297 return Edge2PtConicalEffect::Create(ctx, shader, matrix, tm);
1299 return FocalOutside2PtConicalEffect::Create(ctx, shader, matrix, tm, focalX);
1303 CircleConicalInfo info;
1304 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1306 if (type == kInside_ConicalType) {
1307 return CircleInside2PtConicalEffect::Create(ctx, shader, matrix, tm, info);
1308 } else if (type == kEdge_ConicalType) {
1309 set_matrix_edge_conical(shader, &matrix);
1310 return Edge2PtConicalEffect::Create(ctx, shader, matrix, tm);
1312 return CircleOutside2PtConicalEffect::Create(ctx, shader, matrix, tm, info);