[PATCH 10/10] Made the KoCompositeOpCopy2 work properly and used this mode for the smudge brush.

Silvio Heinrich plassy at web.de
Tue Jan 11 18:45:55 CET 2011


The COMPOSITE_COPY mode didn't work right because it blended between the
destination and source pixel even if the source's pixel had undefined
color (zero opacy).
I also did some fine tuning on the rate values of the smudge brush and
did some minor fixes.
---
 .../defaultpaintops/smudge/kis_smudgeop.cpp        |   17 +--
 .../paintops/defaultpaintops/smudge/kis_smudgeop.h |    1 -
 .../libpaintop/kis_pressure_composite_option.cpp   |    4 +-
 .../libpaintop/kis_pressure_rate_option.cpp        |   11 +-
 .../paintops/libpaintop/kis_pressure_rate_option.h |    4 +-
 libs/pigment/compositeops/KoCompositeOpCopy2.h     |  140 +++++++++-----------
 6 files changed, 78 insertions(+), 99 deletions(-)

diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
index d8bbd14..8abeb97 100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
@@ -110,19 +110,12 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     const KoCompositeOp* oldMode    = painter()->compositeOp();
     
     if(!m_firstRun) {
-        // set opacity calculated by the rate option (but fit the rate inbetween the range 0.0 - 0.25)
-        m_rateOption.apply(painter(), info, 0.0, 0.25);
+        // set opacity calculated by the rate option
+        m_rateOption.apply(painter(), info);
         
         // 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 are in the area (shape) of the brush
-        painter()->setCompositeOp(COMPOSITE_OVER);
-        painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, maskDab->bounds().width(), maskDab->bounds().height());
-        
-        // apply the opacity rate calculated by the rate option for smudging the alpha channel
-        // (this time we use the full range of the rate value)
-        m_rateOption.apply(painter(), info);
-        
-        painter()->setCompositeOp(COMPOSITE_COPY_OPACITY);
+        painter()->setCompositeOp(COMPOSITE_COPY);
         painter()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, maskDab->bounds().width(), maskDab->bounds().height());
     }
     else m_firstRun = false;
@@ -144,7 +137,9 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     // we will mix some color into the temorary painting device (m_tempDev)
     if(m_compositeOption.isChecked()) {
         // this will apply the opacy and the composite mode (selected by the user) to copyPainter
-        m_compositeOption.applyOpacityRate(&copyPainter, info, 0.0, 0.5);
+        // (but fit the rate inbetween the range 0.0 to (1.0-SmudgeRate))
+        qreal maxColorRate = qMax<qreal>(1.0-m_rateOption.rate(), 0.2);
+        m_compositeOption.applyOpacityRate(&copyPainter, info, 0.0, maxColorRate);
         m_compositeOption.applyCompositeOp(&copyPainter);
         
         // paint a rectangle with the current color (foreground color)
diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h
index 333df09..63346bd 100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.h
@@ -29,7 +29,6 @@
 
 #include "kis_brush_based_paintop.h"
 #include <kis_types.h>
-#include <kis_pressure_opacity_option.h>
 #include <kis_pressure_size_option.h>
 #include <kis_pressure_rate_option.h>
 #include <kis_pressure_composite_option.h>
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp
index 510768f..36d9062 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp
@@ -56,8 +56,10 @@ void KisPressureCompositeOption::readOptionSetting(const KisPropertiesConfigurat
 
 void KisPressureCompositeOption::applyOpacityRate(KisPainter* painter, const KisPaintInformation& info, qreal scaleMin, qreal scaleMax) const
 {
-    if(!isChecked())
+    if(!isChecked()) {
+        painter->setOpacity((quint8)(scaleMax * 255.0));
         return;
+    }
     
     qreal  rate    = scaleMin + (scaleMax - scaleMin) * m_rate; // scale m_rate into the range scaleMin - scaleMax
     quint8 opacity = qBound(OPACITY_TRANSPARENT_U8, (quint8)(rate * computeValue(info) * 255.0), OPACITY_OPAQUE_U8);
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.cpp b/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.cpp
index bd643d1..b40d88b 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.cpp
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.cpp
@@ -1,5 +1,6 @@
 /* This file is part of the KDE project
- * Copyright (C) Boudewijn Rempt <boud at valdyas.org>, (C) 2008
+ * Copyright (C) 2008 Boudewijn Rempt <boud at valdyas.org>
+ * Copyright (C) 2011 Silvio Heinrich <plassy at web.de>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -47,11 +48,13 @@ void KisPressureRateOption::readOptionSetting(const KisPropertiesConfiguration*
 
 void KisPressureRateOption::apply(KisPainter* painter, const KisPaintInformation& info, qreal scaleMin, qreal scaleMax) const
 {
-    if(!isChecked())
+    if(!isChecked()) {
+        painter->setOpacity((quint8)(scaleMax * 255.0));
         return;
+    }
     
-    qreal  rate    = scaleMin + (scaleMax - scaleMin) * m_rate;
-    quint8 opacity = qBound(OPACITY_TRANSPARENT_U8, (quint8)(m_rate * computeValue(info) * 255.0), OPACITY_OPAQUE_U8);
+    qreal  rate    = scaleMin + (scaleMax - scaleMin) * m_rate; // scale m_rate into the range scaleMin - scaleMax
+    quint8 opacity = qBound(OPACITY_TRANSPARENT_U8, (quint8)(rate * computeValue(info) * 255.0), OPACITY_OPAQUE_U8);
 
     painter->setOpacity(opacity);
 }
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.h b/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.h
index c0d9d66..e71102e 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.h
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.h
@@ -1,5 +1,6 @@
 /* This file is part of the KDE project
  * Copyright (C) Boudewijn Rempt <boud at valdyas.org>, (C) 2008
+ * Copyright (C) Silvio Heinrich <plassy at 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
@@ -45,10 +46,9 @@ public:
     void apply(KisPainter* painter, const KisPaintInformation& info, qreal scaleMin=0.0, qreal scaleMax=1.0) const;
 
     void writeOptionSetting(KisPropertiesConfiguration* setting) const;
-
     void readOptionSetting(const KisPropertiesConfiguration* setting);
 
-    void setRate(qreal rate) { m_rate = rate; }
+    void setRate(qreal rate) { m_rate = qBound<qreal>(0.0, rate, 1.0); }
     qreal rate() const { return m_rate; }
     
 private:
diff --git a/libs/pigment/compositeops/KoCompositeOpCopy2.h b/libs/pigment/compositeops/KoCompositeOpCopy2.h
index 5257d1a..1d8b04a 100644
--- a/libs/pigment/compositeops/KoCompositeOpCopy2.h
+++ b/libs/pigment/compositeops/KoCompositeOpCopy2.h
@@ -2,6 +2,7 @@
  *  Copyright (c) 2006, 2010 Cyrille Berger <cberger at cberger.net>
  *  Copyright (c) 2007 Emanuele Tamponi <emanuele at valinor.it>
  *  Copyright (c) 2010 Lukáš Tvrdý <lukast.dev at gmail.com>
+ *  Copyright (c) 2011 Silvio Heinrich <plassy at web.de>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,102 +25,81 @@
 
 #include <KoColorSpaceMaths.h>
 
-#define NATIVE_OPACITY_OPAQUE KoColorSpaceMathsTraits<channels_type>::unitValue
-#define NATIVE_OPACITY_TRANSPARENT KoColorSpaceMathsTraits<channels_type>::zeroValue
-
 /**
  * Generic implementation of the COPY composite op. That respect selection.
  */
 template<class _CSTraits>
 class KoCompositeOpCopy2 : 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;
+    
+    template<class T>
+    inline static T mul(T a, T b) { return T(KoColorSpaceMaths<T>::multiply(a, b)); }
+    
+    template<class T>
+    inline static T mul(T a, T b, T c) { return T(KoColorSpaceMaths<T>::multiply(a, b, c)); }
+    
+    template<class T>
+    inline static T lerp(T a, T b, T alpha) { return KoColorSpaceMaths<T>::blend(b, a, alpha); }
+    
+    template<class TRet, class T>
+    inline static TRet scale(T a) { return KoColorSpaceMaths<T,TRet>::scaleToA(a); }
 
 public:
-
     explicit KoCompositeOpCopy2(KoColorSpace * cs)
-            : KoCompositeOp(cs, COMPOSITE_COPY, i18n("Copy"), KoCompositeOp::categoryMix(), false) {
-    }
+        : KoCompositeOp(cs, COMPOSITE_COPY, i18n("Copy"), KoCompositeOp::categoryMix(), false) { }
 
-public:
     using KoCompositeOp::composite;
-
-    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
-    {
-        Q_UNUSED(channelFlags);
-        if(maskRowStart == 0 && U8_opacity == OPACITY_OPAQUE_U8)
-        {
-            quint8 *dst = dstRowStart;
-            const quint8 *src = srcRowStart;
-            quint8 bytesPerPixel = _CSTraits::pixelSize;
-            while (rows > 0) {
-                if (srcRowStride == 0) {
-                    quint8* dstN = dst;
-                    qint32 columns = cols;
-                    while (columns > 0) {
-                        memcpy(dstN, src, bytesPerPixel);
-                        dstN += bytesPerPixel;
-                        --columns;
-                    }
-                } else {
-                    memcpy(dst, src, cols * bytesPerPixel);
-                }
-
-                dst += dstRowStride;
-                src += srcRowStride;
-                --rows;
-            }
-        } else {
-            qint32 srcInc = (srcRowStride == 0) ? 0 : _CSTraits::channels_nb;
-            channels_type opacity = KoColorSpaceMaths<quint8, channels_type>::scaleToA(U8_opacity);
-            while (rows > 0)
-            {
-                const channels_type *srcN = reinterpret_cast<const channels_type *>(srcRowStart);
-                channels_type *dstN = reinterpret_cast<channels_type *>(dstRowStart);
-                const quint8 *mask = maskRowStart;
-
-                qint32 columns = cols;
-
-                while (columns > 0)
-                {
-                    channels_type blend;
-                    // compute the blend
-                    if (!mask){
-                        blend = opacity;
-                    }else if (*mask == OPACITY_OPAQUE_U8){
-                        blend = opacity;
-                        ++mask;
-                    } else {
-                        blend = KoColorSpaceMaths<channels_type, quint8>::multiply(opacity, *mask);
-                        ++mask;
-                    }
-                    
-                    for (uint i = 0; i < _CSTraits::channels_nb; i++) {
-                        dstN[i] = KoColorSpaceMaths<channels_type>::blend(srcN[i], dstN[i], blend);
-                    }
-                    --columns;
-                    srcN += srcInc;
-                    dstN += _CSTraits::channels_nb;
+    
+    virtual 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 {
+        
+        const QBitArray& flags   = channelFlags.isEmpty() ? QBitArray(channels_nb, true) : channelFlags;
+        bool             useMask = maskRowStart != 0;
+        qint32           srcInc  = srcRowStride != 0 ? channels_nb : 0;
+        channels_type    opacity = KoColorSpaceMaths<quint8,channels_type>::scaleToA(U8_opacity);
+        
+        for(; rows>0; --rows) {
+            const quint8*        msk = maskRowStart;
+            const channels_type* src = reinterpret_cast<const channels_type*>(srcRowStart);
+            channels_type*       dst = reinterpret_cast<channels_type*>(dstRowStart);
+            
+            for(qint32 c=cols; c>0; --c) {
+                channels_type srcAlpha   = (alpha_pos != -1) ? scale<channels_type>(src[alpha_pos]) : KoColorSpaceMathsTraits<channels_type>::unitValue;
+                channels_type dstAlpha   = (alpha_pos != -1) ? scale<channels_type>(dst[alpha_pos]) : KoColorSpaceMathsTraits<channels_type>::unitValue;
+                channels_type blendAlpha = useMask ? mul(opacity, scale<channels_type>(*msk)) : opacity;
+                channels_type blendColor = mul(srcAlpha, blendAlpha);
+                
+                if(dstAlpha != KoColorSpaceMathsTraits<channels_type>::zeroValue) {
+                    // blend the color channels
+                    for(qint32 i=0; i<channels_nb; ++i)
+                        if(i != alpha_pos && flags.testBit(i)) 
+                            dst[i] = lerp(dst[i], src[i], blendColor);
                 }
-
-                rows--;
-                srcRowStart += srcRowStride;
-                dstRowStart += dstRowStride;
-                if (maskRowStart) {
-                    maskRowStart += maskRowStride;
+                else {
+                    // don't blend if the color of the destination is undefined (has zero opacity)
+                    // copy the source channel instead
+                    for(qint32 i=0; i<channels_nb; ++i)
+                        if(i != alpha_pos && flags.testBit(i)) 
+                            dst[i] = src[i];
                 }
+                
+                // blend the alpha channel if there exists one
+                if(alpha_pos != -1)
+                    dst[alpha_pos] = lerp(dstAlpha, srcAlpha, blendAlpha);
+                
+                src += srcInc;
+                dst += channels_nb;
+                ++msk;
             }
             
+            srcRowStart  += srcRowStride;
+            dstRowStart  += dstRowStride;
+            maskRowStart += maskRowStride;
         }
     }
 };
-- 
1.7.1


--------------080902090707010407080904--


More information about the kimageshop mailing list