diff --git a/libs/image/kis_brush_mask_applicators.h b/libs/image/kis_brush_mask_applicators.h index 4c1a15494e..4ecd348da9 100644 --- a/libs/image/kis_brush_mask_applicators.h +++ b/libs/image/kis_brush_mask_applicators.h @@ -1,214 +1,202 @@ /* * Copyright (c) 2012 Sven Langkamp * Copyright (c) 2012 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_BRUSH_MASK_APPLICATORS_H #define __KIS_BRUSH_MASK_APPLICATORS_H #include "kis_brush_mask_applicator_base.h" #include "kis_global.h" +#include "kis_random_source.h" // 3x3 supersampling #define SUPERSAMPLING 3 -#if defined(_WIN32) || defined(_WIN64) -#include -#define srand48 srand -inline double drand48() { - return double(rand()) / RAND_MAX; -} -#endif - -#include - template struct KisBrushMaskScalarApplicator : public KisBrushMaskApplicatorBase { KisBrushMaskScalarApplicator(MaskGenerator *maskGenerator) : m_maskGenerator(maskGenerator) { } void process(const QRect &rect) override { processScalar(rect); } protected: void processScalar(const QRect &rect); protected: MaskGenerator *m_maskGenerator; - std::random_device m_rand_dev; + KisRandomSource m_randomSource; // TODO: make it more deterministic for LoD }; #if defined HAVE_VC template struct KisBrushMaskVectorApplicator : public KisBrushMaskScalarApplicator { KisBrushMaskVectorApplicator(MaskGenerator *maskGenerator) : KisBrushMaskScalarApplicator(maskGenerator) { } void process(const QRect &rect) { startProcessing(rect, TypeHelper()); } protected: void processVector(const QRect &rect); private: template struct TypeHelper {}; private: template inline void startProcessing(const QRect &rect, TypeHelper) { KisBrushMaskScalarApplicator::processScalar(rect); } template inline void startProcessing(const QRect &rect, TypeHelper) { MaskGenerator *m_maskGenerator = KisBrushMaskScalarApplicator::m_maskGenerator; if (m_maskGenerator->shouldVectorize()) { processVector(rect); } else { KisBrushMaskScalarApplicator::processScalar(rect); } } }; template void KisBrushMaskVectorApplicator::processVector(const QRect &rect) { const MaskProcessingData *m_d = KisBrushMaskApplicatorBase::m_d; MaskGenerator *m_maskGenerator = KisBrushMaskScalarApplicator::m_maskGenerator; qreal random = 1.0; quint8* dabPointer = m_d->device->data() + rect.y() * rect.width() * m_d->pixelSize; quint8 alphaValue = OPACITY_TRANSPARENT_U8; // this offset is needed when brush size is smaller then fixed device size int offset = (m_d->device->bounds().width() - rect.width()) * m_d->pixelSize; int width = rect.width(); // We need to calculate with a multiple of the width of the simd register int alignOffset = 0; if (width % Vc::float_v::size() != 0) { alignOffset = Vc::float_v::size() - (width % Vc::float_v::size()); } int simdWidth = width + alignOffset; float *buffer = Vc::malloc(simdWidth); typename MaskGenerator::FastRowProcessor processor(m_maskGenerator); for (int y = rect.y(); y < rect.y() + rect.height(); y++) { processor.template process<_impl>(buffer, simdWidth, y, m_d->cosa, m_d->sina, m_d->centerX, m_d->centerY); if (m_d->randomness != 0.0 || m_d->density != 1.0) { for (int x = 0; x < width; x++) { if (m_d->randomness!= 0.0){ - random = (1.0 - m_d->randomness) + m_d->randomness * float(rand()) / RAND_MAX; + random = (1.0 - m_d->randomness) + m_d->randomness * KisBrushMaskScalarApplicator::m_randomSource.generateNormalized(); } alphaValue = quint8( (OPACITY_OPAQUE_U8 - buffer[x]*255) * random); // avoid computation of random numbers if density is full if (m_d->density != 1.0){ // compute density only for visible pixels of the mask if (alphaValue != OPACITY_TRANSPARENT_U8){ - if ( !(m_d->density >= drand48()) ){ + if ( !(m_d->density >= KisBrushMaskScalarApplicator::m_randomSource.generateNormalized()) ){ alphaValue = OPACITY_TRANSPARENT_U8; } } } m_d->colorSpace->applyAlphaU8Mask(dabPointer, &alphaValue, 1); dabPointer += m_d->pixelSize; } } else { m_d->colorSpace->applyInverseNormedFloatMask(dabPointer, buffer, width); dabPointer += width * m_d->pixelSize; }//endfor x dabPointer += offset; }//endfor y Vc::free(buffer); } #endif /* defined HAVE_VC */ template void KisBrushMaskScalarApplicator::processScalar(const QRect &rect) { const MaskProcessingData *m_d = KisBrushMaskApplicatorBase::m_d; MaskGenerator *m_maskGenerator = KisBrushMaskScalarApplicator::m_maskGenerator; - std::default_random_engine rand_engine{m_rand_dev()}; - std::uniform_real_distribution<> rand_distr(0.0f, 1.0f); - qreal random = 1.0; quint8* dabPointer = m_d->device->data() + rect.y() * rect.width() * m_d->pixelSize; quint8 alphaValue = OPACITY_TRANSPARENT_U8; // this offset is needed when brush size is smaller then fixed device size int offset = (m_d->device->bounds().width() - rect.width()) * m_d->pixelSize; int supersample = (m_maskGenerator->shouldSupersample() ? SUPERSAMPLING : 1); double invss = 1.0 / supersample; int samplearea = pow2(supersample); for (int y = rect.y(); y < rect.y() + rect.height(); y++) { for (int x = rect.x(); x < rect.x() + rect.width(); x++) { int value = 0; for (int sy = 0; sy < supersample; sy++) { for (int sx = 0; sx < supersample; sx++) { double x_ = x + sx * invss - m_d->centerX; double y_ = y + sy * invss - m_d->centerY; double maskX = m_d->cosa * x_ - m_d->sina * y_; double maskY = m_d->sina * x_ + m_d->cosa * y_; value += m_maskGenerator->valueAt(maskX, maskY); } } if (supersample != 1) value /= samplearea; if (m_d->randomness!= 0.0){ - random = (1.0 - m_d->randomness) + m_d->randomness * rand_distr(rand_engine); + random = (1.0 - m_d->randomness) + m_d->randomness * m_randomSource.generateNormalized(); } alphaValue = quint8( (OPACITY_OPAQUE_U8 - value) * random); // avoid computation of random numbers if density is full if (m_d->density != 1.0){ // compute density only for visible pixels of the mask if (alphaValue != OPACITY_TRANSPARENT_U8){ - if ( !(m_d->density >= rand_distr(rand_engine)) ){ + if ( !(m_d->density >= m_randomSource.generateNormalized()) ){ alphaValue = OPACITY_TRANSPARENT_U8; } } } m_d->colorSpace->applyAlphaU8Mask(dabPointer, &alphaValue, 1); dabPointer += m_d->pixelSize; }//endfor x dabPointer += offset; }//endfor y } #endif /* __KIS_BRUSH_MASK_APPLICATORS_H */