blob: ed21d7518032bc616033317a25f03809095b35b6 [file] [log] [blame]
rileya@google.com589708b2012-07-26 20:04:23 +00001
2/*
3 * Copyright 2012 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 */
8
9 #include "SkTwoPointRadialGradient.h"
10
11/* Two-point radial gradients are specified by two circles, each with a center
12 point and radius. The gradient can be considered to be a series of
13 concentric circles, with the color interpolated from the start circle
14 (at t=0) to the end circle (at t=1).
15
16 For each point (x, y) in the span, we want to find the
17 interpolated circle that intersects that point. The center
18 of the desired circle (Cx, Cy) falls at some distance t
19 along the line segment between the start point (Sx, Sy) and
20 end point (Ex, Ey):
21
22 Cx = (1 - t) * Sx + t * Ex (0 <= t <= 1)
23 Cy = (1 - t) * Sy + t * Ey
24
25 The radius of the desired circle (r) is also a linear interpolation t
26 between the start and end radii (Sr and Er):
27
28 r = (1 - t) * Sr + t * Er
29
30 But
31
32 (x - Cx)^2 + (y - Cy)^2 = r^2
33
34 so
35
36 (x - ((1 - t) * Sx + t * Ex))^2
37 + (y - ((1 - t) * Sy + t * Ey))^2
38 = ((1 - t) * Sr + t * Er)^2
39
40 Solving for t yields
41
42 [(Sx - Ex)^2 + (Sy - Ey)^2 - (Er - Sr)^2)] * t^2
43 + [2 * (Sx - Ex)(x - Sx) + 2 * (Sy - Ey)(y - Sy) - 2 * (Er - Sr) * Sr] * t
44 + [(x - Sx)^2 + (y - Sy)^2 - Sr^2] = 0
45
46 To simplify, let Dx = Sx - Ex, Dy = Sy - Ey, Dr = Er - Sr, dx = x - Sx, dy = y - Sy
47
48 [Dx^2 + Dy^2 - Dr^2)] * t^2
49 + 2 * [Dx * dx + Dy * dy - Dr * Sr] * t
50 + [dx^2 + dy^2 - Sr^2] = 0
51
52 A quadratic in t. The two roots of the quadratic reflect the two
53 possible circles on which the point may fall. Solving for t yields
54 the gradient value to use.
55
56 If a<0, the start circle is entirely contained in the
57 end circle, and one of the roots will be <0 or >1 (off the line
58 segment). If a>0, the start circle falls at least partially
59 outside the end circle (or vice versa), and the gradient
60 defines a "tube" where a point may be on one circle (on the
61 inside of the tube) or the other (outside of the tube). We choose
62 one arbitrarily.
63
64 In order to keep the math to within the limits of fixed point,
65 we divide the entire quadratic by Dr^2, and replace
66 (x - Sx)/Dr with x' and (y - Sy)/Dr with y', giving
67
68 [Dx^2 / Dr^2 + Dy^2 / Dr^2 - 1)] * t^2
69 + 2 * [x' * Dx / Dr + y' * Dy / Dr - Sr / Dr] * t
70 + [x'^2 + y'^2 - Sr^2/Dr^2] = 0
71
72 (x' and y' are computed by appending the subtract and scale to the
73 fDstToIndex matrix in the constructor).
74
75 Since the 'A' component of the quadratic is independent of x' and y', it
76 is precomputed in the constructor. Since the 'B' component is linear in
77 x' and y', if x and y are linear in the span, 'B' can be computed
78 incrementally with a simple delta (db below). If it is not (e.g.,
79 a perspective projection), it must be computed in the loop.
80
81*/
82
83namespace {
84
85inline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
86 SkScalar sr2d2, SkScalar foura,
87 SkScalar oneOverTwoA, bool posRoot) {
88 SkScalar c = SkScalarSquare(fx) + SkScalarSquare(fy) - sr2d2;
89 if (0 == foura) {
90 return SkScalarToFixed(SkScalarDiv(-c, b));
91 }
92
93 SkScalar discrim = SkScalarSquare(b) - SkScalarMul(foura, c);
94 if (discrim < 0) {
95 discrim = -discrim;
96 }
97 SkScalar rootDiscrim = SkScalarSqrt(discrim);
98 SkScalar result;
99 if (posRoot) {
100 result = SkScalarMul(-b + rootDiscrim, oneOverTwoA);
101 } else {
102 result = SkScalarMul(-b - rootDiscrim, oneOverTwoA);
103 }
104 return SkScalarToFixed(result);
105}
106
107typedef void (* TwoPointRadialShadeProc)(SkScalar fx, SkScalar dx,
108 SkScalar fy, SkScalar dy,
109 SkScalar b, SkScalar db,
110 SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
111 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
112 int count);
113
114void shadeSpan_twopoint_clamp(SkScalar fx, SkScalar dx,
115 SkScalar fy, SkScalar dy,
116 SkScalar b, SkScalar db,
117 SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
118 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
119 int count) {
120 for (; count > 0; --count) {
121 SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
122 fOneOverTwoA, posRoot);
123 SkFixed index = SkClampMax(t, 0xFFFF);
124 SkASSERT(index <= 0xFFFF);
125 *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
126 fx += dx;
127 fy += dy;
128 b += db;
129 }
130}
131void shadeSpan_twopoint_mirror(SkScalar fx, SkScalar dx,
132 SkScalar fy, SkScalar dy,
133 SkScalar b, SkScalar db,
134 SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
135 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
136 int count) {
137 for (; count > 0; --count) {
138 SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
139 fOneOverTwoA, posRoot);
140 SkFixed index = mirror_tileproc(t);
141 SkASSERT(index <= 0xFFFF);
142 *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
143 fx += dx;
144 fy += dy;
145 b += db;
146 }
147}
148
149void shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx,
150 SkScalar fy, SkScalar dy,
151 SkScalar b, SkScalar db,
152 SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
153 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
154 int count) {
155 for (; count > 0; --count) {
156 SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
157 fOneOverTwoA, posRoot);
158 SkFixed index = repeat_tileproc(t);
159 SkASSERT(index <= 0xFFFF);
160 *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
161 fx += dx;
162 fy += dy;
163 b += db;
164 }
165}
166}
167
168SkTwoPointRadialGradient::SkTwoPointRadialGradient(
169 const SkPoint& start, SkScalar startRadius,
170 const SkPoint& end, SkScalar endRadius,
171 const SkColor colors[], const SkScalar pos[],
172 int colorCount, SkShader::TileMode mode,
173 SkUnitMapper* mapper)
174 : SkGradientShaderBase(colors, pos, colorCount, mode, mapper),
175 fCenter1(start),
176 fCenter2(end),
177 fRadius1(startRadius),
178 fRadius2(endRadius) {
179 init();
180}
181
182SkShader::BitmapType SkTwoPointRadialGradient::asABitmap(
183 SkBitmap* bitmap,
184 SkMatrix* matrix,
185 SkShader::TileMode* xy) const {
186 if (bitmap) {
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000187 this->getGradientTableBitmap(bitmap);
rileya@google.com589708b2012-07-26 20:04:23 +0000188 }
189 SkScalar diffL = 0; // just to avoid gcc warning
190 if (matrix) {
191 diffL = SkScalarSqrt(SkScalarSquare(fDiff.fX) +
192 SkScalarSquare(fDiff.fY));
193 }
194 if (matrix) {
195 if (diffL) {
196 SkScalar invDiffL = SkScalarInvert(diffL);
197 matrix->setSinCos(-SkScalarMul(invDiffL, fDiff.fY),
198 SkScalarMul(invDiffL, fDiff.fX));
199 } else {
200 matrix->reset();
201 }
202 matrix->preConcat(fPtsToUnit);
203 }
204 if (xy) {
205 xy[0] = fTileMode;
206 xy[1] = kClamp_TileMode;
207 }
208 return kTwoPointRadial_BitmapType;
209}
210
211SkShader::GradientType SkTwoPointRadialGradient::asAGradient(
212 SkShader::GradientInfo* info) const {
213 if (info) {
214 commonAsAGradient(info);
215 info->fPoint[0] = fCenter1;
216 info->fPoint[1] = fCenter2;
217 info->fRadius[0] = fRadius1;
218 info->fRadius[1] = fRadius2;
219 }
220 return kRadial2_GradientType;
221}
222
223GrCustomStage* SkTwoPointRadialGradient::asNewCustomStage(
224 GrContext* context, GrSamplerState* sampler) const {
225 SkASSERT(NULL != context && NULL != sampler);
226 SkScalar diffLen = fDiff.length();
227 if (0 != diffLen) {
228 SkScalar invDiffLen = SkScalarInvert(diffLen);
229 sampler->matrix()->setSinCos(-SkScalarMul(invDiffLen, fDiff.fY),
230 SkScalarMul(invDiffLen, fDiff.fX));
231 } else {
232 sampler->matrix()->reset();
233 }
234 sampler->matrix()->preConcat(fPtsToUnit);
235 sampler->textureParams()->setTileModeX(fTileMode);
236 sampler->textureParams()->setTileModeY(kClamp_TileMode);
237 sampler->textureParams()->setBilerp(true);
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000238 return SkNEW_ARGS(GrRadial2Gradient, (context, *this, sampler));
rileya@google.com589708b2012-07-26 20:04:23 +0000239}
240
241void SkTwoPointRadialGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
242 int count) {
243 SkASSERT(count > 0);
244
245 SkPMColor* SK_RESTRICT dstC = dstCParam;
246
247 // Zero difference between radii: fill with transparent black.
248 if (fDiffRadius == 0) {
249 sk_bzero(dstC, count * sizeof(*dstC));
250 return;
251 }
252 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
253 TileProc proc = fTileProc;
254 const SkPMColor* SK_RESTRICT cache = this->getCache32();
255
256 SkScalar foura = fA * 4;
257 bool posRoot = fDiffRadius < 0;
258 if (fDstToIndexClass != kPerspective_MatrixClass) {
259 SkPoint srcPt;
260 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
261 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
262 SkScalar dx, fx = srcPt.fX;
263 SkScalar dy, fy = srcPt.fY;
264
265 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
266 SkFixed fixedX, fixedY;
267 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY);
268 dx = SkFixedToScalar(fixedX);
269 dy = SkFixedToScalar(fixedY);
270 } else {
271 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
272 dx = fDstToIndex.getScaleX();
273 dy = fDstToIndex.getSkewY();
274 }
275 SkScalar b = (SkScalarMul(fDiff.fX, fx) +
276 SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
277 SkScalar db = (SkScalarMul(fDiff.fX, dx) +
278 SkScalarMul(fDiff.fY, dy)) * 2;
279
280 TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat;
281 if (SkShader::kClamp_TileMode == fTileMode) {
282 shadeProc = shadeSpan_twopoint_clamp;
283 } else if (SkShader::kMirror_TileMode == fTileMode) {
284 shadeProc = shadeSpan_twopoint_mirror;
285 } else {
286 SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
287 }
288 (*shadeProc)(fx, dx, fy, dy, b, db,
289 fSr2D2, foura, fOneOverTwoA, posRoot,
290 dstC, cache, count);
291 } else { // perspective case
292 SkScalar dstX = SkIntToScalar(x);
293 SkScalar dstY = SkIntToScalar(y);
294 for (; count > 0; --count) {
295 SkPoint srcPt;
296 dstProc(fDstToIndex, dstX, dstY, &srcPt);
297 SkScalar fx = srcPt.fX;
298 SkScalar fy = srcPt.fY;
299 SkScalar b = (SkScalarMul(fDiff.fX, fx) +
300 SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
301 SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
302 fOneOverTwoA, posRoot);
303 SkFixed index = proc(t);
304 SkASSERT(index <= 0xFFFF);
305 *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
306 dstX += SK_Scalar1;
307 }
308 }
309}
310
311bool SkTwoPointRadialGradient::setContext(
312 const SkBitmap& device,
313 const SkPaint& paint,
314 const SkMatrix& matrix){
315 if (!this->INHERITED::setContext(device, paint, matrix)) {
316 return false;
317 }
318
319 // For now, we might have divided by zero, so detect that
320 if (0 == fDiffRadius) {
321 return false;
322 }
323
324 // we don't have a span16 proc
325 fFlags &= ~kHasSpan16_Flag;
326 return true;
327}
328
329SkTwoPointRadialGradient::SkTwoPointRadialGradient(
330 SkFlattenableReadBuffer& buffer)
331 : INHERITED(buffer),
332 fCenter1(buffer.readPoint()),
333 fCenter2(buffer.readPoint()),
334 fRadius1(buffer.readScalar()),
335 fRadius2(buffer.readScalar()) {
336 init();
337};
338
339void SkTwoPointRadialGradient::flatten(
340 SkFlattenableWriteBuffer& buffer) const {
341 this->INHERITED::flatten(buffer);
342 buffer.writePoint(fCenter1);
343 buffer.writePoint(fCenter2);
344 buffer.writeScalar(fRadius1);
345 buffer.writeScalar(fRadius2);
346}
347
348void SkTwoPointRadialGradient::init() {
349 fDiff = fCenter1 - fCenter2;
350 fDiffRadius = fRadius2 - fRadius1;
351 // hack to avoid zero-divide for now
352 SkScalar inv = fDiffRadius ? SkScalarInvert(fDiffRadius) : 0;
353 fDiff.fX = SkScalarMul(fDiff.fX, inv);
354 fDiff.fY = SkScalarMul(fDiff.fY, inv);
355 fStartRadius = SkScalarMul(fRadius1, inv);
356 fSr2D2 = SkScalarSquare(fStartRadius);
357 fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
358 fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
359
360 fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
361 fPtsToUnit.postScale(inv, inv);
362}
363
rileya@google.comd7cc6512012-07-27 14:00:39 +0000364/////////////////////////////////////////////////////////////////////
365
366// For brevity
367typedef GrGLUniformManager::UniformHandle UniformHandle;
368static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
369
370class GrGLRadial2Gradient : public GrGLGradientStage {
371
372public:
373
374 GrGLRadial2Gradient(const GrProgramStageFactory& factory,
375 const GrCustomStage&);
376 virtual ~GrGLRadial2Gradient() { }
377
378 virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
379 virtual void emitVS(GrGLShaderBuilder* builder,
380 const char* vertexCoords) SK_OVERRIDE;
381 virtual void emitFS(GrGLShaderBuilder* builder,
382 const char* outputColor,
383 const char* inputColor,
384 const char* samplerName) SK_OVERRIDE;
385 virtual void setData(const GrGLUniformManager&,
386 const GrCustomStage&,
387 const GrRenderTarget*,
388 int stageNum) SK_OVERRIDE;
389
390 static StageKey GenKey(const GrCustomStage& s) {
391 return (static_cast<const GrRadial2Gradient&>(s).isDegenerate());
392 }
393
394protected:
395
396 UniformHandle fVSParamUni;
397 UniformHandle fFSParamUni;
398
399 const char* fVSVaryingName;
400 const char* fFSVaryingName;
401
402 bool fIsDegenerate;
403
404 // @{
405 /// Values last uploaded as uniforms
406
407 GrScalar fCachedCenter;
408 GrScalar fCachedRadius;
409 bool fCachedPosRoot;
410
411 // @}
412
413private:
414
415 typedef GrGLGradientStage INHERITED;
416
417};
418
419GrGLRadial2Gradient::GrGLRadial2Gradient(
420 const GrProgramStageFactory& factory,
421 const GrCustomStage& baseData)
422 : INHERITED(factory)
423 , fVSParamUni(kInvalidUniformHandle)
424 , fFSParamUni(kInvalidUniformHandle)
425 , fVSVaryingName(NULL)
426 , fFSVaryingName(NULL)
427 , fCachedCenter(GR_ScalarMax)
428 , fCachedRadius(-GR_ScalarMax)
429 , fCachedPosRoot(0) {
430
431 const GrRadial2Gradient& data =
432 static_cast<const GrRadial2Gradient&>(baseData);
433 fIsDegenerate = data.isDegenerate();
434}
435
436void GrGLRadial2Gradient::setupVariables(GrGLShaderBuilder* builder) {
437 // 2 copies of uniform array, 1 for each of vertex & fragment shader,
438 // to work around Xoom bug. Doesn't seem to cause performance decrease
439 // in test apps, but need to keep an eye on it.
440 fVSParamUni = builder->addUniformArray(GrGLShaderBuilder::kVertex_ShaderType,
441 kFloat_GrSLType, "Radial2VSParams", 6);
442 fFSParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_ShaderType,
443 kFloat_GrSLType, "Radial2FSParams", 6);
444
445 // For radial gradients without perspective we can pass the linear
446 // part of the quadratic as a varying.
447 if (builder->fVaryingDims == builder->fCoordDims) {
448 builder->addVarying(kFloat_GrSLType, "Radial2BCoeff",
449 &fVSVaryingName, &fFSVaryingName);
450 }
451}
452
453void GrGLRadial2Gradient::emitVS(GrGLShaderBuilder* builder,
454 const char* vertexCoords) {
455 SkString* code = &builder->fVSCode;
456 SkString p2;
457 SkString p3;
458 builder->getUniformVariable(fVSParamUni).appendArrayAccess(2, &p2);
459 builder->getUniformVariable(fVSParamUni).appendArrayAccess(3, &p3);
460
461 // For radial gradients without perspective we can pass the linear
462 // part of the quadratic as a varying.
463 if (builder->fVaryingDims == builder->fCoordDims) {
464 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
465 code->appendf("\t%s = 2.0 *(%s * %s.x - %s);\n",
466 fVSVaryingName, p2.c_str(),
467 vertexCoords, p3.c_str());
468 }
469}
470
471void GrGLRadial2Gradient::emitFS(GrGLShaderBuilder* builder,
472 const char* outputColor,
473 const char* inputColor,
474 const char* samplerName) {
475 SkString* code = &builder->fFSCode;
476 SkString cName("c");
477 SkString ac4Name("ac4");
478 SkString rootName("root");
479 SkString t;
480 SkString p0;
481 SkString p1;
482 SkString p2;
483 SkString p3;
484 SkString p4;
485 SkString p5;
486 builder->getUniformVariable(fFSParamUni).appendArrayAccess(0, &p0);
487 builder->getUniformVariable(fFSParamUni).appendArrayAccess(1, &p1);
488 builder->getUniformVariable(fFSParamUni).appendArrayAccess(2, &p2);
489 builder->getUniformVariable(fFSParamUni).appendArrayAccess(3, &p3);
490 builder->getUniformVariable(fFSParamUni).appendArrayAccess(4, &p4);
491 builder->getUniformVariable(fFSParamUni).appendArrayAccess(5, &p5);
492
493 // If we we're able to interpolate the linear component,
494 // bVar is the varying; otherwise compute it
495 SkString bVar;
496 if (builder->fCoordDims == builder->fVaryingDims) {
497 bVar = fFSVaryingName;
498 GrAssert(2 == builder->fVaryingDims);
499 } else {
500 GrAssert(3 == builder->fVaryingDims);
501 bVar = "b";
502 //bVar.appendS32(stageNum);
503 code->appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
504 bVar.c_str(), p2.c_str(),
505 builder->fSampleCoords.c_str(), p3.c_str());
506 }
507
508 // c = (x^2)+(y^2) - params[4]
509 code->appendf("\tfloat %s = dot(%s, %s) - %s;\n",
510 cName.c_str(), builder->fSampleCoords.c_str(),
511 builder->fSampleCoords.c_str(),
512 p4.c_str());
513
514 // If we aren't degenerate, emit some extra code, and accept a slightly
515 // more complex coord.
516 if (!fIsDegenerate) {
517
518 // ac4 = 4.0 * params[0] * c
519 code->appendf("\tfloat %s = %s * 4.0 * %s;\n",
520 ac4Name.c_str(), p0.c_str(),
521 cName.c_str());
522
523 // root = sqrt(b^2-4ac)
524 // (abs to avoid exception due to fp precision)
525 code->appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
526 rootName.c_str(), bVar.c_str(), bVar.c_str(),
527 ac4Name.c_str());
528
529 // t is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
530 t.printf("(-%s + %s * %s) * %s", bVar.c_str(), p5.c_str(),
531 rootName.c_str(), p1.c_str());
532 } else {
533 // t is: -c/b
534 t.printf("-%s / %s", cName.c_str(), bVar.c_str());
535 }
536
537 this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
538}
539
540void GrGLRadial2Gradient::setData(const GrGLUniformManager& uman,
541 const GrCustomStage& baseData,
542 const GrRenderTarget*,
543 int stageNum) {
544 const GrRadial2Gradient& data =
545 static_cast<const GrRadial2Gradient&>(baseData);
546 GrAssert(data.isDegenerate() == fIsDegenerate);
547 GrScalar centerX1 = data.center();
548 GrScalar radius0 = data.radius();
549 if (fCachedCenter != centerX1 ||
550 fCachedRadius != radius0 ||
551 fCachedPosRoot != data.isPosRoot()) {
552
553 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
554
555 // When we're in the degenerate (linear) case, the second
556 // value will be INF but the program doesn't read it. (We
557 // use the same 6 uniforms even though we don't need them
558 // all in the linear case just to keep the code complexity
559 // down).
560 float values[6] = {
561 GrScalarToFloat(a),
562 1 / (2.f * GrScalarToFloat(a)),
563 GrScalarToFloat(centerX1),
564 GrScalarToFloat(radius0),
565 GrScalarToFloat(GrMul(radius0, radius0)),
566 data.isPosRoot() ? 1.f : -1.f
567 };
568
569 uman.set1fv(fVSParamUni, 0, 6, values);
570 uman.set1fv(fFSParamUni, 0, 6, values);
571 fCachedCenter = centerX1;
572 fCachedRadius = radius0;
573 fCachedPosRoot = data.isPosRoot();
574 }
575}
576
577
578/////////////////////////////////////////////////////////////////////
579
580GrRadial2Gradient::GrRadial2Gradient(GrTexture* texture,
581 GrScalar center,
582 GrScalar radius,
583 bool posRoot)
584 : INHERITED(texture)
585 , fCenterX1 (center)
586 , fRadius0 (radius)
587 , fPosRoot (posRoot) {
588
589}
590
591GrRadial2Gradient::GrRadial2Gradient(GrContext* ctx,
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000592 const SkTwoPointRadialGradient& shader,
593 GrSamplerState* sampler)
594 : INHERITED(ctx, shader, sampler)
595 , fCenterX1(shader.getCenterX1())
596 , fRadius0(shader.getStartRadius())
597 , fPosRoot(shader.getDiffRadius() < 0) {
rileya@google.comd7cc6512012-07-27 14:00:39 +0000598}
599
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000600
rileya@google.comd7cc6512012-07-27 14:00:39 +0000601GrRadial2Gradient::~GrRadial2Gradient() {
602
603}
604
605
606const GrProgramStageFactory& GrRadial2Gradient::getFactory() const {
607 return GrTProgramStageFactory<GrRadial2Gradient>::getInstance();
608}
609
610bool GrRadial2Gradient::isEqual(const GrCustomStage& sBase) const {
611 const GrRadial2Gradient& s = static_cast<const GrRadial2Gradient&>(sBase);
612 return (INHERITED::isEqual(sBase) &&
613 this->fCenterX1 == s.fCenterX1 &&
614 this->fRadius0 == s.fRadius0 &&
615 this->fPosRoot == s.fPosRoot);
616}
617