File indexing completed on 2024-12-22 04:15:36
0001 /* 0002 * KDE. Krita Project. 0003 * 0004 * SPDX-FileCopyrightText: 2019 Eoin O 'Neill <eoinoneill1991@gmail.com> 0005 * SPDX-FileCopyrightText: 2019 Emmet O 'Neill <emmetoneill.pdx@gmail.com> 0006 * 0007 * SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "simplexnoisegenerator.h" 0011 #include "ui_wdgsimplexnoiseoptions.h" 0012 #include "kis_wdg_simplex_noise.h" 0013 #include "3rdparty/c-open-simplex/open-simplex-noise.h" 0014 0015 #include <KisSequentialIteratorProgress.h> 0016 #include <KoUpdater.h> 0017 #include <QCryptographicHash> 0018 #include <filter/kis_filter_configuration.h> 0019 #include <generator/kis_generator_registry.h> 0020 #include <KoColorModelStandardIds.h> 0021 #include <KoColorSpaceRegistry.h> 0022 #include <kis_processing_information.h> 0023 #include <kpluginfactory.h> 0024 0025 K_PLUGIN_FACTORY_WITH_JSON(KritaSimplexNoiseGeneratorFactory, "kritasimplexnoisegenerator.json", registerPlugin<KisSimplexNoiseGeneratorHandle>();) 0026 0027 KisSimplexNoiseGeneratorHandle::KisSimplexNoiseGeneratorHandle(QObject *parent, const QVariantList &) 0028 : QObject(parent) 0029 { 0030 KisGeneratorRegistry::instance()->add(new KisSimplexNoiseGenerator()); 0031 0032 } 0033 0034 KisSimplexNoiseGeneratorHandle::~KisSimplexNoiseGeneratorHandle() 0035 { 0036 } 0037 0038 KisSimplexNoiseGenerator::KisSimplexNoiseGenerator() : KisGenerator(id(), KoID("basic"), i18n("&Simplex Noise...")) 0039 { 0040 setColorSpaceIndependence(FULLY_INDEPENDENT); 0041 setSupportsPainting(true); 0042 } 0043 0044 void KisSimplexNoiseGenerator::generate(KisProcessingInformation dst, const QSize &size, const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const 0045 { 0046 KisPaintDeviceSP device = dst.paintDevice(); 0047 Q_ASSERT(!device.isNull()); 0048 0049 osn_context *noise_context; 0050 0051 QRect bounds = QRect(dst.topLeft(), size); 0052 QRect whole_image_bounds = device->defaultBounds()->bounds(); 0053 0054 const KoColorSpace *cs = device->colorSpace(); 0055 const KoColorSpace *src = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Float32BitsColorDepthID.id(), "Gray-D50-elle-V2-srgbtrc.icc"); 0056 KoColorConversionTransformation *conv = KoColorSpaceRegistry::instance()->createColorConverter(src, cs, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); 0057 0058 KisSequentialIteratorProgress it(device, bounds, progressUpdater); 0059 0060 QVariant property; 0061 0062 const uint default_seed = (config->getProperty("seed", property)) ? property.toUInt() : 0; 0063 const QString custom_seed_string = (config->getProperty("custom_seed_string", property)) ? property.toString() : ""; 0064 const bool use_custom_seed = !custom_seed_string.trimmed().isEmpty(); 0065 0066 const uint seed = use_custom_seed ? seedFromString(custom_seed_string) : default_seed; 0067 open_simplex_noise(seed, &noise_context); 0068 0069 double frequency = (config && config->getProperty("frequency", property)) ? property.toDouble() : 25.0; 0070 double ratio_x = (config && config->getProperty("ratio_x", property)) ? property.toDouble() : 1.0; 0071 double ratio_y = (config && config->getProperty("ratio_y", property)) ? property.toDouble() : 1.0; 0072 0073 bool looping = (config && config->getProperty("looping", property)) ? property.toBool() : false; 0074 0075 if( looping ){ 0076 float major_radius = 0.5f * frequency * ratio_x; 0077 float minor_radius = 0.5f * frequency * ratio_y; 0078 while(it.nextPixel()){ 0079 double x_phase = (double)it.x() / (double)whole_image_bounds.width() * M_PI * 2; 0080 double y_phase = (double)it.y() / (double)(whole_image_bounds.height()) * M_PI * 2; 0081 double x_coordinate = major_radius * map_range(cos(x_phase), -1.0, 1.0, 0.0, 1.0); 0082 double y_coordinate = major_radius * map_range(sin(x_phase), -1.0, 1.0, 0.0, 1.0); 0083 double z_coordinate = minor_radius * map_range(cos(y_phase), -1.0, 1.0, 0.0, 1.0); 0084 double w_coordinate = minor_radius * map_range(sin(y_phase), -1.0, 1.0, 0.0, 1.0); 0085 double value = open_simplex_noise4(noise_context, x_coordinate, y_coordinate, z_coordinate, w_coordinate); 0086 value = map_range(value, -1.0, 1.0, 0.0, 1.0); 0087 0088 KoColor c(src); 0089 reinterpret_cast<float *>(c.data())[0] = value; 0090 c.setOpacity(OPACITY_OPAQUE_F); 0091 0092 conv->transform(c.data(), it.rawData(), 1); 0093 } 0094 } else { 0095 while(it.nextPixel()){ 0096 double x_phase = (double)it.x() / (double)(whole_image_bounds.width()) * ratio_x; 0097 double y_phase = (double)it.y() / (double)(whole_image_bounds.height()) * ratio_y; 0098 double value = open_simplex_noise4(noise_context, x_phase * frequency, y_phase * frequency, x_phase * frequency, y_phase * frequency); 0099 value = map_range(value, -1.0, 1.0, 0.0, 1.0); 0100 0101 KoColor c(src); 0102 reinterpret_cast<float *>(c.data())[0] = value; 0103 c.setOpacity(OPACITY_OPAQUE_F); 0104 0105 conv->transform(c.data(), it.rawData(), 1); 0106 } 0107 } 0108 delete conv; 0109 open_simplex_noise_free(noise_context); 0110 } 0111 0112 KisFilterConfigurationSP KisSimplexNoiseGenerator::defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const 0113 { 0114 KisFilterConfigurationSP config = factoryConfiguration(resourcesInterface); 0115 config->setProperty("looping", false); 0116 config->setProperty("frequency", 25.0); 0117 uint seed = static_cast<uint>(rand()); 0118 config->setProperty("seed", seed); 0119 config->setProperty("custom_seed_string", ""); 0120 config->setProperty("ratio_x", 1.0f); 0121 config->setProperty("ratio_y", 1.0f); 0122 return config; 0123 } 0124 0125 KisConfigWidget * KisSimplexNoiseGenerator::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev, bool) const 0126 { 0127 Q_UNUSED(dev); 0128 return new KisWdgSimplexNoise((KisFilter*)this, (QWidget*)parent); 0129 } 0130 0131 0132 uint KisSimplexNoiseGenerator::seedFromString(const QString &string) const 0133 { 0134 QByteArray bytes = QCryptographicHash::hash(string.toUtf8(),QCryptographicHash::Md5); 0135 uint hash = 0; 0136 for( int index = 0; index < bytes.length(); index++){ 0137 hash += rotateLeft(bytes[index], index % 32); 0138 } 0139 return hash; 0140 } 0141 0142 quint64 KisSimplexNoiseGenerator::rotateLeft(const quint64 input, uint shift) const 0143 { 0144 return (input << shift)|(input >> (64 - shift)); 0145 } 0146 0147 #include "simplexnoisegenerator.moc" 0148