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