File indexing completed on 2024-05-19 04:24:14

0001 /*
0002  *  SPDX-FileCopyrightText: 2008 Boudewijn Rempt <boud@valdyas.org>
0003  *  SPDX-FileCopyrightText: 2010-2011 Lukáš Tvrdý <lukast.dev@gmail.com>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include "kis_auto_brush_factory.h"
0009 
0010 #include <QDomDocument>
0011 
0012 #include "kis_auto_brush.h"
0013 #include "kis_mask_generator.h"
0014 #include <kis_dom_utils.h>
0015 #include <KoResourceLoadResult.h>
0016 #include "kis_mask_generator.h"
0017 
0018 
0019 KoResourceLoadResult KisAutoBrushFactory::createBrush(const QDomElement &brushDefinition, KisResourcesInterfaceSP resourcesInterface)
0020 {
0021     std::optional<KisBrushModel::BrushData> data =
0022         createBrushModel(brushDefinition, resourcesInterface);
0023 
0024     if (data) {
0025         return createBrush(*data, resourcesInterface);
0026     }
0027 
0028     // fallback, should never reach!
0029     return KoResourceSignature(ResourceType::Brushes, "", "", "");
0030 }
0031 
0032 KoResourceLoadResult KisAutoBrushFactory::createBrush(const KisBrushModel::BrushData &data, KisResourcesInterfaceSP resourcesInterface)
0033 {
0034     return createBrush(data.common, data.autoBrush, resourcesInterface);
0035 }
0036 
0037 std::optional<KisBrushModel::BrushData>
0038 KisAutoBrushFactory::createBrushModel(const QDomElement &element, KisResourcesInterfaceSP resourcesInterface)
0039 {
0040     Q_UNUSED(resourcesInterface);
0041 
0042     KisBrushModel::BrushData brush;
0043 
0044     brush.type = KisBrushModel::Auto;
0045     brush.common.angle = KisDomUtils::toDouble(element.attribute("angle", "0.0"));
0046     brush.common.spacing = KisDomUtils::toDouble(element.attribute("spacing", "1.0"));
0047     brush.common.useAutoSpacing = KisDomUtils::toInt(element.attribute("useAutoSpacing", "0"));
0048     brush.common.autoSpacingCoeff = KisDomUtils::toDouble(element.attribute("autoSpacingCoeff", "1.0"));
0049 
0050     // auto brush settings
0051 
0052     brush.autoBrush.randomness = KisDomUtils::toDouble(element.attribute("randomness", "0.0"));
0053     brush.autoBrush.density = KisDomUtils::toDouble(element.attribute("density", "1.0"));
0054 
0055     // generator settings
0056 
0057     QDomElement generatorEl = element.firstChildElement("MaskGenerator");
0058 
0059     // backward compatibility -- it was mistakenly named radius for 2.2
0060     brush.autoBrush.generator.diameter =
0061             generatorEl.hasAttribute("radius") ?
0062                 KisDomUtils::toDouble(generatorEl.attribute("radius", "1.0")) :
0063                 KisDomUtils::toDouble(generatorEl.attribute("diameter", "1.0"));
0064 
0065     brush.autoBrush.generator.ratio = KisDomUtils::toDouble(generatorEl.attribute("ratio", "1.0"));
0066     brush.autoBrush.generator.horizontalFade = KisDomUtils::toDouble(generatorEl.attribute("hfade", "0.0"));
0067     brush.autoBrush.generator.verticalFade = KisDomUtils::toDouble(generatorEl.attribute("vfade", "0.0"));
0068     brush.autoBrush.generator.antialiasEdges = generatorEl.attribute("antialiasEdges", "0").toInt();
0069     brush.autoBrush.generator.spikes = generatorEl.attribute("spikes", "2").toInt();
0070 
0071     const QString shape = generatorEl.attribute("type", "circle");
0072     brush.autoBrush.generator.shape =
0073             shape == "circle" ? KisBrushModel::Circle : KisBrushModel::Rectangle;
0074 
0075     const QString type = generatorEl.attribute("id", DefaultId.id());
0076     brush.autoBrush.generator.type =
0077             type == DefaultId.id() ? KisBrushModel::Default :
0078             type == SoftId.id() ? KisBrushModel::Soft :
0079             KisBrushModel::Gaussian;
0080 
0081     if (generatorEl.hasAttribute("softness_curve")) {
0082         brush.autoBrush.generator.curveString = generatorEl.attribute("softness_curve","");
0083     }
0084 
0085     return {brush};
0086 }
0087 
0088 void KisAutoBrushFactory::toXML(QDomDocument &doc, QDomElement &e, const KisBrushModel::BrushData &model)
0089 {
0090     e.setAttribute("type", id());
0091     e.setAttribute("BrushVersion", "2");
0092 
0093     e.setAttribute("spacing", QString::number(model.common.spacing));
0094     e.setAttribute("useAutoSpacing", QString::number(model.common.useAutoSpacing));
0095     e.setAttribute("autoSpacingCoeff", QString::number(model.common.autoSpacingCoeff));
0096     e.setAttribute("angle", QString::number(model.common.angle));
0097     e.setAttribute("randomness", QString::number(model.autoBrush.randomness));
0098     e.setAttribute("density", QString::number(model.autoBrush.density));
0099 
0100     {
0101         QDomElement shapeElt = doc.createElement("MaskGenerator");
0102 
0103         shapeElt.setAttribute("diameter", QString::number(model.autoBrush.generator.diameter));
0104         shapeElt.setAttribute("ratio", QString::number(model.autoBrush.generator.ratio));
0105         shapeElt.setAttribute("hfade", QString::number(model.autoBrush.generator.horizontalFade));
0106         shapeElt.setAttribute("vfade", QString::number(model.autoBrush.generator.verticalFade));
0107         shapeElt.setAttribute("spikes", model.autoBrush.generator.spikes);
0108         shapeElt.setAttribute("type", model.autoBrush.generator.shape == KisBrushModel::Circle ? "circle" : "rct");
0109         shapeElt.setAttribute("antialiasEdges", model.autoBrush.generator.antialiasEdges);
0110 
0111 
0112         QString idString;
0113         if (model.autoBrush.generator.type == KisBrushModel::Default) {
0114             idString = DefaultId.id();
0115         } else if (model.autoBrush.generator.type == KisBrushModel::Soft) {
0116             idString = SoftId.id();
0117         } else {
0118             idString = GaussId.id();
0119         }
0120 
0121         shapeElt.setAttribute("id", idString);
0122 
0123         if (!model.autoBrush.generator.curveString.isEmpty()) {
0124             shapeElt.setAttribute("softness_curve", model.autoBrush.generator.curveString);
0125         }
0126 
0127         e.appendChild(shapeElt);
0128     }
0129 }
0130 
0131 KoResourceLoadResult KisAutoBrushFactory::createBrush(const KisBrushModel::CommonData &commonData, const KisBrushModel::AutoBrushData &autoBrushData, KisResourcesInterfaceSP resourcesInterface)
0132 {
0133     Q_UNUSED(resourcesInterface);
0134 
0135     KisMaskGenerator *generator = 0;
0136 
0137     if (autoBrushData.generator.type == KisBrushModel::Default &&
0138             autoBrushData.generator.shape == KisBrushModel::Circle) {
0139 
0140         generator = new KisCircleMaskGenerator(autoBrushData.generator.diameter,
0141                                                autoBrushData.generator.ratio,
0142                                                autoBrushData.generator.horizontalFade,
0143                                                autoBrushData.generator.verticalFade,
0144                                                autoBrushData.generator.spikes,
0145                                                autoBrushData.generator.antialiasEdges);
0146 
0147     } else if (autoBrushData.generator.type == KisBrushModel::Default &&
0148                autoBrushData.generator.shape == KisBrushModel::Rectangle) {
0149 
0150         generator = new KisRectangleMaskGenerator(autoBrushData.generator.diameter,
0151                                                   autoBrushData.generator.ratio,
0152                                                   autoBrushData.generator.horizontalFade,
0153                                                   autoBrushData.generator.verticalFade,
0154                                                   autoBrushData.generator.spikes,
0155                                                   autoBrushData.generator.antialiasEdges);
0156 
0157 
0158     } else  if (autoBrushData.generator.type == KisBrushModel::Soft) {
0159 
0160         QString curveString = autoBrushData.generator.curveString;
0161         if (curveString.isEmpty()) {
0162             curveString = "0,1;1,0";
0163         }
0164 
0165         const KisCubicCurve curve(curveString);
0166 
0167         if (autoBrushData.generator.shape == KisBrushModel::Circle) {
0168             generator = new KisCurveCircleMaskGenerator(autoBrushData.generator.diameter,
0169                                                         autoBrushData.generator.ratio,
0170                                                         autoBrushData.generator.horizontalFade,
0171                                                         autoBrushData.generator.verticalFade,
0172                                                         autoBrushData.generator.spikes,
0173                                                         curve,
0174                                                         autoBrushData.generator.antialiasEdges);
0175         } else {
0176             generator = new KisCurveRectangleMaskGenerator(autoBrushData.generator.diameter,
0177                                                            autoBrushData.generator.ratio,
0178                                                            autoBrushData.generator.horizontalFade,
0179                                                            autoBrushData.generator.verticalFade,
0180                                                            autoBrushData.generator.spikes,
0181                                                            curve,
0182                                                            autoBrushData.generator.antialiasEdges);
0183         }
0184 
0185     } else  if (autoBrushData.generator.type == KisBrushModel::Gaussian &&
0186                 autoBrushData.generator.shape == KisBrushModel::Circle) {
0187 
0188         generator = new KisGaussCircleMaskGenerator(autoBrushData.generator.diameter,
0189                                                     autoBrushData.generator.ratio,
0190                                                     autoBrushData.generator.horizontalFade,
0191                                                     autoBrushData.generator.verticalFade,
0192                                                     autoBrushData.generator.spikes,
0193                                                     autoBrushData.generator.antialiasEdges);
0194 
0195     } else if (autoBrushData.generator.type == KisBrushModel::Gaussian &&
0196                autoBrushData.generator.shape == KisBrushModel::Rectangle) {
0197 
0198         generator = new KisGaussRectangleMaskGenerator(autoBrushData.generator.diameter,
0199                                                        autoBrushData.generator.ratio,
0200                                                        autoBrushData.generator.horizontalFade,
0201                                                        autoBrushData.generator.verticalFade,
0202                                                        autoBrushData.generator.spikes,
0203                                                        autoBrushData.generator.antialiasEdges);
0204     }
0205 
0206     KisBrushSP brush = KisBrushSP(new KisAutoBrush(generator, commonData.angle, autoBrushData.randomness, autoBrushData.density));
0207     brush->setSpacing(commonData.spacing);
0208     brush->setAutoSpacing(commonData.useAutoSpacing, commonData.autoSpacingCoeff);
0209 
0210     return {brush};
0211 }