File indexing completed on 2024-05-19 04:26:08

0001 /*
0002  *  SPDX-FileCopyrightText: 2012 Sven Langkamp <sven.langkamp@gmail.com>
0003  *  SPDX-FileCopyrightText: 2012 Dmitry Kazakov <dimula73@gmail.com>
0004  *  SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #ifndef KIS_BRUSH_SCALAR_APPLICATOR_H
0010 #define KIS_BRUSH_SCALAR_APPLICATOR_H
0011 
0012 #include "kis_brush_mask_applicator_base.h"
0013 #include "kis_global.h"
0014 #include "kis_random_source.h"
0015 
0016 template<class MaskGenerator, typename impl>
0017 struct KisBrushMaskScalarApplicator : public KisBrushMaskApplicatorBase {
0018     KisBrushMaskScalarApplicator(MaskGenerator *maskGenerator)
0019         : m_maskGenerator(maskGenerator)
0020     {
0021     }
0022 
0023     void process(const QRect &rect) override
0024     {
0025         processScalar(rect);
0026     }
0027 
0028 protected:
0029     void processScalar(const QRect &rect)
0030     {
0031         const MaskProcessingData *m_d = KisBrushMaskApplicatorBase::m_d;
0032         MaskGenerator *m_maskGenerator = KisBrushMaskScalarApplicator<MaskGenerator, impl>::m_maskGenerator;
0033 
0034         qreal random = 1.0;
0035         quint8 *dabPointer = m_d->device->data() + rect.y() * rect.width() * m_d->pixelSize;
0036         quint8 alphaValue = OPACITY_TRANSPARENT_U8;
0037         // this offset is needed when brush size is smaller then fixed device size
0038         int offset = (m_d->device->bounds().width() - rect.width()) * m_d->pixelSize;
0039         int supersample = 1;
0040         if (m_maskGenerator->shouldSupersample()) {
0041             // strengthen supersampling from 3x3 for very small dabs, to smooth out dashed strokes
0042             supersample = (m_maskGenerator->shouldSupersample6x6() ? 6 : 3);
0043         }
0044         double invss = 1.0 / supersample;
0045         int samplearea = pow2(supersample);
0046         for (int y = rect.y(); y < rect.y() + rect.height(); y++) {
0047             for (int x = rect.x(); x < rect.x() + rect.width(); x++) {
0048                 int value = 0;
0049                 for (int sy = 0; sy < supersample; sy++) {
0050                     for (int sx = 0; sx < supersample; sx++) {
0051                         double x_ = x + sx * invss - m_d->centerX;
0052                         double y_ = y + sy * invss - m_d->centerY;
0053                         double maskX = m_d->cosa * x_ - m_d->sina * y_;
0054                         double maskY = m_d->sina * x_ + m_d->cosa * y_;
0055                         value += m_maskGenerator->valueAt(maskX, maskY);
0056                     }
0057                 }
0058                 if (supersample != 1)
0059                     value /= samplearea;
0060 
0061                 if (m_d->randomness != 0.0) {
0062                     random = (1.0 - m_d->randomness) + m_d->randomness * m_randomSource.generateNormalized();
0063                 }
0064 
0065                 alphaValue = quint8((OPACITY_OPAQUE_U8 - value) * random);
0066 
0067                 // avoid computation of random numbers if density is full
0068                 if (m_d->density != 1.0) {
0069                     // compute density only for visible pixels of the mask
0070                     if (alphaValue != OPACITY_TRANSPARENT_U8) {
0071                         if (!(m_d->density >= m_randomSource.generateNormalized())) {
0072                             alphaValue = OPACITY_TRANSPARENT_U8;
0073                         }
0074                     }
0075                 }
0076 
0077                 if (m_d->color) {
0078                     memcpy(dabPointer, m_d->color, static_cast<size_t>(m_d->pixelSize));
0079                 }
0080 
0081                 m_d->colorSpace->applyAlphaU8Mask(dabPointer, &alphaValue, 1);
0082                 dabPointer += m_d->pixelSize;
0083             } // endfor x
0084             dabPointer += offset;
0085         } // endfor y
0086     }
0087 
0088 protected:
0089     MaskGenerator *m_maskGenerator;
0090     KisRandomSource m_randomSource; // TODO: make it more deterministic for LoD
0091 };
0092 
0093 #endif /* KIS_BRUSH_SCALAR_APPLICATOR_H */