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 */