1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkBitmapFilter_DEFINED
9#define SkBitmapFilter_DEFINED
10
11#include "SkFixed.h"
12#include "SkMath.h"
13#include "SkScalar.h"
14
15#include "SkNx.h"
16
17// size of the precomputed bitmap filter tables for high quality filtering.
18// Used to precompute the shape of the filter kernel.
19// Table size chosen from experiments to see where I could start to see a difference.
20
21#define SKBITMAP_FILTER_TABLE_SIZE 128
22
23class SkBitmapFilter {
24public:
25    SkBitmapFilter(float width) : fWidth(width), fInvWidth(1.f/width) {
26        fPrecomputed = false;
27        fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1);
28    }
29    virtual ~SkBitmapFilter() {}
30
31    SkScalar lookupScalar(float x) const {
32        if (!fPrecomputed) {
33            precomputeTable();
34        }
35        int filter_idx = int(sk_float_abs(x * fLookupMultiplier));
36        SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE);
37        return fFilterTableScalar[filter_idx];
38    }
39
40    float width() const { return fWidth; }
41    float invWidth() const { return fInvWidth; }
42    virtual float evaluate(float x) const = 0;
43
44    virtual float evaluate_n(float val, float diff, int count, float* output) const {
45        float sum = 0;
46        for (int index = 0; index < count; index++) {
47            float filterValue = evaluate(val);
48            *output++ = filterValue;
49            sum += filterValue;
50            val += diff;
51        }
52        return sum;
53    }
54
55protected:
56    float fWidth;
57    float fInvWidth;
58    float fLookupMultiplier;
59
60    mutable bool fPrecomputed;
61    mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE];
62
63private:
64    void precomputeTable() const {
65        fPrecomputed = true;
66        SkScalar *ftpScalar = fFilterTableScalar;
67        for (int x = 0; x < SKBITMAP_FILTER_TABLE_SIZE; ++x) {
68            float fx = ((float)x + .5f) * this->width() / SKBITMAP_FILTER_TABLE_SIZE;
69            float filter_value = evaluate(fx);
70            *ftpScalar++ = filter_value;
71        }
72    }
73};
74
75class SkMitchellFilter final : public SkBitmapFilter {
76public:
77    SkMitchellFilter()
78        : INHERITED(2)
79        , fB(1.f / 3.f)
80        , fC(1.f / 3.f)
81        , fA1(-fB - 6*fC)
82        , fB1(6*fB + 30*fC)
83        , fC1(-12*fB - 48*fC)
84        , fD1(8*fB + 24*fC)
85        , fA2(12 - 9*fB - 6*fC)
86        , fB2(-18 + 12*fB + 6*fC)
87        , fD2(6 - 2*fB)
88    {}
89
90    float evaluate(float x) const override {
91        x = fabsf(x);
92        if (x > 2.f) {
93            return 0;
94        } else if (x > 1.f) {
95            return (((fA1 * x + fB1) * x + fC1) * x + fD1) * (1.f/6.f);
96        } else {
97            return ((fA2 * x + fB2) * x*x + fD2) * (1.f/6.f);
98        }
99    }
100
101    Sk4f evalcore_n(const Sk4f& val) const {
102        Sk4f x = val.abs();
103        Sk4f over2 = x > Sk4f(2);
104        Sk4f over1 = x > Sk4f(1);
105        Sk4f poly1 = (((Sk4f(fA1) * x + Sk4f(fB1)) * x + Sk4f(fC1)) * x + Sk4f(fD1))
106                     * Sk4f(1.f/6.f);
107        Sk4f poly0 = ((Sk4f(fA2) * x + Sk4f(fB2)) * x*x + Sk4f(fD2)) * Sk4f(1.f/6.f);
108        return over2.thenElse(Sk4f(0), over1.thenElse(poly1, poly0));
109    }
110
111    float evaluate_n(float val, float diff, int count, float* output) const override {
112        Sk4f sum(0);
113        while (count >= 4) {
114            float v0 = val;
115            float v1 = val += diff;
116            float v2 = val += diff;
117            float v3 = val += diff;
118            val += diff;
119            Sk4f filterValue = evalcore_n(Sk4f(v0, v1, v2, v3));
120            filterValue.store(output);
121            output += 4;
122            sum = sum + filterValue;
123            count -= 4;
124        }
125        float sums[4];
126        sum.store(sums);
127        float result = sums[0] + sums[1] + sums[2] + sums[3];
128        result += INHERITED::evaluate_n(val, diff, count, output);
129        return result;
130    }
131
132  protected:
133      float fB, fC;
134      float fA1, fB1, fC1, fD1;
135      float fA2, fB2, fD2;
136private:
137    typedef SkBitmapFilter INHERITED;
138};
139
140class SkGaussianFilter final : public SkBitmapFilter {
141    float fAlpha, fExpWidth;
142
143public:
144    SkGaussianFilter(float a, float width = 2)
145        : SkBitmapFilter(width)
146        , fAlpha(a)
147        , fExpWidth(expf(-a * width * width))
148    {}
149
150    float evaluate(float x) const override {
151        return SkTMax(0.f, float(expf(-fAlpha*x*x) - fExpWidth));
152    }
153};
154
155class SkTriangleFilter final : public SkBitmapFilter {
156public:
157    SkTriangleFilter(float width = 1) : SkBitmapFilter(width) {}
158
159    float evaluate(float x) const override {
160        return SkTMax(0.f, fWidth - fabsf(x));
161    }
162};
163
164class SkBoxFilter final : public SkBitmapFilter {
165public:
166    SkBoxFilter(float width = 0.5f) : SkBitmapFilter(width) {}
167
168    float evaluate(float x) const override {
169        return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f;
170    }
171};
172
173class SkHammingFilter final : public SkBitmapFilter {
174public:
175    SkHammingFilter(float width = 1) : SkBitmapFilter(width) {}
176
177    float evaluate(float x) const override {
178        if (x <= -fWidth || x >= fWidth) {
179            return 0.0f;  // Outside of the window.
180        }
181        if (x > -FLT_EPSILON && x < FLT_EPSILON) {
182            return 1.0f;  // Special case the sinc discontinuity at the origin.
183        }
184        const float xpi = x * static_cast<float>(SK_ScalarPI);
185
186        return ((sk_float_sin(xpi) / xpi) *  // sinc(x)
187                (0.54f + 0.46f * sk_float_cos(xpi / fWidth)));  // hamming(x)
188    }
189};
190
191class SkLanczosFilter final : public SkBitmapFilter {
192public:
193    SkLanczosFilter(float width = 3.f) : SkBitmapFilter(width) {}
194
195    float evaluate(float x) const override {
196        if (x <= -fWidth || x >= fWidth) {
197            return 0.0f;  // Outside of the window.
198        }
199        if (x > -FLT_EPSILON && x < FLT_EPSILON) {
200            return 1.0f;  // Special case the discontinuity at the origin.
201        }
202        float xpi = x * static_cast<float>(SK_ScalarPI);
203        return (sk_float_sin(xpi) / xpi) *  // sinc(x)
204               sk_float_sin(xpi / fWidth) / (xpi / fWidth);  // sinc(x/fWidth)
205    }
206};
207
208
209#endif
210