1 /*
2  *  Copyright (c) 2014 Dmitry Kazakov <dimula73@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #ifndef __KIS_ANTIALIASING_FADE_MAKER_H
20 #define __KIS_ANTIALIASING_FADE_MAKER_H
21 
22 #include "kis_global.h"
23 
24 template <class BaseFade>
25 class KisAntialiasingFadeMaker1D
26 {
27 public:
KisAntialiasingFadeMaker1D(const BaseFade & baseFade,bool enableAntialiasing)28     KisAntialiasingFadeMaker1D(const BaseFade &baseFade, bool enableAntialiasing)
29         : m_radius(0.0),
30           m_fadeStartValue(0),
31           m_antialiasingFadeStart(0),
32           m_antialiasingFadeCoeff(0),
33           m_enableAntialiasing(enableAntialiasing),
34           m_baseFade(baseFade)
35     {
36     }
37 
KisAntialiasingFadeMaker1D(const KisAntialiasingFadeMaker1D & rhs,const BaseFade & baseFade)38     KisAntialiasingFadeMaker1D(const KisAntialiasingFadeMaker1D &rhs, const BaseFade &baseFade)
39         : m_radius(rhs.m_radius),
40           m_fadeStartValue(rhs.m_fadeStartValue),
41           m_antialiasingFadeStart(rhs.m_antialiasingFadeStart),
42           m_antialiasingFadeCoeff(rhs.m_antialiasingFadeCoeff),
43           m_enableAntialiasing(rhs.m_enableAntialiasing),
44           m_baseFade(baseFade)
45     {
46     }
47 
setSquareNormCoeffs(qreal xcoeff,qreal ycoeff)48     void setSquareNormCoeffs(qreal xcoeff, qreal ycoeff) {
49         m_radius = 1.0;
50 
51         qreal xf = qMax(0.0, ((1.0 / xcoeff) - 1.0) * xcoeff);
52         qreal yf = qMax(0.0, ((1.0 / ycoeff) - 1.0) * ycoeff);
53 
54         m_antialiasingFadeStart = pow2(0.5 * (xf + yf));
55 
56         m_fadeStartValue = m_baseFade.value(m_antialiasingFadeStart);
57         m_antialiasingFadeCoeff = qMax(0.0, 255.0 - m_fadeStartValue) / (m_radius - m_antialiasingFadeStart);
58     }
59 
setRadius(qreal radius)60     void setRadius(qreal radius) {
61         m_radius = radius;
62         m_antialiasingFadeStart = qMax(0.0, m_radius - 1.0);
63 
64         m_fadeStartValue = m_baseFade.value(m_antialiasingFadeStart);
65         m_antialiasingFadeCoeff = qMax(0.0, 255.0 - m_fadeStartValue) / (m_radius - m_antialiasingFadeStart);
66     }
67 
needFade(qreal dist,quint8 * value)68     inline bool needFade(qreal dist, quint8 *value) {
69         if (dist > m_radius) {
70             *value = 255;
71             return true;
72         }
73 
74         if (!m_enableAntialiasing) {
75             return false;
76         }
77 
78         if (dist > m_antialiasingFadeStart) {
79             *value = m_fadeStartValue + (dist - m_antialiasingFadeStart) * m_antialiasingFadeCoeff;
80             return true;
81         }
82 
83         return false;
84     }
85 
86 #if defined HAVE_VC
needFade(Vc::float_v & dist)87     Vc::float_m needFade(Vc::float_v &dist) {
88         const Vc::float_v vOne(Vc::One);
89         const Vc::float_v vValMax(255.f);
90 
91         Vc::float_v vRadius(m_radius);
92         Vc::float_v vFadeStartValue(m_fadeStartValue);
93         Vc::float_v vAntialiasingFadeStart(m_antialiasingFadeStart);
94         Vc::float_v vAntialiasingFadeCoeff(m_antialiasingFadeCoeff);
95 
96         Vc::float_m outsideMask = dist > vRadius;
97         dist(outsideMask) = vOne;
98 
99         Vc::float_m fadeStartMask(false);
100 
101         if(m_enableAntialiasing){
102             fadeStartMask = dist > vAntialiasingFadeStart;
103             dist((outsideMask ^ fadeStartMask) & fadeStartMask) = (vFadeStartValue +
104                                                                 (dist - vAntialiasingFadeStart) * vAntialiasingFadeCoeff) / vValMax;
105         }
106         return (outsideMask | fadeStartMask);
107     }
108 
109 #endif /* defined HAVE_VC */
110 
111 private:
112     qreal m_radius;
113     quint8 m_fadeStartValue;
114     qreal m_antialiasingFadeStart;
115     qreal m_antialiasingFadeCoeff;
116     bool m_enableAntialiasing;
117     const BaseFade &m_baseFade;
118 };
119 
120 template <class BaseFade>
121 class KisAntialiasingFadeMaker2D
122 {
123 public:
KisAntialiasingFadeMaker2D(const BaseFade & baseFade,bool enableAntialiasing)124     KisAntialiasingFadeMaker2D(const BaseFade &baseFade, bool enableAntialiasing)
125         : m_xLimit(0),
126           m_yLimit(0),
127           m_xFadeLimitStart(0),
128           m_yFadeLimitStart(0),
129           m_xFadeCoeff(0),
130           m_yFadeCoeff(0),
131           m_enableAntialiasing(enableAntialiasing),
132           m_baseFade(baseFade)
133     {
134     }
135 
KisAntialiasingFadeMaker2D(const KisAntialiasingFadeMaker2D & rhs,const BaseFade & baseFade)136     KisAntialiasingFadeMaker2D(const KisAntialiasingFadeMaker2D &rhs, const BaseFade &baseFade)
137         : m_xLimit(rhs.m_xLimit),
138           m_yLimit(rhs.m_yLimit),
139           m_xFadeLimitStart(rhs.m_xFadeLimitStart),
140           m_yFadeLimitStart(rhs.m_yFadeLimitStart),
141           m_xFadeCoeff(rhs.m_xFadeCoeff),
142           m_yFadeCoeff(rhs.m_yFadeCoeff),
143           m_enableAntialiasing(rhs.m_enableAntialiasing),
144           m_baseFade(baseFade)
145     {
146     }
147 
setLimits(qreal halfWidth,qreal halfHeight)148     void setLimits(qreal halfWidth, qreal halfHeight) {
149         m_xLimit = halfWidth;
150         m_yLimit = halfHeight;
151 
152         m_xFadeLimitStart = m_xLimit - 1.0;
153         m_yFadeLimitStart = m_yLimit - 1.0;
154 
155         m_xFadeCoeff = 1.0 / (m_xLimit - m_xFadeLimitStart);
156         m_yFadeCoeff = 1.0 / (m_yLimit - m_yFadeLimitStart);
157     }
158 
needFade(qreal x,qreal y,quint8 * value)159     inline bool needFade(qreal x, qreal y, quint8 *value) {
160         x = qAbs(x);
161         y = qAbs(y);
162 
163         if (x > m_xLimit) {
164             *value = 255;
165             return true;
166         }
167 
168         if (y > m_yLimit) {
169             *value = 255;
170             return true;
171         }
172 
173         if (!m_enableAntialiasing) {
174             return false;
175         }
176 
177         if (x > m_xFadeLimitStart) {
178             quint8 baseValue = m_baseFade.value(x, y);
179             *value = baseValue + (255.0 - baseValue) * (x - m_xFadeLimitStart) * m_xFadeCoeff;
180 
181             if (y > m_yFadeLimitStart && *value < 255) {
182                 *value += (255.0 - *value) * (y - m_yFadeLimitStart) * m_yFadeCoeff;
183             }
184 
185             return true;
186         }
187 
188         if (y > m_yFadeLimitStart) {
189             quint8 baseValue = m_baseFade.value(x, y);
190             *value = baseValue + (255.0 - baseValue) * (y - m_yFadeLimitStart) * m_yFadeCoeff;
191 
192             if (x > m_xFadeLimitStart && *value < 255) {
193                 *value += (255.0 - *value) * (x - m_xFadeLimitStart) * m_xFadeCoeff;
194             }
195 
196             return true;
197         }
198 
199         return false;
200     }
201 
202 #if defined HAVE_VC
needFade(Vc::float_v & xr,Vc::float_v & yr)203     Vc::float_m needFade(Vc::float_v &xr, Vc::float_v &yr) const {
204 
205         Vc::float_v vXLimit(m_xLimit);
206         Vc::float_v vYLimit(m_yLimit);
207 
208         Vc::float_m outXMask = Vc::abs(xr) > vXLimit;
209         Vc::float_m outYMask = Vc::abs(yr) > vYLimit;
210 
211         return (outXMask | outYMask);
212     }
213 
214     // Apply fader separately to avoid calculating vValue twice.
apply2DFader(Vc::float_v & vValue,Vc::float_m & excludeMask,Vc::float_v & xr,Vc::float_v & yr)215     void apply2DFader(Vc::float_v &vValue, Vc::float_m &excludeMask, Vc::float_v &xr, Vc::float_v &yr) const {
216         const Vc::float_v vValMax(255.f);
217 
218         if(m_enableAntialiasing){
219             Vc::float_v vXFadeLimitStart(m_xFadeLimitStart);
220             Vc::float_v vYFadeLimitStart(m_yFadeLimitStart);
221             Vc::float_v vXFadeCoeff(m_xFadeCoeff);
222             Vc::float_v vYFadeCoeff(m_yFadeCoeff);
223 
224             Vc::float_v xra = abs(xr);
225             Vc::float_m fadeXStartMask(false);
226             Vc::float_m fadeYStartMask(false);
227 
228             Vc::float_v fadeValue;
229             Vc::SimdArray<quint16,Vc::float_v::size()> vBaseValue(vValue);
230 
231             fadeXStartMask = xra > vXFadeLimitStart;
232             fadeXStartMask = (fadeXStartMask ^ excludeMask) & fadeXStartMask;
233             if (!fadeXStartMask.isFull()) {
234                 fadeValue = vBaseValue + (vValMax - vBaseValue) * (xra - vXFadeLimitStart) * vXFadeCoeff;
235                 fadeValue(fadeXStartMask & ((yr > vYFadeLimitStart) & (fadeValue < vValMax)) ) =
236                         fadeValue + (vValMax - fadeValue) * (yr - vYFadeLimitStart) * vYFadeCoeff;
237                 vValue(fadeXStartMask) = fadeValue;
238             }
239 
240             fadeYStartMask = yr > vYFadeLimitStart;
241             fadeYStartMask = (fadeYStartMask ^ fadeXStartMask) & fadeYStartMask;
242             if (!fadeYStartMask.isFull()) {
243                 fadeValue = vBaseValue + (vValMax - vBaseValue) * (yr - vYFadeLimitStart) * vYFadeCoeff;
244                 fadeValue(fadeYStartMask & ((xra > vXFadeLimitStart) & (fadeValue < vValMax)) ) =
245                         fadeValue + (vValMax - fadeValue) * (xra - vXFadeLimitStart) * vXFadeCoeff;
246                 vValue(fadeYStartMask) = fadeValue;
247             }
248         }
249         return;
250     }
251 
252 #endif /* defined HAVE_VC */
253 
254 private:
255     qreal m_xLimit;
256     qreal m_yLimit;
257 
258     qreal m_xFadeLimitStart;
259     qreal m_yFadeLimitStart;
260 
261     qreal m_xFadeCoeff;
262     qreal m_yFadeCoeff;
263 
264     bool m_enableAntialiasing;
265 
266     const BaseFade &m_baseFade;
267 };
268 
269 #endif /* __KIS_ANTIALIASING_FADE_MAKER_H */
270