Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_dab_cache_base.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2012 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <KoColor.h>
10#include "kis_color_source.h"
11#include "kis_paint_device.h"
12#include "kis_brush.h"
13#include <KisMirrorOption.h>
14#include <KisSharpnessOption.h>
15#include <kis_texture_option.h>
19
20#include <kundo2command.h>
21
23 qreal angle;
24 qreal sizeFrac;
25 qreal subPixel;
28 qreal ratio;
29};
30
31const qreal eps = 1e-6;
33 {M_PI / 180, 0.05, 1, 0.01, 0.01, 0.05},
34 {M_PI / 180, 0.01, 1, 0.01, 0.01, 0.01},
35 {M_PI / 180, 0, 1, 0.01, 0.01, eps},
36 {M_PI / 180, 0, 0.5, 0.01, 0.01, eps},
37 { eps, 0, eps, eps, eps, eps}
38};
39
42 qreal angle;
43 int width;
44 int height;
45 qreal subPixelX;
46 qreal subPixelY;
49 qreal ratio;
50 int index;
52
53 bool compare(const SavedDabParameters &rhs, int precisionLevel) const {
54 const PrecisionValues &prec = precisionLevels[precisionLevel];
55
56 return color == rhs.color &&
57 qAbs(angle - rhs.angle) <= prec.angle &&
58 qAbs(width - rhs.width) <= (int)(prec.sizeFrac * width) &&
59 qAbs(height - rhs.height) <= (int)(prec.sizeFrac * height) &&
60 qAbs(subPixelX - rhs.subPixelX) <= prec.subPixel &&
61 qAbs(subPixelY - rhs.subPixelY) <= prec.subPixel &&
62 qAbs(softnessFactor - rhs.softnessFactor) <= prec.softnessFactor &&
64 qAbs(ratio - rhs.ratio) <= prec.ratio &&
65 index == rhs.index &&
68 }
69};
70
87
88
89
91 : m_d(new Private())
92{
93}
94
99
104
109
114
117 const KoColor& color,
118 KisDabShape const& shape,
119 const KisPaintInformation& info,
120 double subPixelX, double subPixelY,
121 qreal softnessFactor,
122 qreal lightnessStrength,
123 MirrorProperties mirrorProperties)
124{
125 SavedDabParameters params;
126
127 params.color = color;
128 params.angle = shape.rotation();
129 params.width = brush->maskWidth(shape, subPixelX, subPixelY, info);
130 params.height = brush->maskHeight(shape, subPixelX, subPixelY, info);
131 params.subPixelX = subPixelX;
132 params.subPixelY = subPixelY;
133 params.softnessFactor = softnessFactor;
134 params.lightnessStrength = lightnessStrength;
135 params.index = brush->brushIndex();
136 params.mirrorProperties = mirrorProperties;
137 params.ratio = shape.ratio();
138
139 return params;
140}
141
143 KisSharpnessOption *sharpnessOption) const
144{
145 return (textureOption && textureOption->m_enabled) ||
146 (sharpnessOption && sharpnessOption->isChecked());
147}
148
150 DabPosition(const QRect &_rect,
151 const QPointF &_subPixel,
152 qreal _realAngle)
153 : rect(_rect),
154 subPixel(_subPixel),
155 realAngle(_realAngle) {
156 }
157
158 QRect rect;
159 QPointF subPixel;
161};
162
164 qint32 unused = 0;
165 qreal fraction = 0.0;
166 KisPaintOp::splitCoordinate(x, &unused, &fraction);
167
168 return fraction;
169}
170
171inline
174 const QPointF &cursorPoint,
175 KisDabShape shape,
176 const KisPaintInformation& info,
177 const MirrorProperties &mirrorProperties,
178 KisSharpnessOption *sharpnessOption)
179{
180 qint32 x = 0, y = 0;
181 qreal subPixelX = 0.0, subPixelY = 0.0;
182
183 if (mirrorProperties.coordinateSystemFlipped) {
184 shape = KisDabShape(shape.scale(), shape.ratio(), 2 * M_PI - shape.rotation());
185 }
186
187 QPointF hotSpot = brush->hotSpot(shape, info);
188 QPointF pt = cursorPoint - hotSpot;
189
190 if (sharpnessOption) {
191 sharpnessOption->apply(info, pt, x, y, subPixelX, subPixelY);
192 }
193 else {
194 KisPaintOp::splitCoordinate(pt.x(), &x, &subPixelX);
195 KisPaintOp::splitCoordinate(pt.y(), &y, &subPixelY);
196 }
197
199 subPixelX = 0;
200 subPixelY = 0;
201 }
202
203 if (qIsNaN(subPixelX)) {
204 subPixelX = 0;
205 }
206
207 if (qIsNaN(subPixelY)) {
208 subPixelY = 0;
209 }
210
211 int width = brush->maskWidth(shape, subPixelX, subPixelY, info);
212 int height = brush->maskHeight(shape, subPixelX, subPixelY, info);
213
214 if (mirrorProperties.horizontalMirror) {
215 subPixelX = Private::positiveFraction(-(cursorPoint.x() + hotSpot.x()));
216 width = brush->maskWidth(shape, subPixelX, subPixelY, info);
217 x = qRound(cursorPoint.x() + subPixelX + hotSpot.x()) - width;
218 }
219
220 if (mirrorProperties.verticalMirror) {
221 subPixelY = Private::positiveFraction(-(cursorPoint.y() + hotSpot.y()));
222 height = brush->maskHeight(shape, subPixelX, subPixelY, info);
223 y = qRound(cursorPoint.y() + subPixelY + hotSpot.y()) - height;
224 }
225
226 return DabPosition(QRect(x, y, width, height),
227 QPointF(subPixelX, subPixelY),
228 shape.rotation());
229}
230
235 bool *shouldUseCache)
236{
237 di->info = request.info;
238 di->softnessFactor = request.softnessFactor;
239 di->lightnessStrength = request.lightnessStrength;
240
241 if (m_d->mirrorOption) {
242 di->mirrorProperties = m_d->mirrorOption->apply(request.info);
243 }
244
245 DabPosition position = calculateDabRect(resources->brush,
246 request.cursorPoint,
247 request.shape,
248 request.info,
250 resources->sharpnessOption.data());
251 di->shape = KisDabShape(request.shape.scale(), request.shape.ratio(), position.realAngle);
252 di->dstDabRect = position.rect;
253 di->subPixel = position.subPixel;
254
255 const bool supportsCaching = resources->brush->supportsCaching();
256
257 const KisUniformColorSource *uniformColorSource =
258 resources->colorSource ? dynamic_cast<const KisUniformColorSource*>(resources->colorSource.data()) : 0;
259
260 di->solidColorFill = !resources->colorSource || uniformColorSource;
261 di->paintColor = uniformColorSource ?
262 uniformColorSource->uniformColor() : request.color;
263
264 SavedDabParameters newParams = getDabParameters(resources->brush,
265 di->paintColor,
266 di->shape,
267 di->info,
268 di->subPixel.x(),
269 di->subPixel.y(),
270 di->softnessFactor,
272 di->mirrorProperties);
273
274 int precisionLevel = 4;
275 if (m_d->precisionOption) {
276 const int effectiveDabSize = qMin(newParams.width, newParams.height);
277 precisionLevel = m_d->precisionOption->effectivePrecisionLevel(effectiveDabSize) - 1;
278 }
279 *shouldUseCache = hasDabInCache && supportsCaching && di->solidColorFill &&
280 newParams.compare(m_d->lastSavedDabParameters, precisionLevel);
281
282 if (!*shouldUseCache) {
283 m_d->lastSavedDabParameters = newParams;
284 }
285
286 di->needsPostprocessing = needSeparateOriginal(resources->textureOption.data(), resources->sharpnessOption.data());
287}
288
bool isChecked() const
void setPrecisionOption(KisPrecisionOption *option)
KisDabCacheBase::DabPosition calculateDabRect(KisBrushSP brush, const QPointF &cursorPoint, KisDabShape, const KisPaintInformation &info, const MirrorProperties &mirrorProperties, KisSharpnessOption *sharpnessOption)
void fetchDabGenerationInfo(bool hasDabInCache, KisDabCacheUtils::DabRenderingResources *resources, const KisDabCacheUtils::DabRequestInfo &request, KisDabCacheUtils::DabGenerationInfo *di, bool *shouldUseCache)
SavedDabParameters getDabParameters(KisBrushSP brush, const KoColor &color, KisDabShape const &, const KisPaintInformation &info, double subPixelX, double subPixelY, qreal softnessFactor, qreal lightnessStrength, MirrorProperties mirrorProperties)
void setMirrorPostprocessing(KisMirrorOption *option)
bool needSeparateOriginal(KisTextureOption *textureOption, KisSharpnessOption *sharpnessOption) const
qreal scale() const
qreal rotation() const
qreal ratio() const
MirrorProperties apply(const KisPaintInformation &info) const
int effectivePrecisionLevel(qreal effectiveDabSize) const
void apply(const KisPaintInformation &info, const QPointF &pt, qint32 &x, qint32 &y, qreal &xFraction, qreal &yFraction) const
const KoColor & uniformColor() const
static const PrecisionValues precisionLevels[]
const qreal eps
#define M_PI
Definition kis_global.h:111
DabPosition(const QRect &_rect, const QPointF &_subPixel, qreal _realAngle)
KisPrecisionOption * precisionOption
static qreal positiveFraction(qreal x)
SavedDabParameters lastSavedDabParameters
bool compare(const SavedDabParameters &rhs, int precisionLevel) const
QScopedPointer< KisColorSource > colorSource
QScopedPointer< KisSharpnessOption > sharpnessOption
QScopedPointer< KisTextureOption > textureOption
static void splitCoordinate(qreal coordinate, qint32 *whole, qreal *fraction)