gfx/skia/trunk/src/effects/gradients/SkSweepGradient.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/effects/gradients/SkSweepGradient.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,302 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2012 Google Inc.
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +#include "SkSweepGradient.h"
    1.13 +
    1.14 +SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy,
    1.15 +                                 const Descriptor& desc)
    1.16 +    : SkGradientShaderBase(desc)
    1.17 +    , fCenter(SkPoint::Make(cx, cy))
    1.18 +{
    1.19 +    fPtsToUnit.setTranslate(-cx, -cy);
    1.20 +
    1.21 +    // overwrite the tilemode to a canonical value (since sweep ignores it)
    1.22 +    fTileMode = SkShader::kClamp_TileMode;
    1.23 +}
    1.24 +
    1.25 +SkShader::BitmapType SkSweepGradient::asABitmap(SkBitmap* bitmap,
    1.26 +    SkMatrix* matrix, SkShader::TileMode* xy) const {
    1.27 +    if (bitmap) {
    1.28 +        this->getGradientTableBitmap(bitmap);
    1.29 +    }
    1.30 +    if (matrix) {
    1.31 +        *matrix = fPtsToUnit;
    1.32 +    }
    1.33 +    if (xy) {
    1.34 +        xy[0] = fTileMode;
    1.35 +        xy[1] = kClamp_TileMode;
    1.36 +    }
    1.37 +    return kSweep_BitmapType;
    1.38 +}
    1.39 +
    1.40 +SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
    1.41 +    if (info) {
    1.42 +        commonAsAGradient(info);
    1.43 +        info->fPoint[0] = fCenter;
    1.44 +    }
    1.45 +    return kSweep_GradientType;
    1.46 +}
    1.47 +
    1.48 +SkSweepGradient::SkSweepGradient(SkReadBuffer& buffer)
    1.49 +    : INHERITED(buffer),
    1.50 +      fCenter(buffer.readPoint()) {
    1.51 +}
    1.52 +
    1.53 +void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
    1.54 +    this->INHERITED::flatten(buffer);
    1.55 +    buffer.writePoint(fCenter);
    1.56 +}
    1.57 +
    1.58 +//  returns angle in a circle [0..2PI) -> [0..255]
    1.59 +static unsigned SkATan2_255(float y, float x) {
    1.60 +    //    static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
    1.61 +    static const float g255Over2PI = 40.584510488433314f;
    1.62 +
    1.63 +    float result = sk_float_atan2(y, x);
    1.64 +    if (result < 0) {
    1.65 +        result += 2 * SK_ScalarPI;
    1.66 +    }
    1.67 +    SkASSERT(result >= 0);
    1.68 +    // since our value is always >= 0, we can cast to int, which is faster than
    1.69 +    // calling floorf()
    1.70 +    int ir = (int)(result * g255Over2PI);
    1.71 +    SkASSERT(ir >= 0 && ir <= 255);
    1.72 +    return ir;
    1.73 +}
    1.74 +
    1.75 +void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
    1.76 +                               int count) {
    1.77 +    SkMatrix::MapXYProc proc = fDstToIndexProc;
    1.78 +    const SkMatrix&     matrix = fDstToIndex;
    1.79 +    const SkPMColor* SK_RESTRICT cache = this->getCache32();
    1.80 +    int                 toggle = init_dither_toggle(x, y);
    1.81 +    SkPoint             srcPt;
    1.82 +
    1.83 +    if (fDstToIndexClass != kPerspective_MatrixClass) {
    1.84 +        proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
    1.85 +                     SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    1.86 +        SkScalar dx, fx = srcPt.fX;
    1.87 +        SkScalar dy, fy = srcPt.fY;
    1.88 +
    1.89 +        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
    1.90 +            SkFixed storage[2];
    1.91 +            (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
    1.92 +                                      &storage[0], &storage[1]);
    1.93 +            dx = SkFixedToScalar(storage[0]);
    1.94 +            dy = SkFixedToScalar(storage[1]);
    1.95 +        } else {
    1.96 +            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
    1.97 +            dx = matrix.getScaleX();
    1.98 +            dy = matrix.getSkewY();
    1.99 +        }
   1.100 +
   1.101 +        for (; count > 0; --count) {
   1.102 +            *dstC++ = cache[toggle + SkATan2_255(fy, fx)];
   1.103 +            fx += dx;
   1.104 +            fy += dy;
   1.105 +            toggle = next_dither_toggle(toggle);
   1.106 +        }
   1.107 +    } else {  // perspective case
   1.108 +        for (int stop = x + count; x < stop; x++) {
   1.109 +            proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
   1.110 +                         SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
   1.111 +            *dstC++ = cache[toggle + SkATan2_255(srcPt.fY, srcPt.fX)];
   1.112 +            toggle = next_dither_toggle(toggle);
   1.113 +        }
   1.114 +    }
   1.115 +}
   1.116 +
   1.117 +void SkSweepGradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
   1.118 +                                 int count) {
   1.119 +    SkMatrix::MapXYProc proc = fDstToIndexProc;
   1.120 +    const SkMatrix&     matrix = fDstToIndex;
   1.121 +    const uint16_t* SK_RESTRICT cache = this->getCache16();
   1.122 +    int                 toggle = init_dither_toggle16(x, y);
   1.123 +    SkPoint             srcPt;
   1.124 +
   1.125 +    if (fDstToIndexClass != kPerspective_MatrixClass) {
   1.126 +        proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
   1.127 +                     SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
   1.128 +        SkScalar dx, fx = srcPt.fX;
   1.129 +        SkScalar dy, fy = srcPt.fY;
   1.130 +
   1.131 +        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
   1.132 +            SkFixed storage[2];
   1.133 +            (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
   1.134 +                                      &storage[0], &storage[1]);
   1.135 +            dx = SkFixedToScalar(storage[0]);
   1.136 +            dy = SkFixedToScalar(storage[1]);
   1.137 +        } else {
   1.138 +            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
   1.139 +            dx = matrix.getScaleX();
   1.140 +            dy = matrix.getSkewY();
   1.141 +        }
   1.142 +
   1.143 +        for (; count > 0; --count) {
   1.144 +            int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits);
   1.145 +            *dstC++ = cache[toggle + index];
   1.146 +            toggle = next_dither_toggle16(toggle);
   1.147 +            fx += dx;
   1.148 +            fy += dy;
   1.149 +        }
   1.150 +    } else {  // perspective case
   1.151 +        for (int stop = x + count; x < stop; x++) {
   1.152 +            proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
   1.153 +                         SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
   1.154 +
   1.155 +            int index = SkATan2_255(srcPt.fY, srcPt.fX);
   1.156 +            index >>= (8 - kCache16Bits);
   1.157 +            *dstC++ = cache[toggle + index];
   1.158 +            toggle = next_dither_toggle16(toggle);
   1.159 +        }
   1.160 +    }
   1.161 +}
   1.162 +
   1.163 +/////////////////////////////////////////////////////////////////////
   1.164 +
   1.165 +#if SK_SUPPORT_GPU
   1.166 +
   1.167 +#include "GrTBackendEffectFactory.h"
   1.168 +
   1.169 +class GrGLSweepGradient : public GrGLGradientEffect {
   1.170 +public:
   1.171 +
   1.172 +    GrGLSweepGradient(const GrBackendEffectFactory& factory,
   1.173 +                      const GrDrawEffect&) : INHERITED (factory) { }
   1.174 +    virtual ~GrGLSweepGradient() { }
   1.175 +
   1.176 +    virtual void emitCode(GrGLShaderBuilder*,
   1.177 +                          const GrDrawEffect&,
   1.178 +                          EffectKey,
   1.179 +                          const char* outputColor,
   1.180 +                          const char* inputColor,
   1.181 +                          const TransformedCoordsArray&,
   1.182 +                          const TextureSamplerArray&) SK_OVERRIDE;
   1.183 +
   1.184 +    static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
   1.185 +        return GenBaseGradientKey(drawEffect);
   1.186 +    }
   1.187 +
   1.188 +private:
   1.189 +
   1.190 +    typedef GrGLGradientEffect INHERITED;
   1.191 +
   1.192 +};
   1.193 +
   1.194 +/////////////////////////////////////////////////////////////////////
   1.195 +
   1.196 +class GrSweepGradient : public GrGradientEffect {
   1.197 +public:
   1.198 +    static GrEffectRef* Create(GrContext* ctx,
   1.199 +                               const SkSweepGradient& shader,
   1.200 +                               const SkMatrix& matrix) {
   1.201 +        AutoEffectUnref effect(SkNEW_ARGS(GrSweepGradient, (ctx, shader, matrix)));
   1.202 +        return CreateEffectRef(effect);
   1.203 +    }
   1.204 +    virtual ~GrSweepGradient() { }
   1.205 +
   1.206 +    static const char* Name() { return "Sweep Gradient"; }
   1.207 +    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
   1.208 +        return GrTBackendEffectFactory<GrSweepGradient>::getInstance();
   1.209 +    }
   1.210 +
   1.211 +    typedef GrGLSweepGradient GLEffect;
   1.212 +
   1.213 +private:
   1.214 +    GrSweepGradient(GrContext* ctx,
   1.215 +                    const SkSweepGradient& shader,
   1.216 +                    const SkMatrix& matrix)
   1.217 +    : INHERITED(ctx, shader, matrix, SkShader::kClamp_TileMode) { }
   1.218 +    GR_DECLARE_EFFECT_TEST;
   1.219 +
   1.220 +    typedef GrGradientEffect INHERITED;
   1.221 +};
   1.222 +
   1.223 +/////////////////////////////////////////////////////////////////////
   1.224 +
   1.225 +GR_DEFINE_EFFECT_TEST(GrSweepGradient);
   1.226 +
   1.227 +GrEffectRef* GrSweepGradient::TestCreate(SkRandom* random,
   1.228 +                                         GrContext* context,
   1.229 +                                         const GrDrawTargetCaps&,
   1.230 +                                         GrTexture**) {
   1.231 +    SkPoint center = {random->nextUScalar1(), random->nextUScalar1()};
   1.232 +
   1.233 +    SkColor colors[kMaxRandomGradientColors];
   1.234 +    SkScalar stopsArray[kMaxRandomGradientColors];
   1.235 +    SkScalar* stops = stopsArray;
   1.236 +    SkShader::TileMode tmIgnored;
   1.237 +    int colorCount = RandomGradientParams(random, colors, &stops, &tmIgnored);
   1.238 +    SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY,
   1.239 +                                                                colors, stops, colorCount));
   1.240 +    SkPaint paint;
   1.241 +    return shader->asNewEffect(context, paint);
   1.242 +}
   1.243 +
   1.244 +/////////////////////////////////////////////////////////////////////
   1.245 +
   1.246 +void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder,
   1.247 +                                 const GrDrawEffect&,
   1.248 +                                 EffectKey key,
   1.249 +                                 const char* outputColor,
   1.250 +                                 const char* inputColor,
   1.251 +                                 const TransformedCoordsArray& coords,
   1.252 +                                 const TextureSamplerArray& samplers) {
   1.253 +    this->emitUniforms(builder, key);
   1.254 +    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
   1.255 +    const GrGLContextInfo ctxInfo = builder->ctxInfo();
   1.256 +    SkString t;
   1.257 +    // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
   1.258 +    // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int
   1.259 +    // thus must us -1.0 * %s.x to work correctly
   1.260 +    if (kIntel_GrGLVendor != ctxInfo.vendor()){
   1.261 +        t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
   1.262 +                 coords2D.c_str(), coords2D.c_str());
   1.263 +    } else {
   1.264 +        t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5",
   1.265 +                 coords2D.c_str(), coords2D.c_str());
   1.266 +    }
   1.267 +    this->emitColor(builder, t.c_str(), key,
   1.268 +                          outputColor, inputColor, samplers);
   1.269 +}
   1.270 +
   1.271 +/////////////////////////////////////////////////////////////////////
   1.272 +
   1.273 +GrEffectRef* SkSweepGradient::asNewEffect(GrContext* context, const SkPaint&) const {
   1.274 +    SkMatrix matrix;
   1.275 +    if (!this->getLocalMatrix().invert(&matrix)) {
   1.276 +        return NULL;
   1.277 +    }
   1.278 +    matrix.postConcat(fPtsToUnit);
   1.279 +    return GrSweepGradient::Create(context, *this, matrix);
   1.280 +}
   1.281 +
   1.282 +#else
   1.283 +
   1.284 +GrEffectRef* SkSweepGradient::asNewEffect(GrContext*, const SkPaint&) const {
   1.285 +    SkDEBUGFAIL("Should not call in GPU-less build");
   1.286 +    return NULL;
   1.287 +}
   1.288 +
   1.289 +#endif
   1.290 +
   1.291 +#ifndef SK_IGNORE_TO_STRING
   1.292 +void SkSweepGradient::toString(SkString* str) const {
   1.293 +    str->append("SkSweepGradient: (");
   1.294 +
   1.295 +    str->append("center: (");
   1.296 +    str->appendScalar(fCenter.fX);
   1.297 +    str->append(", ");
   1.298 +    str->appendScalar(fCenter.fY);
   1.299 +    str->append(") ");
   1.300 +
   1.301 +    this->INHERITED::toString(str);
   1.302 +
   1.303 +    str->append(")");
   1.304 +}
   1.305 +#endif

mercurial