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

0001 /*
0002  *  SPDX-FileCopyrightText: 2012 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef __KIS_BRUSHES_PIPE_H
0008 #define __KIS_BRUSHES_PIPE_H
0009 
0010 #include <kis_fixed_paint_device.h>
0011 #include <kis_brush.h>
0012 
0013 template<class BrushType>
0014 class KisBrushesPipe
0015 {
0016 public:
0017     KisBrushesPipe() {
0018     }
0019 
0020     KisBrushesPipe(const KisBrushesPipe &rhs) {
0021         m_brushes.clear();
0022         Q_FOREACH (QSharedPointer<BrushType> brush, rhs.m_brushes) {
0023             KoResourceSP clonedBrush = brush->clone();
0024             QSharedPointer<BrushType> actualClonedBrush = clonedBrush.dynamicCast<BrushType>();
0025             m_brushes.append(actualClonedBrush );
0026             KIS_ASSERT_RECOVER(clonedBrush) {continue;}
0027         }
0028     }
0029 
0030     virtual ~KisBrushesPipe() {
0031     }
0032 
0033     virtual void clear() {
0034         m_brushes.clear();
0035     }
0036 
0037     QSharedPointer<BrushType> firstBrush() const {
0038         return m_brushes.first();
0039     }
0040 
0041     QSharedPointer<BrushType> lastBrush() const {
0042         return m_brushes.last();
0043     }
0044 
0045 
0046     QSharedPointer<BrushType> currentBrush(const KisPaintInformation& info) {
0047         Q_UNUSED(info);
0048         return !m_brushes.isEmpty() ? m_brushes.at(currentBrushIndex()) : 0;
0049     }
0050 
0051     qint32 maskWidth(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) {
0052         QSharedPointer<BrushType> brush = currentBrush(info);
0053         return brush ? brush->maskWidth(shape, subPixelX, subPixelY, info) : 0;
0054     }
0055 
0056     qint32 maskHeight(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) {
0057         QSharedPointer<BrushType> brush = currentBrush(info);
0058         return brush ? brush->maskHeight(shape, subPixelX, subPixelY, info) : 0;
0059     }
0060 
0061     void setAngle(qreal angle) {
0062         Q_FOREACH (QSharedPointer<BrushType> brush, m_brushes) {
0063             brush->setAngle(angle);
0064         }
0065     }
0066 
0067     void setScale(qreal scale) {
0068         Q_FOREACH (QSharedPointer<BrushType> brush, m_brushes) {
0069             brush->setScale(scale);
0070         }
0071     }
0072 
0073     void setSpacing(double spacing) {
0074         Q_FOREACH (QSharedPointer<BrushType> brush, m_brushes) {
0075             brush->setSpacing(spacing);
0076         }
0077     }
0078 
0079     bool isImageType() const {
0080         Q_FOREACH (QSharedPointer<BrushType> brush, m_brushes) {
0081             if (brush->isImageType()) return true;
0082         }
0083         return false;
0084     }
0085 
0086     bool hasColorAndTransparency() const {
0087         Q_FOREACH (QSharedPointer<BrushType> brush, m_brushes) {
0088             if (brush->hasColorAndTransparency()) return true;
0089         }
0090         return false;
0091     }
0092 
0093     void setBrushApplication(enumBrushApplication brushApplication) const {
0094         Q_FOREACH(QSharedPointer<BrushType> brush, m_brushes) {
0095             brush->setBrushApplication(brushApplication);
0096         }
0097     }
0098 
0099     void setGradient(KoAbstractGradientSP gradient) const {
0100         Q_FOREACH(QSharedPointer<BrushType> brush, m_brushes) {
0101             brush->setGradient(gradient);
0102         }
0103     }
0104 
0105     void prepareForSeqNo(const KisPaintInformation& info, int seqNo) {
0106         chooseNextBrush(info);
0107         updateBrushIndexes(info, seqNo);
0108     }
0109 
0110     void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* coloringInformation,
0111             KisDabShape const& shape,
0112             const KisPaintInformation& info,
0113             double subPixelX , double subPixelY,
0114             qreal softnessFactor, qreal lightnessStrength = DEFAULT_LIGHTNESS_STRENGTH) {
0115 
0116         QSharedPointer<BrushType> brush = currentBrush(info);
0117         if (!brush) return;
0118 
0119 
0120         brush->generateMaskAndApplyMaskOrCreateDab(dst, coloringInformation, shape, info, subPixelX, subPixelY, softnessFactor, lightnessStrength);
0121     }
0122 
0123     KisFixedPaintDeviceSP paintDevice(const KoColorSpace * colorSpace,
0124                                       KisDabShape const& shape,
0125                                       const KisPaintInformation& info,
0126                                       double subPixelX, double subPixelY) {
0127 
0128         QSharedPointer<BrushType> brush = currentBrush(info);
0129         if (!brush) return 0;
0130 
0131         KisFixedPaintDeviceSP device = brush->paintDevice(colorSpace, shape, info, subPixelX, subPixelY);
0132         return device;
0133     }
0134 
0135     void notifyBrushIsGoingToBeClonedForStroke() {
0136         Q_FOREACH(QSharedPointer<BrushType> brush, m_brushes) {
0137             brush->notifyBrushIsGoingToBeClonedForStroke();
0138         }
0139     }
0140 
0141     QVector<QSharedPointer<BrushType>> brushes() {
0142         return m_brushes;
0143     }
0144 
0145     void testingSelectNextBrush(const KisPaintInformation& info) {
0146         (void) chooseNextBrush(info);
0147         updateBrushIndexes(info, -1);
0148     }
0149 
0150     /**
0151      * Is called by the paint op when a paintop starts a stroke. The
0152      * brushes are shared among different strokes, so sometimes the
0153      * brush should be reset.
0154      */
0155     virtual void notifyStrokeStarted() = 0;
0156 
0157 protected:
0158     void addBrush(QSharedPointer<BrushType> brush) {
0159         m_brushes.append(brush);
0160     }
0161 
0162     int sizeBrush() {
0163         return m_brushes.size();
0164     }
0165 
0166     /**
0167      * Returns the index of the next brush that corresponds to the current
0168      * values of \p info. This method is called *before* the dab is
0169      * actually painted.
0170      *
0171      */
0172     virtual int chooseNextBrush(const KisPaintInformation& info) = 0;
0173 
0174     /**
0175      * Returns the current index of the brush
0176      * This method is called *before* the dab is
0177      * actually painted.
0178      *
0179      * The method is const, so no internal counters of the brush should
0180      * change during its execution
0181      */
0182     virtual int currentBrushIndex() = 0;
0183 
0184     /**
0185      * Updates internal counters of the brush *after* a dab has been
0186      * painted on the canvas. Some incremental switching of the brushes
0187      * may me implemented in this method.
0188      *
0189      * If \p seqNo is equal or greater than zero, then incremental iteration is
0190      * overridden by this seqNo value
0191      */
0192     virtual void updateBrushIndexes(const KisPaintInformation& info, int seqNo) = 0;
0193 
0194 protected:
0195     QVector<QSharedPointer<BrushType>> m_brushes;
0196 };
0197 
0198 #endif /* __KIS_BRUSHES_PIPE_H */