Home | History | Annotate | Download | only in gradients
      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 "SkSweepGradient.h"
     10 
     11 SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, const SkColor colors[],
     12                const SkScalar pos[], int count, SkUnitMapper* mapper)
     13 : SkGradientShaderBase(colors, pos, count, SkShader::kClamp_TileMode, mapper),
     14   fCenter(SkPoint::Make(cx, cy))
     15 {
     16     fPtsToUnit.setTranslate(-cx, -cy);
     17 }
     18 
     19 SkShader::BitmapType SkSweepGradient::asABitmap(SkBitmap* bitmap,
     20     SkMatrix* matrix, SkShader::TileMode* xy) const {
     21     if (bitmap) {
     22         this->getGradientTableBitmap(bitmap);
     23     }
     24     if (matrix) {
     25         *matrix = fPtsToUnit;
     26     }
     27     if (xy) {
     28         xy[0] = fTileMode;
     29         xy[1] = kClamp_TileMode;
     30     }
     31     return kSweep_BitmapType;
     32 }
     33 
     34 SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
     35     if (info) {
     36         commonAsAGradient(info);
     37         info->fPoint[0] = fCenter;
     38     }
     39     return kSweep_GradientType;
     40 }
     41 
     42 SkSweepGradient::SkSweepGradient(SkFlattenableReadBuffer& buffer)
     43     : INHERITED(buffer),
     44       fCenter(buffer.readPoint()) {
     45 }
     46 
     47 void SkSweepGradient::flatten(SkFlattenableWriteBuffer& buffer) const {
     48     this->INHERITED::flatten(buffer);
     49     buffer.writePoint(fCenter);
     50 }
     51 
     52 #ifndef SK_SCALAR_IS_FLOAT
     53 #ifdef COMPUTE_SWEEP_TABLE
     54 #define PI  3.14159265
     55 static bool gSweepTableReady;
     56 static uint8_t gSweepTable[65];
     57 
     58 /*  Our table stores precomputed values for atan: [0...1] -> [0..PI/4]
     59     We scale the results to [0..32]
     60 */
     61 static const uint8_t* build_sweep_table() {
     62     if (!gSweepTableReady) {
     63         const int N = 65;
     64         const double DENOM = N - 1;
     65 
     66         for (int i = 0; i < N; i++)
     67         {
     68             double arg = i / DENOM;
     69             double v = atan(arg);
     70             int iv = (int)round(v * DENOM * 2 / PI);
     71 //            printf("[%d] atan(%g) = %g %d\n", i, arg, v, iv);
     72             printf("%d, ", iv);
     73             gSweepTable[i] = iv;
     74         }
     75         gSweepTableReady = true;
     76     }
     77     return gSweepTable;
     78 }
     79 #else
     80 static const uint8_t gSweepTable[] = {
     81     0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9,
     82     10, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18,
     83     19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26,
     84     26, 27, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32,
     85     32
     86 };
     87 static const uint8_t* build_sweep_table() { return gSweepTable; }
     88 #endif
     89 #endif
     90 
     91 // divide numer/denom, with a bias of 6bits. Assumes numer <= denom
     92 // and denom != 0. Since our table is 6bits big (+1), this is a nice fit.
     93 // Same as (but faster than) SkFixedDiv(numer, denom) >> 10
     94 
     95 //unsigned div_64(int numer, int denom);
     96 #ifndef SK_SCALAR_IS_FLOAT
     97 static unsigned div_64(int numer, int denom) {
     98     SkASSERT(numer <= denom);
     99     SkASSERT(numer > 0);
    100     SkASSERT(denom > 0);
    101 
    102     int nbits = SkCLZ(numer);
    103     int dbits = SkCLZ(denom);
    104     int bits = 6 - nbits + dbits;
    105     SkASSERT(bits <= 6);
    106 
    107     if (bits < 0) {  // detect underflow
    108         return 0;
    109     }
    110 
    111     denom <<= dbits - 1;
    112     numer <<= nbits - 1;
    113 
    114     unsigned result = 0;
    115 
    116     // do the first one
    117     if ((numer -= denom) >= 0) {
    118         result = 1;
    119     } else {
    120         numer += denom;
    121     }
    122 
    123     // Now fall into our switch statement if there are more bits to compute
    124     if (bits > 0) {
    125         // make room for the rest of the answer bits
    126         result <<= bits;
    127         switch (bits) {
    128         case 6:
    129             if ((numer = (numer << 1) - denom) >= 0)
    130                 result |= 32;
    131             else
    132                 numer += denom;
    133         case 5:
    134             if ((numer = (numer << 1) - denom) >= 0)
    135                 result |= 16;
    136             else
    137                 numer += denom;
    138         case 4:
    139             if ((numer = (numer << 1) - denom) >= 0)
    140                 result |= 8;
    141             else
    142                 numer += denom;
    143         case 3:
    144             if ((numer = (numer << 1) - denom) >= 0)
    145                 result |= 4;
    146             else
    147                 numer += denom;
    148         case 2:
    149             if ((numer = (numer << 1) - denom) >= 0)
    150                 result |= 2;
    151             else
    152                 numer += denom;
    153         case 1:
    154         default:    // not strictly need, but makes GCC make better ARM code
    155             if ((numer = (numer << 1) - denom) >= 0)
    156                 result |= 1;
    157             else
    158                 numer += denom;
    159         }
    160     }
    161     return result;
    162 }
    163 #endif
    164 
    165 // Given x,y in the first quadrant, return 0..63 for the angle [0..90]
    166 #ifndef SK_SCALAR_IS_FLOAT
    167 static unsigned atan_0_90(SkFixed y, SkFixed x) {
    168 #ifdef SK_DEBUG
    169     {
    170         static bool gOnce;
    171         if (!gOnce) {
    172             gOnce = true;
    173             SkASSERT(div_64(55, 55) == 64);
    174             SkASSERT(div_64(128, 256) == 32);
    175             SkASSERT(div_64(2326528, 4685824) == 31);
    176             SkASSERT(div_64(753664, 5210112) == 9);
    177             SkASSERT(div_64(229376, 4882432) == 3);
    178             SkASSERT(div_64(2, 64) == 2);
    179             SkASSERT(div_64(1, 64) == 1);
    180             // test that we handle underflow correctly
    181             SkASSERT(div_64(12345, 0x54321234) == 0);
    182         }
    183     }
    184 #endif
    185 
    186     SkASSERT(y > 0 && x > 0);
    187     const uint8_t* table = build_sweep_table();
    188 
    189     unsigned result;
    190     bool swap = (x < y);
    191     if (swap) {
    192         // first part of the atan(v) = PI/2 - atan(1/v) identity
    193         // since our div_64 and table want v <= 1, where v = y/x
    194         SkTSwap<SkFixed>(x, y);
    195     }
    196 
    197     result = div_64(y, x);
    198 
    199 #ifdef SK_DEBUG
    200     {
    201         unsigned result2 = SkDivBits(y, x, 6);
    202         SkASSERT(result2 == result ||
    203                  (result == 1 && result2 == 0));
    204     }
    205 #endif
    206 
    207     SkASSERT(result < SK_ARRAY_COUNT(gSweepTable));
    208     result = table[result];
    209 
    210     if (swap) {
    211         // complete the atan(v) = PI/2 - atan(1/v) identity
    212         result = 64 - result;
    213         // pin to 63
    214         result -= result >> 6;
    215     }
    216 
    217     SkASSERT(result <= 63);
    218     return result;
    219 }
    220 #endif
    221 
    222 //  returns angle in a circle [0..2PI) -> [0..255]
    223 #ifdef SK_SCALAR_IS_FLOAT
    224 static unsigned SkATan2_255(float y, float x) {
    225     //    static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
    226     static const float g255Over2PI = 40.584510488433314f;
    227 
    228     float result = sk_float_atan2(y, x);
    229     if (result < 0) {
    230         result += 2 * SK_ScalarPI;
    231     }
    232     SkASSERT(result >= 0);
    233     // since our value is always >= 0, we can cast to int, which is faster than
    234     // calling floorf()
    235     int ir = (int)(result * g255Over2PI);
    236     SkASSERT(ir >= 0 && ir <= 255);
    237     return ir;
    238 }
    239 #else
    240 static unsigned SkATan2_255(SkFixed y, SkFixed x) {
    241     if (x == 0) {
    242         if (y == 0) {
    243             return 0;
    244         }
    245         return y < 0 ? 192 : 64;
    246     }
    247     if (y == 0) {
    248         return x < 0 ? 128 : 0;
    249     }
    250 
    251     /*  Find the right quadrant for x,y
    252         Since atan_0_90 only handles the first quadrant, we rotate x,y
    253         appropriately before calling it, and then add the right amount
    254         to account for the real quadrant.
    255         quadrant 0 : add 0                  | x > 0 && y > 0
    256         quadrant 1 : add 64 (90 degrees)    | x < 0 && y > 0
    257         quadrant 2 : add 128 (180 degrees)  | x < 0 && y < 0
    258         quadrant 3 : add 192 (270 degrees)  | x > 0 && y < 0
    259 
    260         map x<0 to (1 << 6)
    261         map y<0 to (3 << 6)
    262         add = map_x ^ map_y
    263     */
    264     int xsign = x >> 31;
    265     int ysign = y >> 31;
    266     int add = ((-xsign) ^ (ysign & 3)) << 6;
    267 
    268 #ifdef SK_DEBUG
    269     if (0 == add)
    270         SkASSERT(x > 0 && y > 0);
    271     else if (64 == add)
    272         SkASSERT(x < 0 && y > 0);
    273     else if (128 == add)
    274         SkASSERT(x < 0 && y < 0);
    275     else if (192 == add)
    276         SkASSERT(x > 0 && y < 0);
    277     else
    278         SkDEBUGFAIL("bad value for add");
    279 #endif
    280 
    281     /*  This ^ trick makes x, y positive, and the swap<> handles quadrants
    282         where we need to rotate x,y by 90 or -90
    283     */
    284     x = (x ^ xsign) - xsign;
    285     y = (y ^ ysign) - ysign;
    286     if (add & 64) {             // quads 1 or 3 need to swap x,y
    287         SkTSwap<SkFixed>(x, y);
    288     }
    289 
    290     unsigned result = add + atan_0_90(y, x);
    291     SkASSERT(result < 256);
    292     return result;
    293 }
    294 #endif
    295 
    296 void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
    297                                int count) {
    298     SkMatrix::MapXYProc proc = fDstToIndexProc;
    299     const SkMatrix&     matrix = fDstToIndex;
    300     const SkPMColor* SK_RESTRICT cache = this->getCache32();
    301     SkPoint             srcPt;
    302 
    303     if (fDstToIndexClass != kPerspective_MatrixClass) {
    304         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
    305                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    306         SkScalar dx, fx = srcPt.fX;
    307         SkScalar dy, fy = srcPt.fY;
    308 
    309         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
    310             SkFixed storage[2];
    311             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
    312                                       &storage[0], &storage[1]);
    313             dx = SkFixedToScalar(storage[0]);
    314             dy = SkFixedToScalar(storage[1]);
    315         } else {
    316             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
    317             dx = matrix.getScaleX();
    318             dy = matrix.getSkewY();
    319         }
    320 
    321         for (; count > 0; --count) {
    322             *dstC++ = cache[SkATan2_255(fy, fx)];
    323             fx += dx;
    324             fy += dy;
    325         }
    326     } else {  // perspective case
    327         for (int stop = x + count; x < stop; x++) {
    328             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
    329                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    330             *dstC++ = cache[SkATan2_255(srcPt.fY, srcPt.fX)];
    331         }
    332     }
    333 }
    334 
    335 void SkSweepGradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
    336                                  int count) {
    337     SkMatrix::MapXYProc proc = fDstToIndexProc;
    338     const SkMatrix&     matrix = fDstToIndex;
    339     const uint16_t* SK_RESTRICT cache = this->getCache16();
    340     int                 toggle = init_dither_toggle16(x, y);
    341     SkPoint             srcPt;
    342 
    343     if (fDstToIndexClass != kPerspective_MatrixClass) {
    344         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
    345                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    346         SkScalar dx, fx = srcPt.fX;
    347         SkScalar dy, fy = srcPt.fY;
    348 
    349         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
    350             SkFixed storage[2];
    351             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
    352                                       &storage[0], &storage[1]);
    353             dx = SkFixedToScalar(storage[0]);
    354             dy = SkFixedToScalar(storage[1]);
    355         } else {
    356             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
    357             dx = matrix.getScaleX();
    358             dy = matrix.getSkewY();
    359         }
    360 
    361         for (; count > 0; --count) {
    362             int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits);
    363             *dstC++ = cache[toggle + index];
    364             toggle = next_dither_toggle16(toggle);
    365             fx += dx;
    366             fy += dy;
    367         }
    368     } else {  // perspective case
    369         for (int stop = x + count; x < stop; x++) {
    370             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
    371                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    372 
    373             int index = SkATan2_255(srcPt.fY, srcPt.fX);
    374             index >>= (8 - kCache16Bits);
    375             *dstC++ = cache[toggle + index];
    376             toggle = next_dither_toggle16(toggle);
    377         }
    378     }
    379 }
    380 
    381 /////////////////////////////////////////////////////////////////////
    382 
    383 #if SK_SUPPORT_GPU
    384 
    385 #include "GrTBackendEffectFactory.h"
    386 
    387 class GrGLSweepGradient : public GrGLGradientEffect {
    388 public:
    389 
    390     GrGLSweepGradient(const GrBackendEffectFactory& factory,
    391                       const GrEffectRef&) : INHERITED (factory) { }
    392     virtual ~GrGLSweepGradient() { }
    393 
    394     virtual void emitCode(GrGLShaderBuilder*,
    395                           const GrEffectStage&,
    396                           EffectKey,
    397                           const char* vertexCoords,
    398                           const char* outputColor,
    399                           const char* inputColor,
    400                           const TextureSamplerArray&) SK_OVERRIDE;
    401 
    402     static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
    403         return GenMatrixKey(stage);
    404     }
    405 
    406 private:
    407 
    408     typedef GrGLGradientEffect INHERITED;
    409 
    410 };
    411 
    412 /////////////////////////////////////////////////////////////////////
    413 
    414 class GrSweepGradient : public GrGradientEffect {
    415 public:
    416     static GrEffectRef* Create(GrContext* ctx,
    417                                const SkSweepGradient& shader,
    418                                const SkMatrix& matrix) {
    419         AutoEffectUnref effect(SkNEW_ARGS(GrSweepGradient, (ctx, shader, matrix)));
    420         return CreateEffectRef(effect);
    421     }
    422     virtual ~GrSweepGradient() { }
    423 
    424     static const char* Name() { return "Sweep Gradient"; }
    425     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
    426         return GrTBackendEffectFactory<GrSweepGradient>::getInstance();
    427     }
    428 
    429     typedef GrGLSweepGradient GLEffect;
    430 
    431 private:
    432     GrSweepGradient(GrContext* ctx,
    433                     const SkSweepGradient& shader,
    434                     const SkMatrix& matrix)
    435     : INHERITED(ctx, shader, matrix, SkShader::kClamp_TileMode) { }
    436     GR_DECLARE_EFFECT_TEST;
    437 
    438     typedef GrGradientEffect INHERITED;
    439 };
    440 
    441 /////////////////////////////////////////////////////////////////////
    442 
    443 GR_DEFINE_EFFECT_TEST(GrSweepGradient);
    444 
    445 GrEffectRef* GrSweepGradient::TestCreate(SkRandom* random,
    446                                          GrContext* context,
    447                                          GrTexture**) {
    448     SkPoint center = {random->nextUScalar1(), random->nextUScalar1()};
    449 
    450     SkColor colors[kMaxRandomGradientColors];
    451     SkScalar stopsArray[kMaxRandomGradientColors];
    452     SkScalar* stops = stopsArray;
    453     SkShader::TileMode tmIgnored;
    454     int colorCount = RandomGradientParams(random, colors, &stops, &tmIgnored);
    455     SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY,
    456                                                                 colors, stops, colorCount));
    457     SkPaint paint;
    458     return shader->asNewEffect(context, paint);
    459 }
    460 
    461 /////////////////////////////////////////////////////////////////////
    462 
    463 void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder,
    464                                  const GrEffectStage& stage,
    465                                  EffectKey key,
    466                                  const char* vertexCoords,
    467                                  const char* outputColor,
    468                                  const char* inputColor,
    469                                  const TextureSamplerArray& samplers) {
    470     this->emitYCoordUniform(builder);
    471     const char* coords;
    472     this->setupMatrix(builder, key, vertexCoords, &coords);
    473     SkString t;
    474     t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", coords, coords);
    475     this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
    476 }
    477 
    478 /////////////////////////////////////////////////////////////////////
    479 
    480 GrEffectRef* SkSweepGradient::asNewEffect(GrContext* context, const SkPaint&) const {
    481     SkMatrix matrix;
    482     if (!this->getLocalMatrix().invert(&matrix)) {
    483         return NULL;
    484     }
    485     matrix.postConcat(fPtsToUnit);
    486     return GrSweepGradient::Create(context, *this, matrix);
    487 }
    488 
    489 #else
    490 
    491 GrEffectRef* SkSweepGradient::asNewEffect(GrContext*, const SkPaint&) const {
    492     SkDEBUGFAIL("Should not call in GPU-less build");
    493     return NULL;
    494 }
    495 
    496 #endif
    497 
    498 #ifdef SK_DEVELOPER
    499 void SkSweepGradient::toString(SkString* str) const {
    500     str->append("SkSweepGradient: (");
    501 
    502     str->append("center: (");
    503     str->appendScalar(fCenter.fX);
    504     str->append(", ");
    505     str->appendScalar(fCenter.fY);
    506     str->append(") ");
    507 
    508     this->INHERITED::toString(str);
    509 
    510     str->append(")");
    511 }
    512 #endif
    513