Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(683)

Side by Side Diff: src/effects/gradients/SkTwoPointRadialGradient.cpp

Issue 1114243005: remove (redundant) twopointradial shader (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/effects/gradients/SkTwoPointRadialGradient.h ('k') | src/gpu/SkGpuDevice.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1
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
83 namespace {
84
85 inline 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
107 typedef 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
114 void 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 }
131 void 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
149 void 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
168 /////////////////////////////////////////////////////////////////////
169
170 static SkMatrix pts_to_unit(const SkPoint& start, SkScalar diffRadius) {
171 SkScalar inv = diffRadius ? SkScalarInvert(diffRadius) : 0;
172 SkMatrix matrix;
173 matrix.setTranslate(-start.fX, -start.fY);
174 matrix.postScale(inv, inv);
175 return matrix;
176 }
177
178 SkTwoPointRadialGradient::SkTwoPointRadialGradient(const SkPoint& start, SkScala r startRadius,
179 const SkPoint& end, SkScalar endRadius,
180 const Descriptor& desc)
181 : SkGradientShaderBase(desc, pts_to_unit(start, endRadius - startRadius))
182 , fCenter1(start)
183 , fCenter2(end)
184 , fRadius1(startRadius)
185 , fRadius2(endRadius)
186 {
187 fDiff = fCenter1 - fCenter2;
188 fDiffRadius = fRadius2 - fRadius1;
189 // hack to avoid zero-divide for now
190 SkScalar inv = fDiffRadius ? SkScalarInvert(fDiffRadius) : 0;
191 fDiff.fX = SkScalarMul(fDiff.fX, inv);
192 fDiff.fY = SkScalarMul(fDiff.fY, inv);
193 fStartRadius = SkScalarMul(fRadius1, inv);
194 fSr2D2 = SkScalarSquare(fStartRadius);
195 fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
196 fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
197 }
198
199 SkShader::BitmapType SkTwoPointRadialGradient::asABitmap(
200 SkBitmap* bitmap,
201 SkMatrix* matrix,
202 SkShader::TileMode* xy) const {
203 if (bitmap) {
204 this->getGradientTableBitmap(bitmap);
205 }
206 SkScalar diffL = 0; // just to avoid gcc warning
207 if (matrix) {
208 diffL = SkScalarSqrt(SkScalarSquare(fDiff.fX) +
209 SkScalarSquare(fDiff.fY));
210 }
211 if (matrix) {
212 if (diffL) {
213 SkScalar invDiffL = SkScalarInvert(diffL);
214 matrix->setSinCos(-SkScalarMul(invDiffL, fDiff.fY),
215 SkScalarMul(invDiffL, fDiff.fX));
216 } else {
217 matrix->reset();
218 }
219 matrix->preConcat(fPtsToUnit);
220 }
221 if (xy) {
222 xy[0] = fTileMode;
223 xy[1] = kClamp_TileMode;
224 }
225 return kTwoPointRadial_BitmapType;
226 }
227
228 SkShader::GradientType SkTwoPointRadialGradient::asAGradient(
229 SkShader::GradientInfo* info) const {
230 if (info) {
231 commonAsAGradient(info);
232 info->fPoint[0] = fCenter1;
233 info->fPoint[1] = fCenter2;
234 info->fRadius[0] = fRadius1;
235 info->fRadius[1] = fRadius2;
236 }
237 return kRadial2_GradientType;
238 }
239
240 size_t SkTwoPointRadialGradient::contextSize() const {
241 return sizeof(TwoPointRadialGradientContext);
242 }
243
244 SkShader::Context* SkTwoPointRadialGradient::onCreateContext(const ContextRec& r ec,
245 void* storage) cons t {
246 // For now, we might have divided by zero, so detect that.
247 if (0 == fDiffRadius) {
248 return NULL;
249 }
250 return SkNEW_PLACEMENT_ARGS(storage, TwoPointRadialGradientContext, (*this, rec));
251 }
252
253 SkTwoPointRadialGradient::TwoPointRadialGradientContext::TwoPointRadialGradientC ontext(
254 const SkTwoPointRadialGradient& shader, const ContextRec& rec)
255 : INHERITED(shader, rec)
256 {
257 // we don't have a span16 proc
258 fFlags &= ~kHasSpan16_Flag;
259 }
260
261 void SkTwoPointRadialGradient::TwoPointRadialGradientContext::shadeSpan(
262 int x, int y, SkPMColor* dstCParam, int count) {
263 SkASSERT(count > 0);
264
265 const SkTwoPointRadialGradient& twoPointRadialGradient =
266 static_cast<const SkTwoPointRadialGradient&>(fShader);
267
268 SkPMColor* SK_RESTRICT dstC = dstCParam;
269
270 // Zero difference between radii: fill with transparent black.
271 if (twoPointRadialGradient.fDiffRadius == 0) {
272 sk_bzero(dstC, count * sizeof(*dstC));
273 return;
274 }
275 SkMatrix::MapXYProc dstProc = fDstToIndexProc;
276 TileProc proc = twoPointRadialGradient.fTileProc;
277 const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
278
279 SkScalar foura = twoPointRadialGradient.fA * 4;
280 bool posRoot = twoPointRadialGradient.fDiffRadius < 0;
281 if (fDstToIndexClass != kPerspective_MatrixClass) {
282 SkPoint srcPt;
283 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
284 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
285 SkScalar dx, fx = srcPt.fX;
286 SkScalar dy, fy = srcPt.fY;
287
288 if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
289 SkFixed fixedX, fixedY;
290 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY);
291 dx = SkFixedToScalar(fixedX);
292 dy = SkFixedToScalar(fixedY);
293 } else {
294 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
295 dx = fDstToIndex.getScaleX();
296 dy = fDstToIndex.getSkewY();
297 }
298 SkScalar b = (SkScalarMul(twoPointRadialGradient.fDiff.fX, fx) +
299 SkScalarMul(twoPointRadialGradient.fDiff.fY, fy) -
300 twoPointRadialGradient.fStartRadius) * 2;
301 SkScalar db = (SkScalarMul(twoPointRadialGradient.fDiff.fX, dx) +
302 SkScalarMul(twoPointRadialGradient.fDiff.fY, dy)) * 2;
303
304 TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat;
305 if (SkShader::kClamp_TileMode == twoPointRadialGradient.fTileMode) {
306 shadeProc = shadeSpan_twopoint_clamp;
307 } else if (SkShader::kMirror_TileMode == twoPointRadialGradient.fTileMod e) {
308 shadeProc = shadeSpan_twopoint_mirror;
309 } else {
310 SkASSERT(SkShader::kRepeat_TileMode == twoPointRadialGradient.fTileM ode);
311 }
312 (*shadeProc)(fx, dx, fy, dy, b, db,
313 twoPointRadialGradient.fSr2D2, foura,
314 twoPointRadialGradient.fOneOverTwoA, posRoot,
315 dstC, cache, count);
316 } else { // perspective case
317 SkScalar dstX = SkIntToScalar(x);
318 SkScalar dstY = SkIntToScalar(y);
319 for (; count > 0; --count) {
320 SkPoint srcPt;
321 dstProc(fDstToIndex, dstX, dstY, &srcPt);
322 SkScalar fx = srcPt.fX;
323 SkScalar fy = srcPt.fY;
324 SkScalar b = (SkScalarMul(twoPointRadialGradient.fDiff.fX, fx) +
325 SkScalarMul(twoPointRadialGradient.fDiff.fY, fy) -
326 twoPointRadialGradient.fStartRadius) * 2;
327 SkFixed t = two_point_radial(b, fx, fy, twoPointRadialGradient.fSr2D 2, foura,
328 twoPointRadialGradient.fOneOverTwoA, po sRoot);
329 SkFixed index = proc(t);
330 SkASSERT(index <= 0xFFFF);
331 *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
332 dstX += SK_Scalar1;
333 }
334 }
335 }
336
337 #ifndef SK_IGNORE_TO_STRING
338 void SkTwoPointRadialGradient::toString(SkString* str) const {
339 str->append("SkTwoPointRadialGradient: (");
340
341 str->append("center1: (");
342 str->appendScalar(fCenter1.fX);
343 str->append(", ");
344 str->appendScalar(fCenter1.fY);
345 str->append(") radius1: ");
346 str->appendScalar(fRadius1);
347 str->append(" ");
348
349 str->append("center2: (");
350 str->appendScalar(fCenter2.fX);
351 str->append(", ");
352 str->appendScalar(fCenter2.fY);
353 str->append(") radius2: ");
354 str->appendScalar(fRadius2);
355 str->append(" ");
356
357 this->INHERITED::toString(str);
358
359 str->append(")");
360 }
361 #endif
362
363 SkFlattenable* SkTwoPointRadialGradient::CreateProc(SkReadBuffer& buffer) {
364 DescriptorScope desc;
365 if (!desc.unflatten(buffer)) {
366 return NULL;
367 }
368 const SkPoint c1 = buffer.readPoint();
369 const SkPoint c2 = buffer.readPoint();
370 const SkScalar r1 = buffer.readScalar();
371 const SkScalar r2 = buffer.readScalar();
372 return SkGradientShader::CreateTwoPointRadial(c1, r1, c2, r2, desc.fColors, desc.fPos,
373 desc.fCount, desc.fTileMode, d esc.fGradFlags,
374 desc.fLocalMatrix);
375 }
376
377 void SkTwoPointRadialGradient::flatten(
378 SkWriteBuffer& buffer) const {
379 this->INHERITED::flatten(buffer);
380 buffer.writePoint(fCenter1);
381 buffer.writePoint(fCenter2);
382 buffer.writeScalar(fRadius1);
383 buffer.writeScalar(fRadius2);
384 }
385
386 /////////////////////////////////////////////////////////////////////
387
388 #if SK_SUPPORT_GPU
389
390 #include "SkGr.h"
391 #include "gl/builders/GrGLProgramBuilder.h"
392
393 // For brevity
394 typedef GrGLProgramDataManager::UniformHandle UniformHandle;
395
396 class GrGLRadial2Gradient : public GrGLGradientEffect {
397
398 public:
399
400 GrGLRadial2Gradient(const GrProcessor&);
401 virtual ~GrGLRadial2Gradient() { }
402
403 virtual void emitCode(GrGLFPBuilder*,
404 const GrFragmentProcessor&,
405 const char* outputColor,
406 const char* inputColor,
407 const TransformedCoordsArray&,
408 const TextureSamplerArray&) override;
409 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
410
411 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKe yBuilder* b);
412
413 protected:
414
415 UniformHandle fParamUni;
416
417 const char* fVSVaryingName;
418 const char* fFSVaryingName;
419
420 bool fIsDegenerate;
421
422 // @{
423 /// Values last uploaded as uniforms
424
425 SkScalar fCachedCenter;
426 SkScalar fCachedRadius;
427 bool fCachedPosRoot;
428
429 // @}
430
431 private:
432
433 typedef GrGLGradientEffect INHERITED;
434
435 };
436
437 /////////////////////////////////////////////////////////////////////
438
439 class GrRadial2Gradient : public GrGradientEffect {
440 public:
441 static GrFragmentProcessor* Create(GrContext* ctx,
442 const SkTwoPointRadialGradient& shader,
443 const SkMatrix& matrix,
444 SkShader::TileMode tm) {
445 return SkNEW_ARGS(GrRadial2Gradient, (ctx, shader, matrix, tm));
446 }
447
448 virtual ~GrRadial2Gradient() { }
449
450 const char* name() const override { return "Two-Point Radial Gradient"; }
451
452 virtual void getGLProcessorKey(const GrGLSLCaps& caps,
453 GrProcessorKeyBuilder* b) const override {
454 GrGLRadial2Gradient::GenKey(*this, caps, b);
455 }
456
457 GrGLFragmentProcessor* createGLInstance() const override {
458 return SkNEW_ARGS(GrGLRadial2Gradient, (*this));
459 }
460
461 // The radial gradient parameters can collapse to a linear (instead of quadr atic) equation.
462 bool isDegenerate() const { return SK_Scalar1 == fCenterX1; }
463 SkScalar center() const { return fCenterX1; }
464 SkScalar radius() const { return fRadius0; }
465 bool isPosRoot() const { return SkToBool(fPosRoot); }
466
467 private:
468 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
469 const GrRadial2Gradient& s = sBase.cast<GrRadial2Gradient>();
470 return (INHERITED::onIsEqual(sBase) &&
471 this->fCenterX1 == s.fCenterX1 &&
472 this->fRadius0 == s.fRadius0 &&
473 this->fPosRoot == s.fPosRoot);
474 }
475
476 GrRadial2Gradient(GrContext* ctx,
477 const SkTwoPointRadialGradient& shader,
478 const SkMatrix& matrix,
479 SkShader::TileMode tm)
480 : INHERITED(ctx, shader, matrix, tm)
481 , fCenterX1(shader.getCenterX1())
482 , fRadius0(shader.getStartRadius())
483 , fPosRoot(shader.getDiffRadius() < 0) {
484 this->initClassID<GrRadial2Gradient>();
485 // We pass the linear part of the quadratic as a varying.
486 // float b = 2.0 * (fCenterX1 * x - fRadius0 * z)
487 fBTransform = this->getCoordTransform();
488 SkMatrix& bMatrix = *fBTransform.accessMatrix();
489 bMatrix[SkMatrix::kMScaleX] = 2 * (SkScalarMul(fCenterX1, bMatrix[SkMatr ix::kMScaleX]) -
490 SkScalarMul(fRadius0, bMatrix[SkMatri x::kMPersp0]));
491 bMatrix[SkMatrix::kMSkewX] = 2 * (SkScalarMul(fCenterX1, bMatrix[SkMatri x::kMSkewX]) -
492 SkScalarMul(fRadius0, bMatrix[SkMatrix ::kMPersp1]));
493 bMatrix[SkMatrix::kMTransX] = 2 * (SkScalarMul(fCenterX1, bMatrix[SkMatr ix::kMTransX]) -
494 SkScalarMul(fRadius0, bMatrix[SkMatri x::kMPersp2]));
495 this->addCoordTransform(&fBTransform);
496 }
497
498 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
499
500 // @{
501 // Cache of values - these can change arbitrarily, EXCEPT
502 // we shouldn't change between degenerate and non-degenerate?!
503
504 GrCoordTransform fBTransform;
505 SkScalar fCenterX1;
506 SkScalar fRadius0;
507 SkBool8 fPosRoot;
508
509 // @}
510
511 typedef GrGradientEffect INHERITED;
512 };
513
514 /////////////////////////////////////////////////////////////////////
515
516 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRadial2Gradient);
517
518 GrFragmentProcessor* GrRadial2Gradient::TestCreate(SkRandom* random,
519 GrContext* context,
520 const GrDrawTargetCaps&,
521 GrTexture**) {
522 SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
523 SkScalar radius1 = random->nextUScalar1();
524 SkPoint center2;
525 SkScalar radius2;
526 do {
527 center2.set(random->nextUScalar1(), random->nextUScalar1());
528 radius2 = random->nextUScalar1 ();
529 // There is a bug in two point radial gradients with identical radii
530 } while (radius1 == radius2);
531
532 SkColor colors[kMaxRandomGradientColors];
533 SkScalar stopsArray[kMaxRandomGradientColors];
534 SkScalar* stops = stopsArray;
535 SkShader::TileMode tm;
536 int colorCount = RandomGradientParams(random, colors, &stops, &tm);
537 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointRadial(center1 , radius1,
538 center2 , radius2,
539 colors, stops, colorCount,
540 tm));
541 SkPaint paint;
542 GrFragmentProcessor* fp;
543 GrColor paintColor;
544 SkAssertResult(shader->asFragmentProcessor(context, paint,
545 GrTest::TestMatrix(random), NULL,
546 &paintColor, &fp));
547 return fp;
548 }
549
550 /////////////////////////////////////////////////////////////////////
551
552 GrGLRadial2Gradient::GrGLRadial2Gradient(const GrProcessor& processor)
553 : fVSVaryingName(NULL)
554 , fFSVaryingName(NULL)
555 , fCachedCenter(SK_ScalarMax)
556 , fCachedRadius(-SK_ScalarMax)
557 , fCachedPosRoot(0) {
558
559 const GrRadial2Gradient& data = processor.cast<GrRadial2Gradient>();
560 fIsDegenerate = data.isDegenerate();
561 }
562
563 void GrGLRadial2Gradient::emitCode(GrGLFPBuilder* builder,
564 const GrFragmentProcessor& fp,
565 const char* outputColor,
566 const char* inputColor,
567 const TransformedCoordsArray& coords,
568 const TextureSamplerArray& samplers) {
569 const GrRadial2Gradient& ge = fp.cast<GrRadial2Gradient>();
570 this->emitUniforms(builder, ge);
571 fParamUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibilit y,
572 kFloat_GrSLType, kDefault_GrSLPrecision ,
573 "Radial2FSParams", 6);
574
575 SkString cName("c");
576 SkString ac4Name("ac4");
577 SkString rootName("root");
578 SkString t;
579 SkString p0;
580 SkString p1;
581 SkString p2;
582 SkString p3;
583 SkString p4;
584 SkString p5;
585 builder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
586 builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
587 builder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
588 builder->getUniformVariable(fParamUni).appendArrayAccess(3, &p3);
589 builder->getUniformVariable(fParamUni).appendArrayAccess(4, &p4);
590 builder->getUniformVariable(fParamUni).appendArrayAccess(5, &p5);
591
592 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
593 // We interpolate the linear component in coords[1].
594 SkASSERT(coords[0].getType() == coords[1].getType());
595 const char* coords2D;
596 SkString bVar;
597 if (kVec3f_GrSLType == coords[0].getType()) {
598 fsBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy, %s.x) / %s.z;\ n",
599 coords[0].c_str(), coords[1].c_str(), coords[0].c _str());
600 coords2D = "interpolants.xy";
601 bVar = "interpolants.z";
602 } else {
603 coords2D = coords[0].c_str();
604 bVar.printf("%s.x", coords[1].c_str());
605 }
606
607 // c = (x^2)+(y^2) - params[4]
608 fsBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
609 cName.c_str(), coords2D, coords2D, p4.c_str());
610
611 // If we aren't degenerate, emit some extra code, and accept a slightly
612 // more complex coord.
613 if (!fIsDegenerate) {
614
615 // ac4 = 4.0 * params[0] * c
616 fsBuilder->codeAppendf("\tfloat %s = %s * 4.0 * %s;\n",
617 ac4Name.c_str(), p0.c_str(),
618 cName.c_str());
619
620 // root = sqrt(b^2-4ac)
621 // (abs to avoid exception due to fp precision)
622 fsBuilder->codeAppendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
623 rootName.c_str(), bVar.c_str(), bVar.c_str(),
624 ac4Name.c_str());
625
626 // t is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
627 t.printf("(-%s + %s * %s) * %s", bVar.c_str(), p5.c_str(),
628 rootName.c_str(), p1.c_str());
629 } else {
630 // t is: -c/b
631 t.printf("-%s / %s", cName.c_str(), bVar.c_str());
632 }
633
634 this->emitColor(builder, ge, t.c_str(), outputColor, inputColor, samplers);
635 }
636
637 void GrGLRadial2Gradient::setData(const GrGLProgramDataManager& pdman,
638 const GrProcessor& processor) {
639 INHERITED::setData(pdman, processor);
640 const GrRadial2Gradient& data = processor.cast<GrRadial2Gradient>();
641 SkASSERT(data.isDegenerate() == fIsDegenerate);
642 SkScalar centerX1 = data.center();
643 SkScalar radius0 = data.radius();
644 if (fCachedCenter != centerX1 ||
645 fCachedRadius != radius0 ||
646 fCachedPosRoot != data.isPosRoot()) {
647
648 SkScalar a = SkScalarMul(centerX1, centerX1) - SK_Scalar1;
649
650 // When we're in the degenerate (linear) case, the second
651 // value will be INF but the program doesn't read it. (We
652 // use the same 6 uniforms even though we don't need them
653 // all in the linear case just to keep the code complexity
654 // down).
655 float values[6] = {
656 SkScalarToFloat(a),
657 1 / (2.f * SkScalarToFloat(a)),
658 SkScalarToFloat(centerX1),
659 SkScalarToFloat(radius0),
660 SkScalarToFloat(SkScalarMul(radius0, radius0)),
661 data.isPosRoot() ? 1.f : -1.f
662 };
663
664 pdman.set1fv(fParamUni, 6, values);
665 fCachedCenter = centerX1;
666 fCachedRadius = radius0;
667 fCachedPosRoot = data.isPosRoot();
668 }
669 }
670
671 void GrGLRadial2Gradient::GenKey(const GrProcessor& processor,
672 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
673 uint32_t* key = b->add32n(2);
674 key[0] = GenBaseGradientKey(processor);
675 key[1] = processor.cast<GrRadial2Gradient>().isDegenerate();
676 }
677
678 /////////////////////////////////////////////////////////////////////
679
680 bool SkTwoPointRadialGradient::asFragmentProcessor(GrContext* context, const SkP aint& paint,
681 const SkMatrix&,
682 const SkMatrix* localMatrix, GrColor* paintColor,
683 GrFragmentProcessor** fp) co nst {
684 SkASSERT(context);
685
686 // invert the localM, translate to center1 (fPtsToUni), rotate so center2 is on x axis.
687 SkMatrix matrix;
688 if (!this->getLocalMatrix().invert(&matrix)) {
689 return false;
690 }
691 if (localMatrix) {
692 SkMatrix inv;
693 if (!localMatrix->invert(&inv)) {
694 return false;
695 }
696 matrix.postConcat(inv);
697 }
698 matrix.postConcat(fPtsToUnit);
699
700 SkScalar diffLen = fDiff.length();
701 if (0 != diffLen) {
702 SkScalar invDiffLen = SkScalarInvert(diffLen);
703 SkMatrix rot;
704 rot.setSinCos(-SkScalarMul(invDiffLen, fDiff.fY),
705 SkScalarMul(invDiffLen, fDiff.fX));
706 matrix.postConcat(rot);
707 }
708
709 *paintColor = SkColor2GrColorJustAlpha(paint.getColor());
710 *fp = GrRadial2Gradient::Create(context, *this, matrix, fTileMode);
711
712 return true;
713 }
714
715 #else
716
717 bool SkTwoPointRadialGradient::asFragmentProcessor(GrContext*, const SkPaint&, c onst SkMatrix&,
718 const SkMatrix*,
719 GrColor*, GrFragmentProcessor **) const {
720 SkDEBUGFAIL("Should not call in GPU-less build");
721 return false;
722 }
723
724 #endif
OLDNEW
« no previous file with comments | « src/effects/gradients/SkTwoPointRadialGradient.h ('k') | src/gpu/SkGpuDevice.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698