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,
     12                                  const Descriptor& desc, const SkMatrix* localMatrix)
     13     : SkGradientShaderBase(desc, localMatrix)
     14     , fCenter(SkPoint::Make(cx, cy))
     15 {
     16     fPtsToUnit.setTranslate(-cx, -cy);
     17 
     18     // overwrite the tilemode to a canonical value (since sweep ignores it)
     19     fTileMode = SkShader::kClamp_TileMode;
     20 }
     21 
     22 SkShader::BitmapType SkSweepGradient::asABitmap(SkBitmap* bitmap,
     23     SkMatrix* matrix, SkShader::TileMode* xy) const {
     24     if (bitmap) {
     25         this->getGradientTableBitmap(bitmap);
     26     }
     27     if (matrix) {
     28         *matrix = fPtsToUnit;
     29     }
     30     if (xy) {
     31         xy[0] = fTileMode;
     32         xy[1] = kClamp_TileMode;
     33     }
     34     return kSweep_BitmapType;
     35 }
     36 
     37 SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
     38     if (info) {
     39         commonAsAGradient(info);
     40         info->fPoint[0] = fCenter;
     41     }
     42     return kSweep_GradientType;
     43 }
     44 
     45 SkSweepGradient::SkSweepGradient(SkReadBuffer& buffer)
     46     : INHERITED(buffer),
     47       fCenter(buffer.readPoint()) {
     48 }
     49 
     50 void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
     51     this->INHERITED::flatten(buffer);
     52     buffer.writePoint(fCenter);
     53 }
     54 
     55 size_t SkSweepGradient::contextSize() const {
     56     return sizeof(SweepGradientContext);
     57 }
     58 
     59 SkShader::Context* SkSweepGradient::onCreateContext(const ContextRec& rec, void* storage) const {
     60     return SkNEW_PLACEMENT_ARGS(storage, SweepGradientContext, (*this, rec));
     61 }
     62 
     63 SkSweepGradient::SweepGradientContext::SweepGradientContext(
     64         const SkSweepGradient& shader, const ContextRec& rec)
     65     : INHERITED(shader, rec) {}
     66 
     67 //  returns angle in a circle [0..2PI) -> [0..255]
     68 static unsigned SkATan2_255(float y, float x) {
     69     //    static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
     70     static const float g255Over2PI = 40.584510488433314f;
     71 
     72     float result = sk_float_atan2(y, x);
     73     if (result < 0) {
     74         result += 2 * SK_ScalarPI;
     75     }
     76     SkASSERT(result >= 0);
     77     // since our value is always >= 0, we can cast to int, which is faster than
     78     // calling floorf()
     79     int ir = (int)(result * g255Over2PI);
     80     SkASSERT(ir >= 0 && ir <= 255);
     81     return ir;
     82 }
     83 
     84 void SkSweepGradient::SweepGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
     85                                                       int count) {
     86     SkMatrix::MapXYProc proc = fDstToIndexProc;
     87     const SkMatrix&     matrix = fDstToIndex;
     88     const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
     89     int                 toggle = init_dither_toggle(x, y);
     90     SkPoint             srcPt;
     91 
     92     if (fDstToIndexClass != kPerspective_MatrixClass) {
     93         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
     94                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
     95         SkScalar dx, fx = srcPt.fX;
     96         SkScalar dy, fy = srcPt.fY;
     97 
     98         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
     99             SkFixed storage[2];
    100             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
    101                                       &storage[0], &storage[1]);
    102             dx = SkFixedToScalar(storage[0]);
    103             dy = SkFixedToScalar(storage[1]);
    104         } else {
    105             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
    106             dx = matrix.getScaleX();
    107             dy = matrix.getSkewY();
    108         }
    109 
    110         for (; count > 0; --count) {
    111             *dstC++ = cache[toggle + SkATan2_255(fy, fx)];
    112             fx += dx;
    113             fy += dy;
    114             toggle = next_dither_toggle(toggle);
    115         }
    116     } else {  // perspective case
    117         for (int stop = x + count; x < stop; x++) {
    118             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
    119                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    120             *dstC++ = cache[toggle + SkATan2_255(srcPt.fY, srcPt.fX)];
    121             toggle = next_dither_toggle(toggle);
    122         }
    123     }
    124 }
    125 
    126 void SkSweepGradient::SweepGradientContext::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
    127                                                         int count) {
    128     SkMatrix::MapXYProc proc = fDstToIndexProc;
    129     const SkMatrix&     matrix = fDstToIndex;
    130     const uint16_t* SK_RESTRICT cache = fCache->getCache16();
    131     int                 toggle = init_dither_toggle16(x, y);
    132     SkPoint             srcPt;
    133 
    134     if (fDstToIndexClass != kPerspective_MatrixClass) {
    135         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
    136                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    137         SkScalar dx, fx = srcPt.fX;
    138         SkScalar dy, fy = srcPt.fY;
    139 
    140         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
    141             SkFixed storage[2];
    142             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
    143                                       &storage[0], &storage[1]);
    144             dx = SkFixedToScalar(storage[0]);
    145             dy = SkFixedToScalar(storage[1]);
    146         } else {
    147             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
    148             dx = matrix.getScaleX();
    149             dy = matrix.getSkewY();
    150         }
    151 
    152         for (; count > 0; --count) {
    153             int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits);
    154             *dstC++ = cache[toggle + index];
    155             toggle = next_dither_toggle16(toggle);
    156             fx += dx;
    157             fy += dy;
    158         }
    159     } else {  // perspective case
    160         for (int stop = x + count; x < stop; x++) {
    161             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
    162                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    163 
    164             int index = SkATan2_255(srcPt.fY, srcPt.fX);
    165             index >>= (8 - kCache16Bits);
    166             *dstC++ = cache[toggle + index];
    167             toggle = next_dither_toggle16(toggle);
    168         }
    169     }
    170 }
    171 
    172 /////////////////////////////////////////////////////////////////////
    173 
    174 #if SK_SUPPORT_GPU
    175 
    176 #include "GrTBackendEffectFactory.h"
    177 #include "SkGr.h"
    178 
    179 class GrGLSweepGradient : public GrGLGradientEffect {
    180 public:
    181 
    182     GrGLSweepGradient(const GrBackendEffectFactory& factory,
    183                       const GrDrawEffect&) : INHERITED (factory) { }
    184     virtual ~GrGLSweepGradient() { }
    185 
    186     virtual void emitCode(GrGLShaderBuilder*,
    187                           const GrDrawEffect&,
    188                           EffectKey,
    189                           const char* outputColor,
    190                           const char* inputColor,
    191                           const TransformedCoordsArray&,
    192                           const TextureSamplerArray&) SK_OVERRIDE;
    193 
    194     static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
    195         return GenBaseGradientKey(drawEffect);
    196     }
    197 
    198 private:
    199 
    200     typedef GrGLGradientEffect INHERITED;
    201 
    202 };
    203 
    204 /////////////////////////////////////////////////////////////////////
    205 
    206 class GrSweepGradient : public GrGradientEffect {
    207 public:
    208     static GrEffectRef* Create(GrContext* ctx,
    209                                const SkSweepGradient& shader,
    210                                const SkMatrix& matrix) {
    211         AutoEffectUnref effect(SkNEW_ARGS(GrSweepGradient, (ctx, shader, matrix)));
    212         return CreateEffectRef(effect);
    213     }
    214     virtual ~GrSweepGradient() { }
    215 
    216     static const char* Name() { return "Sweep Gradient"; }
    217     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
    218         return GrTBackendEffectFactory<GrSweepGradient>::getInstance();
    219     }
    220 
    221     typedef GrGLSweepGradient GLEffect;
    222 
    223 private:
    224     GrSweepGradient(GrContext* ctx,
    225                     const SkSweepGradient& shader,
    226                     const SkMatrix& matrix)
    227     : INHERITED(ctx, shader, matrix, SkShader::kClamp_TileMode) { }
    228     GR_DECLARE_EFFECT_TEST;
    229 
    230     typedef GrGradientEffect INHERITED;
    231 };
    232 
    233 /////////////////////////////////////////////////////////////////////
    234 
    235 GR_DEFINE_EFFECT_TEST(GrSweepGradient);
    236 
    237 GrEffectRef* GrSweepGradient::TestCreate(SkRandom* random,
    238                                          GrContext* context,
    239                                          const GrDrawTargetCaps&,
    240                                          GrTexture**) {
    241     SkPoint center = {random->nextUScalar1(), random->nextUScalar1()};
    242 
    243     SkColor colors[kMaxRandomGradientColors];
    244     SkScalar stopsArray[kMaxRandomGradientColors];
    245     SkScalar* stops = stopsArray;
    246     SkShader::TileMode tmIgnored;
    247     int colorCount = RandomGradientParams(random, colors, &stops, &tmIgnored);
    248     SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY,
    249                                                                 colors, stops, colorCount));
    250     SkPaint paint;
    251     GrEffectRef* effect;
    252     GrColor grColor;
    253     shader->asNewEffect(context, paint, NULL, &grColor, &effect);
    254     return effect;
    255 }
    256 
    257 /////////////////////////////////////////////////////////////////////
    258 
    259 void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder,
    260                                  const GrDrawEffect&,
    261                                  EffectKey key,
    262                                  const char* outputColor,
    263                                  const char* inputColor,
    264                                  const TransformedCoordsArray& coords,
    265                                  const TextureSamplerArray& samplers) {
    266     this->emitUniforms(builder, key);
    267     SkString coords2D = builder->ensureFSCoords2D(coords, 0);
    268     const GrGLContextInfo ctxInfo = builder->ctxInfo();
    269     SkString t;
    270     // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
    271     // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int
    272     // thus must us -1.0 * %s.x to work correctly
    273     if (kIntel_GrGLVendor != ctxInfo.vendor()){
    274         t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
    275                  coords2D.c_str(), coords2D.c_str());
    276     } else {
    277         t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5",
    278                  coords2D.c_str(), coords2D.c_str());
    279     }
    280     this->emitColor(builder, t.c_str(), key,
    281                           outputColor, inputColor, samplers);
    282 }
    283 
    284 /////////////////////////////////////////////////////////////////////
    285 
    286 bool SkSweepGradient::asNewEffect(GrContext* context, const SkPaint& paint,
    287                                   const SkMatrix* localMatrix, GrColor* grColor,
    288                                   GrEffectRef** grEffect)  const {
    289 
    290     SkMatrix matrix;
    291     if (!this->getLocalMatrix().invert(&matrix)) {
    292         return false;
    293     }
    294     if (localMatrix) {
    295         SkMatrix inv;
    296         if (!localMatrix->invert(&inv)) {
    297             return false;
    298         }
    299         matrix.postConcat(inv);
    300     }
    301     matrix.postConcat(fPtsToUnit);
    302 
    303     *grEffect = GrSweepGradient::Create(context, *this, matrix);
    304     *grColor = SkColor2GrColorJustAlpha(paint.getColor());
    305 
    306     return true;
    307 }
    308 
    309 #else
    310 
    311 bool SkSweepGradient::asNewEffect(GrContext* context, const SkPaint& paint,
    312                                   const SkMatrix* localMatrix, GrColor* grColor,
    313                                   GrEffectRef** grEffect)  const {
    314     SkDEBUGFAIL("Should not call in GPU-less build");
    315     return false;
    316 }
    317 
    318 #endif
    319 
    320 #ifndef SK_IGNORE_TO_STRING
    321 void SkSweepGradient::toString(SkString* str) const {
    322     str->append("SkSweepGradient: (");
    323 
    324     str->append("center: (");
    325     str->appendScalar(fCenter.fX);
    326     str->append(", ");
    327     str->appendScalar(fCenter.fY);
    328     str->append(") ");
    329 
    330     this->INHERITED::toString(str);
    331 
    332     str->append(")");
    333 }
    334 #endif
    335