Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tangent_normal_paintop.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2015 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QRect>
10
12#include <KoColor.h>
13
14#include <kis_brush.h>
15#include <kis_paint_device.h>
16#include <kis_painter.h>
17#include <kis_node.h>
20#include <kis_image.h>
21#include <kis_lod_transform.h>
23
24
26 : KisBrushBasedPaintOp(settings, painter)
27 , m_tangentTiltOption(settings.data())
28 , m_opacityOption(settings.data(), node)
29 , m_flowOption(settings.data())
30 , m_sizeOption(settings.data())
31 , m_spacingOption(settings.data())
32 , m_softnessOption(settings.data())
33 , m_sharpnessOption(settings.data())
34 , m_scatterOption(settings.data())
35 , m_rotationOption(settings.data())
36 , m_rateOption(settings.data())
37 , m_tempDev(painter->device()->createCompositionSourceDevice())
38
39{
40 Q_UNUSED(image);
41 //Init, read settings, etc//
42 m_airbrushData.read(settings.data());
43
46}
47
49{
50 //destroy things here//
51}
52
54{
55 /*
56 * For the color, the precision of tilt is only 60x60, and the precision of direction and rotation are 360 and 360*90.
57 * You can't get more precise than 8bit. Therefore, we will check if the current space is RGB,
58 * if so we request a profile with that space and 8bit bit depth, if not, just sRGB
59 */
60 KoColor currentColor = painter()->paintColor();
61 QString currentSpace = currentColor.colorSpace()->colorModelId().id();
62 const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8();
63 if (currentSpace != "RGBA") {
64 rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8();
65 } else {
66 rgbColorSpace = currentColor.colorSpace();
67 }
68 QVector <float> channelValues(4);
69 qreal r, g, b;
70
71 if (currentColor.colorSpace()->colorDepthId().id()=="F16" || currentColor.colorSpace()->colorDepthId().id()=="F32"){
72 channelValues[0] = 0.5;//red
73 channelValues[1] = 0.5;//green
74 channelValues[2] = 1.0;//blue
75 channelValues[3] = 1.0;//alpha, leave alone.
76
77
78 m_tangentTiltOption.apply(info, &r, &g, &b);
79
80 channelValues[0] = r;//red
81 channelValues[1] = g;//green
82 channelValues[2] = b;//blue
83 } else {
84 channelValues[0] = 1.0;//blue
85 channelValues[1] = 0.5;//green
86 channelValues[2] = 0.5;//red
87 channelValues[3] = 1.0;//alpha, leave alone.
88
89 m_tangentTiltOption.apply(info, &r, &g, &b);
90
91 channelValues[0] = b;//blue
92 channelValues[1] = g;//green
93 channelValues[2] = r;//red
94 }
95
96 quint8 data[MAX_PIXEL_SIZE];
97 rgbColorSpace->fromNormalisedChannelsValue(data, channelValues);
98 KoColor color(data, rgbColorSpace);//Should be default RGB(0.5,0.5,1.0)
99 //draw stuff here, return kisspacinginformation.
100 KisBrushSP brush = m_brush;
101
102 if (!painter()->device() || !brush || !brush->canPaintFor(info)) {
103 return KisSpacingInformation(1.0);
104 }
105
106 qreal scale = m_sizeOption.apply(info);
107 scale *= KisLodTransform::lodToScale(painter()->device());
108 qreal rotation = m_rotationOption.apply(info);
109 if (checkSizeTooSmall(scale)) return KisSpacingInformation();
110 KisDabShape shape(scale, 1.0, rotation);
111
112
113 QPointF cursorPos =
115 brush->maskWidth(shape, 0, 0, info),
116 brush->maskHeight(shape, 0, 0, info));
117
118 m_maskDab =
119 m_dabCache->fetchDab(rgbColorSpace, color, cursorPos,
120 shape,
121 info, m_softnessOption.apply(info),
122 &m_dstDabRect);
123
124 if (m_dstDabRect.isEmpty()) return KisSpacingInformation(1.0);
125
126 QRect dabRect = m_maskDab->bounds();
127
128 // sanity check
129 Q_ASSERT(m_dstDabRect.size() == dabRect.size());
130 Q_UNUSED(dabRect);
131
132 qreal oldOpacityF = painter()->opacityF();
133 QString oldCompositeOpId = painter()->compositeOpId();
134
135
137 //paint with the default color? Copied this from color smudge.//
138 //painter()->setCompositeOp(COMPOSITE_COPY);
139 //painter()->fill(0, 0, m_dstDabRect.width(), m_dstDabRect.height(), color);
142
143 // restore original opacity and composite mode values
144 painter()->setOpacityF(oldOpacityF);
145 painter()->setCompositeOpId(oldCompositeOpId);
146
147 return computeSpacing(info, scale, rotation);
148}
149
151{
152 qreal scale = m_sizeOption.apply(info) * KisLodTransform::lodToScale(painter()->device());
153 qreal rotation = m_rotationOption.apply(info);
154 return computeSpacing(info, scale, rotation);
155}
156
161
163 qreal scale, qreal rotation) const
164{
165 return effectiveSpacing(scale, rotation, &m_airbrushData, &m_spacingOption, info);
166}
167
169{
170 if (m_sharpnessOption.isChecked() && m_brush && (m_brush->width() == 1) && (m_brush->height() == 1)) {
171
172 if (!m_lineCacheDevice) {
174 }
175 else {
177 }
178
180 KoColor currentColor = painter()->paintColor();
181 QString currentSpace = currentColor.colorSpace()->colorModelId().id();
182 const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8();
183 if (currentSpace != "RGBA") {
184 rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8();
185 } else {
186 rgbColorSpace = currentColor.colorSpace();
187 }
188 QVector <float> channelValues(4);
189 qreal r, g, b;
190
191 if (currentColor.colorSpace()->colorDepthId().id()=="F16" || currentColor.colorSpace()->colorDepthId().id()=="F32"){
192 channelValues[0] = 0.5;//red
193 channelValues[1] = 0.5;//green
194 channelValues[2] = 1.0;//blue
195 channelValues[3] = 1.0;//alpha, leave alone.
196
197
198 m_tangentTiltOption.apply(pi2, &r, &g, &b);
199
200 channelValues[0] = r;//red
201 channelValues[1] = g;//green
202 channelValues[2] = b;//blue
203 } else {
204 channelValues[0] = 1.0;//blue
205 channelValues[1] = 0.5;//green
206 channelValues[2] = 0.5;//red
207 channelValues[3] = 1.0;//alpha, leave alone.
208
209 m_tangentTiltOption.apply(pi2, &r, &g, &b);
210
211 channelValues[0] = b;//blue
212 channelValues[1] = g;//green
213 channelValues[2] = r;//red
214 }
215
216 quint8 data[4];
217 rgbColorSpace->fromNormalisedChannelsValue(data, channelValues);
218 KoColor color(data, rgbColorSpace);
219 p.setPaintColor(color);
220 p.drawDDALine(pi1.pos(), pi2.pos());
221
222 QRect rc = m_lineCacheDevice->extent();
223 painter()->bitBlt(rc.x(), rc.y(), m_lineCacheDevice, rc.x(), rc.y(), rc.width(), rc.height());
225 }
226 else {
227 KisPaintOp::paintLine(pi1, pi2, currentDistance);
228 }
229}
const Params2D p
const int MAX_PIXEL_SIZE
KisSpacingInformation effectiveSpacing(qreal scale) const
bool isChecked() const
bool needSeparateOriginal() const
KisFixedPaintDeviceSP fetchDab(const KoColorSpace *cs, KisColorSource *colorSource, const QPointF &cursorPoint, KisDabShape const &, const KisPaintInformation &info, qreal softnessFactor, QRect *dstDabRect, qreal lightnessStrength=1.0)
void setSharpnessPostprocessing(KisSharpnessOption *option)
void apply(KisPainter *painter, const KisPaintInformation &info)
static qreal lodToScale(int levelOfDetail)
virtual void clear()
QRect extent() const
const QPointF & pos() const
QString compositeOpId
qreal opacityF() const
Returns the opacity that is used in painting.
KoColor paintColor
void renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab)
void setOpacityF(qreal opacity)
void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
void renderMirrorMaskSafe(QRect rc, KisFixedPaintDeviceSP dab, bool preserveDab)
void bltFixed(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
void setCompositeOpId(const KoCompositeOp *op)
qreal apply(const KisPaintInformation &info) const
void applyFanCornersInfo(KisPaintOp *op)
QPointF apply(const KisPaintInformation &info, qreal width, qreal height) const
qreal apply(const KisPaintInformation &info) const
KisAirbrushOptionData m_airbrushData
KisTimingInformation updateTimingImpl(const KisPaintInformation &info) const override
KisTangentTiltOption m_tangentTiltOption
KisFlowOpacityOption2 m_opacityOption
void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) override
KisTangentNormalPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image)
KisSpacingInformation computeSpacing(const KisPaintInformation &info, qreal scale, qreal rotation) const
KisSpacingInformation paintAt(const KisPaintInformation &info) override
KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const override
void apply(const KisPaintInformation &info, qreal *r, qreal *g, qreal *b)
virtual KoID colorModelId() const =0
virtual KoID colorDepthId() const =0
virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector< float > &values) const =0
const KoColorSpace * colorSpace() const
return the current colorSpace
Definition KoColor.h:82
QString id() const
Definition KoID.cpp:63
KisTimingInformation effectiveTiming(const KisAirbrushOptionData *airbrushOption, const KisRateOption *rateOption, const KisPaintInformation &pi)
bool read(const KisPropertiesConfiguration *setting)
KisPainter * painter
virtual void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance)
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())