2
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
3
* Copyright (c) 2004-2008 Boudewijn Rempt <boud@valdyas.org>
4
* Copyright (c) 2004 Clarence Dang <dang@kde.org>
5
* Copyright (c) 2004 Adrian Page <adrian@pagenet.plus.com>
6
* Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
#include "kis_smudgeop.h"
27
#include <kis_debug.h>
29
#include <KoColorSpaceRegistry.h>
30
#include <KoColorTransformation.h>
32
#include <KoCompositeOp.h>
34
#include <kis_brush.h>
35
#include <kis_global.h>
36
#include <kis_paint_device.h>
37
#include <kis_painter.h>
38
#include <kis_selection.h>
39
#include <kis_brush_based_paintop_settings.h>
41
KisSmudgeOp::KisSmudgeOp(const KisBrushBasedPaintOpSettings *settings, KisPainter *painter, KisImageWSP image)
42
: KisBrushBasedPaintOp(settings, painter)
49
m_sizeOption.readOptionSetting(settings);
50
m_opacityOption.readOptionSetting(settings);
51
m_rateOption.readOptionSetting(settings);
52
m_sizeOption.sensor()->reset();
53
m_opacityOption.sensor()->reset();
54
m_rateOption.sensor()->reset();
56
m_srcdev = new KisPaintDevice(painter->device()->colorSpace());
59
KisSmudgeOp::~KisSmudgeOp()
63
double KisSmudgeOp::paintAt(const KisPaintInformation& info)
65
if (!painter()->device()) return 1.0;
67
KisBrushSP brush = m_brush;
71
if (! brush->canPaintFor(info))
74
double scale = KisPaintOp::scaleForPressure(m_sizeOption.apply(info));
75
if ((scale * brush->width()) <= 0.01 || (scale * brush->height()) <= 0.01) return 1.0;
77
KisPaintDeviceSP device = painter()->device();
78
QPointF hotSpot = brush->hotSpot(scale, scale);
79
QPointF pt = info.pos() - hotSpot;
81
// Split the coordinates into integer plus fractional parts. The integer
82
// is where the dab will be positioned and the fractional part determines
83
// the sub-pixel positioning.
89
splitCoordinate(pt.x(), &x, &xFraction);
90
splitCoordinate(pt.y(), &y, &yFraction);
92
KisFixedPaintDeviceSP dab = 0;
94
QRect dabRect = QRect(0, 0, brush->maskWidth(scale, 0.0), brush->maskHeight(scale, 0.0));
95
QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height());
96
if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return 1.0;
98
if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
99
dab = brush->paintDevice(device->colorSpace(), scale, 0.0, info, xFraction, yFraction);
100
dab->convertTo(KoColorSpaceRegistry::instance()->alpha8());
103
KoColor color = painter()->paintColor();
104
color.convertTo(dab->colorSpace());
105
brush->mask(dab, color, scale, scale, 0.0, info, xFraction, yFraction);
106
dab->convertTo(KoColorSpaceRegistry::instance()->alpha8());
109
qint32 sw = dab->bounds().width();
110
qint32 sh = dab->bounds().height();
113
/* To smudge, one does the following:
114
* at first, initialize a temporary paint device with a copy of the original (dab-sized piece, really).
116
reduce the transparency of the temporary paint device so as to let it mix gradually
117
* combine the temp device with the piece the brush currently is 'painting', according to a mix (opacity)
118
note that in the first step, this does the actual copying of the data
119
* this combination is then composited upon the actual image
120
TODO: what happened exactly in 1.6 (and should happen now) when the dab resizes halfway due to pressure?
122
int opacity = OPACITY_OPAQUE_U8;
126
opacity = m_rateOption.apply(opacity, info);
128
KisRectIterator it = m_srcdev->createRectIterator(sw2, sh2, sw, sh);
129
KoColorSpace* cs = m_srcdev->colorSpace();
130
while (!it.isDone()) {
131
cs->setOpacity(it.rawData(), quint8(cs->opacityF(it.rawData()) * opacity), 1);
134
opacity = OPACITY_OPAQUE_U8 - opacity;
140
KisPainter copyPainter(m_srcdev);
141
copyPainter.setOpacity(opacity);
142
copyPainter.bitBlt(sw2, sh2, device, pt.x(), pt.y(), sw, sh);
145
qint32 sx = dstRect.x() - x + sw2;
146
qint32 sy = dstRect.y() - y + sh2;
147
sw = dstRect.width();
148
sh = dstRect.height();
150
painter()->bitBlt(dstRect.x(), dstRect.y(), m_srcdev, dab, sx, sy, sw, sh);
151
return spacing(scale);