File indexing completed on 2024-05-12 15:56:10

0001 /*
0002  *  SPDX-FileCopyrightText: 1999 Matthias Elter <me@kde.org>
0003  *  SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
0004  *  SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 #ifndef KIS_BRUSH_
0009 #define KIS_BRUSH_
0010 
0011 #include <QImage>
0012 
0013 #include <KoResource.h>
0014 
0015 #include <kis_types.h>
0016 #include <kis_shared.h>
0017 #include <kis_dab_shape.h>
0018 #include <kritabrush_export.h>
0019 
0020 class QString;
0021 class KoColor;
0022 class KoColorSpace;
0023 
0024 class KisPaintInformation;
0025 class KisPaintopLodLimitations;
0026 class KoAbstractGradient;
0027 class KisOptimizedBrushOutline;
0028 typedef QSharedPointer<KoAbstractGradient> KoAbstractGradientSP;
0029 
0030 enum enumBrushType {
0031     INVALID,
0032     MASK,
0033     IMAGE,
0034     PIPE_MASK,
0035     PIPE_IMAGE
0036 };
0037 
0038 enum enumBrushApplication {
0039     ALPHAMASK,
0040     IMAGESTAMP,
0041     LIGHTNESSMAP,
0042     GRADIENTMAP
0043 };
0044 
0045 static const qreal DEFAULT_SOFTNESS_FACTOR = 1.0;
0046 static const qreal DEFAULT_LIGHTNESS_STRENGTH = 1.0;
0047 
0048 class KisBrush;
0049 typedef QSharedPointer<KisBrush> KisBrushSP;
0050 
0051 /**
0052  * KisBrush is the base class for brush resources. A brush resource
0053  * defines one or more images that are used to potato-stamp along
0054  * the drawn path. The brush type defines how this brush is used --
0055  * the important difference is between masks (which take the current
0056  * painting color) and images (which do not). It is up to the paintop
0057  * to make use of this feature.
0058  *
0059  * Brushes must be serializable to an xml representation and provide
0060  * a factory class that can recreate or retrieve the brush based on
0061  * this representation.
0062  *
0063  * XXX: This api is still a big mess -- it needs a good refactoring.
0064  * And the whole KoResource architecture is way over-designed.
0065  */
0066 class BRUSH_EXPORT KisBrush : public KoResource
0067 {
0068 public:
0069     class ColoringInformation
0070     {
0071     public:
0072         virtual ~ColoringInformation();
0073         virtual const quint8* color() const = 0;
0074         virtual void nextColumn() = 0;
0075         virtual void nextRow() = 0;
0076     };
0077 
0078 protected:
0079 
0080     class PlainColoringInformation : public ColoringInformation
0081     {
0082     public:
0083         PlainColoringInformation(const quint8* color);
0084         ~PlainColoringInformation() override;
0085         const quint8* color() const override ;
0086         void nextColumn() override;
0087         void nextRow() override;
0088     private:
0089         const quint8* m_color;
0090     };
0091 
0092     class PaintDeviceColoringInformation : public ColoringInformation
0093     {
0094 
0095     public:
0096 
0097         PaintDeviceColoringInformation(const KisPaintDeviceSP source, int width);
0098         ~PaintDeviceColoringInformation() override;
0099         const quint8* color() const override ;
0100         void nextColumn() override;
0101         void nextRow() override;
0102 
0103     private:
0104 
0105         const KisPaintDeviceSP m_source;
0106         KisHLineConstIteratorSP m_iterator;
0107     };
0108 
0109 public:
0110 
0111     KisBrush();
0112     KisBrush(const QString& filename);
0113     ~KisBrush() override;
0114 
0115     KisBrush(const KisBrush &rhs);
0116     KisBrush &operator=(const KisBrush &rhs) = delete;
0117 
0118     virtual qreal userEffectiveSize() const = 0;
0119     virtual void setUserEffectiveSize(qreal value) = 0;
0120 
0121     QPair<QString, QString> resourceType() const override {
0122         return QPair<QString, QString>(ResourceType::Brushes, "");
0123     }
0124 
0125     /**
0126      * @brief brushImage the image the brush tip can paint with. Not all brush types have a single
0127      * image.
0128      * @return a valid QImage.
0129      */
0130     virtual QImage brushTipImage() const;
0131 
0132     /**
0133      * Is a pait device of the brush that shoudl be used for generation
0134      * of the brush outline. Usually, it is the same device returned
0135      * by brushTipImage(), but might be different in some types
0136      * of brushes, like in KisAutoBrush.
0137      */
0138     virtual KisFixedPaintDeviceSP outlineSourceImage() const;
0139 
0140 
0141     /**
0142      * Change the spacing of the brush.
0143      * @param spacing a spacing of 1.0 means that strokes will be separated from one time the size
0144      *                of the brush.
0145      */
0146     virtual void setSpacing(double spacing);
0147 
0148     /**
0149      * @return the spacing between two strokes for this brush
0150      */
0151     double spacing() const;
0152 
0153     void setAutoSpacing(bool active, qreal coeff);
0154 
0155     bool autoSpacingActive() const;
0156     qreal autoSpacingCoeff() const;
0157 
0158 
0159     /**
0160      * @return the width (for scale == 1.0)
0161      */
0162     qint32 width() const;
0163 
0164     /**
0165      * @return the height (for scale == 1.0)
0166      */
0167     qint32 height() const;
0168 
0169     /**
0170      * @return the width of the mask for the given scale and angle
0171      */
0172     virtual qint32 maskWidth(KisDabShape const&, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const;
0173 
0174     /**
0175      * @return the height of the mask for the given scale and angle
0176      */
0177     virtual qint32 maskHeight(KisDabShape const&, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const;
0178 
0179     /**
0180      * @return the logical size of the brush, that is the size measured
0181      *         in floating point value.
0182      *
0183      *         This value should not be used for calculating future dab sizes
0184      *         because it doesn't take any rounding into account. The only use
0185      *         of this metric is calculation of brush-size derivatives like
0186      *         hotspots and spacing.
0187      */
0188      virtual QSizeF characteristicSize(KisDabShape const&) const;
0189 
0190     /**
0191      * @return the angle of the mask adding the given angle
0192      */
0193     double maskAngle(double angle = 0) const;
0194 
0195     /**
0196      * @return the currently selected index of the brush
0197      *         if the brush consists of multiple images
0198      *
0199      * @see prepareForSeqNo()
0200      */
0201     virtual quint32 brushIndex() const;
0202 
0203     /**
0204      * The brush type defines how the brush is used.
0205      */
0206     virtual enumBrushType brushType() const;
0207 
0208     QPointF hotSpot(KisDabShape const&, const KisPaintInformation& info) const;
0209 
0210     /**
0211      * Returns true if this brush can return something useful for the info. This is used
0212      * by Pipe Brushes that can't paint sometimes
0213      **/
0214     virtual bool canPaintFor(const KisPaintInformation& /*info*/);
0215 
0216 
0217     /**
0218      * Is called by the paint op when a paintop starts a stroke.  The
0219      * point is that we store brushes a server while the paint ops are
0220      * are recreated all the time. Is means that upon a stroke start
0221      * the brushes may need to clear its state.
0222      */
0223     virtual void notifyStrokeStarted();
0224 
0225     /**
0226      * Is called by the paint op before it is going to clone the brush into
0227      * multiple instances to pass to different threads. During this call the
0228      * brush is free to prepare some structures that may be shared by all the
0229      * clones without excessive recalculation.
0230      */
0231     virtual void notifyBrushIsGoingToBeClonedForStroke();
0232 
0233     /**
0234      * Is called by the multithreaded queue to prepare a specific brush
0235      * tip for the particular seqNo.
0236      *
0237      * NOTE: one should use always call prepareForSeqNo() before using the brush
0238      *
0239      * Currently, this is used by pipe'd brushes to implement
0240      * incremental and random parasites
0241      */
0242     virtual void prepareForSeqNo(const KisPaintInformation& info, int seqNo);
0243 
0244     /**
0245      * Return a fixed paint device that contains a correctly scaled image dab.
0246      */
0247     virtual KisFixedPaintDeviceSP paintDevice(const KoColorSpace * colorSpace,
0248             KisDabShape const&,
0249             const KisPaintInformation& info,
0250             double subPixelX = 0, double subPixelY = 0) const;
0251 
0252     /**
0253      * clear dst fill it with a mask colored with KoColor
0254      */
0255     void mask(KisFixedPaintDeviceSP dst,
0256               const KoColor& color,
0257               KisDabShape const& shape,
0258               const KisPaintInformation& info,
0259               double subPixelX = 0, double subPixelY = 0, 
0260               qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR, qreal lightnessStrength = DEFAULT_LIGHTNESS_STRENGTH) const;
0261 
0262     /**
0263      * clear dst and fill it with a mask colored with the corresponding colors of src
0264      */
0265     void mask(KisFixedPaintDeviceSP dst,
0266               const KisPaintDeviceSP src,
0267               KisDabShape const& shape,
0268               const KisPaintInformation& info,
0269               double subPixelX = 0, double subPixelY = 0, 
0270               qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR, qreal lightnessStrength = DEFAULT_LIGHTNESS_STRENGTH) const;
0271 
0272 
0273     virtual enumBrushApplication brushApplication() const;
0274 
0275     virtual void setBrushApplication(enumBrushApplication brushApplication);
0276 
0277     virtual bool preserveLightness() const;
0278 
0279     virtual bool applyingGradient() const;
0280 
0281     virtual void setGradient(KoAbstractGradientSP gradient);
0282 
0283 
0284     /**
0285      * Create a mask and either mask dst (that is, change all alpha values of the
0286      * existing pixels to those of the mask) or, if coloringInfo is present, clear
0287      * dst and fill dst with pixels according to coloringInfo, masked according to the
0288      * generated mask.
0289      *
0290      * @param dst the destination that will be draw on the image, and this function
0291      *            will edit its alpha channel
0292      * @param coloringInfo coloring information that will be copied on the dab, it can be null
0293      * @param shape a shape applied on the alpha mask
0294      * @param info the painting information (this is only and should only be used by
0295      *             KisImagePipeBrush and only to be backward compatible with the Gimp,
0296      *             KisImagePipeBrush is ignoring scale and angle information)
0297      * @param subPixelX sub position of the brush (contained between 0.0 and 1.0)
0298      * @param subPixelY sub position of the brush (contained between 0.0 and 1.0)
0299      * @param softnessFactor softness factor of the brush
0300      *
0301      * @return a mask computed from the grey-level values of the
0302      * pixels in the brush.
0303      */
0304     virtual void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst,
0305             ColoringInformation* coloringInfo,
0306             KisDabShape const&,
0307             const KisPaintInformation& info,
0308             double subPixelX, double subPixelY,
0309             qreal softnessFactor, qreal lightnessStrength) const;
0310 
0311     void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst,
0312         ColoringInformation* coloringInfo,
0313         KisDabShape const&,
0314         const KisPaintInformation& info,
0315         double subPixelX = 0, double subPixelY = 0,
0316         qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR) const;
0317 
0318 
0319     /**
0320      * Serialize this brush to XML.
0321      */
0322     virtual void toXML(QDomDocument& , QDomElement&) const;
0323 
0324     static KisBrushSP fromXML(const QDomElement& element, KisResourcesInterfaceSP resourcesInterface);
0325 
0326     static KoResourceLoadResult fromXMLLoadResult(const QDomElement& element, KisResourcesInterfaceSP resourcesInterface);
0327 
0328     virtual KisOptimizedBrushOutline outline(bool forcePreciseOutline = false) const;
0329 
0330     virtual void setScale(qreal _scale);
0331     qreal scale() const;
0332     virtual void setAngle(qreal _angle);
0333     qreal angle() const;
0334 
0335     void clearBrushPyramid();
0336 
0337     virtual void lodLimitations(KisPaintopLodLimitations *l) const;
0338 
0339     virtual bool supportsCaching() const;
0340 
0341     virtual void coldInitBrush();
0342 
0343     static const QString brushTypeMetaDataKey;
0344 
0345 protected:
0346 
0347     void setWidth(qint32 width);
0348 
0349     void setHeight(qint32 height);
0350 
0351     void setHotSpot(QPointF);
0352 
0353     /**
0354      * XXX
0355      */
0356     virtual void setBrushType(enumBrushType type);
0357 
0358 public:
0359 
0360     /**
0361      * The image is used to represent the brush in the gui, and may also, depending on the brush type
0362      * be used to define the actual brush instance.
0363      */
0364     virtual void setBrushTipImage(const QImage& image);
0365 
0366     /**
0367      * Returns true if the brush has a bunch of pixels almost
0368      * fully transparent in the very center. If the brush is pierced,
0369      * then dulling mode may not work correctly due to empty samples.
0370      *
0371      * WARNING: this method is relatively expensive since it iterates
0372      *          up to 100 pixels of the brush.
0373      */
0374     virtual bool isPiercedApprox() const;
0375 
0376 protected:
0377 
0378     void resetOutlineCache();
0379     void generateOutlineCache();
0380     bool outlineCacheIsValid() const;
0381 
0382     void predefinedBrushToXML(const QString &type, QDomElement& e) const;
0383 
0384 private:
0385 
0386     struct Private;
0387     Private* const d;
0388 
0389 };
0390 
0391 Q_DECLARE_METATYPE(KisBrushSP)
0392 
0393 #endif // KIS_BRUSH_
0394