File indexing completed on 2024-05-26 04:33:20

0001 /*
0002  * This file is part of Krita
0003  *
0004  * SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include <KisSequentialIteratorProgress.h>
0010 #include <KoUpdater.h>
0011 #include <cstring>
0012 #include <filter/kis_filter_configuration.h>
0013 #include <generator/kis_generator_registry.h>
0014 #include <kis_debug.h>
0015 #include <kis_fill_painter.h>
0016 #include <kis_global.h>
0017 #include <kis_image.h>
0018 #include <kis_layer.h>
0019 #include <kis_paint_device.h>
0020 #include <kis_processing_information.h>
0021 #include <kis_selection.h>
0022 #include <kis_types.h>
0023 #include <klocalizedstring.h>
0024 #include <kpluginfactory.h>
0025 
0026 #include "SeExprExpressionContext.h"
0027 #include "generator.h"
0028 #include "kis_wdg_seexpr.h"
0029 #include "ui_wdgseexpr.h"
0030 
0031 /****************************************************************************/
0032 /*              KisSeExprGeneratorConfiguration                             */
0033 /****************************************************************************/
0034 
0035 class KisSeExprGeneratorConfiguration : public KisFilterConfiguration
0036 {
0037 public:
0038     KisSeExprGeneratorConfiguration(const QString &name, qint32 version, KisResourcesInterfaceSP resourcesInterface)
0039         : KisFilterConfiguration(name, version, resourcesInterface)
0040     {
0041     }
0042 
0043     KisSeExprGeneratorConfiguration(const KisSeExprGeneratorConfiguration &rhs)
0044         : KisFilterConfiguration(rhs)
0045     {
0046     }
0047 
0048     virtual KisFilterConfigurationSP clone() const override
0049     {
0050         return new KisSeExprGeneratorConfiguration(*this);
0051     }
0052 
0053     QString script() const
0054     {
0055         return this->getString("script", QStringLiteral(BASE_SCRIPT));
0056     }
0057 };
0058 
0059 K_PLUGIN_FACTORY_WITH_JSON(KritaSeExprGeneratorFactory, "generator.json", registerPlugin<KritaSeExprGenerator>();)
0060 
0061 KritaSeExprGenerator::KritaSeExprGenerator(QObject *parent, const QVariantList &)
0062     : QObject(parent)
0063 {
0064     KisGeneratorRegistry::instance()->add(new KisSeExprGenerator());
0065 }
0066 
0067 KritaSeExprGenerator::~KritaSeExprGenerator()
0068 {
0069 }
0070 
0071 KisSeExprGenerator::KisSeExprGenerator()
0072     : KisGenerator(id(), KoID("basic"), i18n("&SeExpr..."))
0073 {
0074     setColorSpaceIndependence(FULLY_INDEPENDENT);
0075     setSupportsPainting(true);
0076 }
0077 
0078 KisFilterConfigurationSP KisSeExprGenerator::factoryConfiguration(KisResourcesInterfaceSP resourcesInterface) const
0079 {
0080     return new KisSeExprGeneratorConfiguration(id().id(), 1, resourcesInterface);
0081 }
0082 
0083 KisFilterConfigurationSP KisSeExprGenerator::defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const
0084 {
0085     KisFilterConfigurationSP config = factoryConfiguration(resourcesInterface);
0086 
0087     QVariant v;
0088     v.setValue(QString("Disney_noisecolor2"));
0089     config->setProperty("pattern", v);
0090     return config;
0091 }
0092 
0093 KisConfigWidget *KisSeExprGenerator::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev, bool) const
0094 {
0095     Q_UNUSED(dev);
0096     return new KisWdgSeExpr(parent);
0097 }
0098 
0099 void KisSeExprGenerator::generate(KisProcessingInformation dstInfo, const QSize &size, const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const
0100 {
0101     KisPaintDeviceSP device = dstInfo.paintDevice();
0102 
0103     Q_ASSERT(!device.isNull());
0104     Q_ASSERT(config);
0105 
0106     if (config) {
0107         QString script = config->getString("script");
0108 
0109         QRect bounds = QRect(dstInfo.topLeft(), size);
0110         QRect whole_image_bounds = device->defaultBounds()->bounds();
0111 
0112         SeExprExpressionContext expression(script);
0113 
0114         expression.m_vars["u"] = new SeExprVariable();
0115         expression.m_vars["v"] = new SeExprVariable();
0116         expression.m_vars["w"] = new SeExprVariable(whole_image_bounds.width());
0117         expression.m_vars["h"] = new SeExprVariable(whole_image_bounds.height());
0118 
0119         if (expression.isValid() && expression.returnType().isFP(3)) {
0120             double pixel_stride_x = 1. / whole_image_bounds.width();
0121             double pixel_stride_y = 1. / whole_image_bounds.height();
0122             double &u = expression.m_vars["u"]->m_value;
0123             double &v = expression.m_vars["v"]->m_value;
0124 
0125             // SeExpr already outputs floating-point RGB
0126             const KoColorSpace *dst = device->colorSpace();
0127             const KoColorSpace *src = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), KoColorSpaceRegistry::instance()->p709SRGBProfile());
0128             auto conv = KoColorSpaceRegistry::instance()->createColorConverter(src, dst, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
0129 
0130             KisSequentialIteratorProgress it(device, bounds, progressUpdater);
0131 
0132             while (it.nextPixel()) {
0133                 u = pixel_stride_x * (it.x() + .5);
0134                 v = pixel_stride_y * (it.y() + .5);
0135 
0136                 const double *value = expression.evalFP();
0137 
0138                 KoColor c(src);
0139                 reinterpret_cast<float *>(c.data())[0] = value[0];
0140                 reinterpret_cast<float *>(c.data())[1] = value[1];
0141                 reinterpret_cast<float *>(c.data())[2] = value[2];
0142                 c.setOpacity(OPACITY_OPAQUE_F);
0143 
0144                 conv->transform(c.data(), it.rawData(), 1);
0145             }
0146             delete conv;
0147         }
0148     }
0149 }
0150 
0151 #include "generator.moc"