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

List:       kde-kimageshop
Subject:    [calligra/krita-chili-kazakov] krita: [FEATURE] Implemented Wash mode for the liquify transform tool
From:       Dmitry Kazakov <dimula73 () gmail ! com>
Date:       2014-10-17 13:16:04
Message-ID: E1Xf7O0-0005rN-9h () scm ! kde ! org
[Download RAW message or body]

Git commit 16d55c02bb56c766892717d3508f7f13620f947d by Dmitry Kazakov.
Committed on 17/10/2014 at 13:15.
Pushed by dkazakov into branch 'krita-chili-kazakov'.

[FEATURE] Implemented Wash mode for the liquify transform tool

There is a fundamental difference between Wash mode and BuildUp mode of
the liquify brush. When you paint on the same place with in BuildUp
(default) mode it adds deformations infinitely, until you hardly see the
original piece. When you use Wash mode, all deformations are limited
by the Amount value, that is they will not exceed this level. You can also
control how fast the deformations will rush to the maximum level by
adjusting 'Flow' parameter, which is available only in this mode.

CCMAIL:kimageshop@kde.org

M  +78   -10   krita/image/kis_liquify_transform_worker.cpp
M  +9    -3    krita/image/kis_liquify_transform_worker.h
M  +6    -6    krita/image/tests/kis_liquify_transform_worker_test.cpp
M  +6    -5    krita/plugins/tools/tool_transform2/kis_liquify_paintop.cpp
M  +5    -0    krita/plugins/tools/tool_transform2/kis_liquify_properties.cpp
 M  +20   -1    krita/plugins/tools/tool_transform2/kis_liquify_properties.h
 M  +47   -0    krita/plugins/tools/tool_transform2/kis_tool_transform_config_widget.cpp
 M  +2    -0    krita/plugins/tools/tool_transform2/kis_tool_transform_config_widget.h
 M  +22   -5    krita/plugins/tools/tool_transform2/wdg_tool_transform.ui

http://commits.kde.org/calligra/16d55c02bb56c766892717d3508f7f13620f947d

diff --git a/krita/image/kis_liquify_transform_worker.cpp \
b/krita/image/kis_liquify_transform_worker.cpp index a8ed648..3e4c850 \
                100644
--- a/krita/image/kis_liquify_transform_worker.cpp
+++ b/krita/image/kis_liquify_transform_worker.cpp
@@ -45,9 +45,22 @@ struct KisLiquifyTransformWorker::Private
     struct MapIndexesOp;
 
     template <class ProcessOp>
+    void processTransformedPixelsBuildUp(ProcessOp op,
+                                         const QPointF &base,
+                                         qreal sigma);
+
+    template <class ProcessOp>
+    void processTransformedPixelsWash(ProcessOp op,
+                                      const QPointF &base,
+                                      qreal sigma,
+                                      qreal flow);
+
+    template <class ProcessOp>
     void processTransformedPixels(ProcessOp op,
                                   const QPointF &base,
-                                  qreal sigma);
+                                  qreal sigma,
+                                  bool useWashMode,
+                                  qreal flow);
 };
 
 KisLiquifyTransformWorker::KisLiquifyTransformWorker(const QRect \
&srcBounds, @@ -159,9 +172,9 @@ void \
KisLiquifyTransformWorker::undoPoints(const QPointF &base,  
 template <class ProcessOp>
 void KisLiquifyTransformWorker::Private::
-processTransformedPixels(ProcessOp op,
-                         const QPointF &base,
-                         qreal sigma)
+processTransformedPixelsBuildUp(ProcessOp op,
+                                const QPointF &base,
+                                qreal sigma)
 {
     const qreal maxDist = ProcessOp::maxDistCoeff * sigma;
     QRectF clipRect(base.x() - maxDist, base.y() - maxDist,
@@ -182,6 +195,55 @@ processTransformedPixels(ProcessOp op,
     }
 }
 
+template <class ProcessOp>
+void KisLiquifyTransformWorker::Private::
+processTransformedPixelsWash(ProcessOp op,
+                             const QPointF &base,
+                             qreal sigma,
+                             qreal flow)
+{
+    const qreal maxDist = ProcessOp::maxDistCoeff * sigma;
+    QRectF clipRect(base.x() - maxDist, base.y() - maxDist,
+                    2 * maxDist, 2 * maxDist);
+
+    QVector<QPointF>::iterator it = transformedPoints.begin();
+    QVector<QPointF>::iterator end = transformedPoints.end();
+
+    QVector<QPointF>::iterator refIt = originalPoints.begin();
+    KIS_ASSERT_RECOVER_RETURN(originalPoints.size() ==
+                              transformedPoints.size());
+
+    for (; it != end; ++it, ++refIt) {
+        if (!clipRect.contains(*it)) continue;
+
+        QPointF diff = *refIt - base;
+        qreal dist = KisAlgebra2D::norm(diff);
+        if (dist > maxDist) continue;
+
+        const qreal lambda = exp(-0.5 * pow2(dist / sigma));
+        QPointF dstPt = op(*refIt, base, diff, lambda);
+
+        if (kisDistance(dstPt, *refIt) > kisDistance(*it, *refIt)) {
+            *it = (1.0 - flow) * (*it) + flow * dstPt;
+        }
+    }
+}
+
+template <class ProcessOp>
+void KisLiquifyTransformWorker::Private::
+processTransformedPixels(ProcessOp op,
+                         const QPointF &base,
+                         qreal sigma,
+                         bool useWashMode,
+                         qreal flow)
+{
+    if (useWashMode) {
+        processTransformedPixelsWash(op, base, sigma, flow);
+    } else {
+        processTransformedPixelsBuildUp(op, base, sigma);
+    }
+}
+
 struct TranslateOp
 {
     TranslateOp(const QPointF &offset) : m_offset(offset) {}
@@ -248,26 +310,32 @@ struct RotateOp
 
 void KisLiquifyTransformWorker::translatePoints(const QPointF &base,
                                                 const QPointF &offset,
-                                                qreal sigma)
+                                                qreal sigma,
+                                                bool useWashMode,
+                                                qreal flow)
 {
     TranslateOp op(offset);
-    m_d->processTransformedPixels(op, base, sigma);
+    m_d->processTransformedPixels(op, base, sigma, useWashMode, flow);
 }
 
 void KisLiquifyTransformWorker::scalePoints(const QPointF &base,
                                             qreal scale,
-                                            qreal sigma)
+                                            qreal sigma,
+                                            bool useWashMode,
+                                            qreal flow)
 {
     ScaleOp op(scale);
-    m_d->processTransformedPixels(op, base, sigma);
+    m_d->processTransformedPixels(op, base, sigma, useWashMode, flow);
 }
 
 void KisLiquifyTransformWorker::rotatePoints(const QPointF &base,
                                              qreal angle,
-                                             qreal sigma)
+                                             qreal sigma,
+                                             bool useWashMode,
+                                             qreal flow)
 {
     RotateOp op(angle);
-    m_d->processTransformedPixels(op, base, sigma);
+    m_d->processTransformedPixels(op, base, sigma, useWashMode, flow);
 }
 
 struct KisLiquifyTransformWorker::Private::MapIndexesOp {
diff --git a/krita/image/kis_liquify_transform_worker.h \
b/krita/image/kis_liquify_transform_worker.h index 8977097..b6f269b 100644
--- a/krita/image/kis_liquify_transform_worker.h
+++ b/krita/image/kis_liquify_transform_worker.h
@@ -45,15 +45,21 @@ public:
 
     void translatePoints(const QPointF &base,
                          const QPointF &offset,
-                         qreal sigma);
+                         qreal sigma,
+                         bool useWashMode,
+                         qreal flow);
 
     void scalePoints(const QPointF &base,
                      qreal scale,
-                     qreal sigma);
+                     qreal sigma,
+                     bool useWashMode,
+                     qreal flow);
 
     void rotatePoints(const QPointF &base,
                       qreal angle,
-                      qreal sigma);
+                      qreal sigma,
+                      bool useWashMode,
+                      qreal flow);
 
     void undoPoints(const QPointF &base,
                     qreal amount,
diff --git a/krita/image/tests/kis_liquify_transform_worker_test.cpp \
b/krita/image/tests/kis_liquify_transform_worker_test.cpp index \
                507c0a4..180efac 100644
--- a/krita/image/tests/kis_liquify_transform_worker_test.cpp
+++ b/krita/image/tests/kis_liquify_transform_worker_test.cpp
@@ -148,11 +148,11 @@ void KisLiquifyTransformWorkerTest::testPoints()
     QBENCHMARK_ONCE {
         worker.translatePoints(QPointF(100,100),
                                QPointF(50, 0),
-                               50);
+                               50, false, 0.2);
 
         worker.scalePoints(QPointF(400,100),
                            0.9,
-                           50);
+                           50, false, 0.2);
 
         worker.undoPoints(QPointF(400,100),
                            1.0,
@@ -160,15 +160,15 @@ void KisLiquifyTransformWorkerTest::testPoints()
 
         worker.scalePoints(QPointF(400,300),
                            0.5,
-                           50);
+                           50, false, 0.2);
 
         worker.scalePoints(QPointF(100,300),
                            -0.5,
-                           30);
+                           30, false, 0.2);
 
         worker.rotatePoints(QPointF(100,500),
                             M_PI / 4,
-                            50);
+                            50, false, 0.2);
     }
 
     worker.run(dev);
@@ -198,7 +198,7 @@ void KisLiquifyTransformWorkerTest::testPointsQImage()
 
     worker.translatePoints(QPointF(100,100),
                            QPointF(50, 0),
-                           50);
+                           50, false, 0.2);
 
     QRect rc = dev->exactBounds();
     dev->setX(50);
diff --git a/krita/plugins/tools/tool_transform2/kis_liquify_paintop.cpp \
b/krita/plugins/tools/tool_transform2/kis_liquify_paintop.cpp index \
                478dc73..a7e07c7 100644
--- a/krita/plugins/tools/tool_transform2/kis_liquify_paintop.cpp
+++ b/krita/plugins/tools/tool_transform2/kis_liquify_paintop.cpp
@@ -121,32 +121,33 @@ KisSpacingInformation \
KisLiquifyPaintop::paintAt(const KisPaintInformation &pi)  pi.pressure() * \
reverseCoeff * m_d->props.amount():  reverseCoeff * m_d->props.amount();
 
-
+    const bool useWashMode = m_d->props.useWashMode();
+    const qreal flow = m_d->props.flow();
 
     switch (m_d->props.mode()) {
     case KisLiquifyProperties::MOVE: {
         const qreal offsetLength = size * amount;
         m_d->worker->translatePoints(pi.pos(),
                                      pi.drawingDirectionVector() * \
                offsetLength,
-                                     size);
+                                     size, useWashMode, flow);
 
         break;
     }
     case KisLiquifyProperties::SCALE:
         m_d->worker->scalePoints(pi.pos(),
                                  amount,
-                                 size);
+                                 size, useWashMode, flow);
         break;
     case KisLiquifyProperties::ROTATE:
         m_d->worker->rotatePoints(pi.pos(),
                                   2.0 * M_PI * amount,
-                                  size);
+                                  size, useWashMode, flow);
         break;
     case KisLiquifyProperties::OFFSET: {
         const qreal offsetLength = size * amount;
         m_d->worker->translatePoints(pi.pos(),
                                      \
                KisAlgebra2D::rightUnitNormal(pi.drawingDirectionVector()) \
                * offsetLength,
-                                     size);
+                                     size, useWashMode, flow);
         break;
     }
     case KisLiquifyProperties::UNDO:
diff --git a/krita/plugins/tools/tool_transform2/kis_liquify_properties.cpp \
b/krita/plugins/tools/tool_transform2/kis_liquify_properties.cpp index \
                ad497fe..8f468a4 100644
--- a/krita/plugins/tools/tool_transform2/kis_liquify_properties.cpp
+++ b/krita/plugins/tools/tool_transform2/kis_liquify_properties.cpp
@@ -61,6 +61,9 @@ void KisLiquifyProperties::saveMode() const
     cfg.writeEntry("sizeHasPressure", m_sizeHasPressure);
     cfg.writeEntry("amountHasPressure", m_amountHasPressure);
     cfg.writeEntry("reverseDirection", m_reverseDirection);
+    cfg.writeEntry("useWashMode", m_useWashMode);
+    cfg.writeEntry("flow", m_flow);
+
 }
 
 void KisLiquifyProperties::loadMode()
@@ -74,4 +77,6 @@ void KisLiquifyProperties::loadMode()
     m_sizeHasPressure = cfg.readEntry("sizeHasPressure", \
                m_sizeHasPressure);
     m_amountHasPressure = cfg.readEntry("amountHasPressure", \
                m_amountHasPressure);
     m_reverseDirection = cfg.readEntry("reverseDirection", \
m_reverseDirection); +    m_useWashMode = cfg.readEntry("useWashMode", \
m_useWashMode); +    m_flow = cfg.readEntry("flow", m_flow);
 }
diff --git a/krita/plugins/tools/tool_transform2/kis_liquify_properties.h \
b/krita/plugins/tools/tool_transform2/kis_liquify_properties.h index \
                ab888aa..08e32c0 100644
--- a/krita/plugins/tools/tool_transform2/kis_liquify_properties.h
+++ b/krita/plugins/tools/tool_transform2/kis_liquify_properties.h
@@ -39,7 +39,9 @@ public:
           m_spacing(0.2),
           m_sizeHasPressure(false),
           m_amountHasPressure(false),
-          m_reverseDirection(false)
+          m_reverseDirection(false),
+          m_useWashMode(false),
+          m_flow(0.2)
     {
     }
 
@@ -100,6 +102,20 @@ public:
         m_reverseDirection = value;
     }
 
+    bool useWashMode() const {
+        return m_useWashMode;
+    }
+    void setUseWashMode(bool value) {
+        m_useWashMode = value;
+    }
+
+    qreal flow() const {
+        return m_flow;
+    }
+    void setFlow(qreal value) {
+        m_flow = value;
+    }
+
     void saveMode() const;
     void loadMode();
 
@@ -111,6 +127,9 @@ private:
     bool m_sizeHasPressure;
     bool m_amountHasPressure;
     bool m_reverseDirection;
+
+    bool m_useWashMode;
+    qreal m_flow;
 };
 
 #endif /* __KIS_LIQUIFY_PROPERTIES_H */
diff --git a/krita/plugins/tools/tool_transform2/kis_tool_transform_config_widget.cpp \
b/krita/plugins/tools/tool_transform2/kis_tool_transform_config_widget.cpp \
                index ca1623f..841e0a2 100644
--- a/krita/plugins/tools/tool_transform2/kis_tool_transform_config_widget.cpp
                
+++ b/krita/plugins/tools/tool_transform2/kis_tool_transform_config_widget.cpp
 @@ -144,6 +144,15 @@ \
KisToolTransformConfigWidget::KisToolTransformConfigWidget(TransformTransactionP
                
     connect(liquifyAmountSlider, SIGNAL(valueChanged(qreal)), this, \
                SLOT(liquifyAmountChanged(qreal)));
     liquifyAmountSlider->setToolTip(i18nc("@info:tooltip", "Amount of the \
deformation you get"));  
+    liquifyFlowSlider->setRange(0.0, 1.0, 2);
+    liquifyFlowSlider->setValue(1.0);
+    connect(liquifyFlowSlider, SIGNAL(valueChanged(qreal)), this, \
SLOT(liquifyFlowChanged(qreal))); +    \
liquifyFlowSlider->setToolTip(i18nc("@info:tooltip", "When in non-buildup \
mode, shows how fast the deformation limit is reached.")); +
+    liquifyBuildUpBox->setChecked(true);
+    connect(liquifyBuildUpBox, SIGNAL(toggled(bool)), this, \
SLOT(liquifyBuildUpChanged(bool))); +    \
liquifyBuildUpBox->setToolTip(i18nc("@info:tooltip", "Switch between Build \
Up and Wash mode of painting. Build Up mode adds deformations one on top of \
the other without any limits. Wash mode gradually deforms the piece to the \
selected deformation level.")); +
     liquifySpacingSlider->setRange(0.0, 3.0, 2);
     liquifySizeSlider->setExponentRatio(3);
     liquifySpacingSlider->setSingleStep(0.01);
@@ -265,8 +274,12 @@ void \
KisToolTransformConfigWidget::updateLiquifyControls()  KisLiquifyProperties \
*props =  config->liquifyProperties();
 
+    const bool useWashMode = props->useWashMode();
+
     liquifySizeSlider->setValue(props->size());
     liquifyAmountSlider->setValue(props->amount());
+    liquifyFlowSlider->setValue(props->flow());
+    liquifyBuildUpBox->setChecked(!useWashMode);
     liquifySpacingSlider->setValue(props->spacing());
     liquifySizePressureBox->setChecked(props->sizeHasPressure());
     liquifyAmountPressureBox->setChecked(props->amountHasPressure());
@@ -279,7 +292,14 @@ void \
KisToolTransformConfigWidget::updateLiquifyControls()  bool \
canInverseDirection =  mode != KisLiquifyProperties::UNDO;
 
+    bool canUseWashMode = mode != KisLiquifyProperties::UNDO;
+
     liquifyReverseDirectionChk->setEnabled(canInverseDirection);
+    liquifyFlowSlider->setEnabled(canUseWashMode && useWashMode);
+    liquifyBuildUpBox->setEnabled(canUseWashMode);
+
+    const qreal maxAmount = canUseWashMode ? 5.0 : 1.0;
+    liquifyAmountSlider->setRange(0.0, maxAmount, 2);
 
     unblockUiSlots();
 }
@@ -330,6 +350,33 @@ void \
KisToolTransformConfigWidget::liquifyAmountChanged(qreal value)  \
notifyConfigChanged();  }
 
+void KisToolTransformConfigWidget::liquifyFlowChanged(qreal value)
+{
+    if (m_uiSlotsBlocked) return;
+
+    ToolTransformArgs *config = m_transaction->currentConfig();
+    KisLiquifyProperties *props =
+        config->liquifyProperties();
+
+    props->setFlow(value);
+    notifyConfigChanged();
+}
+
+void KisToolTransformConfigWidget::liquifyBuildUpChanged(bool value)
+{
+    if (m_uiSlotsBlocked) return;
+
+    ToolTransformArgs *config = m_transaction->currentConfig();
+    KisLiquifyProperties *props =
+        config->liquifyProperties();
+
+    props->setUseWashMode(!value);
+    notifyConfigChanged();
+
+    // we need to enable/disable flow slider
+    updateLiquifyControls();
+}
+
 void KisToolTransformConfigWidget::liquifySpacingChanged(qreal value)
 {
     if (m_uiSlotsBlocked) return;
diff --git a/krita/plugins/tools/tool_transform2/kis_tool_transform_config_widget.h \
b/krita/plugins/tools/tool_transform2/kis_tool_transform_config_widget.h \
                index 94cf109..6dc79f1 100644
--- a/krita/plugins/tools/tool_transform2/kis_tool_transform_config_widget.h
                
+++ b/krita/plugins/tools/tool_transform2/kis_tool_transform_config_widget.h
 @@ -90,6 +90,8 @@ public slots:
 
     void liquifySizeChanged(qreal value);
     void liquifyAmountChanged(qreal value);
+    void liquifyFlowChanged(qreal value);
+    void liquifyBuildUpChanged(bool value);
     void liquifySpacingChanged(qreal value);
     void liquifySizePressureChanged(bool value);
     void liquifyAmountPressureChanged(bool value);
diff --git a/krita/plugins/tools/tool_transform2/wdg_tool_transform.ui \
b/krita/plugins/tools/tool_transform2/wdg_tool_transform.ui index \
                47f13ea..52284c9 100755
--- a/krita/plugins/tools/tool_transform2/wdg_tool_transform.ui
+++ b/krita/plugins/tools/tool_transform2/wdg_tool_transform.ui
@@ -1054,7 +1054,7 @@ big!</string>
              <bool>true</bool>
             </property>
             <attribute name="buttonGroup">
-             <string notr="true">buttonGroup</string>
+             <string>buttonGroup</string>
             </attribute>
            </widget>
           </item>
@@ -1120,7 +1120,7 @@ big!</string>
              <bool>true</bool>
             </property>
             <attribute name="buttonGroup">
-             <string notr="true">buttonGroup</string>
+             <string>buttonGroup</string>
             </attribute>
            </widget>
           </item>
@@ -1373,17 +1373,17 @@ big!</string>
            </property>
           </widget>
          </item>
-         <item row="2" column="0">
+         <item row="3" column="0">
           <widget class="QLabel" name="lblSpacing">
            <property name="text">
             <string>Spacing:</string>
            </property>
           </widget>
          </item>
-         <item row="2" column="1">
+         <item row="3" column="1">
           <widget class="KisDoubleSliderSpinBox" \
name="liquifySpacingSlider" native="true"/>  </item>
-         <item row="3" column="1">
+         <item row="4" column="1">
           <widget class="QPushButton" name="liquifyReverseDirectionChk">
            <property name="sizePolicy">
             <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@@ -1399,6 +1399,23 @@ big!</string>
            </property>
           </widget>
          </item>
+         <item row="2" column="0">
+          <widget class="QLabel" name="lblFlow">
+           <property name="text">
+            <string>Flow:</string>
+           </property>
+          </widget>
+         </item>
+         <item row="2" column="1">
+          <widget class="KisDoubleSliderSpinBox" name="liquifyFlowSlider" \
native="true"/> +         </item>
+         <item row="2" column="2">
+          <widget class="QCheckBox" name="liquifyBuildUpBox">
+           <property name="text">
+            <string>Build Up</string>
+           </property>
+          </widget>
+         </item>
         </layout>
        </item>
        <item>
_______________________________________________
Krita 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