diff --git a/plugins/paintops/watercolor/kis_splat.cpp b/plugins/paintops/watercolor/kis_splat.cpp index 33f6544c42..cbf7642aa4 100644 --- a/plugins/paintops/watercolor/kis_splat.cpp +++ b/plugins/paintops/watercolor/kis_splat.cpp @@ -1,216 +1,245 @@ /* This file is part of the KDE project * * Copyright (C) 2017 Grigory Tantsevov * * 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_splat.h" #include "kis_random_generator.h" #include #include +#include "kis_sequential_iterator.h" + #define START_OPACITY 100 #define STANDART_LIFETIME 60 double get_random(qreal min, qreal max) { return (qreal)rand() / RAND_MAX*(max - min) + min; } KisSplat::KisSplat(QPointF offset, int width, const KoColor &color) : m_life(STANDART_LIFETIME), m_roughness(1.f), m_flow(1.f), - m_motionBias(QPointF(0.f, 0.f)) + m_motionBias(QPointF(0.f, 0.f)), m_state(Flowing) { m_initColor.fromKoColor(color); m_fix = 8*STANDART_LIFETIME; int r = width / 2; int n = 128; qreal dt = 2.f * M_PI / n; QPointF p; for (int i = 0; i < n; i++) { p.setX(cos(i * dt)); p.setY(sin(i * dt)); m_vertices.push_back(QPointF(static_cast (r * p.x()) + offset.x(), static_cast (r * p.y()) + offset.y())); m_velocities.push_back(QPointF(2.f * p.x(), 2.f * p.y())); } m_initSize = CalcSize(); m_startTime = QTime::currentTime(); } KisSplat::KisSplat(QPointF offset, QPointF velocityBias, int width, int life, qreal roughness, qreal flow, qreal radialSpeed, const KoColor &color) : m_life(life), m_roughness(roughness), m_flow(flow), - m_motionBias(velocityBias) + m_motionBias(velocityBias), m_state(Flowing) { m_initColor.fromKoColor(color); m_fix = 8*STANDART_LIFETIME; int r = width / 2; int n = 128; qreal dt = 2.f * M_PI / n; QPointF p; for (int i = 0; i < n; i++) { p.setX(cos(i * dt)); p.setY(sin(i * dt)); m_vertices.push_back(QPointF(static_cast (r * p.x()) + offset.x(), static_cast (r * p.y()) + offset.y())); m_velocities.push_back(QPointF(radialSpeed * p.x(), radialSpeed * p.y())); } m_initSize = CalcSize(); m_startTime = QTime::currentTime(); } qreal KisSplat::CalcSize() { if (m_vertices.length() < 3) return 0.f; QPointF v0 = m_vertices[0]; qreal v0x = v0.x(); qreal v0y = v0.y(); QPointF e0 = m_vertices[1] - v0; qreal e0x = e0.x(); qreal e0y = e0.y(); qreal s = 0.f; int length = m_vertices.length(); for (int i = 2; i < length; i++) { QPointF v2 = m_vertices[i]; qreal e1x = v2.x() - v0x; qreal e1y = v2.y() - v0y; s += e0x * e1y - e0y * e1x; e0x = e1x; e0y = e1y; } return s >= 0 ? s : -s; } +void KisSplat::clearOldPath(KisPaintDeviceSP dev) +{ +// QRect rc = m_oldPath.boundingRect().toRect(); +// dev->clear(rc); + QRect rect = m_oldPath.boundingRect().toRect(); + KisSequentialIterator it(dev, rect); + + do { + QPoint place(it.x(), it.y()); + if (m_oldPath.contains(place)) { + qint16 *mydata = reinterpret_cast(it.rawData()); + mydata[0] = 0; + } + } while (it.nextPixel()); + +} + void KisSplat::doPaint(KisPainter *painter) { qreal multiply = m_initSize / CalcSize(); if (multiply < 0.f || multiply > 1.f) multiply = 1; qint8 oldOpacity = painter->opacity(); KisPainter::FillStyle oldFillStyle = painter->fillStyle(); KoColor oldColor = painter->paintColor(); +// if (m_state == Flowing) +// clearOldPath(painter->device()); + painter->setOpacity(START_OPACITY * multiply); painter->setFillStyle(KisPainter::FillStyleForegroundColor); painter->setPaintColor(m_initColor); painter->fillPainterPath(this->shape()); painter->setOpacity(oldOpacity); painter->setFillStyle(oldFillStyle); painter->setPaintColor(oldColor); } QPainterPath KisSplat::shape() const { QPainterPath path; int len = m_vertices.length(); path = *(new QPainterPath(m_vertices[0])); for (int i = 0; i < len-2; i+=2) { path.quadTo(m_vertices[i+1], m_vertices[i+2]); } path.quadTo(m_vertices[len-1], m_vertices[0]); return path; } QRectF KisSplat::boundingRect() const { return m_vertices.boundingRect(); } int KisSplat::update(KisWetMap *wetMap) { if (m_life <= 0) { if (m_fix <= 0) { + m_state = Dried; return KisSplat::Dried; } else { + m_state = Fixed; m_fix--; return KisSplat::Fixed; } } m_life--; + m_oldPath = shape(); QVector newVertices; for (int i = 0; i < m_vertices.length(); i++) { QPointF x = m_vertices[i]; QPointF v = m_velocities[i]; QPointF d = (1.f - alpha) * m_motionBias + alpha / get_random(1.f, 1.f + m_roughness) * v; QPointF x1 = x + m_flow * d; + QPointF(get_random(-m_roughness, m_roughness), get_random(-m_roughness, m_roughness)); newVertices.push_back(x1); } QVector wetPoints = wetMap->getWater(newVertices); for (int i = 0; i < wetPoints.size(); i++) { if (wetPoints.at(i) > 0) m_vertices[i] = newVertices.at(i); } if (!m_life) { for (int i = 0; i < m_vertices.length(); i++) { m_velocities[i] = QPointF(0, 0); } } + m_state = Flowing; return KisSplat::Flowing; } int KisSplat::rewet(KisWetMap *wetMap, QPointF pos, qreal radius) { QVector vertNum; QVector vertUpdate; for (int i = 0; i < m_vertices.size(); i++) { QVector2D vec(m_vertices.at(i) - pos); if (vec.length() <= radius) { vertNum.push_back(i); vertUpdate.push_back(m_vertices[i]); } } if (vertNum.size() > 0) { QVector newSpeed = wetMap->getSpeed(vertUpdate); for (int i = 0; i < vertNum.size(); i++) { int num = vertNum.at(i); m_velocities[num] = newSpeed.at(i); } m_life = STANDART_LIFETIME; m_fix = 8*STANDART_LIFETIME; + m_state = Flowing; return KisSplat::Flowing; - } else + } else { + m_state = Fixed; return KisSplat::Fixed; + } } diff --git a/plugins/paintops/watercolor/kis_splat.h b/plugins/paintops/watercolor/kis_splat.h index 4f4a81de0c..8c07853530 100644 --- a/plugins/paintops/watercolor/kis_splat.h +++ b/plugins/paintops/watercolor/kis_splat.h @@ -1,80 +1,84 @@ /* This file is part of the KDE project * * Copyright (C) 2017 Grigory Tantsevov * * 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_SPLAT_H #define KIS_SPLAT_H #include #include #include #include #include #include "kis_wetmap.h" #include "kis_random_generator.h" #include "kritawatercolorpaintop_export.h" #include "kis_painter.h" double get_random(qreal min, qreal max); class WATERCOLORPAINT_EXPORT KisSplat { public: enum SplatState { Flowing, Fixed, Dried }; KisSplat(QPointF offset, int width, const KoColor &color); KisSplat(QPointF offset, QPointF velocityBias, int width, int life, qreal roughness, qreal flow, qreal radialSpeed, const KoColor &color); void doPaint(KisPainter *painter); QPainterPath shape() const; QRectF boundingRect() const; int update(KisWetMap *wetMap); int rewet(KisWetMap *wetMap, QPointF pos, qreal radius); private: qreal CalcSize(); + void clearOldPath(KisPaintDeviceSP dev); const float alpha = 0.33f; QPolygonF m_vertices; QVector m_velocities; int m_life; qreal m_roughness; qreal m_flow; QPointF m_motionBias; QTime m_startTime; qreal m_initSize; KoColor m_initColor; int m_fix; + int m_state; + + QPainterPath m_oldPath; }; #endif diff --git a/plugins/paintops/watercolor/kis_watercolor_paintop.cpp b/plugins/paintops/watercolor/kis_watercolor_paintop.cpp index fa9097a219..9a54870976 100644 --- a/plugins/paintops/watercolor/kis_watercolor_paintop.cpp +++ b/plugins/paintops/watercolor/kis_watercolor_paintop.cpp @@ -1,67 +1,129 @@ /* This file is part of the KDE project * * Copyright (C) 2017 Grigory Tantsevov * * 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_watercolor_paintop.h" #include "kis_watercolor_base_items.h" #include #include #include "KoCompositeOps.h" +#include "kis_splat_generator_strategy.h" + KisWatercolorPaintOp::KisWatercolorPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) - : KisPaintOp(painter) + : KisPaintOp(painter), m_fixed(4, 2) { Q_UNUSED(image); Q_UNUSED(node); + + m_wetMap = new KisWetMap(); m_watercolorOption.readOptionSetting(settings); m_lastTime = 0; m_timer.start(); } KisWatercolorPaintOp::~KisWatercolorPaintOp() { - KisWatercolorBaseItems::instance()->drySystem(); +// KisWatercolorBaseItems::instance()->drySystem(); } KisSpacingInformation KisWatercolorPaintOp::paintAt(const KisPaintInformation &info) { + // Painting new stroke qint16 time = m_timer.elapsed(); qint16 timeGone = time - m_lastTime; - KisWatercolorBaseItems::instance()->paint(info.pos(), m_watercolorOption.radius, - m_watercolorOption.type, painter()->paintColor()); +// KisWatercolorBaseItems::instance()->paint(info.pos(), m_watercolorOption.radius, +// m_watercolorOption.type, painter()->paintColor()); + KisSplatGeneratorStrategy *strategy; + switch (m_watercolorOption.type) { + case 0: + strategy = new KisSimpleBrushGenerator(); + break; + case 1: + strategy = new KisWetOnDryGenerator(); + break; + case 2: + strategy = new KisWetOnWetGenerator(); + break; + case 3: + strategy = new KisBlobbyGenerator(); + break; + case 4: + strategy = new KisCrunchyGenerator(); + break; + default: + strategy = new KisSimpleBrushGenerator(); + break; + } + + strategy->generate(&m_flowing, + m_wetMap, + info.pos(), + m_watercolorOption.radius, + painter()->paintColor()); + + KisPaintDeviceSP driedPD = new KisPaintDevice(source()->colorSpace()); + KisPainter *driedPainter = new KisPainter(driedPD); + // Updating system for (int i = 0; i < timeGone / 33; i++) { - KisWatercolorBaseItems::instance()->update(); +// KisWatercolorBaseItems::instance()->update(); + foreach (KisSplat *splat, m_flowing) { + if (splat->update(m_wetMap) == KisSplat::Fixed) { + m_fixed.insert(splat->boundingRect(), splat); + m_flowing.removeOne(splat); + } + } + foreach (KisSplat *splat, m_fixed.values()) { + if (splat->update(m_wetMap) == KisSplat::Dried) { + m_dried.push_back(splat); + m_fixed.remove(splat); + } + } + + m_wetMap->update(); } m_lastTime = time - time % 33; + source()->clear(); + KisWatercolorBaseItems::instance()->repaint(painter()); + foreach (KisSplat *splat, m_dried) { + splat->doPaint(driedPainter); + } + + foreach (KisSplat *splat, m_fixed.values()) { + splat->doPaint(driedPainter); + } + QRect rect = driedPD->extent(); + painter()->bitBlt(rect.topLeft(), driedPD, rect); - painter()->device()->clear(); - KisWatercolorBaseItems::instance()->repaint(painter()); + foreach (KisSplat *splat, m_flowing) { + splat->doPaint(painter()); + } return updateSpacingImpl(info); } KisSpacingInformation KisWatercolorPaintOp::updateSpacingImpl(const KisPaintInformation &info) const { Q_UNUSED(info); return KisSpacingInformation(m_watercolorOption.radius / 5); } diff --git a/plugins/paintops/watercolor/kis_watercolor_paintop.h b/plugins/paintops/watercolor/kis_watercolor_paintop.h index 20b47534dd..916c6eae26 100644 --- a/plugins/paintops/watercolor/kis_watercolor_paintop.h +++ b/plugins/paintops/watercolor/kis_watercolor_paintop.h @@ -1,55 +1,65 @@ /* This file is part of the KDE project * * Copyright (C) 2017 Grigory Tantsevov * * 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_EXPERIMENT_PAINTOP_H_ #define KIS_EXPERIMENT_PAINTOP_H_ #include #include #include #include "kis_paint_information.h" #include "kis_watercolorop_option.h" #include +#include "kis_wetmap.h" +#include "kis_splat.h" +#include "KoRTree.h" + class KisPainter; class KisWatercolorPaintOp : public KisPaintOp { public: KisWatercolorPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image); ~KisWatercolorPaintOp(); KisSpacingInformation paintAt(const KisPaintInformation& info) override; protected: KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const override; private: WatercolorOption m_watercolorOption; QElapsedTimer m_timer; qint16 m_lastTime; + + + KisWetMap *m_wetMap; + QList m_flowing; + KoRTree m_fixed; + QList m_dried; }; #endif // KIS_EXPERIMENT_PAINTOP_H_