blob: c6fee2c008bbc29b04a1eddeee3b777529f6ba51 [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkBitmapFilter_DEFINED
#define SkBitmapFilter_DEFINED
#include "SkMath.h"
// size of the precomputed bitmap filter tables for high quality filtering.
// Used to precompute the shape of the filter kernel.
// Table size chosen from experiments to see where I could start to see a difference.
#define SKBITMAP_FILTER_TABLE_SIZE 32
class SkBitmapFilter {
public:
SkBitmapFilter(float width)
: fWidth(width), fInvWidth(1.f/width) {
precomputed = false;
}
SkFixed lookup( float x ) const {
if (!precomputed) {
precomputeTable();
}
int filter_idx = int(fabsf(x * invWidth() * SKBITMAP_FILTER_TABLE_SIZE));
return fFilterTable[ SkTMin(filter_idx, SKBITMAP_FILTER_TABLE_SIZE-1) ];
}
float lookupFloat( float x ) const {
if (!precomputed) {
precomputeTable();
}
int filter_idx = int(fabsf(x * invWidth() * SKBITMAP_FILTER_TABLE_SIZE));
return fFilterTableFloat[ SkTMin(filter_idx, SKBITMAP_FILTER_TABLE_SIZE-1) ];
}
float width() const { return fWidth; }
float invWidth() const { return fInvWidth; }
virtual float evaluate(float x) const = 0;
virtual ~SkBitmapFilter() {}
protected:
float fWidth;
float fInvWidth;
mutable bool precomputed;
mutable SkFixed fFilterTable[SKBITMAP_FILTER_TABLE_SIZE];
mutable float fFilterTableFloat[SKBITMAP_FILTER_TABLE_SIZE];
private:
void precomputeTable() const {
precomputed = true;
SkFixed *ftp = fFilterTable;
float *ftp_float = fFilterTableFloat;
for (int x = 0; x < SKBITMAP_FILTER_TABLE_SIZE; ++x) {
float fx = ((float)x + .5f) * this->width() / SKBITMAP_FILTER_TABLE_SIZE;
float filter_value = evaluate(fx);
*ftp_float++ = filter_value;
*ftp++ = SkFloatToFixed(filter_value);
}
}
};
class SkMitchellFilter: public SkBitmapFilter {
public:
SkMitchellFilter(float b, float c, float width=2.0f)
: SkBitmapFilter(width), B(b), C(c) {
}
virtual float evaluate(float x) const SK_OVERRIDE {
x = fabsf(x);
if (x > 2.f) {
return 0;
} else if (x > 1.f) {
return ((-B - 6*C) * x*x*x + (6*B + 30*C) * x*x +
(-12*B - 48*C) * x + (8*B + 24*C)) * (1.f/6.f);
} else {
return ((12 - 9*B - 6*C) * x*x*x +
(-18 + 12*B + 6*C) * x*x +
(6 - 2*B)) * (1.f/6.f);
}
}
protected:
float B, C;
};
class SkGaussianFilter: public SkBitmapFilter {
public:
SkGaussianFilter(float a, float width=2.0f)
: SkBitmapFilter(width), alpha(a), expWidth(expf(-alpha * width * width)) {
}
virtual float evaluate(float x) const SK_OVERRIDE {
return SkTMax(0.f, float(expf(-alpha*x*x) - expWidth));
}
protected:
float alpha, expWidth;
};
class SkTriangleFilter: public SkBitmapFilter {
public:
SkTriangleFilter(float width=1)
: SkBitmapFilter(width) {
}
virtual float evaluate(float x) const SK_OVERRIDE {
return SkTMax(0.f, fWidth - fabsf(x));
}
protected:
};
class SkBoxFilter: public SkBitmapFilter {
public:
SkBoxFilter(float width=0.5f)
: SkBitmapFilter(width) {
}
virtual float evaluate(float x) const SK_OVERRIDE {
return 1;
}
protected:
};
class SkSincFilter: public SkBitmapFilter {
public:
SkSincFilter(float t, float width=3.f)
: SkBitmapFilter(width), tau(t) {
}
virtual float evaluate(float x) const SK_OVERRIDE {
x = sk_float_abs(x * fInvWidth);
if (x < 1e-5f) return 1.f;
if (x > 1.f) return 0.f;
x *= SK_ScalarPI;
float sinc = sk_float_sin(x) / x;
float lanczos = sk_float_sin(x * tau) / (x * tau);
return sinc * lanczos;
}
protected:
float tau;
};
#endif