Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_brush_mask_processor_factories.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2012 Dmitry Kazakov <dimula73@gmail.com>
3 * SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
9
10#if !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE) && XSIMD_UNIVERSAL_BUILD_PASS
11
24
27
28#include "vc_extra_math.h"
29
30#define a(_s) #_s
31#define b(_s) a(_s)
32
33template<>
34template<>
36 int width,
37 float y,
38 float cosa,
39 float sina,
40 float centerX,
41 float centerY)
42{
43 using float_v = xsimd::batch<float, xsimd::current_arch>;
44 using float_m = typename float_v::batch_bool_type;
45
46 const bool useSmoothing = d->copyOfAntialiasEdges;
47
48 const float y_ = y - centerY;
49 const float sinay_ = sina * y_;
50 const float cosay_ = cosa * y_;
51
52 float *bufferPointer = buffer;
53
54 float_v currentIndices =
55 xsimd::detail::make_sequence_as_batch<float_v>();
56
57 const float_v increment((float)float_v::size);
58 const float_v vCenterX(centerX);
59
60 const float_v vCosa(cosa);
61 const float_v vSina(sina);
62 const float_v vCosaY_(cosay_);
63 const float_v vSinaY_(sinay_);
64
65 const float_v vXCoeff(static_cast<float>(d->xcoef));
66 const float_v vYCoeff(static_cast<float>(d->ycoef));
67
68 const float_v vTransformedFadeX(static_cast<float>(d->transformedFadeX));
69 const float_v vTransformedFadeY(static_cast<float>(d->transformedFadeY));
70
71 const float_v vOne(1);
72
73 for (size_t i = 0; i < static_cast<size_t>(width); i += float_v::size) {
74 const float_v x_ = currentIndices - vCenterX;
75
76 float_v xr = x_ * vCosa - vSinaY_;
77 float_v yr = x_ * vSina + vCosaY_;
78
79 const float_v n = xsimd::pow2(xr * vXCoeff) + xsimd::pow2(yr * vYCoeff);
80 const float_m outsideMask = n > vOne;
81
82 if (!xsimd::all(outsideMask)) {
83 if (useSmoothing) {
84 xr = xsimd::abs(xr) + vOne;
85 yr = xsimd::abs(yr) + vOne;
86 }
87 float_v vNormFade = xsimd::pow2(xr * vTransformedFadeX)
88 + xsimd::pow2(yr * vTransformedFadeY);
89 const float_m vNormLowMask = vNormFade < vOne;
90 vNormFade = xsimd::set_zero(vNormFade, vNormLowMask);
91
92 // 255 * n * (normeFade - 1) / (normeFade - n)
93 float_v vFade = n * (vNormFade - vOne) / (vNormFade - n);
94
95 // Mask in the inner circle of the mask
96 const float_m mask = vNormFade < vOne;
97 vFade = xsimd::set_zero(vFade, mask);
98
99 // Mask out the outer circle of the mask
100 vFade = xsimd::set_one(vFade, outsideMask);
101
102 vFade.store_aligned(bufferPointer);
103 } else {
104 // Mask out everything outside the circle
105 vOne.store_aligned(bufferPointer);
106 }
107
108 currentIndices = currentIndices + increment;
109
110 bufferPointer += float_v::size;
111 }
112}
113
114template<>
115template<>
117 int width,
118 float y,
119 float cosa,
120 float sina,
121 float centerX,
122 float centerY)
123{
124 using float_v = xsimd::batch<float, xsimd::current_arch>;
125 using float_m = float_v::batch_bool_type;
126
127 const float y_ = y - centerY;
128 const float sinay_ = sina * y_;
129 const float cosay_ = cosa * y_;
130
131 float *bufferPointer = buffer;
132
133 float_v currentIndices = xsimd::detail::make_sequence_as_batch<float_v>();
134
135 const float_v increment(static_cast<float>(float_v::size));
136 const float_v vCenterX(centerX);
137 const float_v vCenter(static_cast<float>(d->center));
138
139 const float_v vCosa(cosa);
140 const float_v vSina(sina);
141 const float_v vCosaY_(cosay_);
142 const float_v vSinaY_(sinay_);
143
144 const float_v vYCoeff(static_cast<float>(d->ycoef));
145 const float_v vDistfactor(static_cast<float>(d->distfactor));
146 const float_v vAlphafactor(static_cast<float>(d->alphafactor));
147
148 const float_v vZero(0);
149 const float_v vValMax(255.f);
150
151 for (size_t i = 0; i < static_cast<size_t>(width); i += float_v::size) {
152 const float_v x_ = currentIndices - vCenterX;
153
154 const float_v xr = x_ * vCosa - vSinaY_;
155 const float_v yr = x_ * vSina + vCosaY_;
156
157 float_v dist =
158 xsimd::sqrt(xsimd::pow2(xr) + xsimd::pow2(yr * vYCoeff));
159
160 // Apply FadeMaker mask and operations
161 const float_m excludeMask = d->fadeMaker.needFade(dist);
162
163 if (!xsimd::all(excludeMask)) {
164 const float_v valDist = dist * vDistfactor;
165 float_v fullFade = vAlphafactor
166 * (VcExtraMath::erf(valDist + vCenter)
167 - VcExtraMath::erf(valDist - vCenter));
168
169 // Mask in the inner circle of the mask
170 const float_m mask = fullFade < vZero;
171 fullFade = xsimd::set_zero(fullFade, mask);
172
173 // Mask the outer circle
174 const float_m outerMask = fullFade > 254.974f;
175 fullFade = xsimd::select(outerMask, vValMax, fullFade);
176
177 // Mask (value - value), precision errors.
178 float_v vFade = (vValMax - fullFade) / vValMax;
179
180 // return original dist values before vFade transform
181 vFade = xsimd::select(excludeMask, dist, vFade);
182 vFade.store_aligned(bufferPointer);
183 } else {
184 dist.store_aligned(bufferPointer);
185 }
186 currentIndices = currentIndices + increment;
187
188 bufferPointer += float_v::size;
189 }
190}
191
192template<>
193template<>
195 int width,
196 float y,
197 float cosa,
198 float sina,
199 float centerX,
200 float centerY)
201{
202 using int_v = xsimd::batch<int, xsimd::current_arch>;
203 using float_v = xsimd::batch<float, xsimd::current_arch>;
204 using float_m = float_v::batch_bool_type;
205
206 const float y_ = y - centerY;
207 const float sinay_ = sina * y_;
208 const float cosay_ = cosa * y_;
209
210 float *bufferPointer = buffer;
211
212 const qreal *curveDataPointer = d->curveData.data();
213
214 float_v currentIndices = xsimd::detail::make_sequence_as_batch<float_v>();
215
216 const float_v increment((float)float_v::size);
217 const float_v vCenterX(centerX);
218
219 const float_v vCosa(cosa);
220 const float_v vSina(sina);
221 const float_v vCosaY_(cosay_);
222 const float_v vSinaY_(sinay_);
223
224 const float_v vYCoeff(static_cast<float>(d->ycoef));
225 const float_v vXCoeff(static_cast<float>(d->xcoef));
226 const float_v vCurveResolution(static_cast<float>(d->curveResolution));
227
228 float_v vCurvedData(0);
229 float_v vCurvedData1(0);
230
231 const float_v vOne(1);
232 const float_v vZero(0);
233
234 for (size_t i = 0; i < static_cast<size_t>(width); i += float_v::size) {
235 const float_v x_ = currentIndices - vCenterX;
236
237 const float_v xr = x_ * vCosa - vSinaY_;
238 const float_v yr = x_ * vSina + vCosaY_;
239
240 float_v dist = xsimd::pow2(xr * vXCoeff) + xsimd::pow2(yr * vYCoeff);
241
242 // Apply FadeMaker mask and operations
243 const float_m excludeMask = d->fadeMaker.needFade(dist);
244
245 if (!xsimd::all(excludeMask)) {
246 const float_v valDist = dist * vCurveResolution;
247 // truncate
248 int_v vAlphaValue = xsimd::to_int(valDist);
249 const float_v vFloatAlphaValue = xsimd::to_float(vAlphaValue);
250
251 const float_v alphaValueF = valDist - vFloatAlphaValue;
252
253 const auto alphaMask = vAlphaValue < int_v(0);
254 vAlphaValue = xsimd::set_zero(vAlphaValue, alphaMask);
255
256 vCurvedData = float_v::gather(curveDataPointer, vAlphaValue);
257 vCurvedData1 = float_v::gather(curveDataPointer, vAlphaValue + 1);
258
259 // vAlpha
260 float_v fullFade = ((vOne - alphaValueF) * vCurvedData
261 + alphaValueF * vCurvedData1);
262
263 // Mask in the inner circle of the mask
264 const float_m mask = fullFade < vZero;
265 fullFade = xsimd::set_zero(fullFade, mask);
266
267 // Mask outer circle of mask
268 const float_m outerMask = fullFade >= vOne;
269 float_v vFade = (vOne - fullFade);
270 vFade = xsimd::set_zero(vFade, outerMask);
271
272 // return original dist values before vFade transform
273 vFade = xsimd::select(excludeMask, dist, vFade);
274 vFade.store_aligned(bufferPointer);
275 } else {
276 dist.store_aligned(bufferPointer);
277 }
278 currentIndices = currentIndices + increment;
279
280 bufferPointer += float_v::size;
281 }
282}
283
284template<>
285template<>
287 int width,
288 float y,
289 float cosa,
290 float sina,
291 float centerX,
292 float centerY)
293{
294 using float_v = xsimd::batch<float, xsimd::current_arch>;
295 using float_m = float_v::batch_bool_type;
296
297 const bool useSmoothing = d->copyOfAntialiasEdges;
298
299 const float y_ = y - centerY;
300 const float sinay_ = sina * y_;
301 const float cosay_ = cosa * y_;
302
303 float *bufferPointer = buffer;
304
305 float_v currentIndices = xsimd::detail::make_sequence_as_batch<float_v>();
306
307 const float_v increment((float)float_v::size);
308 const float_v vCenterX(centerX);
309
310 const float_v vCosa(cosa);
311 const float_v vSina(sina);
312 const float_v vCosaY_(cosay_);
313 const float_v vSinaY_(sinay_);
314
315 const float_v vXCoeff(static_cast<float>(d->xcoeff));
316 const float_v vYCoeff(static_cast<float>(d->ycoeff));
317
318 const float_v vTransformedFadeX(static_cast<float>(d->transformedFadeX));
319 const float_v vTransformedFadeY(static_cast<float>(d->transformedFadeY));
320
321 const float_v vOne(1);
322 const float_v vZero(0);
323 const float_v vTolerance(10000.f);
324
325 for (size_t i = 0; i < static_cast<size_t>(width); i += float_v::size) {
326 const float_v x_ = currentIndices - vCenterX;
327
328 float_v xr = xsimd::abs(x_ * vCosa - vSinaY_);
329 float_v yr = xsimd::abs(x_ * vSina + vCosaY_);
330
331 const float_v nxr = xr * vXCoeff;
332 const float_v nyr = yr * vYCoeff;
333
334 float_m outsideMask = (nxr > vOne) || (nyr > vOne);
335
336 if (!xsimd::all(outsideMask)) {
337 if (useSmoothing) {
338 xr = xsimd::abs(xr) + vOne;
339 yr = xsimd::abs(yr) + vOne;
340 }
341
342 const float_v fxr = xr * vTransformedFadeX;
343 const float_v fyr = yr * vTransformedFadeY;
344
345 const float_v fxrNorm = nxr * (fxr - vOne) / (fxr - nxr);
346 const float_v fyrNorm = nyr * (fyr - vOne) / (fyr - nyr);
347
348 float_v vFade(vZero);
349
350 const float_m vFadeMask = fxrNorm < fyrNorm;
351 float_v vMaxVal = vFade;
352 vMaxVal = xsimd::select(fxr > vOne, fxrNorm, vMaxVal);
353 vMaxVal = xsimd::select(vFadeMask && fyr > vOne, fyrNorm, vMaxVal);
354 vFade = vMaxVal;
355
356 // Mask out the outer circle of the mask
357 vFade = xsimd::select(outsideMask, vOne, vFade);
358 vFade.store_aligned(bufferPointer);
359 } else {
360 // Mask out everything outside the circle
361 vOne.store_aligned(bufferPointer);
362 }
363
364 currentIndices = currentIndices + increment;
365
366 bufferPointer += float_v::size;
367 }
368}
369
370template<>
371template<>
373 int width,
374 float y,
375 float cosa,
376 float sina,
377 float centerX,
378 float centerY)
379{
380 using float_v = xsimd::batch<float, xsimd::current_arch>;
381 using float_m = float_v::batch_bool_type;
382
383 const float y_ = y - centerY;
384 const float sinay_ = sina * y_;
385 const float cosay_ = cosa * y_;
386
387 float *bufferPointer = buffer;
388
389 float_v currentIndices = xsimd::detail::make_sequence_as_batch<float_v>();
390
391 const float_v increment((float)float_v::size);
392 const float_v vCenterX(centerX);
393
394 const float_v vCosa(cosa);
395 const float_v vSina(sina);
396 const float_v vCosaY_(cosay_);
397 const float_v vSinaY_(sinay_);
398
399 const float_v vhalfWidth(static_cast<float>(d->halfWidth));
400 const float_v vhalfHeight(static_cast<float>(d->halfHeight));
401 const float_v vXFade(static_cast<float>(d->xfade));
402 const float_v vYFade(static_cast<float>(d->yfade));
403
404 const float_v vAlphafactor(static_cast<float>(d->alphafactor));
405
406 const float_v vOne(1);
407 const float_v vZero(0);
408 const float_v vValMax(255.f);
409
410 for (size_t i = 0; i < static_cast<size_t>(width); i += float_v::size) {
411 const float_v x_ = currentIndices - vCenterX;
412
413 float_v xr = x_ * vCosa - vSinaY_;
414 float_v yr = xsimd::abs(x_ * vSina + vCosaY_);
415
416 // check if we need to apply fader on values
417 float_m excludeMask = d->fadeMaker.needFade(xr, yr);
418
419 if (!xsimd::all(excludeMask)) {
420 float_v fullFade = vValMax
421 - (vAlphafactor * (VcExtraMath::erf((vhalfWidth + xr) * vXFade) + VcExtraMath::erf((vhalfWidth - xr) * vXFade))
422 * (VcExtraMath::erf((vhalfHeight + yr) * vYFade) + VcExtraMath::erf((vhalfHeight - yr) * vYFade)));
423
424 // apply antialias fader
425 d->fadeMaker.apply2DFader(fullFade, excludeMask, xr, yr);
426
427 // Mask in the inner circle of the mask
428 const float_m mask = fullFade < vZero;
429 fullFade = xsimd::set_zero(fullFade, mask);
430
431 // Mask the outer circle
432 const float_m outerMask = fullFade > 254.974f;
433 fullFade = xsimd::select(outerMask, vValMax, fullFade);
434
435 // Mask (value - value), precision errors.
436 float_v vFade = fullFade / vValMax;
437
438 vFade = xsimd::select(excludeMask, vOne, vFade);
439 vFade.store_aligned(bufferPointer);
440
441 } else {
442 vOne.store_aligned(bufferPointer);
443 }
444 currentIndices = currentIndices + increment;
445
446 bufferPointer += float_v::size;
447 }
448}
449
450template<>
451template<>
453 int width,
454 float y,
455 float cosa,
456 float sina,
457 float centerX,
458 float centerY)
459{
460 using float_v = xsimd::batch<float, xsimd::current_arch>;
461 using float_m = float_v::batch_bool_type;
462
463 const float y_ = y - centerY;
464 const float sinay_ = sina * y_;
465 const float cosay_ = cosa * y_;
466
467 float *bufferPointer = buffer;
468
469 const qreal *curveDataPointer = d->curveData.data();
470
471 float_v currentIndices = xsimd::detail::make_sequence_as_batch<float_v>();
472
473 const float_v increment((float)float_v::size);
474 const float_v vCenterX(centerX);
475
476 const float_v vCosa(cosa);
477 const float_v vSina(sina);
478 const float_v vCosaY_(cosay_);
479 const float_v vSinaY_(sinay_);
480
481 const float_v vYCoeff(static_cast<float>(d->ycoeff));
482 const float_v vXCoeff(static_cast<float>(d->xcoeff));
483 const float_v vCurveResolution(static_cast<float>(d->curveResolution));
484
485 const float_v vOne(1);
486 const float_v vZero(0);
487 const float_v vValMax(255.f);
488
489 for (size_t i = 0; i < static_cast<size_t>(width); i += float_v::size) {
490 const float_v x_ = currentIndices - vCenterX;
491
492 float_v xr = x_ * vCosa - vSinaY_;
493 float_v yr = xsimd::abs(x_ * vSina + vCosaY_);
494
495 // check if we need to apply fader on values
496 float_m excludeMask = d->fadeMaker.needFade(xr, yr);
497 const float_v vValue = xsimd::set_one(float_v(0), excludeMask);
498
499 if (!xsimd::all(excludeMask)) {
500 // We need to mask the extra area given for aliniation
501 // the next operation should never give values above 1
502 float_v preSIndex = xsimd::abs(xr) * vXCoeff;
503 float_v preTIndex = xsimd::abs(yr) * vYCoeff;
504
505 preSIndex = xsimd::select(preSIndex > vOne, vOne, preSIndex);
506 preTIndex = xsimd::select(preTIndex > vOne, vOne, preTIndex);
507
508 const auto sIndex = xsimd::nearbyint_as_int(preSIndex * vCurveResolution);
509 const auto tIndex = xsimd::nearbyint_as_int(preTIndex * vCurveResolution);
510
511 const auto sIndexInverted = xsimd::to_int(vCurveResolution - xsimd::to_float(sIndex));
512 const auto tIndexInverted = xsimd::to_int(vCurveResolution - xsimd::to_float(tIndex));
513
514 const auto vCurvedDataSIndex = float_v::gather(curveDataPointer, sIndex);
515 const auto vCurvedDataTIndex = float_v::gather(curveDataPointer, tIndex);
516 const auto vCurvedDataSIndexInv = float_v::gather(curveDataPointer, sIndexInverted);
517 const auto vCurvedDataTIndexInv = float_v::gather(curveDataPointer, tIndexInverted);
518
519 float_v fullFade = vValMax
520 * (vOne
521 - (vCurvedDataSIndex * (vOne - vCurvedDataSIndexInv) * vCurvedDataTIndex
522 * (vOne - vCurvedDataTIndexInv)));
523
524 // apply antialias fader
525 d->fadeMaker.apply2DFader(fullFade, excludeMask, xr, yr);
526
527 // Mask in the inner circle of the mask
528 const float_m mask = fullFade < vZero;
529 fullFade = xsimd::set_zero(fullFade, mask);
530
531 // Mask the outer circle
532 const float_m outerMask = fullFade > 254.974f;
533 fullFade = xsimd::select(outerMask, vValMax, fullFade);
534
535 // Mask (value - value), precision errors.
536 float_v vFade = fullFade / vValMax;
537
538 // return original vValue values before vFade transform
539 vFade = xsimd::select(excludeMask, vValue, vFade);
540 vFade.store_aligned(bufferPointer);
541 } else {
542 vValue.store_aligned(bufferPointer);
543 }
544 currentIndices = currentIndices + increment;
545
546 bufferPointer += float_v::size;
547 }
548}
549
550#endif /* XSIMD_UNIVERSAL_BUILD_PASS */
static xsimd::batch< float, A > erf(const xsimd::batch< float, A > x)
auto set_one(const batch< T, A > &src, const batch_bool< T, A > &mask) noexcept
batch< T, A > pow2(batch< T, A > const &self) noexcept
auto set_zero(const batch< T, A > &src, const batch_bool< T, A > &mask) noexcept