[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