Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_colorsmudgeop.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "kis_colorsmudgeop.h"
8
9#include <QRect>
10
11#include <KoColor.h>
12
13#include <kis_brush.h>
14#include <kis_image.h>
15#include <kis_selection.h>
17#include <kis_lod_transform.h>
20
21#include "KisInterstrokeData.h"
23
24#include "kis_brush_option.h"
25
32
34{
35 bool isCompatible(KisInterstrokeData *data) override {
36 KisColorSmudgeInterstrokeData *colorSmudgeData =
37 dynamic_cast<KisColorSmudgeInterstrokeData*>(data);
38
39 return colorSmudgeData;
40 }
41
44 return data;
45 }
46};
47
49 : KisBrushBasedPaintOp(settings, painter)
50 , m_firstRun(true)
51 , m_sizeOption(settings.data())
52 , m_ratioOption(settings.data())
53 , m_opacityOption(settings.data(), node)
54 , m_spacingOption(settings.data())
55 , m_rateOption(settings.data())
56 , m_rotationOption(settings.data())
57 , m_scatterOption(settings.data())
58 , m_paintThicknessOption(settings.data())
59 , m_gradientOption(settings.data())
60 , m_smudgeRateOption(settings.data())
61 , m_colorRateOption(settings.data())
62 , m_smudgeRadiusOption(settings.data())
63{
64 Q_UNUSED(node);
65 Q_ASSERT(painter);
66
67 m_airbrushData.read(settings.data());
68 m_overlayModeData.read(settings.data());
69
71
72 // useNewEngine should be true if brushApplication is not ALPHAMASK
74
75 const bool useSmearAlpha = m_smudgeRateOption.smearAlpha();
76 const bool useDullingMode = m_smudgeRateOption.mode() == KisSmudgeLengthOptionData::DULLING_MODE;
77 const bool useOverlayMode = m_overlayModeData.isChecked;
78
80
81 if (m_brush->brushApplication() == LIGHTNESSMAP) {
82 KisPaintThicknessOptionData::ThicknessMode thicknessMode =
85 KisPaintThicknessOptionData::OVERWRITE;
86
88 useSmearAlpha,
89 useDullingMode,
90 thicknessMode));
91 } else if (m_smudgeRateOption.useNewEngine() &&
92 m_brush->brushApplication() == ALPHAMASK) {
94 image,
95 useSmearAlpha,
96 useDullingMode,
97 useOverlayMode));
98 } else if (m_brush->brushApplication() == IMAGESTAMP ||
99 m_brush->brushApplication() == GRADIENTMAP) {
101 image,
102 useSmearAlpha,
103 useDullingMode,
104 useOverlayMode));
105 } else {
107 image,
108 useSmearAlpha,
109 useDullingMode,
110 useOverlayMode));
111 }
112
113 m_strategy->initializePainting();
114 m_paintColor = painter->paintColor().convertedTo(m_strategy->preciseColorSpace());
115
119
122 Q_FOREACH (KisHSVOption * option, m_hsvOptions) {
123 if (option->isChecked() && !m_hsvTransform) {
124 m_hsvTransform = m_paintColor.colorSpace()->createColorTransformation("hsv_adjustment", QHash<QString, QVariant>());
125 }
126 }
127}
128
130{
131 qDeleteAll(m_hsvOptions);
132 delete m_hsvTransform;
133}
134
136{
137 KisBrushSP brush = m_brush;
138
139 // Simple error catching
140 if (!painter()->device() || !brush || !brush->canPaintFor(info)) {
141 return KisSpacingInformation(1.0);
142 }
143 if (m_smudgeRateOption.mode() == KisSmudgeLengthOptionData::SMEARING_MODE) {
155 }
156
157 // get the scaling factor calculated by the size option
158 qreal scale = m_sizeOption.apply(info);
159 scale *= KisLodTransform::lodToScale(painter()->device());
160 qreal rotation = m_rotationOption.apply(info);
161 if (checkSizeTooSmall(scale)) return KisSpacingInformation();
162
163 qreal ratio = m_ratioOption.apply(info);
164
165 KisDabShape shape(scale, ratio, rotation);
166
167 QPointF scatteredPos =
169 brush->maskWidth(shape, 0, 0, info),
170 brush->maskHeight(shape, 0, 0, info));
171
172 const qreal smudgeRadiusPortion = m_smudgeRadiusOption.isChecked() ? m_smudgeRadiusOption.computeSizeLikeValue(info) : 0.0;
173
174 KisSpacingInformation spacingInfo =
175 effectiveSpacing(scale, rotation,
177
179
180
181 const qreal paintThickness = m_paintThicknessOption.apply(info);
182 m_strategy->updateMask(m_dabCache, info, shape, scatteredPos, &m_dstDabRect, paintThickness);
183
184 QPointF newCenterPos = QRectF(m_dstDabRect).center();
192 QRect srcDabRect = m_dstDabRect.translated((m_lastPaintPos - newCenterPos).toPoint());
193
194 m_lastPaintPos = newCenterPos;
195
196 if (m_firstRun) {
197 m_firstRun = false;
198 return spacingInfo;
199 }
200
201 const qreal colorRate = m_colorRateOption.isChecked() ? m_colorRateOption.computeSizeLikeValue(info) : 0.0;
202 const qreal smudgeRate = m_smudgeRateOption.isChecked() ? m_smudgeRateOption.computeSizeLikeValue(info) : 1.0;
203 const qreal maxSmudgeRate = m_smudgeRateOption.strengthValue();
204 const qreal fpOpacity = m_opacityOption.apply(info);
205
206 KoColor paintColor = m_paintColor;
207
208 m_gradientOption.apply(paintColor, m_gradient, info);
209 if (m_hsvTransform) {
210 Q_FOREACH (KisHSVOption *option, m_hsvOptions) {
211 option->apply(m_hsvTransform, info);
212 }
213 m_hsvTransform->transform(paintColor.data(), paintColor.data(), 1);
214 }
215
216 const QVector<QRect> dirtyRects =
217 m_strategy->paintDab(srcDabRect, m_dstDabRect,
218 paintColor,
219 fpOpacity, colorRate,
220 smudgeRate,
221 maxSmudgeRate,
222 paintThickness,
223 smudgeRadiusPortion);
224
225 painter()->addDirtyRects(dirtyRects);
226
227 return spacingInfo;
228}
229
231{
232 const qreal scale = m_sizeOption.apply(info) * KisLodTransform::lodToScale(painter()->device());
233 const qreal rotation = m_rotationOption.apply(info);
234 return effectiveSpacing(scale, rotation, &m_airbrushData, &m_spacingOption, info);
235}
236
241
243{
244
245 KisBrushOptionProperties brushOption;
246 const bool needsInterstrokeData =
247 brushOption.brushApplication(settings.data(), resourcesInterface) == LIGHTNESSMAP;
248
249 const bool needsNewEngine = settings->getBool(QString("SmudgeRate") + "UseNewEngine", false);
250 KIS_SAFE_ASSERT_RECOVER_NOOP(!needsInterstrokeData || needsNewEngine);
251
252 return needsInterstrokeData ? new ColorSmudgeInterstrokeDataFactory() : 0;
253}
KisSpacingInformation effectiveSpacing(qreal scale) const
enumBrushApplication brushApplication(const KisPropertiesConfiguration *settings, KisResourcesInterfaceSP resourcesInterface)
KisSpacingOption m_spacingOption
KisTimingInformation updateTimingImpl(const KisPaintInformation &info) const override
static KisInterstrokeDataFactory * createInterstrokeDataFactory(const KisPaintOpSettingsSP settings, KisResourcesInterfaceSP resourcesInterface)
KisAirbrushOptionData m_airbrushData
KoAbstractGradientSP m_gradient
KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const override
KisRateOption m_rateOption
KisSmudgeOverlayModeOptionData m_overlayModeData
KisSmudgeRadiusOption2 m_smudgeRadiusOption
QScopedPointer< KisColorSmudgeStrategy > m_strategy
KisColorRateOption2 m_colorRateOption
QList< KisHSVOption * > m_hsvOptions
KisRotationOption m_rotationOption
KisOpacityOption m_opacityOption
KisSpacingInformation paintAt(const KisPaintInformation &info) override
KisPaintThicknessOption m_paintThicknessOption
KisGradientOption m_gradientOption
KisScatterOption m_scatterOption
KisSmudgeLengthOption m_smudgeRateOption
KisSizeOption m_sizeOption
KisRatioOption m_ratioOption
KoColorTransformation * m_hsvTransform
KisColorSmudgeOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image)
qreal strengthValue() const
bool isChecked() const
qreal computeSizeLikeValue(const KisPaintInformation &info, bool useStrengthValue=true) const
void apply(KoColor &color, const KoAbstractGradientSP gradient, const KisPaintInformation &info) const
static KisHSVOption * createSaturationOption(const KisPropertiesConfiguration *setting)
void apply(KoColorTransformation *transfo, const KisPaintInformation &info) const
static KisHSVOption * createValueOption(const KisPropertiesConfiguration *setting)
static KisHSVOption * createHueOption(const KisPropertiesConfiguration *setting)
static qreal lodToScale(int levelOfDetail)
void apply(KisPainter *painter, const KisPaintInformation &info) const
KisPaintThicknessOptionData::ThicknessMode mode() const
qreal apply(const KisPaintInformation &info) const
void addDirtyRects(const QVector< QRect > &rects)
KoColor paintColor
KoAbstractGradientSP gradient
qreal apply(const KisPaintInformation &info) const
void applyFanCornersInfo(KisPaintOp *op)
QPointF apply(const KisPaintInformation &info, qreal width, qreal height) const
KisSmudgeLengthOptionData::Mode mode() const
qreal apply(const KisPaintInformation &info) const
KoColorTransformation * createColorTransformation(const QString &id, const QHash< QString, QVariant > &parameters) const
virtual void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const =0
KoColor convertedTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
Definition KoColor.cpp:163
quint8 * data()
Definition KoColor.h:144
const KoColorSpace * colorSpace() const
return the current colorSpace
Definition KoColor.h:82
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
@ ALPHAMASK
Definition kis_brush.h:39
@ IMAGESTAMP
Definition kis_brush.h:40
@ GRADIENTMAP
Definition kis_brush.h:42
@ LIGHTNESSMAP
Definition kis_brush.h:41
KisTimingInformation effectiveTiming(const KisAirbrushOptionData *airbrushOption, const KisRateOption *rateOption, const KisPaintInformation &pi)
bool isCompatible(KisInterstrokeData *data) override
KisInterstrokeData * create(KisPaintDeviceSP device) override
bool read(const KisPropertiesConfiguration *setting)
KisPainter * painter
bool read(const KisPropertiesConfiguration *setting)