[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-kimageshop
Subject:    Patch: Smudge Brush fixes
From:       Silvio Heinrich <plassy () web ! de>
Date:       2011-01-04 0:20:34
Message-ID: 4D2267D2.6010303 () web ! de
[Download RAW message or body]

Now it should work pretty similar to the smudge tool in gimp.
But I still need to do some tweaks to how the rate values (color and 
smudge rates) are used.
It only smudges/paints correctly in a certain region of the rates.
But the transparency issues should be solved by now, so no black color 
should be introduced anymore (hopefully :P).

["SmudgeBrush.patch" (text/x-diff)]

From db2c5f5cc5aee64ff8af4c6470fe879e09981a18 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Fri, 31 Dec 2010 00:23:07 +0100
Subject: [PATCH 1/6] Fixed (reprogrammed) smudge brush

Reprogrammed the smudge brush with a simpler algorithm.
An option to mix color into the smudge process is also introduced.
---
 .../defaultpaintops/smudge/kis_smudgeop.cpp        |  107 ++++++++++++++++----
 .../paintops/defaultpaintops/smudge/kis_smudgeop.h |    3 +-
 .../smudge/kis_smudgeop_settings_widget.cpp        |   10 +-
 krita/plugins/paintops/libpaintop/CMakeLists.txt   |    2 +
 .../libpaintop/kis_pressure_composite_option.cpp   |   76 ++++++++++++++
 .../libpaintop/kis_pressure_composite_option.h     |   58 +++++++++++
 .../kis_pressure_composite_option_widget.cpp       |  104 +++++++++++++++++++
 .../kis_pressure_composite_option_widget.h         |   46 +++++++++
 8 files changed, 380 insertions(+), 26 deletions(-)
 create mode 100644 krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp
  create mode 100644 \
krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h  create mode 100644 \
krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp  create \
mode 100644 krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h

diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index \
                ee7927f..c8dde6d 100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
@@ -58,11 +58,11 @@ KisSmudgeOp::KisSmudgeOp(const KisBrushBasedPaintOpSettings \
*settings, KisPainte  Q_ASSERT(settings);
     Q_ASSERT(painter);
     m_sizeOption.readOptionSetting(settings);
-    m_opacityOption.readOptionSetting(settings);
     m_rateOption.readOptionSetting(settings);
+    m_compositeOption.readOptionSetting(settings);
     m_sizeOption.sensor()->reset();
-    m_opacityOption.sensor()->reset();
     m_rateOption.sensor()->reset();
+    m_compositeOption.sensor()->reset();
 
     m_tempDev = new KisPaintDevice(painter->device()->colorSpace());
     
@@ -76,9 +76,77 @@ KisSmudgeOp::~KisSmudgeOp()
 {
 }
 
-/* To smudge, one does the following:
 
- 1.- First step: initialize a temporary paint device (m_tempDev) with a copy of the \
colors below the mouse pointer. +
+qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
+{
+    // Simple error catching
+    if (!painter()->device())
+        return 1.0;
+    
+    KisBrushSP brush = m_brush;
+    
+    if(!brush || !brush->canPaintFor(info))
+        return 1.0;
+    
+    double scale = m_sizeOption.apply(info);
+    
+    if((scale*brush->width()) <= 0.01 || (scale*brush->height()) <= 0.01)
+        return 1.0;
+    
+    setCurrentScale(scale);
+    
+    QPointF point = info.pos() - brush->hotSpot(scale, scale);
+    
+    qint32 x, y;
+    qreal xFraction, yFraction;
+    splitCoordinate(point.x(), &x, &xFraction);
+    splitCoordinate(point.y(), &y, &yFraction);
+    
+    KisFixedPaintDeviceSP maskDab = cachedDab(painter()->device()->colorSpace());
+    
+    // Extract the brush mask (maskDab) from brush, and turn it into a transparency \
mask (alpha8). +    if(brush->brushType() == IMAGE || brush->brushType() == \
PIPE_IMAGE) { +        // This is for bitmap brushes
+        maskDab = brush->paintDevice(painter()->device()->colorSpace(), scale, 0.0, \
info, xFraction, yFraction); +    } else {
+        // This is for parametric brushes, those created in the Autobrush popup \
config dialogue +        maskDab = cachedDab();
+        brush->mask(maskDab, painter()->paintColor(), scale, scale, 0.0, info, \
xFraction, yFraction); +    }
+    
+    maskDab->convertTo(KoColorSpaceRegistry::instance()->alpha8());
+    
+    KisPainter copyPainter(m_tempDev);
+    
+    if(m_compositeOption.isChecked()) {
+        m_compositeOption.apply(&copyPainter, OPACITY_OPAQUE_U8, info);
+        
+        copyPainter.setFillStyle(KisPainter::FillStyleForegroundColor);
+        copyPainter.setPaintColor(painter()->paintColor());
+        copyPainter.paintRect(maskDab->bounds());
+    }
+    
+    quint8 newOpacity = m_rateOption.apply(OPACITY_OPAQUE_U8, info);
+    
+    painter()->setOpacity(newOpacity);
+    painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, \
maskDab->bounds().width(), maskDab->bounds().height()); +    \
//painter()->bitBlt(QPoint(x,y), m_tempDev, dab->bounds()); +    
+    m_tempDev->clear(maskDab->bounds());
+    
+    copyPainter.setCompositeOp(COMPOSITE_OVER);
+    copyPainter.setOpacity(OPACITY_OPAQUE_U8);
+    copyPainter.bitBlt(0, 0, painter()->device(), x, y, maskDab->bounds().width(), \
maskDab->bounds().height()); +    copyPainter.end();
+    
+    return spacing(scale);
+}
+
+
+/* To smudge, one does the following:
+ * 
+ 1 *.- First step: initialize a temporary paint device (m_tempDev) with a copy of \
the colors below the mouse pointer.  All other times:
  2.- Vanishing step: Reduce the transparency of the temporary paint device so as to \
let it mix gradually.  3.- Combine: Combine the temporary device with the piece the \
brush currently is 'painting', according to a ratio: @@ -93,8 +161,7 @@ \
KisSmudgeOp::~KisSmudgeOp()  temporary device is cached such that only the colored \
areas are considered.  TODO: Make this cached value dump colors that have faded \
nearly completely and lie outside of the rectangle (dab)  of the current iteration.
-*/
-    
+ *
 qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
 {
     KisBrushSP brush = m_brush;
@@ -109,14 +176,14 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     if ((scale * brush->width()) <= 0.01 || (scale * brush->height()) <= 0.01) \
return 1.0;  setCurrentScale(scale);
     
-    /* Align a point that represents the top-left corner of the \
                brush-stroke-rendering
-    with the mouse pointer and take into account the brush mask size */
+    // Align a point that represents the top-left corner of the \
brush-stroke-rendering +    // with the mouse pointer and take into account the brush \
mask size  QPointF hotSpot = brush->hotSpot(scale, scale);
     QPointF pt = info.pos() - hotSpot;
 
-    /* Split the coordinates into integer plus fractional parts. The integer
-    is where the dab will be positioned and the fractional part determines
-    the sub-pixel positioning. */
+    // Split the coordinates into integer plus fractional parts. The integer
+    //is where the dab will be positioned and the fractional part determines
+    // the sub-pixel positioning.
     qint32 x, y;
     qreal xFraction, yFraction;
 
@@ -141,17 +208,17 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     qint32 sw = maskDab->bounds().width();
     qint32 sh = maskDab->bounds().height();
     
-    /* Prepare the top left corner of the temporary paint device where the extracted \
color will be drawn */ +    // Prepare the top left corner of the temporary paint \
device where the extracted color will be drawn  QPoint extractionTopLeft = \
QPoint(ANCHOR_POINT.x() - sw / 2,  ANCHOR_POINT.y() - sh / 2);
                                       
-    /* In the block below, the opacity of the colors stored in m_tempDev
-    is reduced in opacity. Nothing of the color present inside it is left out */
+    // In the block below, the opacity of the colors stored in m_tempDev
+    // is reduced in opacity. Nothing of the color present inside it is left out
     quint8 opacity = OPACITY_OPAQUE_U8;
     if (!m_firstRun) {
         opacity = m_rateOption.apply(opacity, info);
-        /* Without those limits, the smudge brush doesn't smudge anymore, it either \
                makes a single
-        dropplet of color, or drags a frame indefinitely over the canvas. */
+        // Without those limits, the smudge brush doesn't smudge anymore, it either \
makes a single +        // dropplet of color, or drags a frame indefinitely over the \
                canvas.
         opacity = qBound(MIXABLE_LOWER_LIMIT, opacity, MIXABLE_UPPER_LIMIT);
                 
         // Invert the opacity value for color absorption in the next lines \
(copyPainter) @@ -162,9 +229,9 @@ qreal KisSmudgeOp::paintAt(const \
KisPaintInformation& info)  m_firstRun = false;
         m_wholeTempData = QRect(extractionTopLeft, maskDab->bounds().size());
     }
-    /* copyPainter will extract the piece of color (image) to be duplicated to \
                generate the smudge effect,
-    it extracts a simple unmasked rectangle and adds it to what was extracted before \
                in this same block of code,
-    this sometimes shows artifacts when the brush is used with stylus and high \
spacing */ +    // copyPainter will extract the piece of color (image) to be \
duplicated to generate the smudge effect, +    // it extracts a simple unmasked \
rectangle and adds it to what was extracted before in this same block of code, +    \
// this sometimes shows artifacts when the brush is used with stylus and high spacing \
KisPainter copyPainter(m_tempDev);  copyPainter.setCompositeOp(COMPOSITE_COPY);
     copyPainter.setOpacity(opacity);
@@ -179,4 +246,4 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     renderMirrorMask(QRect(QPoint(x,y),QSize(sw,sh)),m_tempDev,extractionTopLeft.x(), \
extractionTopLeft.y(),maskDab);  
     return spacing(scale);
-}
+}//*/
diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h index 6e3e63f..35a5b64 \
                100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h
@@ -31,6 +31,7 @@
 #include <kis_pressure_opacity_option.h>
 #include <kis_pressure_size_option.h>
 #include <kis_pressure_rate_option.h>
+#include <kis_pressure_composite_option.h>
 
 class KisBrushBasedPaintOpSettings;
 
@@ -56,8 +57,8 @@ private:
     KoColor m_color;
     
     KisPressureSizeOption m_sizeOption;
-    KisPressureOpacityOption m_opacityOption;
     KisPressureRateOption m_rateOption;
+    KisPressureCompositeOption m_compositeOption;
 };
 
 #endif // KIS_SMUDGEOP_H_
diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp \
                index 07a70ca..3f01533 100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp
@@ -24,12 +24,13 @@
 #include "kis_brush_based_paintop_settings.h"
 #include <kis_properties_configuration.h>
 #include <kis_paintop_options_widget.h>
-#include <kis_pressure_darken_option.h>
-#include <kis_pressure_opacity_option.h>
 #include <kis_pressure_size_option.h>
+#include <kis_pressure_composite_option.h>
 #include <kis_pressure_rate_option.h>
 #include <kis_curve_option_widget.h>
 #include <kis_pressure_rate_option_widget.h>
+#include <kis_pressure_composite_option_widget.h>
+
 
 KisSmudgeOpSettingsWidget::KisSmudgeOpSettingsWidget(QWidget* parent)
     : KisBrushBasedPaintopOptionWidget(parent)
@@ -37,9 +38,8 @@ KisSmudgeOpSettingsWidget::KisSmudgeOpSettingsWidget(QWidget* \
parent)  setObjectName("brush option widget");
 
     addPaintOpOption(new KisCurveOptionWidget(new KisPressureSizeOption()));
-    addPaintOpOption(new KisCurveOptionWidget(new KisPressureOpacityOption()));
-    addPaintOpOption(new KisCurveOptionWidget(new KisPressureDarkenOption));
     addPaintOpOption(new KisPressureRateOptionWidget());
+    addPaintOpOption(new KisPressureCompositeOptionWidget());
 
 }
 
@@ -51,7 +51,7 @@ KisPropertiesConfiguration* \
KisSmudgeOpSettingsWidget::configuration() const  {
     KisBrushBasedPaintOpSettings *config = new KisBrushBasedPaintOpSettings();
     config->setOptionsWidget(const_cast<KisSmudgeOpSettingsWidget*>(this));
-    config->setProperty("paintop", "smudge"); // XXX: make this a const id string
+    config->setProperty("paintop", "smudge"); // TODO: make this a const id string
     writeConfiguration(config);
     return config;
 }
diff --git a/krita/plugins/paintops/libpaintop/CMakeLists.txt \
b/krita/plugins/paintops/libpaintop/CMakeLists.txt index 996cafc..b0bc55d 100644
--- a/krita/plugins/paintops/libpaintop/CMakeLists.txt
+++ b/krita/plugins/paintops/libpaintop/CMakeLists.txt
@@ -38,6 +38,8 @@ set(kritalibpaintop_LIB_SRCS
     kis_pressure_size_option.cpp
     kis_pressure_softness_option.cpp
     kis_pressure_mix_option.cpp
+    kis_pressure_composite_option.cpp
+    kis_pressure_composite_option_widget.cpp
     kis_sensor_selector.cc
     kis_text_brush_chooser.cpp
     kis_brush_based_paintop_options_widget.cpp
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp new file mode \
100644 index 0000000..18a9882
--- /dev/null
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp
@@ -0,0 +1,76 @@
+/* This file is part of the KDE project
+ * Copyright (C) Boudewijn Rempt <boud@valdyas.org>, (C) 2008
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_pressure_composite_option.h"
+
+
+#include <klocale.h>
+
+#include <kis_painter.h>
+#include <widgets/kis_curve_widget.h>
+
+#include <KoColor.h>
+#include <KoColorSpace.h>
+#include <KoCompositeOp.h>
+
+KisPressureCompositeOption::KisPressureCompositeOption()
+        : KisCurveOption(i18n("Color"), "Color", KisPaintOpOption::brushCategory(), \
false) +{
+    setMinimumLabel(i18n("Full Color"));
+    setMaximumLabel(i18n("No Color"));
+}
+
+void KisPressureCompositeOption::writeOptionSetting(KisPropertiesConfiguration* \
setting) const +{
+    KisCurveOption::writeOptionSetting(setting);
+    setting->setProperty("CompositeOp", m_compositeOp);
+    setting->setProperty("CompositeRateValue", m_rate);
+}
+
+void KisPressureCompositeOption::readOptionSetting(const KisPropertiesConfiguration* \
setting) +{
+    KisCurveOption::readOptionSetting(setting);
+    m_compositeOp = setting->getString("CompositeOp");
+    m_rate        = setting->getInt("CompositeRateValue");
+    
+    if(m_compositeOp == "") //TODO: test if compositeOp is valid instead of just \
testing for an empty string +        m_compositeOp = COMPOSITE_OVER;
+}
+
+QString KisPressureCompositeOption::apply(KisPainter* painter, qint8 opacity, const \
KisPaintInformation& info) const +{
+    if(!isChecked())
+        return painter->compositeOp()->id();
+    
+    QString oldCompositeOp = painter->compositeOp()->id();
+    
+    opacity = (m_rate * 255) / 100;
+    opacity = qBound((qint32)OPACITY_TRANSPARENT_U8,
+                     (qint32)(double(opacity) * computeValue(info) / \
PRESSURE_DEFAULT), +                     (qint32)OPACITY_OPAQUE_U8);
+    
+    //qreal  opacity1 = (qreal)(painter->opacity() * computeValue(info));
+    //quint8 opacity2 = (quint8)qRound(qBound<qreal>(OPACITY_TRANSPARENT_U8, \
opacity1, OPACITY_OPAQUE_U8)); +    
+    painter->setCompositeOp(m_compositeOp);
+    painter->setOpacity(opacity);
+
+    return oldCompositeOp;
+}
+
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h new file mode \
100644 index 0000000..f05642a
--- /dev/null
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE project
+ * Copyright (C) Boudewijn Rempt <boud@valdyas.org>, (C) 2008
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_PRESSURE_COMPOSITE_OPTION_H
+#define KIS_PRESSURE_COMPOSITE_OPTION_H
+
+#include "kis_curve_option.h"
+#include <kis_paint_information.h>
+#include <krita_export.h>
+#include <kis_types.h>
+
+class QSlider;
+class KisPropertiesConfiguration;
+class KisPainter;
+
+class PAINTOP_EXPORT KisPressureCompositeOption : public KisCurveOption
+{
+public:
+    KisPressureCompositeOption();
+
+    /**
+     * Set the composite mode and opacity of the painter based on the pressure
+     * and the curve (if checked) and return the old composite mode
+     * of the painter.
+     */
+    QString apply(KisPainter* painter, qint8 opacity, const KisPaintInformation& \
info) const; +
+    void writeOptionSetting(KisPropertiesConfiguration* setting) const;
+    void readOptionSetting(const KisPropertiesConfiguration* setting);
+    
+    void setCompositeOp(const QString& compositeOp) { m_compositeOp = compositeOp; }
+    QString getCompositeOp() { return m_compositeOp; }
+    
+    void setRate(int rate) { m_rate = rate; }
+    int getRate() { return m_rate; }
+    
+private:
+    QString m_compositeOp;
+    int     m_rate;
+};
+
+#endif // KIS_PRESSURE_COMPOSITE_OPTION_H
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp new file \
mode 100644 index 0000000..140c628
--- /dev/null
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp
@@ -0,0 +1,104 @@
+/* This file is part of the KDE project
+ * Copyright (C) Boudewijn Rempt <boud@valdyas.org>, (C) 2008
+ * Copyright (C) Sven Langkamp <sven.langkamp@gmail.com>, (C) 2009
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_pressure_composite_option_widget.h"
+#include "kis_pressure_composite_option.h"
+
+#include <KoCompositeOp.h>
+
+#include <QWidget>
+#include <QCheckBox>
+#include <QLabel>
+#include <QComboBox>
+#include <QSlider>
+#include <QVBoxLayout>
+#include <QGridLayout>
+
+#include <klocale.h>
+
+KisPressureCompositeOptionWidget::KisPressureCompositeOptionWidget()
+    : KisCurveOptionWidget(new KisPressureCompositeOption())
+{
+    QWidget* widget    = new QWidget;
+    QLabel*  modeLabel = new QLabel(i18n("Mode: "));
+    QLabel*  rateLabel = new QLabel(i18n("Rate: "));
+    
+    m_compositeOpBox = new QComboBox();
+    m_compositeOpBox->addItem(COMPOSITE_OVER);
+    m_compositeOpBox->addItem(COMPOSITE_OVERLAY);
+    m_compositeOpBox->addItem(COMPOSITE_SCREEN);
+    m_compositeOpBox->addItem(COMPOSITE_ADD);
+    m_compositeOpBox->addItem(COMPOSITE_SUBTRACT);
+    
+    m_rateSlider = new QSlider();
+    m_rateSlider->setMinimum(0);
+    m_rateSlider->setMaximum(100);
+    m_rateSlider->setPageStep(1);
+    m_rateSlider->setValue(90);
+    m_rateSlider->setOrientation(Qt::Horizontal);
+    
+    connect(m_compositeOpBox, SIGNAL(activated(QString)), this, \
SLOT(compositeOpChanged(QString))); +    connect(m_rateSlider, \
SIGNAL(valueChanged(int)), this, SLOT(rateChanged(int))); +    
+    QGridLayout* gridLayout = new QGridLayout();
+    gridLayout->addWidget(modeLabel, 0, 0);
+    gridLayout->addWidget(m_compositeOpBox, 0, 1);
+    gridLayout->addWidget(rateLabel, 1, 0);
+    gridLayout->addWidget(m_rateSlider, 1, 1);
+
+    QVBoxLayout* vBoxLayout = new QVBoxLayout;
+    vBoxLayout->addLayout(gridLayout);
+    vBoxLayout->addWidget(curveWidget());
+
+    widget->setLayout(vBoxLayout);
+    
+    setConfigurationPage(widget);
+    
+    compositeOpChanged(COMPOSITE_OVER);
+    rateChanged(m_rateSlider->value());
+}
+
+void KisPressureCompositeOptionWidget::readOptionSetting(const \
KisPropertiesConfiguration* setting) +{
+    KisCurveOptionWidget::readOptionSetting(setting);
+    
+    QString compositeOp = \
static_cast<KisPressureCompositeOption*>(curveOption())->getCompositeOp(); +    
+    for(int i=0; i<m_compositeOpBox->count(); ++i) {
+        if(m_compositeOpBox->itemText(i) == compositeOp) {
+            m_compositeOpBox->setCurrentIndex(i);
+            break;
+        }
+    }
+    
+    m_rateSlider->setValue(static_cast<KisPressureCompositeOption*>(curveOption())->getRate());
 +}
+
+void KisPressureCompositeOptionWidget::compositeOpChanged(const QString& \
compositeOp) +{
+    static_cast<KisPressureCompositeOption*>(curveOption())->setCompositeOp(compositeOp);
 +    emit sigSettingChanged();
+}
+
+void KisPressureCompositeOptionWidget::rateChanged(int rate)
+{
+    static_cast<KisPressureCompositeOption*>(curveOption())->setRate(rate);
+    emit sigSettingChanged();
+}
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h new file \
mode 100644 index 0000000..6660f72
--- /dev/null
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h
@@ -0,0 +1,46 @@
+/* This file is part of the KDE project
+ * Copyright (C) Sven Langkamp <sven.langkamp@gmail.com>, (C) 2009
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_PRESSURE_COMPOSITE_OPTION_WIDGET_H
+#define KIS_PRESSURE_COMPOSITE_OPTION_WIDGET_H
+
+#include "kis_curve_option_widget.h"
+
+class QComboBox;
+class QSlider;
+
+class PAINTOP_EXPORT KisPressureCompositeOptionWidget : public KisCurveOptionWidget
+{
+    Q_OBJECT
+    
+public:
+    KisPressureCompositeOptionWidget();
+
+    void readOptionSetting(const KisPropertiesConfiguration* setting);
+    
+private slots:
+     void compositeOpChanged(const QString& compositeOp);
+     void rateChanged(int rate);
+    
+private:
+    QComboBox* m_compositeOpBox;
+    QSlider*   m_rateSlider;
+};
+
+#endif // KIS_PRESSURE_COMPOSITE_OPTION_WIDGET_H
-- 
1.7.1


From 11e99bf63e2cff5667b3a2314eaa7e724ac8de37 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Fri, 31 Dec 2010 21:28:09 +0100
Subject: [PATCH 2/6] Some cleanup and documentation and added more composite modes to \
KisPressureCompositeOptionWidget.

---
 .../defaultpaintops/smudge/kis_smudgeop.cpp        |  163 ++++----------------
 .../paintops/defaultpaintops/smudge/kis_smudgeop.h |    8 +-
 .../libpaintop/kis_pressure_composite_option.cpp   |    7 +-
 .../libpaintop/kis_pressure_composite_option.h     |    7 +-
 .../kis_pressure_composite_option_widget.cpp       |    6 +
 5 files changed, 42 insertions(+), 149 deletions(-)

diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index \
                c8dde6d..372a1b7 100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
@@ -40,19 +40,8 @@
 #include <kis_selection.h>
 #include <kis_brush_based_paintop_settings.h>
 
-
-// Both limits defined to be 15 units away from the min (0) or max (255) to allow \
                actual mixing of colors
-const quint8 MIXABLE_UPPER_LIMIT = 240;
-const quint8 MIXABLE_LOWER_LIMIT = 15;
-
-// All pieces of color extracted from the canvas will be centered around \
                ANCHOR_POINT
-const QPoint ANCHOR_POINT = QPoint(0, 0);
-
-
 KisSmudgeOp::KisSmudgeOp(const KisBrushBasedPaintOpSettings *settings, KisPainter \
                *painter, KisImageWSP image)
-        : KisBrushBasedPaintOp(settings, painter)
-        , m_firstRun(true)
-        , m_tempDev(0)
+        : KisBrushBasedPaintOp(settings, painter), m_tempDev(0)
 {
     Q_UNUSED(image);
     Q_ASSERT(settings);
@@ -65,11 +54,6 @@ KisSmudgeOp::KisSmudgeOp(const KisBrushBasedPaintOpSettings \
*settings, KisPainte  m_compositeOption.sensor()->reset();
 
     m_tempDev = new KisPaintDevice(painter->device()->colorSpace());
-    
-    // Initializing to a valid value to avoid weird errors during modifications
-    m_wholeTempData = QRect(0, 0, 0, 0);
-    
-    m_color = painter->paintColor();
 }
 
 KisSmudgeOp::~KisSmudgeOp()
@@ -89,8 +73,10 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     if(!brush || !brush->canPaintFor(info))
         return 1.0;
     
+    // get the scaling factor calculated by the size option
     double scale = m_sizeOption.apply(info);
     
+    // don't paint anything if the brush is too samll
     if((scale*brush->width()) <= 0.01 || (scale*brush->height()) <= 0.01)
         return 1.0;
     
@@ -105,7 +91,7 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     
     KisFixedPaintDeviceSP maskDab = cachedDab(painter()->device()->colorSpace());
     
-    // Extract the brush mask (maskDab) from brush, and turn it into a transparency \
mask (alpha8). +    // Extract the brush mask (maskDab) from brush with the correct \
scaled size  if(brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
         // This is for bitmap brushes
         maskDab = brush->paintDevice(painter()->device()->colorSpace(), scale, 0.0, \
info, xFraction, yFraction); @@ -115,135 +101,46 @@ qreal KisSmudgeOp::paintAt(const \
                KisPaintInformation& info)
         brush->mask(maskDab, painter()->paintColor(), scale, scale, 0.0, info, \
xFraction, yFraction);  }
     
+    // transforms the fixed paint device with the current brush to alpha color space \
(to use it as alpha/transparency mask)  \
maskDab->convertTo(KoColorSpaceRegistry::instance()->alpha8());  
-    KisPainter copyPainter(m_tempDev);
-    
-    if(m_compositeOption.isChecked()) {
-        m_compositeOption.apply(&copyPainter, OPACITY_OPAQUE_U8, info);
-        
-        copyPainter.setFillStyle(KisPainter::FillStyleForegroundColor);
-        copyPainter.setPaintColor(painter()->paintColor());
-        copyPainter.paintRect(maskDab->bounds());
-    }
-    
+    // GET the opacy calculated by the rate option (apply is misleading because the \
opacy will not be applied)  quint8 newOpacity = m_rateOption.apply(OPACITY_OPAQUE_U8, \
info);  
+    // set opacity calculated by the rate option
+    // then blit the temporary painting device on the canvas at the current brush \
position +    // the alpha mask (maskDab) will be used here to only blit the pixels \
that lie in the area (shape) of the brush  painter()->setOpacity(newOpacity);
     painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, \
                maskDab->bounds().width(), maskDab->bounds().height());
-    //painter()->bitBlt(QPoint(x,y), m_tempDev, dab->bounds());
     
+    // IMPORTANT: clear the temporary painting device to color black with zero \
opacity +    //            it will only clear the extents of the brush
     m_tempDev->clear(maskDab->bounds());
     
+    KisPainter copyPainter(m_tempDev);
+    
+    // reset composite mode and opacity
+    // then cut out the area from the canvas under the brush
+    // and blit it to the temporary painting device
     copyPainter.setCompositeOp(COMPOSITE_OVER);
     copyPainter.setOpacity(OPACITY_OPAQUE_U8);
     copyPainter.bitBlt(0, 0, painter()->device(), x, y, maskDab->bounds().width(), \
                maskDab->bounds().height());
-    copyPainter.end();
-    
-    return spacing(scale);
-}
-
-
-/* To smudge, one does the following:
- * 
- 1 *.- First step: initialize a temporary paint device (m_tempDev) with a copy of \
                the colors below the mouse pointer.
- All other times:
- 2.- Vanishing step: Reduce the transparency of the temporary paint device so as to \
                let it mix gradually.
- 3.- Combine: Combine the temporary device with the piece the brush currently is \
                'painting', according to a ratio:
- in this case, opacity. (This is what in the first step does the copying of the \
                data).
- 4.- Blit to screen: This combination is then composited upon the actual image.
- 5.- Special case: If the size of the dab (brush mask) changes during the stroke \
                (for example, when
- using a stylus sensitive to pressure), align the colors extracted to the center of \
                the previously absorbed colors,
- and in the vanishing step, ensure that all the colors have their opacity slowly \
                reduced, not just the ones below
- the current brush mask.
- 
- For the sake of speed optimization, the extent of the largest area of color \
                contained in the
- temporary device is cached such that only the colored areas are considered.
- TODO: Make this cached value dump colors that have faded nearly completely and lie \
                outside of the rectangle (dab)
- of the current iteration.
- *
-qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
-{
-    KisBrushSP brush = m_brush;
     
-    // Simple error catching
-    if (!painter()->device()) return 1.0;
-    if (!brush) return 1.0;
-    if (!brush->canPaintFor(info)) return 1.0;
-
-    // Grow the brush (this includes the mask) according to pressure or other \
                parameters
-    double scale = m_sizeOption.apply(info);
-    if ((scale * brush->width()) <= 0.01 || (scale * brush->height()) <= 0.01) \
                return 1.0;
-    setCurrentScale(scale);
-    
-    // Align a point that represents the top-left corner of the \
                brush-stroke-rendering
-    // with the mouse pointer and take into account the brush mask size
-    QPointF hotSpot = brush->hotSpot(scale, scale);
-    QPointF pt = info.pos() - hotSpot;
-
-    // Split the coordinates into integer plus fractional parts. The integer
-    //is where the dab will be positioned and the fractional part determines
-    // the sub-pixel positioning.
-    qint32 x, y;
-    qreal xFraction, yFraction;
-
-    splitCoordinate(pt.x(), &x, &xFraction);
-    splitCoordinate(pt.y(), &y, &yFraction);
-
-    KisFixedPaintDeviceSP maskDab = 0;
-
-    // Extract the brush mask (maskDab) from brush, and turn it into a transparency \
                mask (alpha8).
-    if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
-        // This is for bitmap brushes
-        maskDab = brush->paintDevice(painter()->device()->colorSpace(), scale, 0.0, \
                info, xFraction, yFraction);
-        maskDab->convertTo(KoColorSpaceRegistry::instance()->alpha8());
-    } else {
-        // This is for parametric brushes, those created in the Autobrush popup \
                config dialogue
-        maskDab = cachedDab();
-        brush->mask(maskDab, m_color, scale, scale, 0.0, info, xFraction, \
                yFraction);
-        maskDab->convertTo(KoColorSpaceRegistry::instance()->alpha8());
-    }
-
-    // Convenient renaming for the limits of the maskDab
-    qint32 sw = maskDab->bounds().width();
-    qint32 sh = maskDab->bounds().height();
-    
-    // Prepare the top left corner of the temporary paint device where the extracted \
                color will be drawn
-    QPoint extractionTopLeft = QPoint(ANCHOR_POINT.x() - sw / 2,
-                                      ANCHOR_POINT.y() - sh / 2);
-                                      
-    // In the block below, the opacity of the colors stored in m_tempDev
-    // is reduced in opacity. Nothing of the color present inside it is left out
-    quint8 opacity = OPACITY_OPAQUE_U8;
-    if (!m_firstRun) {
-        opacity = m_rateOption.apply(opacity, info);
-        // Without those limits, the smudge brush doesn't smudge anymore, it either \
                makes a single
-        // dropplet of color, or drags a frame indefinitely over the canvas.
-        opacity = qBound(MIXABLE_LOWER_LIMIT, opacity, MIXABLE_UPPER_LIMIT);
-                
-        // Invert the opacity value for color absorption in the next lines \
                (copyPainter)
-        opacity = OPACITY_OPAQUE_U8 - opacity;
-        m_wholeTempData |= QRect(extractionTopLeft, maskDab->bounds().size());
-    }
-    else {
-        m_firstRun = false;
-        m_wholeTempData = QRect(extractionTopLeft, maskDab->bounds().size());
+    // if the user selected the color smudge option
+    // we will mix some color into the temorary painting device (m_tempDev)
+    if(m_compositeOption.isChecked()) {
+        // this will apply the composite mode and the opacy (selected by the user)
+        // to copyPainter
+        m_compositeOption.apply(&copyPainter, OPACITY_OPAQUE_U8, info);
+        
+        // paint a rectangle with the current color (foreground color)
+        // into the temporary painting device
+        copyPainter.setFillStyle(KisPainter::FillStyleForegroundColor);
+        copyPainter.setPaintColor(painter()->paintColor());
+        copyPainter.paintRect(maskDab->bounds());
     }
-    // copyPainter will extract the piece of color (image) to be duplicated to \
                generate the smudge effect,
-    // it extracts a simple unmasked rectangle and adds it to what was extracted \
                before in this same block of code,
-    // this sometimes shows artifacts when the brush is used with stylus and high \
                spacing
-    KisPainter copyPainter(m_tempDev);
-    copyPainter.setCompositeOp(COMPOSITE_COPY);
-    copyPainter.setOpacity(opacity);
-    copyPainter.bitBlt(m_wholeTempData.x(), m_wholeTempData.y(), \
                painter()->device(),
-                       x - m_wholeTempData.x() + extractionTopLeft.x(),
-                       y - m_wholeTempData.y() + extractionTopLeft.y(),
-                       m_wholeTempData.width(), m_wholeTempData.height());
-    copyPainter.end();
     
-    // This is the line that renders the extracted colors to the screen, with \
                maskDab giving it the brush shape
-    painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, 0, 0, \
                extractionTopLeft.x(), extractionTopLeft.y(), sw, sh);
-    renderMirrorMask(QRect(QPoint(x,y),QSize(sw,sh)),m_tempDev,extractionTopLeft.x(), \
extractionTopLeft.y(),maskDab); +    copyPainter.end();
     
     return spacing(scale);
-}//*/
+}
diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h index 35a5b64..5948e04 \
                100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h
@@ -49,13 +49,7 @@ public:
     qreal paintAt(const KisPaintInformation& info);
 
 private:
-    bool m_firstRun;
-    // The "temporary paint device"
-    KisPaintDeviceSP m_tempDev;
-    // The size of the rectangle encompassing the whole data in the temporary device \
                needs to be cached for speed
-    QRect m_wholeTempData;
-    KoColor m_color;
-    
+    KisPaintDeviceSP m_tempDev; // The temporary paint device
     KisPressureSizeOption m_sizeOption;
     KisPressureRateOption m_rateOption;
     KisPressureCompositeOption m_compositeOption;
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp index \
                18a9882..ca09eb6 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp
@@ -30,7 +30,7 @@
 #include <KoCompositeOp.h>
 
 KisPressureCompositeOption::KisPressureCompositeOption()
-        : KisCurveOption(i18n("Color"), "Color", KisPaintOpOption::brushCategory(), \
false) +    : KisCurveOption(i18n("Color"), "Color", \
KisPaintOpOption::brushCategory(), false)  {
     setMinimumLabel(i18n("Full Color"));
     setMaximumLabel(i18n("No Color"));
@@ -53,7 +53,7 @@ void KisPressureCompositeOption::readOptionSetting(const \
KisPropertiesConfigurat  m_compositeOp = COMPOSITE_OVER;
 }
 
-QString KisPressureCompositeOption::apply(KisPainter* painter, qint8 opacity, const \
KisPaintInformation& info) const +void KisPressureCompositeOption::apply(KisPainter* \
painter, qint8 opacity, const KisPaintInformation& info) const  {
     if(!isChecked())
         return painter->compositeOp()->id();
@@ -65,9 +65,6 @@ QString KisPressureCompositeOption::apply(KisPainter* painter, \
                qint8 opacity, co
                      (qint32)(double(opacity) * computeValue(info) / \
PRESSURE_DEFAULT),  (qint32)OPACITY_OPAQUE_U8);
     
-    //qreal  opacity1 = (qreal)(painter->opacity() * computeValue(info));
-    //quint8 opacity2 = (quint8)qRound(qBound<qreal>(OPACITY_TRANSPARENT_U8, \
                opacity1, OPACITY_OPAQUE_U8));
-    
     painter->setCompositeOp(m_compositeOp);
     painter->setOpacity(opacity);
 
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h index \
                f05642a..2ba3d8b 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h
@@ -35,11 +35,10 @@ public:
     KisPressureCompositeOption();
 
     /**
-     * Set the composite mode and opacity of the painter based on the pressure
-     * and the curve (if checked) and return the old composite mode
-     * of the painter.
+     * Set the composite mode and opacity of the painter based on the user selection
+     * and the pressure curve (if checked)
      */
-    QString apply(KisPainter* painter, qint8 opacity, const KisPaintInformation& \
info) const; +    void apply(KisPainter* painter, qint8 opacity, const \
KisPaintInformation& info) const;  
     void writeOptionSetting(KisPropertiesConfiguration* setting) const;
     void readOptionSetting(const KisPropertiesConfiguration* setting);
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp index \
                140c628..6f17544 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp
@@ -46,6 +46,12 @@ KisPressureCompositeOptionWidget::KisPressureCompositeOptionWidget()
  m_compositeOpBox->addItem(COMPOSITE_SCREEN);
     m_compositeOpBox->addItem(COMPOSITE_ADD);
     m_compositeOpBox->addItem(COMPOSITE_SUBTRACT);
+    m_compositeOpBox->addItem(COMPOSITE_DIVIDE);
+    m_compositeOpBox->addItem(COMPOSITE_BURN);
+    m_compositeOpBox->addItem(COMPOSITE_DODGE);
+    m_compositeOpBox->addItem(COMPOSITE_COLOR);
+    m_compositeOpBox->addItem(COMPOSITE_HARD_LIGHT);
+    m_compositeOpBox->addItem(COMPOSITE_SOFT_LIGHT);
     
     m_rateSlider = new QSlider();
     m_rateSlider->setMinimum(0);
-- 
1.7.1


From aa6eb274013a01d46d97d05a6a45f4f3ff9bc2e5 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Mon, 3 Jan 2011 00:43:51 +0100
Subject: [PATCH 3/6] Fixed the handling of transparency for the smudge brush.

Implemented the COMPOSITE_COPY_OPACY mode to fix it
---
 .../defaultpaintops/smudge/kis_smudgeop.cpp        |   28 +++--
 .../paintops/defaultpaintops/smudge/kis_smudgeop.h |    2 +
 .../smudge/kis_smudgeop_settings_widget.cpp        |    1 +
 .../libpaintop/kis_pressure_composite_option.cpp   |   10 +-
 .../libpaintop/kis_pressure_composite_option.h     |    2 +-
 .../kis_pressure_composite_option_widget.cpp       |    3 +-
 .../kis_pressure_composite_option_widget.h         |    2 +-
 libs/pigment/compositeops/KoCompositeOpCopyOpacy.h |  133 ++++++++++++++++++++
 libs/pigment/compositeops/KoCompositeOps.h         |    5 +-
 9 files changed, 165 insertions(+), 21 deletions(-)
 create mode 100644 libs/pigment/compositeops/KoCompositeOpCopyOpacy.h

diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index \
                372a1b7..0dabf9a 100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
@@ -6,6 +6,7 @@
  *  Copyright (c) 2004,2010 Cyrille Berger <cberger@cberger.net>
  *  Copyright (c) 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
  *  Copyright (c) 2010 José Luis Vergara Toloza <pentalis@gmail.com>
+ *  Copyright (C) 2011 Silvio Heinrich <plassy@web.de>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -53,7 +54,8 @@ KisSmudgeOp::KisSmudgeOp(const KisBrushBasedPaintOpSettings \
*settings, KisPainte  m_rateOption.sensor()->reset();
     m_compositeOption.sensor()->reset();
 
-    m_tempDev = new KisPaintDevice(painter->device()->colorSpace());
+    m_tempDev  = new KisPaintDevice(painter->device()->colorSpace());
+    m_firstRun = true;
 }
 
 KisSmudgeOp::~KisSmudgeOp()
@@ -89,7 +91,7 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     splitCoordinate(point.x(), &x, &xFraction);
     splitCoordinate(point.y(), &y, &yFraction);
     
-    KisFixedPaintDeviceSP maskDab = cachedDab(painter()->device()->colorSpace());
+    KisFixedPaintDeviceSP maskDab = 0;
     
     // Extract the brush mask (maskDab) from brush with the correct scaled size
     if(brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
@@ -107,15 +109,22 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     // GET the opacy calculated by the rate option (apply is misleading because the \
opacy will not be applied)  quint8 newOpacity = m_rateOption.apply(OPACITY_OPAQUE_U8, \
info);  
-    // set opacity calculated by the rate option
-    // then blit the temporary painting device on the canvas at the current brush \
                position
-    // the alpha mask (maskDab) will be used here to only blit the pixels that lie \
                in the area (shape) of the brush
-    painter()->setOpacity(newOpacity);
-    painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, \
maskDab->bounds().width(), maskDab->bounds().height()); +    if(!m_firstRun) {
+        // set opacity calculated by the rate option
+        // then blit the temporary painting device on the canvas at the current \
brush position +        // the alpha mask (maskDab) will be used here to only blit \
the pixels that lie in the area (shape) of the brush +        \
painter()->setOpacity(newOpacity / 2); +        \
painter()->setCompositeOp(COMPOSITE_OVER); +        \
painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, \
maskDab->bounds().width(), maskDab->bounds().height()); +        \
painter()->setOpacity(newOpacity); +        \
painter()->setCompositeOp(COMPOSITE_COPY_OPACITY); +        \
painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, \
maskDab->bounds().width(), maskDab->bounds().height()); +    }
+    else m_firstRun = false;
     
     // IMPORTANT: clear the temporary painting device to color black with zero \
opacity  //            it will only clear the extents of the brush
-    m_tempDev->clear(maskDab->bounds());
+    m_tempDev->clear(QRect(0, 0, brush->width(), brush->height()));
     
     KisPainter copyPainter(m_tempDev);
     
@@ -124,7 +133,7 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     // and blit it to the temporary painting device
     copyPainter.setCompositeOp(COMPOSITE_OVER);
     copyPainter.setOpacity(OPACITY_OPAQUE_U8);
-    copyPainter.bitBlt(0, 0, painter()->device(), x, y, maskDab->bounds().width(), \
maskDab->bounds().height()); +    copyPainter.bitBlt(0, 0, painter()->device(), x, y, \
brush->width(), brush->width());  
     // if the user selected the color smudge option
     // we will mix some color into the temorary painting device (m_tempDev)
@@ -141,6 +150,5 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     }
     
     copyPainter.end();
-    
     return spacing(scale);
 }
diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h index 5948e04..333df09 \
                100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h
@@ -5,6 +5,7 @@
  *  Copyright (c) 2004 Adrian Page <adrian@pagenet.plus.com>
  *  Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
  *  Copyright (c) 2010 José Luis Vergara Toloza <pentalis@gmail.com>
+ *  Copyright (C) 2011 Silvio Heinrich <plassy@web.de>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -49,6 +50,7 @@ public:
     qreal paintAt(const KisPaintInformation& info);
 
 private:
+    bool             m_firstRun;
     KisPaintDeviceSP m_tempDev; // The temporary paint device
     KisPressureSizeOption m_sizeOption;
     KisPressureRateOption m_rateOption;
diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp \
                index 3f01533..a07d7f4 100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop_settings_widget.cpp
@@ -4,6 +4,7 @@
  *  Copyright (c) 2004 Clarence Dang <dang@kde.org>
  *  Copyright (c) 2004 Adrian Page <adrian@pagenet.plus.com>
  *  Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
+ *  Copyright (C) 2011 Silvio Heinrich <plassy@web.de>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp index \
                ca09eb6..6d82865 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp
@@ -1,5 +1,5 @@
 /* This file is part of the KDE project
- * Copyright (C) Boudewijn Rempt <boud@valdyas.org>, (C) 2008
+ * Copyright (C) Silvio Heinrich <plassy@web.de>, (C) 2011
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -32,8 +32,8 @@
 KisPressureCompositeOption::KisPressureCompositeOption()
     : KisCurveOption(i18n("Color"), "Color", KisPaintOpOption::brushCategory(), \
false)  {
-    setMinimumLabel(i18n("Full Color"));
-    setMaximumLabel(i18n("No Color"));
+    setMinimumLabel(i18n("No Color"));
+    setMaximumLabel(i18n("Full Color"));
 }
 
 void KisPressureCompositeOption::writeOptionSetting(KisPropertiesConfiguration* \
setting) const @@ -56,7 +56,7 @@ void \
KisPressureCompositeOption::readOptionSetting(const KisPropertiesConfigurat  void \
KisPressureCompositeOption::apply(KisPainter* painter, qint8 opacity, const \
KisPaintInformation& info) const  {
     if(!isChecked())
-        return painter->compositeOp()->id();
+        return;
     
     QString oldCompositeOp = painter->compositeOp()->id();
     
@@ -67,7 +67,5 @@ void KisPressureCompositeOption::apply(KisPainter* painter, qint8 \
opacity, const  
     painter->setCompositeOp(m_compositeOp);
     painter->setOpacity(opacity);
-
-    return oldCompositeOp;
 }
 
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h index \
                2ba3d8b..1ed6ff7 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h
@@ -1,5 +1,5 @@
 /* This file is part of the KDE project
- * Copyright (C) Boudewijn Rempt <boud@valdyas.org>, (C) 2008
+ * Copyright (C) Silvio Heinrich <plassy@web.de>, (C) 2011
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp index \
                6f17544..f075a3c 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp
@@ -1,6 +1,5 @@
 /* This file is part of the KDE project
- * Copyright (C) Boudewijn Rempt <boud@valdyas.org>, (C) 2008
- * Copyright (C) Sven Langkamp <sven.langkamp@gmail.com>, (C) 2009
+ * Copyright (C) Silvio Heinrich <plassy@web.de>, (C) 2011
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h index \
                6660f72..30c09ce 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h
@@ -1,5 +1,5 @@
 /* This file is part of the KDE project
- * Copyright (C) Sven Langkamp <sven.langkamp@gmail.com>, (C) 2009
+ * Copyright (C) Silvio Heinrich <plassy@web.de>, (C) 2011
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
diff --git a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h \
b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h new file mode 100644
index 0000000..97dcbfd
--- /dev/null
+++ b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h
@@ -0,0 +1,133 @@
+/*
+ *  Copyright (c) 2008 Silvio Heinrich <plassy@web.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KOCOMPOSITEOPCOPYOPACY_H_
+#define KOCOMPOSITEOPCOPYOPACY_H_
+
+#include <KoColorSpaceMaths.h>
+#include <KoCompositeOp.h>
+#include <KoColorSpaceConstants.h>
+
+/**
+ * A template version of the copy opacy composite operation to use in colorspaces.
+ */
+template<class _CSTraits>
+class KoCompositeOpCopyOpacy : public KoCompositeOp
+{
+    typedef typename _CSTraits::channels_type channels_type;
+    static const qint32 channels_nb = _CSTraits::channels_nb;
+    static const qint32 alpha_pos   = _CSTraits::alpha_pos;
+    static const qint32 pixelSize   = _CSTraits::pixelSize;
+    
+public:
+    KoCompositeOpCopyOpacy(const KoColorSpace * cs)
+        : KoCompositeOp(cs, COMPOSITE_COPY_OPACITY, i18n("Copy Opacy"), \
KoCompositeOp::categoryArithmetic(), true) { +    }
+    
+public:
+    inline static channels_type selectAlpha(channels_type srcAlpha, channels_type \
dstAlpha) { +        return qMin(srcAlpha, dstAlpha);
+    }
+    
+    void composite(quint8 *dstRowStart,
+                   qint32 dstRowStride,
+                   const quint8 *srcRowStart,
+                   qint32 srcRowStride,
+                   const quint8 *maskRowStart,
+                   qint32 maskRowStride,
+                   qint32 rows,
+                   qint32 cols,
+                   quint8 U8_opacity,
+                   const QBitArray & channelFlags) const
+    {
+        bool          useMask = maskRowStart != 0;
+        channels_type opacity = \
KoColorSpaceMaths<quint8,channels_type>::scaleToA(U8_opacity); +        
+        if(srcRowStride != 0) {
+            for(; rows>0; --rows) {
+                const quint8*        mskRowItr = maskRowStart;
+                const channels_type* srcRowItr = reinterpret_cast<const \
channels_type*>(srcRowStart) + alpha_pos; +                channels_type*       \
dstRowItr = reinterpret_cast<channels_type*>(dstRowStart) + alpha_pos; +              \
 +                for(qint32 c=cols; c>0; --c) {
+                    channels_type value = 0;
+                    
+                    switch(U8_opacity)
+                    {
+                    case OPACITY_TRANSPARENT_U8: { value = *dstRowItr; } break;
+                    case OPACITY_OPAQUE_U8:      { value = *srcRowItr; } break;
+                    default: { value = \
KoColorSpaceMaths<channels_type>::blend(*srcRowItr, *dstRowItr, opacity); } break; +  \
} +                    
+                    if(useMask) {
+                        channels_type blend = \
KoColorSpaceMaths<quint8,channels_type>::scaleToA(*mskRowItr); +                      \
value = KoColorSpaceMaths<channels_type>::blend(value, *dstRowItr, blend); +          \
value = (value > *dstRowItr) ? (value-1) : value; +                        \
++mskRowItr; +                    }
+                    
+                    *dstRowItr = value;
+                    srcRowItr += channels_nb;
+                    dstRowItr += channels_nb;
+                    
+                }
+                
+                srcRowStart  += srcRowStride;
+                dstRowStart  += dstRowStride;
+                maskRowStart += maskRowStride;
+            }
+        }
+        else {
+            channels_type srcValue = *(reinterpret_cast<const \
channels_type*>(srcRowStart) + alpha_pos); +            
+            for(; rows>0; --rows) {
+                const quint8*  mskRowItr = maskRowStart;
+                channels_type* dstRowItr = \
reinterpret_cast<channels_type*>(dstRowStart) + alpha_pos; +                
+                for(qint32 c=cols; c>0; --c) {
+                    channels_type value = 0;
+                    
+                    switch(U8_opacity)
+                    {
+                        case OPACITY_TRANSPARENT_U8: { value = *dstRowItr; } break;
+                        case OPACITY_OPAQUE_U8:      { value = srcValue;   } break;
+                        default: { value = \
KoColorSpaceMaths<channels_type>::blend(srcValue, *dstRowItr, opacity); } break; +    \
} +                    
+                    if(useMask) {
+                        channels_type blend = \
KoColorSpaceMaths<quint8,channels_type>::scaleToA(*mskRowItr); +                      \
value = KoColorSpaceMaths<channels_type>::blend(value, *dstRowItr, blend); +          \
value = (value > *dstRowItr) ? (value-1) : value; +                        \
++mskRowItr; +                    }
+                    
+                    *dstRowItr = value;
+                    dstRowItr += channels_nb;
+                }
+                
+                srcRowStart  += srcRowStride;
+                dstRowStart  += dstRowStride;
+                maskRowStart += maskRowStride;
+            }
+        }
+    }
+                                            
+};
+
+#endif // KOCOMPOSITEOPCOPYOPACY_H_
diff --git a/libs/pigment/compositeops/KoCompositeOps.h \
b/libs/pigment/compositeops/KoCompositeOps.h index d278234..b222f32 100644
--- a/libs/pigment/compositeops/KoCompositeOps.h
+++ b/libs/pigment/compositeops/KoCompositeOps.h
@@ -1,5 +1,6 @@
 /*
- *  Copyright (c) 2007 Cyrille Berger <cberger@cberger.net>
+ * Copyright (c) 2007 Cyrille Berger <cberger@cberger.net>
+ * Copyright (c) 2011 Silvio Heinrich <plassy@web.de>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -37,6 +38,7 @@
 #include "compositeops/KoCompositeOpSoftlight.h"
 #include "compositeops/KoCompositeOpHardlight.h"
 #include "compositeops/KoCompositeOpCopy2.h"
+#include "compositeops/KoCompositeOpCopyOpacy.h"
 
 /**
  * This function add to the colorspace all the composite ops defined by
@@ -59,6 +61,7 @@ void addStandardCompositeOps(KoColorSpace* cs)
     cs->addCompositeOp(new KoCompositeOpSubtract<_Traits_>(cs));
     cs->addCompositeOp(new KoCompositeOpSoftlight<_Traits_>(cs));
     cs->addCompositeOp(new KoCompositeOpHardlight<_Traits_>(cs));
+    cs->addCompositeOp(new KoCompositeOpCopyOpacy<_Traits_>(cs));
 }
 
 #endif
-- 
1.7.1


From bf5ed07167a9bd844c5c0aa608488a26b0d6367b Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Mon, 3 Jan 2011 21:34:41 +0100
Subject: [PATCH 4/6] Fixed some gliches introducing transparency and black color \
where it should not be.

---
 .../defaultpaintops/smudge/kis_smudgeop.cpp        |    6 +++---
 libs/pigment/compositeops/KoCompositeOpCopyOpacy.h |    7 +++----
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index \
                0dabf9a..ef48e1f 100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
@@ -87,7 +87,7 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     QPointF point = info.pos() - brush->hotSpot(scale, scale);
     
     qint32 x, y;
-    qreal xFraction, yFraction;
+    qreal xFraction, yFraction; // will not be used
     splitCoordinate(point.x(), &x, &xFraction);
     splitCoordinate(point.y(), &y, &yFraction);
     
@@ -96,11 +96,11 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     // Extract the brush mask (maskDab) from brush with the correct scaled size
     if(brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
         // This is for bitmap brushes
-        maskDab = brush->paintDevice(painter()->device()->colorSpace(), scale, 0.0, \
info, xFraction, yFraction); +        maskDab = \
brush->paintDevice(painter()->device()->colorSpace(), scale, 0.0, info, 0.0, 0.0);  } \
                else {
         // This is for parametric brushes, those created in the Autobrush popup \
config dialogue  maskDab = cachedDab();
-        brush->mask(maskDab, painter()->paintColor(), scale, scale, 0.0, info, \
xFraction, yFraction); +        brush->mask(maskDab, painter()->paintColor(), scale, \
scale, 0.0, info, 0.0, 0.0);  }
     
     // transforms the fixed paint device with the current brush to alpha color space \
                (to use it as alpha/transparency mask)
diff --git a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h \
b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h index 97dcbfd..48f63ce 100644
--- a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h
+++ b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h
@@ -78,14 +78,13 @@ public:
                     if(useMask) {
                         channels_type blend = \
                KoColorSpaceMaths<quint8,channels_type>::scaleToA(*mskRowItr);
                         value = KoColorSpaceMaths<channels_type>::blend(value, \
                *dstRowItr, blend);
-                        value = (value > *dstRowItr) ? (value-1) : value;
                         ++mskRowItr;
                     }
                     
+                    value      = (value > *dstRowItr) ? (value-1) : value;
                     *dstRowItr = value;
                     srcRowItr += channels_nb;
                     dstRowItr += channels_nb;
-                    
                 }
                 
                 srcRowStart  += srcRowStride;
@@ -113,10 +112,10 @@ public:
                     if(useMask) {
                         channels_type blend = \
                KoColorSpaceMaths<quint8,channels_type>::scaleToA(*mskRowItr);
                         value = KoColorSpaceMaths<channels_type>::blend(value, \
                *dstRowItr, blend);
-                        value = (value > *dstRowItr) ? (value-1) : value;
                         ++mskRowItr;
                     }
                     
+                    value      = (value > *dstRowItr) ? (value-1) : value;
                     *dstRowItr = value;
                     dstRowItr += channels_nb;
                 }
@@ -127,7 +126,7 @@ public:
             }
         }
     }
-                                            
+    
 };
 
 #endif // KOCOMPOSITEOPCOPYOPACY_H_
-- 
1.7.1


From f72641b0df5016f8e11085365110e808aeb1edae Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Tue, 4 Jan 2011 00:49:28 +0100
Subject: [PATCH 5/6] Opacity adjustment.

---
 .../defaultpaintops/smudge/kis_smudgeop.cpp        |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index \
                ef48e1f..e03121f 100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
@@ -112,8 +112,8 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     if(!m_firstRun) {
         // set opacity calculated by the rate option
         // then blit the temporary painting device on the canvas at the current \
                brush position
-        // the alpha mask (maskDab) will be used here to only blit the pixels that \
                lie in the area (shape) of the brush
-        painter()->setOpacity(newOpacity / 2);
+        // the alpha mask (maskDab) will be used here to only blit the pixels that \
are in the area (shape) of the brush +        painter()->setOpacity(newOpacity);
         painter()->setCompositeOp(COMPOSITE_OVER);
         painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, \
maskDab->bounds().width(), maskDab->bounds().height());  \
                painter()->setOpacity(newOpacity);
-- 
1.7.1


From 1f43c1c7113a98f3f4d42b58932a0679736d7706 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Tue, 4 Jan 2011 00:55:43 +0100
Subject: [PATCH 6/6] Fixed copyright/author information

---
 libs/pigment/compositeops/KoCompositeOpCopyOpacy.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h \
b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h index 48f63ce..03a43d2 100644
--- a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h
+++ b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2008 Silvio Heinrich <plassy@web.de>
+ * Copyright (c) 2011 Silvio Heinrich <plassy@web.de>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
-- 
1.7.1



_______________________________________________
kimageshop mailing list
kimageshop@kde.org
https://mail.kde.org/mailman/listinfo/kimageshop


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic