Krita Source Code Documentation
Loading...
Searching...
No Matches
deform_brush.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2008, 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "deform_brush.h"
8#include "kis_painter.h"
9
11
12#include <KoColor.h>
13#include <KoColorSpace.h>
14
15#include <QRect>
16
17#include <kis_types.h>
18#include <kis_iterator_ng.h>
20
21#include <cmath>
22#include <ctime>
24
25const qreal degToRad = M_PI / 180.0;
26
27
29{
30 m_firstPaint = false;
31 m_counter = 1;
33}
34
39
41{
43
44 switch (mode) {
45 case GROW:
46 case SHRINK: {
48 break;
49 }
50 case SWIRL_CW:
51 case SWIRL_CCW: {
53 break;
54 }
55
56 case MOVE: {
58 static_cast<DeformMove*>(m_deformAction)->setFactor(m_properties->deformAmount);
59 break;
60 }
61 case LENS_IN:
62 case LENS_OUT: {
64 static_cast<DeformLens*>(m_deformAction)->setLensFactor(m_properties->deformAmount, 0.0);
65 static_cast<DeformLens*>(m_deformAction)->setMode(mode == LENS_OUT);
66 break;
67 }
68 case DEFORM_COLOR: {
70 static_cast<DeformColor*>(m_deformAction)->setFactor(m_properties->deformAmount);
71 break;
72 }
73 default: {
75 break;
76 }
77 }
78}
79
81 DeformModes mode, const QPointF& pos, QTransform const& rotation)
82{
83
84 switch (mode) {
85 case GROW:
86 case SHRINK: {
87 // grow or shrink, the sign decide
88 qreal sign = (mode == GROW) ? 1.0 : -1.0;
89 qreal factor;
91 factor = (1.0 + sign * (m_counter * m_counter / 100.0));
92 }
93 else {
94 factor = (1.0 + sign * (m_properties->deformAmount));
95 }
96 DeformScale* deformScale = dynamic_cast<DeformScale*>(m_deformAction);
97 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(deformScale, false);
98 deformScale->setFactor(factor);
99 break;
100 }
101 case SWIRL_CW:
102 case SWIRL_CCW: {
103 // CW or CCW, the sign decide
104 qreal sign = (mode == SWIRL_CW) ? 1.0 : -1.0;
105 qreal factor;
107 factor = m_counter * sign * degToRad;
108 }
109 else {
110 factor = (360 * m_properties->deformAmount * 0.5) * sign * degToRad;
111 }
112 DeformRotation* deformRotation = dynamic_cast<DeformRotation*>(m_deformAction);
113 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(deformRotation, false);
114 deformRotation->setAlpha(factor);
115 break;
116 }
117 case MOVE: {
118 if (m_firstPaint == false) {
119 m_prevX = pos.x();
120 m_prevY = pos.y();
121 DeformMove* deformMove = static_cast<DeformMove*>(m_deformAction);
122 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(deformMove, false);
123 deformMove->setDistance(0.0, 0.0);
124 m_firstPaint = true;
125 return false;
126 }
127 else {
128 qreal xDistance = pos.x() - m_prevX;
129 qreal yDistance = pos.y() - m_prevY;
130 rotation.map(xDistance, yDistance, &xDistance, &yDistance);
131 DeformMove* deformMove = static_cast<DeformMove*>(m_deformAction);
132 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(deformMove, false);
133 deformMove->setDistance(xDistance, yDistance);
134 m_prevX = pos.x();
135 m_prevY = pos.y();
136 }
137 break;
138 }
139 case LENS_IN:
140 case LENS_OUT: {
141 DeformLens* deformLens = static_cast<DeformLens*>(m_deformAction);
142 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(deformLens, false);
144 break;
145 }
146 case DEFORM_COLOR: {
147 // no run-time setup
148 break;
149 }
150 default: {
151 break;
152 }
153 }
154 return true;
155}
156
158 KisPaintDeviceSP layer,
159 KisRandomSourceSP randomSource,
160 qreal scale,
161 qreal rotation,
162 QPointF pos, qreal subPixelX, qreal subPixelY, int dabX, int dabY)
163{
165 KisCrossDeviceColorSampler colorSampler(layer, dab);
166
167 qreal fWidth = maskWidth(scale);
168 qreal fHeight = maskHeight(scale);
169
170 int dstWidth = qRound(m_maskRect.width());
171 int dstHeight = qRound(m_maskRect.height());
172
173 // clear
174 if (dab->bounds().width() != dstWidth || dab->bounds().height() != dstHeight) {
175 dab->setRect(m_maskRect.toRect());
177 }
178
179 qreal const centerX = dstWidth * 0.5 + subPixelX;
180 qreal const centerY = dstHeight * 0.5 + subPixelY;
181
182 qreal const majorAxis = 2.0 / fWidth;
183 qreal const minorAxis = 2.0 / fHeight;
184
185 qreal distance;
186
187 QTransform forwardRotationMatrix;
188 forwardRotationMatrix.rotate(rotation);
189 QTransform reverseRotationMatrix;
190 reverseRotationMatrix.rotate(-rotation);
191
192 // if can't paint, stop
194 pos, forwardRotationMatrix))
195 {
196 return 0;
197 }
198
199 mask->setRect(dab->bounds());
201 quint8* maskPointer = mask->data();
202 qint8 maskPixelSize = mask->pixelSize();
203
204 quint8* dabPointer = dab->data();
205 int dabPixelSize = dab->colorSpace()->pixelSize();
206
207 for (int y = 0; y < dstHeight; y++) {
208 for (int x = 0; x < dstWidth; x++) {
209 qreal maskX = x - centerX;
210 qreal maskY = y - centerY;
211 forwardRotationMatrix.map(maskX, maskY, &maskX, &maskY);
212 distance = norme(maskX * majorAxis, maskY * minorAxis);
213
214 if (distance > 1.0) {
215 // leave there OPACITY TRANSPARENT pixel (default pixel)
216
217 colorSampler.sampleOldColor(x + dabX, y + dabY, dabPointer);
218 dabPointer += dabPixelSize;
219
220 *maskPointer = OPACITY_TRANSPARENT_U8;
221 maskPointer += maskPixelSize;
222 continue;
223 }
224
225 if (m_sizeProperties->brushDensity != 1.0) {
226 if (m_sizeProperties->brushDensity < randomSource->generateNormalized()) {
227 dabPointer += dabPixelSize;
228 *maskPointer = OPACITY_TRANSPARENT_U8;
229 maskPointer += maskPixelSize;
230 continue;
231 }
232 }
233
234 m_deformAction->transform(&maskX, &maskY, distance, randomSource);
235 reverseRotationMatrix.map(maskX, maskY, &maskX, &maskY);
236
237 maskX += pos.x();
238 maskY += pos.y();
239
241 maskX = qRound(maskX);
242 maskY = qRound(maskY);
243 }
244
246 colorSampler.sampleOldColor(maskX, maskY, dabPointer);
247 }
248 else {
249 colorSampler.sampleColor(maskX, maskY, dabPointer);
250 }
251
252 dabPointer += dabPixelSize;
253
254 *maskPointer = OPACITY_OPAQUE_U8;
255 maskPointer += maskPixelSize;
256
257 }
258 }
259 m_counter++;
260
261 return mask;
262
263}
264
265void DeformBrush::debugColor(const quint8* data, KoColorSpace * cs)
266{
267 QColor rgbcolor;
268 cs->toQColor(data, &rgbcolor);
269 dbgPlugins << "RGBA: ("
270 << rgbcolor.red()
271 << ", " << rgbcolor.green()
272 << ", " << rgbcolor.blue()
273 << ", " << rgbcolor.alpha() << ")";
274}
275
276QPointF DeformBrush::hotSpot(qreal scale, qreal rotation)
277{
278 qreal fWidth = maskWidth(scale);
279 qreal fHeight = maskHeight(scale);
280
281 QTransform m;
282 m.reset();
283 m.rotate(-rotation);
284
285 m_maskRect = QRect(0, 0, fWidth, fHeight);
286 m_maskRect.translate(-m_maskRect.center());
287 m_maskRect = m.mapRect(m_maskRect);
288 m_maskRect.translate(-m_maskRect.topLeft());
289 return m_maskRect.center();
290}
@ DEFORM_COLOR
@ SWIRL_CCW
const quint8 OPACITY_TRANSPARENT_U8
const quint8 OPACITY_OPAQUE_U8
qreal distance(const QPointF &p1, const QPointF &p2)
virtual void transform(qreal *x, qreal *y, qreal distance, KisRandomSourceSP randomSource)
QRectF m_maskRect
void debugColor(const quint8 *data, KoColorSpace *cs)
KisBrushSizeOptionData * m_sizeProperties
void initDeformAction()
KisFixedPaintDeviceSP paintMask(KisFixedPaintDeviceSP dab, KisPaintDeviceSP layer, KisRandomSourceSP randomSource, qreal scale, qreal rotation, QPointF pos, qreal subPixelX, qreal subPixelY, int dabX, int dabY)
bool setupAction(DeformModes mode, const QPointF &pos, QTransform const &rotation)
KisDeformOptionData * m_properties
qreal maskHeight(qreal scale)
QPointF hotSpot(qreal scale, qreal rotation)
qreal maskWidth(qreal scale)
qreal norme(qreal x, qreal y)
DeformBase * m_deformAction
Randomly disturb the pixels.
Inverse lens distortion.
void setMaxDistance(qreal maxX, qreal maxY)
Inverse move.
void setDistance(qreal dx, qreal dy)
Inverse weighted rotation - swirlCW&&swirlCWW.
void setAlpha(qreal alpha)
Inverse weighted inverse scaling - grow&shrink.
void setFactor(qreal factor)
void sampleOldColor(typename Traits::coord_type x, typename Traits::coord_type y, quint8 *dst)
void sampleColor(typename Traits::coord_type x, typename Traits::coord_type y, quint8 *dst)
void setRect(const QRect &rc)
const KoColorSpace * colorSpace() const
qreal generateNormalized() const
virtual quint32 pixelSize() const =0
virtual void toQColor(const quint8 *src, QColor *c) const =0
const qreal degToRad
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define dbgPlugins
Definition kis_debug.h:51
#define M_PI
Definition kis_global.h:111
static KoColorSpaceRegistry * instance()