blob: ca3e0930f27570ebff359e95370a81f59d189f5c [file] [log] [blame]
humper@google.comb0889472013-07-09 21:37:14 +00001/*
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
humper@google.comb0889472013-07-09 21:37:14 +00008#ifndef SkBitmapFilter_DEFINED
9#define SkBitmapFilter_DEFINED
10
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkFixed.h"
humper@google.comb0889472013-07-09 21:37:14 +000012#include "SkMath.h"
bungemand3ebb482015-08-05 13:57:49 -070013#include "SkScalar.h"
humper@google.comb0889472013-07-09 21:37:14 +000014
caryclark368342c2016-01-12 10:44:02 -080015#include "SkNx.h"
caryclark368342c2016-01-12 10:44:02 -080016
humper@google.comb0889472013-07-09 21:37:14 +000017// 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
humper@google.com87fbf4f2013-07-10 21:49:29 +000021#define SKBITMAP_FILTER_TABLE_SIZE 128
humper@google.comb0889472013-07-09 21:37:14 +000022
23class SkBitmapFilter {
reeda36c7102016-01-14 10:10:56 -080024public:
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() {}
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000030
reeda36c7102016-01-14 10:10:56 -080031 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 }
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000039
reeda36c7102016-01-14 10:10:56 -080040 float width() const { return fWidth; }
41 float invWidth() const { return fInvWidth; }
42 virtual float evaluate(float x) const = 0;
caryclark368342c2016-01-12 10:44:02 -080043
reeda36c7102016-01-14 10:10:56 -080044 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 }
caryclark368342c2016-01-12 10:44:02 -080054
reeda36c7102016-01-14 10:10:56 -080055protected:
56 float fWidth;
57 float fInvWidth;
58 float fLookupMultiplier;
skia.committer@gmail.comfa1bd5f2013-07-13 07:00:56 +000059
reeda36c7102016-01-14 10:10:56 -080060 mutable bool fPrecomputed;
reeda36c7102016-01-14 10:10:56 -080061 mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE];
humper@google.com9c96d4b2013-07-14 01:44:59 +000062
reeda36c7102016-01-14 10:10:56 -080063private:
64 void precomputeTable() const {
65 fPrecomputed = true;
reeda36c7102016-01-14 10:10:56 -080066 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;
reeda36c7102016-01-14 10:10:56 -080071 }
72 }
humper@google.comb0889472013-07-09 21:37:14 +000073};
74
reeda36c7102016-01-14 10:10:56 -080075class SkMitchellFilter final : public SkBitmapFilter {
76public:
reeda36c7102016-01-14 10:10:56 -080077 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 {}
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +000089
reeda36c7102016-01-14 10:10:56 -080090 float evaluate(float x) const override {
91 x = fabsf(x);
92 if (x > 2.f) {
93 return 0;
94 } else if (x > 1.f) {
reeda36c7102016-01-14 10:10:56 -080095 return (((fA1 * x + fB1) * x + fC1) * x + fD1) * (1.f/6.f);
reeda36c7102016-01-14 10:10:56 -080096 } else {
reeda36c7102016-01-14 10:10:56 -080097 return ((fA2 * x + fB2) * x*x + fD2) * (1.f/6.f);
reeda36c7102016-01-14 10:10:56 -080098 }
99 }
caryclark368342c2016-01-12 10:44:02 -0800100
reeda36c7102016-01-14 10:10:56 -0800101 Sk4f evalcore_n(const Sk4f& val) const {
caryclark6b14c6b2016-02-18 05:45:33 -0800102 Sk4f x = val.abs();
reeda36c7102016-01-14 10:10:56 -0800103 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 }
caryclark368342c2016-01-12 10:44:02 -0800110
reeda36c7102016-01-14 10:10:56 -0800111 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 }
caryclark368342c2016-01-12 10:44:02 -0800131
humper@google.comb0889472013-07-09 21:37:14 +0000132 protected:
caryclark368342c2016-01-12 10:44:02 -0800133 float fB, fC;
134 float fA1, fB1, fC1, fD1;
135 float fA2, fB2, fD2;
reeda36c7102016-01-14 10:10:56 -0800136private:
137 typedef SkBitmapFilter INHERITED;
humper@google.comb0889472013-07-09 21:37:14 +0000138};
139
reeda36c7102016-01-14 10:10:56 -0800140class SkGaussianFilter final : public SkBitmapFilter {
141 float fAlpha, fExpWidth;
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000142
humper@google.com138ebc32013-07-19 20:20:04 +0000143public:
reeda36c7102016-01-14 10:10:56 -0800144 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));
humper@google.com138ebc32013-07-19 20:20:04 +0000152 }
reeda36c7102016-01-14 10:10:56 -0800153};
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
mtklein36352bf2015-03-25 18:17:31 -0700177 float evaluate(float x) const override {
humper@google.com138ebc32013-07-19 20:20:04 +0000178 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 }
humper@google.com16acf752013-07-19 21:12:08 +0000184 const float xpi = x * static_cast<float>(SK_ScalarPI);
humper@google.comb0889472013-07-09 21:37:14 +0000185
humper@google.com138ebc32013-07-19 20:20:04 +0000186 return ((sk_float_sin(xpi) / xpi) * // sinc(x)
187 (0.54f + 0.46f * sk_float_cos(xpi / fWidth))); // hamming(x)
188 }
189};
190
reeda36c7102016-01-14 10:10:56 -0800191class SkLanczosFilter final : public SkBitmapFilter {
192public:
193 SkLanczosFilter(float width = 3.f) : SkBitmapFilter(width) {}
skia.committer@gmail.com9e1ec1a2013-07-10 07:00:58 +0000194
reeda36c7102016-01-14 10:10:56 -0800195 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 }
humper@google.comb0889472013-07-09 21:37:14 +0000206};
207
208
209#endif