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

List:       kde-kimageshop
Subject:    New Patch: Smudge Brush
From:       Silvio Heinrich <plassy () web ! de>
Date:       2011-01-12 21:21:47
Message-ID: 4D2E1B6B.7050506 () web ! de
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


On 01/10/2011 11:16 PM, JL VT wrote:
> Silvio, I downloaded your patch and added it to a git branch called
>
> krita-fixsmudgebrush-silvioheinrich
>
> It's available in the remote repository (the master) such that others 
> can check it out and play with it.
Oh, that's cool :D


> I noticed a problem with your version of the brush, slightly 
> transparent colors quickly become opaque:
> http://imagebin.org/132048
>
> That doesn't give the impression of smudging very much. This is a 
> problem the old brush had to an extent, but it was mostly about the 
> darkening (with black).
You are right. My smudge brush did build the color up to much/fast.
This was bugging me all the time but it was due to the fact that i only 
copied the opacity
and not the colors too. But now i actually found out why the 
KoCompositeOpCopy class
was mixing the black color into everything and made it work as expected.
Now i use the COMPOSITE_COPY mode and the smudging behaves much better :).


> I am also having difficulty replicating the "look" of the old smudge 
> brush defaults. Can you try to tune the defaults of your new brush to 
> look as identical as possible to the defaults of the old smudge 
> brush?, this will help avoiding unfamiliar behavior.
>
> I also want to ask you why did you remove this part of the code? -->
>
>         // 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;
>
>         /* 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);
>
> Is it because you put the limits in the controls or the GUI, or is it 
> because you deemed it unnecessary?
>
> From my testing, I think it's because you thought it was unnecessary, 
> but I'll show you a case you can test yourself:
>
> http://imagebin.org/132050
> http://imagebin.org/132051
>
> With the old smudge brush, even at max rate, the brush decolorates 
> with time: it looks like a smudge.
> With the new smudge brush (yours), at max rate (and even at 
> intermediate rates as long as you press hard with the tablet), the 
> "smudge" turns literally into a crayon, there's no decoloration, the 
> same shape the brush started with becomes the one it ends with.
> And also at low rate the brush doesn't smudge anything at all.
Well i think the user should be able to choose from min. to max. smudge 
rate.
The absolute minimum is no smudge and the absolute maximum is smudging 
without fading.
But this is of course a matter of taste. We can set the minimum smudge 
rate a bit above zero if you like.
But the maximum smudge rate should stay at 100% because it gives imho 
pretty nice effects
when using 100% smudge rate and turning on the color option.
I mainly removed this because i hate macros (:P) and hadn't introduced 
any limitation functionality yet.
Now you can limit the rates with the PressureRateOption and 
PressureCompositeOption classes.


> I think you need to address that problem, if not with a hardcoded 
> limit, with a tweak to the controls (a tweak to the controls is harder 
> because tablet users also introduce a new factor to watch out for: the 
> curve), or with a logarithmic curve or something, because currently 
> it's very easy to cause this smudge brush to behave nearly like a 
> clone tool (as displayed in my screenshot).
>
>
> Other than that I think your brush is fine for me (I don't know about 
> the rest), since 2.4 is in development I think it would be good if 
> your brush could be added with a new name, for example Smudge 2, such 
> that artists can test it and directly compare it with the old Smudge 
> Brush, they will be the first ones to notice any regression (because 
> regressions are hard to gauge anyway, sometimes what looks like an 
> advancement to someone will look like a regression to somebody else).
>
>
> Here is me hoping to see you around in the near future,
> Thank you for your contributions!
>
>
> On Mon, Jan 3, 2011 at 9:20 PM, Silvio Heinrich <plassy@web.de 
> <mailto:plassy@web.de>> wrote:
>
>     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).
>
>     _______________________________________________
>     kimageshop mailing list
>     kimageshop@kde.org <mailto:kimageshop@kde.org>
>     https://mail.kde.org/mailman/listinfo/kimageshop
>
>
>
> _______________________________________________
> kimageshop mailing list
> kimageshop@kde.org
> https://mail.kde.org/mailman/listinfo/kimageshop

So here is the newest version of the smudge brush and i hope there are 
not to many flaws this time.
I made the patch against origin/master. So I Don't know whether it will 
apply correct on the branch or not. Maybe you have to reset the branch
or something? I'm not a git pro :D

[Attachment #5 (text/html)]

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
    <title></title>
  </head>
  <body bgcolor="#ffffff" text="#000000">
    On 01/10/2011 11:16 PM, JL VT wrote:
    <blockquote
      cite="mid:AANLkTi=1emVkDQs4vK0csGg-9brx=F8EdOnG7rexjNBk@mail.gmail.com"
      type="cite">Silvio, I downloaded your patch and added it to a git
      branch called
      <div><br>
      </div>
      <div>krita-fixsmudgebrush-silvioheinrich</div>
      <div>
        <div>
          <div><br>
          </div>
          <div>It's available in the remote repository (the master) such
            that others can check it out and play with it.</div>
        </div>
      </div>
    </blockquote>
    Oh, that's cool :D<br>
    <br>
    <br>
    <blockquote
      cite="mid:AANLkTi=1emVkDQs4vK0csGg-9brx=F8EdOnG7rexjNBk@mail.gmail.com"
      type="cite">
      <div>
        <div>
          <div>I noticed a problem with your version of the brush,
            slightly transparent colors quickly become opaque:</div>
          <div><a moz-do-not-send="true"
              href="http://imagebin.org/132048">http://imagebin.org/132048</a></div>
          <div><br>
          </div>
          <div>That doesn't give the impression of smudging very much.
            This is a problem the old brush had to an extent, but it was
            mostly about the darkening (with black).</div>
        </div>
      </div>
    </blockquote>
    You are right. My smudge brush did build the color up to much/fast.<br>
    This was bugging me all the time but it was due to the fact that i
    only copied the opacity<br>
    and not the colors too. But now i actually found out why the
    KoCompositeOpCopy class<br>
    was mixing the black color into everything and made it work as
    expected.<br>
    Now i use the COMPOSITE_COPY mode and the smudging behaves much
    better :).<br>
    <br>
    <br>
    <blockquote
      cite="mid:AANLkTi=1emVkDQs4vK0csGg-9brx=F8EdOnG7rexjNBk@mail.gmail.com"
      type="cite">
      <div>
        <div>
          <div>I am also having difficulty replicating the "look" of the
            old smudge brush defaults. Can you try to tune the defaults
            of your new brush to look as identical as possible to the
            defaults of the old smudge brush?, this will help avoiding
            unfamiliar behavior.</div>
          <div><br>
          </div>
          <div>I also want to ask you why did you remove this part of
            the code? --&gt;</div>
          <div><br>
          </div>
          <div>
            <div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;// Both limits defined to be 15 \
                units away from
              the min (0) or max (255) to allow actual mixing of colors</div>
            <div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;const quint8 MIXABLE_UPPER_LIMIT = \
                240;</div>
            <div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;const quint8 MIXABLE_LOWER_LIMIT = \
15;</div>  </div>
          <div><br>
          </div>
          <div>
            <div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;/* Without those limits, the smudge \
brush  doesn't smudge anymore, it either makes a single</div>
            <div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dropplet of color, or drags a frame
              indefinitely over the canvas. */</div>
            <div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;opacity = \
qBound(MIXABLE_LOWER_LIMIT, opacity,  MIXABLE_UPPER_LIMIT);</div>
          </div>
        </div>
      </div>
    </blockquote>
    <blockquote
      cite="mid:AANLkTi=1emVkDQs4vK0csGg-9brx=F8EdOnG7rexjNBk@mail.gmail.com"
      type="cite">
      <div>
        <div>
          <div><br>
          </div>
          <div>Is it because you put the limits in the controls or the
            GUI, or is it because you deemed it&nbsp;unnecessary?</div>
          <div><br>
          </div>
          <div>From my&nbsp;testing, I think it's because you thought it
            was&nbsp;unnecessary, but I'll show you a case you can
            test&nbsp;yourself:</div>
          <div><br>
          </div>
          <a moz-do-not-send="true" \
                href="http://imagebin.org/132050">http://imagebin.org/132050</a></div>
                
        <div><a moz-do-not-send="true" \
href="http://imagebin.org/132051">http://imagebin.org/132051</a></div>  <div><br>
        </div>
        <div>With the old smudge brush, even at max rate, the brush
          decolorates with time: it looks like a smudge.</div>
        <div>With the new smudge brush (yours), at max rate (and even at
          intermediate rates as long as you press hard with the tablet),
          the "smudge" turns literally into a crayon, there's no
          decoloration, the same shape the brush started with becomes
          the one it ends with.</div>
        <div>And also at low rate the brush doesn't smudge anything at
          all.</div>
      </div>
    </blockquote>
    Well i think the user should be able to choose from min. to max.
    smudge rate.<br>
    The absolute minimum is no smudge and the absolute maximum is
    smudging without fading.<br>
    But this is of course a matter of taste. We can set the minimum
    smudge rate a bit above zero if you like.<br>
    But the maximum smudge rate should stay at 100% because it gives
    imho pretty nice effects<br>
    when using 100% smudge rate and turning on the color option.<br>
    I mainly removed this because i hate macros (:P) and hadn't
    introduced any limitation functionality yet.<br>
    Now you can limit the rates with the PressureRateOption and
    PressureCompositeOption classes.<br>
    &nbsp;<br>
    <br>
    <blockquote
      cite="mid:AANLkTi=1emVkDQs4vK0csGg-9brx=F8EdOnG7rexjNBk@mail.gmail.com"
      type="cite">
      <div>
        <div>I think you need to address that problem, if not with a
          hardcoded limit, with a tweak to the controls (a tweak to the
          controls is harder because tablet users also introduce a new
          factor to watch out for: the curve), or with a logarithmic
          curve or something, because currently it's very easy to cause
          this smudge brush to behave nearly like a clone tool (as
          displayed in my screenshot).</div>
        <div><br>
        </div>
        <div><br>
        </div>
        <div>Other than that I think your brush is fine for me (I don't
          know about the rest), since 2.4 is in development I think it
          would be good if your brush could be added with a new name,
          for example Smudge 2, such that artists can test it and
          directly compare it with the old Smudge Brush, they will be
          the first ones to notice any regression (because regressions
          are hard to gauge anyway, sometimes what looks like an
          advancement to someone will look like a regression to somebody
          else).</div>
        <div><br>
        </div>
        <div><br>
        </div>
        <div>Here is me hoping to see you around in the near future,</div>
        <div>Thank you for your contributions!</div>
        <div><br>
        </div>
        <div><br>
          <div class="gmail_quote">On Mon, Jan 3, 2011 at 9:20 PM,
            Silvio Heinrich <span dir="ltr">&lt;<a
                moz-do-not-send="true" \
href="mailto:plassy@web.de">plassy@web.de</a>&gt;</span>  wrote:<br>
            <blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt
              0.8ex; border-left: 1px solid rgb(204, 204, 204);
              padding-left: 1ex;">Now it should work pretty similar to
              the smudge tool in gimp.<br>
              But I still need to do some tweaks to how the rate values
              (color and smudge rates) are used.<br>
              It only smudges/paints correctly in a certain region of
              the rates.<br>
              But the transparency issues should be solved by now, so no
              black color should be introduced anymore (hopefully :P).<br>
              <br>
              _______________________________________________<br>
              kimageshop mailing list<br>
              <a moz-do-not-send="true" \
href="mailto:kimageshop@kde.org">kimageshop@kde.org</a><br>  <a \
moz-do-not-send="true"  href="https://mail.kde.org/mailman/listinfo/kimageshop"
                target="_blank">https://mail.kde.org/mailman/listinfo/kimageshop</a><br>
  <br>
            </blockquote>
          </div>
          <br>
        </div>
      </div>
      <pre wrap="">
<fieldset class="mimeAttachmentHeader"></fieldset>
_______________________________________________
kimageshop mailing list
<a class="moz-txt-link-abbreviated" \
href="mailto:kimageshop@kde.org">kimageshop@kde.org</a> <a \
class="moz-txt-link-freetext" \
href="https://mail.kde.org/mailman/listinfo/kimageshop">https://mail.kde.org/mailman/listinfo/kimageshop</a>
 </pre>
    </blockquote>
    <br>
    So here is the newest version of the smudge brush and i hope there
    are not to many flaws this time.<br>
    I made the patch against origin/master. So I Don't know whether it
    will apply correct on the branch or not. Maybe you have to reset the
    branch<br>
    or something? I'm not a git pro :D<br>
  </body>
</html>


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

From a52313300fa2a58e8750487748a50949db704989 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Fri, 31 Dec 2010 00:23:07 +0100
Subject: [PATCH 01/10] 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 d2cbf4d..8465a21 100644
--- a/krita/plugins/paintops/libpaintop/CMakeLists.txt
+++ b/krita/plugins/paintops/libpaintop/CMakeLists.txt
@@ -40,6 +40,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 180f3fd385a0ef00b1f98a34876f6f5763c0da05 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Fri, 31 Dec 2010 21:28:09 +0100
Subject: [PATCH 02/10] 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 999e9a2ac8976fd94cf4386c4f1536ccf9312a4c Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Mon, 3 Jan 2011 00:43:51 +0100
Subject: [PATCH 03/10] 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 74fc43729e4249147c37827458cb0a7a0d68fd6a Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Mon, 3 Jan 2011 21:34:41 +0100
Subject: [PATCH 04/10] 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 cc9d4db26cebecabe664693c724c8ed02570fd52 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Tue, 4 Jan 2011 00:49:28 +0100
Subject: [PATCH 05/10] 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 60cdfb72d81057686ca556b28afb928c3097aea4 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Tue, 4 Jan 2011 00:55:43 +0100
Subject: [PATCH 06/10] 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


From ddb2331d0466e5af9cfb3740e20fe69656422548 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Tue, 4 Jan 2011 17:38:49 +0100
Subject: [PATCH 07/10] Made the Copy Opacy composite option invisible for the user.

---
 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 03a43d2..34224a0 100644
--- a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h
+++ b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h
@@ -37,7 +37,7 @@ class KoCompositeOpCopyOpacy : public KoCompositeOp
     
 public:
     KoCompositeOpCopyOpacy(const KoColorSpace * cs)
-        : KoCompositeOp(cs, COMPOSITE_COPY_OPACITY, i18n("Copy Opacy"), \
KoCompositeOp::categoryArithmetic(), true) { +        : KoCompositeOp(cs, \
COMPOSITE_COPY_OPACITY, i18n("Copy Opacy"), KoCompositeOp::categoryMix(), false) {  }
     
 public:
-- 
1.7.1


From 24bc583168a3ce51e3ecf9cdc1ad5a0f701415c0 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Tue, 4 Jan 2011 18:31:30 +0100
Subject: [PATCH 08/10] Improved the calculation and usage of the opacity rates for \
the smudge tool.

Also replaced the QSliders in the brush options with KisDoubleSliderSpinBoxes
---
 .../defaultpaintops/smudge/kis_smudgeop.cpp        |   31 +++++++++++-----
 .../libpaintop/kis_pressure_composite_option.cpp   |   19 +++++-----
 .../libpaintop/kis_pressure_composite_option.h     |    9 +++--
 .../kis_pressure_composite_option_widget.cpp       |   19 ++++++----
 .../kis_pressure_composite_option_widget.h         |    6 ++--
 .../libpaintop/kis_pressure_rate_option.cpp        |   36 +++++---------------
 .../paintops/libpaintop/kis_pressure_rate_option.h |   13 +++----
 .../libpaintop/kis_pressure_rate_option_widget.cpp |   22 ++++++-----
 .../libpaintop/kis_pressure_rate_option_widget.h   |    6 ++--
 libs/pigment/compositeops/KoCompositeOpCopyOpacy.h |    2 +
 10 files changed, 82 insertions(+), 81 deletions(-)

diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index \
                e03121f..b5627e5 100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
@@ -62,8 +62,6 @@ KisSmudgeOp::~KisSmudgeOp()
 {
 }
 
-
-
 qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
 {
     // Simple error catching
@@ -103,20 +101,28 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
         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) +    // transforms the fixed paint device with \
the current brush to alpha color space +    // to use it as an alpha/transparency \
mask  maskDab->convertTo(KoColorSpaceRegistry::instance()->alpha8());
     
-    // 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);
+    // save the old opacity value and composite mode
+    quint8               oldOpacity = painter()->opacity();
+    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.5) +        m_rateOption.apply(painter(), info, 0.0, 0.5);
+        
         // 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 \
                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);
+        
+        // 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()->bitBltWithFixedSelection(x, y, m_tempDev, maskDab, \
maskDab->bounds().width(), maskDab->bounds().height());  }
@@ -138,9 +144,9 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     // 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);
+        // this will apply the opacy and the composite mode (selected by the user) \
to copyPainter +        m_compositeOption.applyOpacityRate(&copyPainter, info, 0.0, \
0.5); +        m_compositeOption.applyCompositeOp(&copyPainter);
         
         // paint a rectangle with the current color (foreground color)
         // into the temporary painting device
@@ -150,5 +156,10 @@ qreal KisSmudgeOp::paintAt(const KisPaintInformation& info)
     }
     
     copyPainter.end();
+    
+    // restore orginal opacy and composite mode values
+    painter()->setOpacity(oldOpacity);
+    painter()->setCompositeOp(oldMode);
+    
     return spacing(scale);
 }
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp index \
                6d82865..510768f 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.cpp
@@ -47,25 +47,26 @@ void KisPressureCompositeOption::readOptionSetting(const \
KisPropertiesConfigurat  {
     KisCurveOption::readOptionSetting(setting);
     m_compositeOp = setting->getString("CompositeOp");
-    m_rate        = setting->getInt("CompositeRateValue");
+    m_rate        = setting->getDouble("CompositeRateValue");
     
     if(m_compositeOp == "") //TODO: test if compositeOp is valid instead of just \
testing for an empty string  m_compositeOp = COMPOSITE_OVER;
 }
 
-void KisPressureCompositeOption::apply(KisPainter* painter, qint8 opacity, const \
KisPaintInformation& info) const +
+void KisPressureCompositeOption::applyOpacityRate(KisPainter* painter, const \
KisPaintInformation& info, qreal scaleMin, qreal scaleMax) const  {
     if(!isChecked())
         return;
     
-    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  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->setCompositeOp(m_compositeOp);
     painter->setOpacity(opacity);
 }
 
+void KisPressureCompositeOption::applyCompositeOp(KisPainter* painter) const
+{
+    if(isChecked())
+        painter->setCompositeOp(m_compositeOp);
+}
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h \
b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h index \
                1ed6ff7..c30e8f4 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option.h
@@ -38,7 +38,8 @@ public:
      * Set the composite mode and opacity of the painter based on the user selection
      * and the pressure curve (if checked)
      */
-    void apply(KisPainter* painter, qint8 opacity, const KisPaintInformation& info) \
const; +    void applyOpacityRate(KisPainter* painter, const KisPaintInformation& \
info, qreal scaleMin=0.0, qreal scaleMax=1.0) const; +    void \
applyCompositeOp(KisPainter* painter) const;  
     void writeOptionSetting(KisPropertiesConfiguration* setting) const;
     void readOptionSetting(const KisPropertiesConfiguration* setting);
@@ -46,12 +47,12 @@ public:
     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; }
+    void setRate(qreal rate) { m_rate = qBound(0.0, rate, 1.0); }
+    qreal getRate() const { return m_rate; }
     
 private:
     QString m_compositeOp;
-    int     m_rate;
+    qreal   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 index \
                f075a3c..cfdc50f 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.cpp
@@ -20,6 +20,7 @@
 #include "kis_pressure_composite_option_widget.h"
 #include "kis_pressure_composite_option.h"
 
+#include <kis_slider_spin_box.h>
 #include <KoCompositeOp.h>
 
 #include <QWidget>
@@ -32,6 +33,8 @@
 
 #include <klocale.h>
 
+const static int MAX_SLIDER_VALUE = 1000;
+
 KisPressureCompositeOptionWidget::KisPressureCompositeOptionWidget()
     : KisCurveOptionWidget(new KisPressureCompositeOption())
 {
@@ -52,21 +55,21 @@ KisPressureCompositeOptionWidget::KisPressureCompositeOptionWidget()
  m_compositeOpBox->addItem(COMPOSITE_HARD_LIGHT);
     m_compositeOpBox->addItem(COMPOSITE_SOFT_LIGHT);
     
-    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);
+    m_rateSlider = new KisDoubleSliderSpinBox();
+    m_rateSlider->setRange(0.0, 1.0, 2);
+    m_rateSlider->setValue(0.3);
+    m_rateSlider->setSingleStep(0.01);
+    m_rateSlider->setSuffix("%");
     
     connect(m_compositeOpBox, SIGNAL(activated(QString)), this, \
                SLOT(compositeOpChanged(QString)));
-    connect(m_rateSlider, SIGNAL(valueChanged(int)), this, SLOT(rateChanged(int)));
+    connect(m_rateSlider, SIGNAL(valueChanged(qreal)), this, \
SLOT(rateChanged(qreal)));  
     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);
+    gridLayout->setColumnStretch(1, 1);
 
     QVBoxLayout* vBoxLayout = new QVBoxLayout;
     vBoxLayout->addLayout(gridLayout);
@@ -102,7 +105,7 @@ void KisPressureCompositeOptionWidget::compositeOpChanged(const \
QString& composi  emit sigSettingChanged();
 }
 
-void KisPressureCompositeOptionWidget::rateChanged(int rate)
+void KisPressureCompositeOptionWidget::rateChanged(qreal 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 index \
                30c09ce..5bc3073 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_composite_option_widget.h
@@ -23,7 +23,7 @@
 #include "kis_curve_option_widget.h"
 
 class QComboBox;
-class QSlider;
+class KisDoubleSliderSpinBox;
 
 class PAINTOP_EXPORT KisPressureCompositeOptionWidget : public KisCurveOptionWidget
 {
@@ -36,11 +36,11 @@ public:
     
 private slots:
      void compositeOpChanged(const QString& compositeOp);
-     void rateChanged(int rate);
+     void rateChanged(qreal rate);
     
 private:
     QComboBox* m_compositeOpBox;
-    QSlider*   m_rateSlider;
+    KisDoubleSliderSpinBox* m_rateSlider;
 };
 
 #endif // KIS_PRESSURE_COMPOSITE_OPTION_WIDGET_H
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.cpp \
b/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.cpp index \
                f2949d8..bd643d1 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.cpp
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.cpp
@@ -22,7 +22,7 @@
 
 #include <klocale.h>
 
-#include <kis_paint_device.h>
+#include <kis_painter.h>
 #include <widgets/kis_curve_widget.h>
 
 #include <KoColor.h>
@@ -33,44 +33,26 @@ KisPressureRateOption::KisPressureRateOption()
 {
 }
 
-void KisPressureRateOption::setRate(int rate)
-{
-    m_rate = rate;
-}
-
-int KisPressureRateOption::rate() const
-{
-    return m_rate;
-}
-
 void KisPressureRateOption::writeOptionSetting(KisPropertiesConfiguration* setting) \
const  {
     KisCurveOption::writeOptionSetting(setting);
     setting->setProperty("RateValue", m_rate);
-    setting->setProperty("RateVersion", "2");
 }
 
 void KisPressureRateOption::readOptionSetting(const KisPropertiesConfiguration* \
setting)  {
     KisCurveOption::readOptionSetting(setting);
-    if (setting->getString("RateVersion", "1") == "1") {
-        m_rate = setting->getInt("RatePressure");
-        setChecked(true);
-    } else {
-        m_rate = setting->getInt("RateValue");
-    }
+    m_rate = setting->getDouble("RateValue");
 }
 
-quint8 KisPressureRateOption::apply(quint8 opacity, const KisPaintInformation& info) \
const +void KisPressureRateOption::apply(KisPainter* painter, const \
KisPaintInformation& info, qreal scaleMin, qreal scaleMax) const  {
-    opacity = (m_rate * 255) / 100;
-
-    if (isChecked()) {
-        opacity = qBound((qint32)OPACITY_TRANSPARENT_U8,
-                         (qint32)(double(opacity) * computeValue(info) / \
                PRESSURE_DEFAULT),
-                         (qint32)OPACITY_OPAQUE_U8);
-    }
+    if(!isChecked())
+        return;
+    
+    qreal  rate    = scaleMin + (scaleMax - scaleMin) * m_rate;
+    quint8 opacity = qBound(OPACITY_TRANSPARENT_U8, (quint8)(m_rate * \
computeValue(info) * 255.0), OPACITY_OPAQUE_U8);  
-    return opacity;
+    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 4a7010e..c0d9d66 \
                100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.h
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_rate_option.h
@@ -27,6 +27,7 @@
 
 class QSlider;
 class KisPropertiesConfiguration;
+class KisPainter;
 
 /**
  * The pressure opacity option defines a curve that is used to
@@ -39,21 +40,19 @@ public:
 
     /**
      * Set the opacity of the painter based on the rate
-     * and the curve (if checked) and return the old opacity
-     * of the painter.
+     * and the curve (if checked)
      */
-    quint8 apply(quint8 opacity, const KisPaintInformation& info) const;
+    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(int rate);
-    
-    int rate() const;
+    void setRate(qreal rate) { m_rate = rate; }
+    qreal rate() const { return m_rate; }
     
 private:
-    int m_rate;
+    qreal m_rate;
 };
 
 #endif
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_rate_option_widget.cpp \
b/krita/plugins/paintops/libpaintop/kis_pressure_rate_option_widget.cpp index \
                c0e664c..b0841cd 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_rate_option_widget.cpp
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_rate_option_widget.cpp
@@ -19,6 +19,8 @@
  */
 
 #include "kis_pressure_rate_option_widget.h"
+#include "kis_pressure_rate_option.h"
+#include <kis_slider_spin_box.h>
 
 #include <QWidget>
 #include <QCheckBox>
@@ -29,23 +31,23 @@
 
 #include <klocale.h>
 
-#include "kis_pressure_rate_option.h"
-
 KisPressureRateOptionWidget::KisPressureRateOptionWidget()
     : KisCurveOptionWidget(new KisPressureRateOption())
 {
     QWidget* w = new QWidget;
     QLabel* rateLabel = new QLabel(i18n("Rate: "));
-    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_rateSlider, SIGNAL(valueChanged(int)),SLOT(rateChanged(int)));
+    m_rateSlider = new KisDoubleSliderSpinBox();
+    m_rateSlider->setRange(0.0, 1.0, 2);
+    m_rateSlider->setSingleStep(0.01);
+    m_rateSlider->setValue(0.3);
+    m_rateSlider->setSuffix("%");
+    
+    connect(m_rateSlider, SIGNAL(valueChanged(qreal)),SLOT(rateChanged(qreal)));
+    
     QHBoxLayout* hl = new QHBoxLayout;
     hl->addWidget(rateLabel);
     hl->addWidget(m_rateSlider);
+    hl->setStretchFactor(m_rateSlider, 1);
 
     QVBoxLayout* vl = new QVBoxLayout;
     vl->addLayout(hl);
@@ -62,7 +64,7 @@ void KisPressureRateOptionWidget::readOptionSetting(const \
                KisPropertiesConfigura
     m_rateSlider->setValue(static_cast<KisPressureRateOption*>(curveOption())->rate());
  }
 
-void KisPressureRateOptionWidget::rateChanged(int rate)
+void KisPressureRateOptionWidget::rateChanged(qreal rate)
 {
     static_cast<KisPressureRateOption*>(curveOption())->setRate(rate);
     emit sigSettingChanged();
diff --git a/krita/plugins/paintops/libpaintop/kis_pressure_rate_option_widget.h \
b/krita/plugins/paintops/libpaintop/kis_pressure_rate_option_widget.h index \
                05c768e..e53250f 100644
--- a/krita/plugins/paintops/libpaintop/kis_pressure_rate_option_widget.h
+++ b/krita/plugins/paintops/libpaintop/kis_pressure_rate_option_widget.h
@@ -22,7 +22,7 @@
 
 #include "kis_curve_option_widget.h"
 
-class QSlider;
+class KisDoubleSliderSpinBox;
 
 class PAINTOP_EXPORT KisPressureRateOptionWidget : public KisCurveOptionWidget
 {
@@ -34,10 +34,10 @@ public:
     void readOptionSetting(const KisPropertiesConfiguration* setting);
     
 private slots:
-    void rateChanged(int rate);
+    void rateChanged(qreal rate);
     
 private:
-    QSlider* m_rateSlider;
+    KisDoubleSliderSpinBox* m_rateSlider;
 };
 
 #endif // KIS_PRESSURE_RATE_OPTION_WIDGET_H
diff --git a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h \
b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h index 34224a0..2ffc3d5 100644
--- a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h
+++ b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h
@@ -56,6 +56,8 @@ public:
                    quint8 U8_opacity,
                    const QBitArray & channelFlags) const
     {
+        Q_UNUSED(channelFlags);
+        
         bool          useMask = maskRowStart != 0;
         channels_type opacity = \
KoColorSpaceMaths<quint8,channels_type>::scaleToA(U8_opacity);  
-- 
1.7.1


From aa9b161db418a516892a855047d8e1fbe7032f0f Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Fri, 7 Jan 2011 21:37:08 +0100
Subject: [PATCH 09/10] Simplified the copy opacy CompositeOp.

---
 .../defaultpaintops/smudge/kis_smudgeop.cpp        |    5 +-
 libs/pigment/compositeops/KoCompositeOpCopyOpacy.h |  109 ++++++--------------
 2 files changed, 36 insertions(+), 78 deletions(-)

diff --git a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp \
b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp index \
                b5627e5..d8bbd14 100644
--- a/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
+++ b/krita/plugins/paintops/defaultpaintops/smudge/kis_smudgeop.cpp
@@ -110,10 +110,9 @@ 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.5)
-        m_rateOption.apply(painter(), info, 0.0, 0.5);
+        // 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
         // 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);
diff --git a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h \
b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h index 2ffc3d5..d1392d5 100644
--- a/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h
+++ b/libs/pigment/compositeops/KoCompositeOpCopyOpacy.h
@@ -41,91 +41,50 @@ public:
     }
     
 public:
-    inline static channels_type selectAlpha(channels_type srcAlpha, channels_type \
                dstAlpha) {
-        return qMin(srcAlpha, dstAlpha);
-    }
+    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
-    {
+    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 { +        
         Q_UNUSED(channelFlags);
         
-        bool          useMask = maskRowStart != 0;
-        channels_type opacity = \
KoColorSpaceMaths<quint8,channels_type>::scaleToA(U8_opacity); +        bool          \
useMask   = maskRowStart != 0; +        qint32        srcInc    = srcRowStride != 0 ? \
channels_nb : 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(; 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;
                 
-                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);
-                        ++mskRowItr;
-                    }
-                    
-                    value      = (value > *dstRowItr) ? (value-1) : value;
-                    *dstRowItr = value;
-                    srcRowItr += channels_nb;
-                    dstRowItr += channels_nb;
+                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;  }
                 
-                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);
-                        ++mskRowItr;
-                    }
-                    
-                    value      = (value > *dstRowItr) ? (value-1) : value;
-                    *dstRowItr = value;
-                    dstRowItr += channels_nb;
+                if(useMask) {
+                    channels_type blend = \
KoColorSpaceMaths<quint8,channels_type>::scaleToA(*mskRowItr); +                    \
value = KoColorSpaceMaths<channels_type>::blend(value, *dstRowItr, blend); +          \
++mskRowItr;  }
                 
-                srcRowStart  += srcRowStride;
-                dstRowStart  += dstRowStride;
-                maskRowStart += maskRowStride;
+                value      = (value > *dstRowItr) ? (value-1) : value;
+                *dstRowItr = value;
+                
+                srcRowItr += srcInc;
+                dstRowItr += channels_nb;
             }
+            
+            srcRowStart  += srcRowStride;
+            dstRowStart  += dstRowStride;
+            maskRowStart += maskRowStride;
         }
     }
     
-- 
1.7.1


From f856c1d42fe55ab33df77f91be4b8a04910b92f2 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
Date: Tue, 11 Jan 2011 18:45:55 +0100
Subject: [PATCH 10/10] Made the KoCompositeOpCopy2 work properly and used this mode \
for the smudge brush.

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@valdyas.org>, (C) 2008
+ * Copyright (C) 2008 Boudewijn Rempt <boud@valdyas.org>
+ * 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 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@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
@@ -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@cberger.net>
  *  Copyright (c) 2007 Emanuele Tamponi <emanuele@valinor.it>
  *  Copyright (c) 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
+ *  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
@@ -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



_______________________________________________
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