| OLD | NEW | 
 | (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 |  | 
| OLD | NEW |