Krita Source Code Documentation
Loading...
Searching...
No Matches
KisColorSmudgeStrategyBase.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2020 Peter Schatz <voronwe13@gmail.com>
3 * SPDX-FileCopyrightText: 2021 Dmitry Kazakov <dimula73@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
10#include "kis_painter.h"
12#include "kis_paint_device.h"
14
15/**********************************************************************************/
16/* DabColoringStrategyMask */
17/**********************************************************************************/
18
23
25 KisFixedPaintDeviceSP dst, KisColorSmudgeSourceSP src, const QRect &dstRect,
26 const KoColor &preparedDullingColor, const KoCompositeOp *smearOp, const qreal smudgeRateOpacity,
27 const KoColor &paintColor, const KoCompositeOp *colorRateOp, const qreal colorRateOpacity) const
28{
29 KoColor dullingFillColor(preparedDullingColor);
30
31 KIS_SAFE_ASSERT_RECOVER_RETURN(*paintColor.colorSpace() == *colorRateOp->colorSpace());
32 colorRateOp->composite(dullingFillColor.data(), 1, paintColor.data(), 1, 0, 0, 1, 1, colorRateOpacity);
33
34 if (smearOp->id() == COMPOSITE_COPY && qFuzzyCompare(smudgeRateOpacity, OPACITY_OPAQUE_F)) {
35 dst->fill(dst->bounds(), dullingFillColor);
36 } else {
37 src->readBytes(dst->data(), dstRect);
38 smearOp->composite(dst->data(), dstRect.width() * dst->pixelSize(),
39 dullingFillColor.data(), 0,
40 0, 0,
41 1, dstRect.width() * dstRect.height(),
42 smudgeRateOpacity);
43 }
44}
45
47 const KoCompositeOp *colorRateOp,
48 qreal colorRateOpacity,
49 KisFixedPaintDeviceSP dstDevice,
50 const QRect &dstRect) const
51{
52 KIS_SAFE_ASSERT_RECOVER_RETURN(*paintColor.colorSpace() == *colorRateOp->colorSpace());
53
54 colorRateOp->composite(dstDevice->data(), dstRect.width() * dstDevice->pixelSize(),
55 paintColor.data(), 0,
56 0, 0,
57 dstRect.height(), dstRect.width(),
59}
60
61/**********************************************************************************/
62/* DabColoringStrategyStamp */
63/**********************************************************************************/
64
69
71 const KoCompositeOp *colorRateOp,
72 qreal colorRateOpacity,
73 KisFixedPaintDeviceSP dstDevice,
74 const QRect &dstRect) const
75{
76 Q_UNUSED(paintColor);
77
78 // TODO: check correctness for composition source device (transparency masks)
79 KIS_ASSERT_RECOVER_RETURN(*dstDevice->colorSpace() == *m_origDab->colorSpace());
80
81 colorRateOp->composite(dstDevice->data(), dstRect.width() * dstDevice->pixelSize(),
82 m_origDab->data(), dstRect.width() * m_origDab->pixelSize(),
83 0, 0,
84 dstRect.height(), dstRect.width(),
86}
87
92
94 KisFixedPaintDeviceSP dst, KisColorSmudgeSourceSP src, const QRect &dstRect,
95 const KoColor &preparedDullingColor, const KoCompositeOp *smearOp, const qreal smudgeRateOpacity,
96 const KoColor &paintColor, const KoCompositeOp *colorRateOp, const qreal colorRateOpacity) const
97{
98 Q_UNUSED(dst);
99 Q_UNUSED(src);
100 Q_UNUSED(dstRect);
101 Q_UNUSED(preparedDullingColor);
102 Q_UNUSED(smearOp);
103 Q_UNUSED(smudgeRateOpacity);
104 Q_UNUSED(paintColor);
105 Q_UNUSED(colorRateOp);
106 Q_UNUSED(colorRateOpacity);
107}
108
109/**********************************************************************************/
110/* KisColorSmudgeStrategyBase */
111/**********************************************************************************/
112
114 : m_useDullingMode(useDullingMode)
115{
116}
117
118void KisColorSmudgeStrategyBase::initializePaintingImpl(const KoColorSpace *dstColorSpace, bool smearAlpha,
119 const QString &colorRateCompositeOpId)
120{
122 m_smearOp = dstColorSpace->compositeOp(smearCompositeOp(smearAlpha));
123 m_colorRateOp = dstColorSpace->compositeOp(colorRateCompositeOpId);
124 m_preparedDullingColor.convertTo(dstColorSpace);
125}
126
128{
129 // verify that initialize() has already been called!
131
132 return m_smearOp->colorSpace();
133}
134
136{
137 return smearAlpha ? COMPOSITE_COPY : COMPOSITE_OVER;
138}
139
141{
142 Q_UNUSED(smearAlpha);
143 return COMPOSITE_COPY;
144}
145
146qreal KisColorSmudgeStrategyBase::finalPainterOpacity(qreal opacity, qreal smudgeRateValue)
147{
148 Q_UNUSED(opacity);
149 Q_UNUSED(smudgeRateValue);
150
151 return OPACITY_OPAQUE_F;
152}
153
154qreal KisColorSmudgeStrategyBase::colorRateOpacity(qreal opacity, qreal smudgeRateValue, qreal colorRateValue,
155 qreal maxPossibleSmudgeRateValue)
156{
157 Q_UNUSED(smudgeRateValue);
158 Q_UNUSED(maxPossibleSmudgeRateValue);
159 return colorRateValue * colorRateValue * opacity;
160}
161
162qreal KisColorSmudgeStrategyBase::dullingRateOpacity(qreal opacity, qreal smudgeRateValue)
163{
164 return 0.8 * smudgeRateValue * opacity;
165}
166
167qreal KisColorSmudgeStrategyBase::smearRateOpacity(qreal opacity, qreal smudgeRateValue)
168{
169 return smudgeRateValue * opacity;
170}
171
172void KisColorSmudgeStrategyBase::sampleDullingColor(const QRect &srcRect, qreal sampleRadiusValue,
173 KisColorSmudgeSourceSP sourceDevice,
174 KisFixedPaintDeviceSP tempFixedDevice,
175 KisFixedPaintDeviceSP maskDab, KoColor *resultColor)
176{
177 using namespace KisColorSmudgeSampleUtils;
178 sampleColor<WeightedSampleWrapper>(srcRect, sampleRadiusValue,
179 sourceDevice, tempFixedDevice,
180 maskDab, resultColor);
181}
182
183void
185 KisFixedPaintDeviceSP maskDab, bool preserveMaskDab, const QRect &srcRect,
186 const QRect &dstRect, const KoColor &currentPaintColor, qreal opacity,
187 qreal smudgeRateValue, qreal maxPossibleSmudgeRateValue, qreal colorRateValue,
188 qreal smudgeRadiusValue)
189{
190 const qreal colorRateOpacity = this->colorRateOpacity(opacity, smudgeRateValue, colorRateValue, maxPossibleSmudgeRateValue);
191
192 if (m_useDullingMode) {
193 this->sampleDullingColor(srcRect,
194 smudgeRadiusValue,
195 srcSampleDevice, m_blendDevice,
196 maskDab, &m_preparedDullingColor);
197
200 }
201 }
202
203 m_blendDevice->setRect(dstRect);
205
207
208 const qreal dullingRateOpacity = this->dullingRateOpacity(opacity, smudgeRateValue);
209
210 if (colorRateOpacity > 0 &&
213 ((m_smearOp->id() == COMPOSITE_OVER &&
215 (m_smearOp->id() == COMPOSITE_COPY &&
216 qFuzzyCompare(dullingRateOpacity, OPACITY_OPAQUE_F)))) {
217
219 srcSampleDevice,
220 dstRect,
222 m_smearOp,
224 currentPaintColor.convertedTo(
228
229 } else {
230 if (!m_useDullingMode) {
231 const qreal smudgeRateOpacity = this->smearRateOpacity(opacity, smudgeRateValue);
233 srcRect, dstRect, smudgeRateOpacity);
234 } else {
236 dstRect,
238 }
239
240 if (colorRateOpacity > 0) {
242 currentPaintColor.convertedTo(m_preparedDullingColor.colorSpace()),
245 m_blendDevice, dstRect);
246 }
247 }
248
249 const bool preserveDab = preserveMaskDab && dstPainters.size() > 1;
250
251 Q_FOREACH (KisPainter *dstPainter, dstPainters) {
252 dstPainter->setOpacityF(finalPainterOpacity(opacity, smudgeRateValue));
253
254 dstPainter->bltFixedWithFixedSelection(dstRect.x(), dstRect.y(),
255 m_blendDevice, maskDab,
256 maskDab->bounds().x(), maskDab->bounds().y(),
258 dstRect.width(), dstRect.height());
259 dstPainter->renderMirrorMaskSafe(dstRect, m_blendDevice, maskDab, preserveDab);
260 }
261
262}
263
265 const QRect &srcRect, const QRect &dstRect,
266 const qreal smudgeRateOpacity)
267{
268 if (m_smearOp->id() == COMPOSITE_COPY && qFuzzyCompare(smudgeRateOpacity, OPACITY_OPAQUE_F)) {
269 src->readBytes(dst->data(), srcRect);
270 } else {
271 src->readBytes(dst->data(), dstRect);
272
273 KisFixedPaintDevice tempDevice(src->colorSpace(), m_memoryAllocator);
274 tempDevice.setRect(srcRect);
276
277 src->readBytes(tempDevice.data(), srcRect);
278 m_smearOp->composite(dst->data(), dstRect.width() * dst->pixelSize(),
279 tempDevice.data(), dstRect.width() * tempDevice.pixelSize(), // stride should be random non-zero
280 0, 0,
281 1, dstRect.width() * dstRect.height(),
282 smudgeRateOpacity);
283 }
284}
285
287 const QRect &dstRect, const KoColor &preparedDullingColor,
288 const qreal smudgeRateOpacity)
289{
290 Q_UNUSED(preparedDullingColor);
291
292 if (m_smearOp->id() == COMPOSITE_COPY && qFuzzyCompare(smudgeRateOpacity, OPACITY_OPAQUE_F)) {
293 dst->fill(dst->bounds(), m_preparedDullingColor);
294 } else {
295 src->readBytes(dst->data(), dstRect);
296 m_smearOp->composite(dst->data(), dstRect.width() * dst->pixelSize(),
298 0, 0,
299 1, dstRect.width() * dstRect.height(),
300 smudgeRateOpacity);
301 }
302}
const qreal OPACITY_OPAQUE_F
const QString COMPOSITE_OVER
const QString COMPOSITE_COPY
virtual void sampleDullingColor(const QRect &srcRect, qreal sampleRadiusValue, KisColorSmudgeSourceSP sourceDevice, KisFixedPaintDeviceSP tempFixedDevice, KisFixedPaintDeviceSP maskDab, KoColor *resultColor)
void blendInBackgroundWithDulling(KisFixedPaintDeviceSP dst, KisColorSmudgeSourceSP src, const QRect &dstRect, const KoColor &preparedDullingColor, const qreal smudgeRateOpacity)
virtual QString finalCompositeOp(bool smearAlpha) const
virtual QString smearCompositeOp(bool smearAlpha) const
virtual qreal colorRateOpacity(qreal opacity, qreal smudgeRateValue, qreal colorRateValue, qreal maxPossibleSmudgeRateValue)
void blendBrush(const QVector< KisPainter * > dstPainters, KisColorSmudgeSourceSP srcSampleDevice, KisFixedPaintDeviceSP maskDab, bool preserveMaskDab, const QRect &srcRect, const QRect &dstRect, const KoColor &currentPaintColor, qreal opacity, qreal smudgeRateValue, qreal maxPossibleSmudgeRateValue, qreal colorRateValue, qreal smudgeRadiusValue)
virtual qreal smearRateOpacity(qreal opacity, qreal smudgeRateValue)
virtual qreal finalPainterOpacity(qreal opacity, qreal smudgeRateValue)
virtual qreal dullingRateOpacity(qreal opacity, qreal smudgeRateValue)
void initializePaintingImpl(const KoColorSpace *dstColorSpace, bool smearAlpha, const QString &colorRateCompositeOpId)
virtual DabColoringStrategy & coloringStrategy()=0
const KoColorSpace * preciseColorSpace() const override
void blendInBackgroundWithSmearing(KisFixedPaintDeviceSP dst, KisColorSmudgeSourceSP src, const QRect &srcRect, const QRect &dstRect, const qreal smudgeRateOpacity)
KisOptimizedByteArray::MemoryAllocatorSP m_memoryAllocator
void setRect(const QRect &rc)
void fill(qint32 x, qint32 y, qint32 w, qint32 h, const quint8 *fillPixel)
const KoColorSpace * colorSpace() const
void bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, quint32 srcWidth, quint32 srcHeight)
void setOpacityF(qreal opacity)
void renderMirrorMaskSafe(QRect rc, KisFixedPaintDeviceSP dab, bool preserveDab)
const KoCompositeOp * compositeOp(const QString &id, const KoColorSpace *srcSpace=nullptr) const
void convertTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
Definition KoColor.cpp:136
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_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:85
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
void blendInColorRate(const KoColor &paintColor, const KoCompositeOp *colorRateOp, qreal colorRateOpacity, KisFixedPaintDeviceSP dstDevice, const QRect &dstRect) const override
void blendInFusedBackgroundAndColorRateWithDulling(KisFixedPaintDeviceSP dst, KisColorSmudgeSourceSP src, const QRect &dstRect, const KoColor &preparedDullingColor, const KoCompositeOp *smearOp, const qreal smudgeRateOpacity, const KoColor &paintColor, const KoCompositeOp *colorRateOp, const qreal colorRateOpacity) const override
void blendInColorRate(const KoColor &paintColor, const KoCompositeOp *colorRateOp, qreal colorRateOpacity, KisFixedPaintDeviceSP dstDevice, const QRect &dstRect) const override
void blendInFusedBackgroundAndColorRateWithDulling(KisFixedPaintDeviceSP dst, KisColorSmudgeSourceSP src, const QRect &dstRect, const KoColor &preparedDullingColor, const KoCompositeOp *smearOp, const qreal smudgeRateOpacity, const KoColor &paintColor, const KoCompositeOp *colorRateOp, const qreal colorRateOpacity) const override
virtual void blendInFusedBackgroundAndColorRateWithDulling(KisFixedPaintDeviceSP dst, KisColorSmudgeSourceSP src, const QRect &dstRect, const KoColor &preparedDullingColor, const KoCompositeOp *smearOp, const qreal smudgeRateOpacity, const KoColor &paintColor, const KoCompositeOp *colorRateOp, const qreal colorRateOpacity) const =0
virtual void blendInColorRate(const KoColor &paintColor, const KoCompositeOp *colorRateOp, qreal colorRateOpacity, KisFixedPaintDeviceSP dstDevice, const QRect &dstRect) const =0
virtual bool supportsFusedDullingBlending() const =0
static KoColorSpaceRegistry * instance()
void composite(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, float opacity, const QBitArray &channelFlags=QBitArray()) const
const KoColorSpace * colorSpace