File indexing completed on 2024-05-12 15:58:08
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com> 0003 * SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef __KIS_ANTIALIASING_FADE_MAKER_H 0009 #define __KIS_ANTIALIASING_FADE_MAKER_H 0010 0011 #include <kis_global.h> 0012 0013 #include <xsimd_extensions/xsimd.hpp> 0014 0015 template<class BaseFade> 0016 class KisAntialiasingFadeMaker1D 0017 { 0018 public: 0019 KisAntialiasingFadeMaker1D(const BaseFade &baseFade, bool enableAntialiasing) 0020 : m_radius(0.0) 0021 , m_fadeStartValue(0) 0022 , m_antialiasingFadeStart(0) 0023 , m_antialiasingFadeCoeff(0) 0024 , m_enableAntialiasing(enableAntialiasing) 0025 , m_baseFade(baseFade) 0026 { 0027 } 0028 0029 KisAntialiasingFadeMaker1D(const KisAntialiasingFadeMaker1D &rhs, const BaseFade &baseFade) 0030 : m_radius(rhs.m_radius) 0031 , m_fadeStartValue(rhs.m_fadeStartValue) 0032 , m_antialiasingFadeStart(rhs.m_antialiasingFadeStart) 0033 , m_antialiasingFadeCoeff(rhs.m_antialiasingFadeCoeff) 0034 , m_enableAntialiasing(rhs.m_enableAntialiasing) 0035 , m_baseFade(baseFade) 0036 { 0037 } 0038 0039 void setSquareNormCoeffs(qreal xcoeff, qreal ycoeff) 0040 { 0041 m_radius = 1.0; 0042 0043 const qreal xf = qMax(0.0, ((1.0 / xcoeff) - 1.0) * xcoeff); 0044 const qreal yf = qMax(0.0, ((1.0 / ycoeff) - 1.0) * ycoeff); 0045 0046 m_antialiasingFadeStart = pow2(0.5 * (xf + yf)); 0047 0048 m_fadeStartValue = m_baseFade.value(m_antialiasingFadeStart); 0049 m_antialiasingFadeCoeff = qMax(0.0, 255.0 - m_fadeStartValue) / (m_radius - m_antialiasingFadeStart); 0050 } 0051 0052 void setRadius(qreal radius) 0053 { 0054 m_radius = radius; 0055 m_antialiasingFadeStart = qMax(0.0, m_radius - 1.0); 0056 0057 m_fadeStartValue = m_baseFade.value(m_antialiasingFadeStart); 0058 m_antialiasingFadeCoeff = qMax(0.0, 255.0 - m_fadeStartValue) / (m_radius - m_antialiasingFadeStart); 0059 } 0060 0061 inline bool needFade(qreal dist, quint8 *value) 0062 { 0063 if (dist > m_radius) { 0064 *value = 255; 0065 return true; 0066 } 0067 0068 if (!m_enableAntialiasing) { 0069 return false; 0070 } 0071 0072 if (dist > m_antialiasingFadeStart) { 0073 *value = m_fadeStartValue + (dist - m_antialiasingFadeStart) * m_antialiasingFadeCoeff; 0074 return true; 0075 } 0076 0077 return false; 0078 } 0079 0080 #if defined(HAVE_XSIMD) && !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE) 0081 template<typename A> 0082 xsimd::batch_bool<float, A> needFade(xsimd::batch<float, A> &dist) 0083 { 0084 using float_v = xsimd::batch<float, A>; 0085 using float_m = typename float_v::batch_bool_type; 0086 0087 const float_v vOne(1); 0088 const float_v vValMax(255.f); 0089 0090 const float_v vRadius(m_radius); 0091 const float_v vFadeStartValue(m_fadeStartValue); 0092 const float_v vAntialiasingFadeStart(m_antialiasingFadeStart); 0093 const float_v vAntialiasingFadeCoeff(m_antialiasingFadeCoeff); 0094 0095 const float_m outsideMask = dist > vRadius; 0096 dist = xsimd::set_one(dist, outsideMask); 0097 0098 float_m fadeStartMask(false); 0099 0100 if (m_enableAntialiasing) { 0101 fadeStartMask = dist > vAntialiasingFadeStart; 0102 dist = xsimd::select((outsideMask ^ fadeStartMask) & fadeStartMask, 0103 (vFadeStartValue + (dist - vAntialiasingFadeStart) * vAntialiasingFadeCoeff) / vValMax, 0104 dist); 0105 } 0106 return (outsideMask | fadeStartMask); 0107 } 0108 0109 #endif /* defined HAVE_XSIMD */ 0110 0111 private: 0112 qreal m_radius; 0113 quint8 m_fadeStartValue; 0114 qreal m_antialiasingFadeStart; 0115 qreal m_antialiasingFadeCoeff; 0116 bool m_enableAntialiasing; 0117 const BaseFade &m_baseFade; 0118 }; 0119 0120 template<class BaseFade> 0121 class KisAntialiasingFadeMaker2D 0122 { 0123 public: 0124 KisAntialiasingFadeMaker2D(const BaseFade &baseFade, bool enableAntialiasing) 0125 : m_xLimit(0) 0126 , m_yLimit(0) 0127 , m_xFadeLimitStart(0) 0128 , m_yFadeLimitStart(0) 0129 , m_xFadeCoeff(0) 0130 , m_yFadeCoeff(0) 0131 , m_enableAntialiasing(enableAntialiasing) 0132 , m_baseFade(baseFade) 0133 { 0134 } 0135 0136 KisAntialiasingFadeMaker2D(const KisAntialiasingFadeMaker2D &rhs, const BaseFade &baseFade) 0137 : m_xLimit(rhs.m_xLimit) 0138 , m_yLimit(rhs.m_yLimit) 0139 , m_xFadeLimitStart(rhs.m_xFadeLimitStart) 0140 , m_yFadeLimitStart(rhs.m_yFadeLimitStart) 0141 , m_xFadeCoeff(rhs.m_xFadeCoeff) 0142 , m_yFadeCoeff(rhs.m_yFadeCoeff) 0143 , m_enableAntialiasing(rhs.m_enableAntialiasing) 0144 , m_baseFade(baseFade) 0145 { 0146 } 0147 0148 void setLimits(qreal halfWidth, qreal halfHeight) 0149 { 0150 m_xLimit = halfWidth; 0151 m_yLimit = halfHeight; 0152 0153 m_xFadeLimitStart = m_xLimit - 1.0; 0154 m_yFadeLimitStart = m_yLimit - 1.0; 0155 0156 m_xFadeCoeff = 1.0 / (m_xLimit - m_xFadeLimitStart); 0157 m_yFadeCoeff = 1.0 / (m_yLimit - m_yFadeLimitStart); 0158 } 0159 0160 inline bool needFade(qreal x, qreal y, quint8 *value) 0161 { 0162 x = qAbs(x); 0163 y = qAbs(y); 0164 0165 if (x > m_xLimit) { 0166 *value = 255; 0167 return true; 0168 } 0169 0170 if (y > m_yLimit) { 0171 *value = 255; 0172 return true; 0173 } 0174 0175 if (!m_enableAntialiasing) { 0176 return false; 0177 } 0178 0179 if (x > m_xFadeLimitStart) { 0180 quint8 baseValue = m_baseFade.value(x, y); 0181 *value = baseValue + (255.0 - baseValue) * (x - m_xFadeLimitStart) * m_xFadeCoeff; 0182 0183 if (y > m_yFadeLimitStart && *value < 255) { 0184 *value += (255.0 - *value) * (y - m_yFadeLimitStart) * m_yFadeCoeff; 0185 } 0186 0187 return true; 0188 } 0189 0190 if (y > m_yFadeLimitStart) { 0191 quint8 baseValue = m_baseFade.value(x, y); 0192 *value = baseValue + (255.0 - baseValue) * (y - m_yFadeLimitStart) * m_yFadeCoeff; 0193 0194 if (x > m_xFadeLimitStart && *value < 255) { 0195 *value += (255.0 - *value) * (x - m_xFadeLimitStart) * m_xFadeCoeff; 0196 } 0197 0198 return true; 0199 } 0200 0201 return false; 0202 } 0203 0204 #if defined(HAVE_XSIMD) && !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE) 0205 template<typename A> 0206 xsimd::batch_bool<float, A> needFade(xsimd::batch<float, A> &xr, xsimd::batch<float, A> &yr) const 0207 { 0208 using float_v = xsimd::batch<float, A>; 0209 using float_m = typename float_v::batch_bool_type; 0210 0211 const float_v vXLimit(m_xLimit); 0212 const float_v vYLimit(m_yLimit); 0213 0214 const float_m outXMask = xsimd::abs(xr) > vXLimit; 0215 const float_m outYMask = xsimd::abs(yr) > vYLimit; 0216 0217 return (outXMask | outYMask); 0218 } 0219 0220 // Apply fader separately to avoid calculating vValue twice. 0221 template<typename A> 0222 void apply2DFader(xsimd::batch<float, A> &vValue, xsimd::batch_bool<float, A> &excludeMask, xsimd::batch<float, A> &xr, xsimd::batch<float, A> &yr) const 0223 { 0224 using float_v = xsimd::batch<float, A>; 0225 using float_m = typename float_v::batch_bool_type; 0226 0227 const float_v vValMax(255.f); 0228 0229 if (m_enableAntialiasing) { 0230 const float_v vXFadeLimitStart(m_xFadeLimitStart); 0231 const float_v vYFadeLimitStart(m_yFadeLimitStart); 0232 const float_v vXFadeCoeff(m_xFadeCoeff); 0233 const float_v vYFadeCoeff(m_yFadeCoeff); 0234 0235 const float_v xra = xsimd::abs(xr); 0236 float_m fadeXStartMask(false); 0237 float_m fadeYStartMask(false); 0238 0239 float_v fadeValue(0); 0240 const float_v vBaseValue = 0241 xsimd::truncate_to_type<uint16_t>(vValue); 0242 0243 fadeXStartMask = xra > vXFadeLimitStart; 0244 fadeXStartMask = (fadeXStartMask ^ excludeMask) & fadeXStartMask; 0245 if (!xsimd::all(fadeXStartMask)) { 0246 fadeValue = vBaseValue + (vValMax - vBaseValue) * (xra - vXFadeLimitStart) * vXFadeCoeff; 0247 fadeValue = xsimd::select(fadeXStartMask & ((yr > vYFadeLimitStart) & (fadeValue < vValMax)), 0248 fadeValue + (vValMax - fadeValue) * (yr - vYFadeLimitStart) * vYFadeCoeff, 0249 fadeValue); 0250 vValue = xsimd::select(fadeXStartMask, fadeValue, vValue); 0251 } 0252 0253 fadeYStartMask = yr > vYFadeLimitStart; 0254 fadeYStartMask = (fadeYStartMask ^ fadeXStartMask) & fadeYStartMask; 0255 if (!xsimd::all(fadeYStartMask)) { 0256 fadeValue = vBaseValue + (vValMax - vBaseValue) * (yr - vYFadeLimitStart) * vYFadeCoeff; 0257 fadeValue = xsimd::select(fadeYStartMask & ((xra > vXFadeLimitStart) & (fadeValue < vValMax)), 0258 fadeValue + (vValMax - fadeValue) * (xra - vXFadeLimitStart) * vXFadeCoeff, 0259 fadeValue); 0260 vValue = xsimd::select(fadeYStartMask, fadeValue, vValue); 0261 } 0262 } 0263 } 0264 0265 #endif /* defined HAVE_XSIMD */ 0266 0267 private: 0268 qreal m_xLimit; 0269 qreal m_yLimit; 0270 0271 qreal m_xFadeLimitStart; 0272 qreal m_yFadeLimitStart; 0273 0274 qreal m_xFadeCoeff; 0275 qreal m_yFadeCoeff; 0276 0277 bool m_enableAntialiasing; 0278 0279 const BaseFade &m_baseFade; 0280 }; 0281 0282 #endif /* __KIS_ANTIALIASING_FADE_MAKER_H */