diff --git a/libs/ui/KisPaintopPropertiesBase.cpp b/libs/ui/KisPaintopPropertiesBase.cpp index 07fb28c237..b31df4386c 100644 --- a/libs/ui/KisPaintopPropertiesBase.cpp +++ b/libs/ui/KisPaintopPropertiesBase.cpp @@ -1,46 +1,45 @@ /* * Copyright (c) 2016 Dmitry Kazakov * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisPaintopPropertiesBase.h" #include "kis_properties_configuration.h" KisPaintopPropertiesBase::~KisPaintopPropertiesBase() { } - void KisPaintopPropertiesBase::readOptionSetting(KisPropertiesConfigurationSP settings) { readOptionSettingImpl(settings.data()); } void KisPaintopPropertiesBase::writeOptionSetting(KisPropertiesConfigurationSP settings) const { writeOptionSettingImpl(settings.data()); } void KisPaintopPropertiesBase::readOptionSetting(const KisPropertiesConfiguration *settings) { readOptionSettingImpl(settings); } void KisPaintopPropertiesBase::writeOptionSetting(KisPropertiesConfiguration *settings) const { writeOptionSettingImpl(settings); } diff --git a/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp b/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp index 8583157ea3..8b91b464bd 100644 --- a/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp +++ b/plugins/paintops/defaultpaintops/brush/kis_brushop.cpp @@ -1,426 +1,426 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_brushop.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "krita_utils.h" #include #include "kis_algebra_2d.h" #include #include #include #include "KisBrushOpResources.h" #include #include #include #include #include "kis_image_config.h" #include "kis_wrapped_rect.h" KisBrushOp::KisBrushOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) : KisBrushBasedPaintOp(settings, painter) , m_opacityOption(node) , m_avgSpacing(50) , m_avgNumDabs(50) , m_avgUpdateTimePerDab(50) , m_idealNumRects(KisImageConfig().maxNumberOfThreads()) , m_minUpdatePeriod(10) , m_maxUpdatePeriod(100) { Q_UNUSED(image); Q_ASSERT(settings); /** * We do our own threading here, so we need to forbid the brushes * to do threading internally */ m_brush->setThreadingAllowed(false); - m_airbrushOptionWidget.readOptionSetting(settings); + m_airbrushOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_flowOption.readOptionSetting(settings); m_sizeOption.readOptionSetting(settings); m_ratioOption.readOptionSetting(settings); m_spacingOption.readOptionSetting(settings); m_rateOption.readOptionSetting(settings); m_softnessOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_scatterOption.readOptionSetting(settings); m_sharpnessOption.readOptionSetting(settings); m_opacityOption.resetAllSensors(); m_flowOption.resetAllSensors(); m_sizeOption.resetAllSensors(); m_ratioOption.resetAllSensors(); m_rateOption.resetAllSensors(); m_softnessOption.resetAllSensors(); m_sharpnessOption.resetAllSensors(); m_rotationOption.resetAllSensors(); m_scatterOption.resetAllSensors(); m_sharpnessOption.resetAllSensors(); m_rotationOption.applyFanCornersInfo(this); KisBrushSP baseBrush = m_brush; auto resourcesFactory = [baseBrush, settings, painter] () { KisDabCacheUtils::DabRenderingResources *resources = new KisBrushOpResources(settings, painter); resources->brush = baseBrush->clone(); return resources; }; m_dabExecutor.reset( new KisDabRenderingExecutor( painter->device()->compositionSourceColorSpace(), resourcesFactory, painter->runnableStrokeJobsInterface(), &m_mirrorOption, &m_precisionOption)); } KisBrushOp::~KisBrushOp() { } KisSpacingInformation KisBrushOp::paintAt(const KisPaintInformation& info) { if (!painter()->device()) return KisSpacingInformation(1.0); KisBrushSP brush = m_brush; Q_ASSERT(brush); if (!brush) return KisSpacingInformation(1.0); if (!brush->canPaintFor(info)) return KisSpacingInformation(1.0); qreal scale = m_sizeOption.apply(info); scale *= KisLodTransform::lodToScale(painter()->device()); if (checkSizeTooSmall(scale)) return KisSpacingInformation(); qreal rotation = m_rotationOption.apply(info); qreal ratio = m_ratioOption.apply(info); KisDabShape shape(scale, ratio, rotation); QPointF cursorPos = m_scatterOption.apply(info, brush->maskWidth(shape, 0, 0, info), brush->maskHeight(shape, 0, 0, info)); m_opacityOption.setFlow(m_flowOption.apply(info)); quint8 dabOpacity = OPACITY_OPAQUE_U8; quint8 dabFlow = OPACITY_OPAQUE_U8; m_opacityOption.apply(info, &dabOpacity, &dabFlow); KisDabCacheUtils::DabRequestInfo request(painter()->paintColor(), cursorPos, shape, info, m_softnessOption.apply(info)); m_dabExecutor->addDab(request, qreal(dabOpacity) / 255.0, qreal(dabFlow) / 255.0); KisSpacingInformation spacingInfo = - effectiveSpacing(scale, rotation, &m_airbrushOptionWidget, &m_spacingOption, info); + effectiveSpacing(scale, rotation, &m_airbrushOption, &m_spacingOption, info); // gather statistics about dabs m_avgSpacing(spacingInfo.scalarApprox()); return spacingInfo; } struct KisBrushOp::UpdateSharedState { // rendering data KisPainter *painter = 0; QList dabsQueue; // speed metrics QVector dabPoints; QElapsedTimer dabRenderingTimer; // final report QVector allDirtyRects; }; void KisBrushOp::addMirroringJobs(Qt::Orientation direction, QVector &rects, UpdateSharedStateSP state, QVector &jobs) { jobs.append(new KisRunnableStrokeJobData(0, KisStrokeJobData::SEQUENTIAL)); for (KisRenderedDab &dab : state->dabsQueue) { jobs.append( new KisRunnableStrokeJobData( [state, &dab, direction] () { state->painter->mirrorDab(direction, &dab); }, KisStrokeJobData::CONCURRENT)); } jobs.append(new KisRunnableStrokeJobData(0, KisStrokeJobData::SEQUENTIAL)); for (QRect &rc : rects) { state->painter->mirrorRect(direction, &rc); jobs.append( new KisRunnableStrokeJobData( [rc, state] () { state->painter->bltFixed(rc, state->dabsQueue); }, KisStrokeJobData::CONCURRENT)); } state->allDirtyRects.append(rects); } std::pair KisBrushOp::doAsyncronousUpdate(QVector &jobs) { bool someDabsAreStillInQueue = false; const bool hasPreparedDabsAtStart = m_dabExecutor->hasPreparedDabs(); if (!m_updateSharedState && hasPreparedDabsAtStart) { m_updateSharedState = toQShared(new UpdateSharedState()); UpdateSharedStateSP state = m_updateSharedState; state->painter = painter(); { const qreal dabRenderingTime = m_dabExecutor->averageDabRenderingTime(); const qreal totalRenderingTimePerDab = dabRenderingTime + m_avgUpdateTimePerDab.rollingMeanSafe(); // we limit the number of fetched dabs to fit the maximum update period and not // make visual hiccups const int dabsLimit = totalRenderingTimePerDab > 0 ? qMax(10, int(m_maxUpdatePeriod / totalRenderingTimePerDab * m_idealNumRects)) : -1; state->dabsQueue = m_dabExecutor->takeReadyDabs(painter()->hasMirroring(), dabsLimit, &someDabsAreStillInQueue); } KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!state->dabsQueue.isEmpty(), std::make_pair(m_currentUpdatePeriod, false)); const int diameter = m_dabExecutor->averageDabSize(); const qreal spacing = m_avgSpacing.rollingMean(); const int idealNumRects = m_idealNumRects; QVector rects; // wrap the dabs if needed if (painter()->device()->defaultBounds()->wrapAroundMode()) { /** * In WA mode we do two things: * * 1) We ensure that the parallel threads do not access the same are on * the image. For normal updates that is ensured by the code in KisImage * and the scheduler. Here we should do that manually by adjusting 'rects' * so that they would not intersect in the wrapped space. * * 2) We duplicate dabs, to ensure that all the pieces of dabs are painted * inside the wrapped rect. No pieces are dabs are painted twice, because * we paint only the parts intersecting the wrap rect. */ const QRect wrapRect = painter()->device()->defaultBounds()->bounds(); QList wrappedDabs; Q_FOREACH (const KisRenderedDab &dab, state->dabsQueue) { const QVector normalizationOrigins = KisWrappedRect::normalizationOriginsForRect(dab.realBounds(), wrapRect); Q_FOREACH(const QPoint &pt, normalizationOrigins) { KisRenderedDab newDab = dab; newDab.offset = pt; rects.append(newDab.realBounds() & wrapRect); wrappedDabs.append(newDab); } } state->dabsQueue = wrappedDabs; } else { // just get all rects Q_FOREACH (const KisRenderedDab &dab, state->dabsQueue) { rects.append(dab.realBounds()); } } // split/merge rects into non-overlapping areas rects = KisPaintOpUtils::splitDabsIntoRects(rects, idealNumRects, diameter, spacing); state->allDirtyRects = rects; Q_FOREACH (const KisRenderedDab &dab, state->dabsQueue) { state->dabPoints.append(dab.realBounds().center()); } state->dabRenderingTimer.start(); Q_FOREACH (const QRect &rc, rects) { jobs.append( new KisRunnableStrokeJobData( [rc, state] () { state->painter->bltFixed(rc, state->dabsQueue); }, KisStrokeJobData::CONCURRENT)); } /** * After the dab has been rendered once, we should mirror it either one * (h __or__ v) or three (h __and__ v) times. This sequence of 'if's achieves * the goal without any extra copying. Please note that it has __no__ 'else' * branches, which is done intentionally! */ if (state->painter->hasHorizontalMirroring()) { addMirroringJobs(Qt::Horizontal, rects, state, jobs); } if (state->painter->hasVerticalMirroring()) { addMirroringJobs(Qt::Vertical, rects, state, jobs); } if (state->painter->hasHorizontalMirroring() && state->painter->hasVerticalMirroring()) { addMirroringJobs(Qt::Horizontal, rects, state, jobs); } jobs.append( new KisRunnableStrokeJobData( [state, this, someDabsAreStillInQueue] () { Q_FOREACH(const QRect &rc, state->allDirtyRects) { state->painter->addDirtyRect(rc); } state->painter->setAverageOpacity(state->dabsQueue.last().averageOpacity); const int updateRenderingTime = state->dabRenderingTimer.elapsed(); const qreal dabRenderingTime = m_dabExecutor->averageDabRenderingTime(); m_avgNumDabs(state->dabsQueue.size()); const qreal currentUpdateTimePerDab = qreal(updateRenderingTime) / state->dabsQueue.size(); m_avgUpdateTimePerDab(currentUpdateTimePerDab); /** * NOTE: using currentUpdateTimePerDab in the calculation for the next update time instead * of the average one makes rendering speed about 40% faster. It happens because the * adaptation period is shorter than if it used */ const qreal totalRenderingTimePerDab = dabRenderingTime + currentUpdateTimePerDab; const int approxDabRenderingTime = qreal(totalRenderingTimePerDab) * m_avgNumDabs.rollingMean() / m_idealNumRects; m_currentUpdatePeriod = someDabsAreStillInQueue ? m_minUpdatePeriod : qBound(m_minUpdatePeriod, int(1.5 * approxDabRenderingTime), m_maxUpdatePeriod); { // debug chunk // ENTER_FUNCTION() << ppVar(state->allDirtyRects.size()) << ppVar(state->dabsQueue.size()) << ppVar(dabRenderingTime) << ppVar(updateRenderingTime); // ENTER_FUNCTION() << ppVar(m_currentUpdatePeriod) << ppVar(someDabsAreStillInQueue); } // release all the dab devices state->dabsQueue.clear(); m_updateSharedState.clear(); }, KisStrokeJobData::SEQUENTIAL)); } else if (m_updateSharedState && hasPreparedDabsAtStart) { someDabsAreStillInQueue = true; } return std::make_pair(m_currentUpdatePeriod, someDabsAreStillInQueue); } KisSpacingInformation KisBrushOp::updateSpacingImpl(const KisPaintInformation &info) const { const qreal scale = m_sizeOption.apply(info) * KisLodTransform::lodToScale(painter()->device()); qreal rotation = m_rotationOption.apply(info); - return effectiveSpacing(scale, rotation, &m_airbrushOptionWidget, &m_spacingOption, info); + return effectiveSpacing(scale, rotation, &m_airbrushOption, &m_spacingOption, info); } KisTimingInformation KisBrushOp::updateTimingImpl(const KisPaintInformation &info) const { - return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOptionWidget, &m_rateOption, info); + return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOption, &m_rateOption, info); } void KisBrushOp::paintLine(const KisPaintInformation& pi1, const KisPaintInformation& pi2, KisDistanceInformation *currentDistance) { if (m_sharpnessOption.isChecked() && m_brush && (m_brush->width() == 1) && (m_brush->height() == 1)) { if (!m_lineCacheDevice) { m_lineCacheDevice = source()->createCompositionSourceDevice(); } else { m_lineCacheDevice->clear(); } KisPainter p(m_lineCacheDevice); p.setPaintColor(painter()->paintColor()); p.drawDDALine(pi1.pos(), pi2.pos()); QRect rc = m_lineCacheDevice->extent(); painter()->bitBlt(rc.x(), rc.y(), m_lineCacheDevice, rc.x(), rc.y(), rc.width(), rc.height()); //fixes Bug 338011 painter()->renderMirrorMask(rc, m_lineCacheDevice); } else { KisPaintOp::paintLine(pi1, pi2, currentDistance); } } diff --git a/plugins/paintops/defaultpaintops/brush/kis_brushop.h b/plugins/paintops/defaultpaintops/brush/kis_brushop.h index 936ef68261..f7156905de 100644 --- a/plugins/paintops/defaultpaintops/brush/kis_brushop.h +++ b/plugins/paintops/defaultpaintops/brush/kis_brushop.h @@ -1,107 +1,107 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Cyrille Berger * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_BRUSHOP_H_ #define KIS_BRUSHOP_H_ #include "kis_brush_based_paintop.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include class KisPainter; class KisColorSource; class KisDabRenderingExecutor; class KisRenderedDab; class KisRunnableStrokeJobData; class KisBrushOp : public KisBrushBasedPaintOp { public: KisBrushOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); ~KisBrushOp() override; void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) override; std::pair doAsyncronousUpdate(QVector &jobs) override; protected: KisSpacingInformation paintAt(const KisPaintInformation& info) override; KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const override; KisTimingInformation updateTimingImpl(const KisPaintInformation &info) const override; struct UpdateSharedState; typedef QSharedPointer UpdateSharedStateSP; void addMirroringJobs(Qt::Orientation direction, QVector &rects, UpdateSharedStateSP state, QVector &jobs); UpdateSharedStateSP m_updateSharedState; private: - KisAirbrushOptionWidget m_airbrushOptionWidget; + KisAirbrushOptionProperties m_airbrushOption; KisPressureSizeOption m_sizeOption; KisPressureRatioOption m_ratioOption; KisPressureSpacingOption m_spacingOption; KisPressureRateOption m_rateOption; KisPressureFlowOption m_flowOption; KisFlowOpacityOption m_opacityOption; KisPressureSoftnessOption m_softnessOption; KisPressureSharpnessOption m_sharpnessOption; KisPressureRotationOption m_rotationOption; KisPressureScatterOption m_scatterOption; KisPaintDeviceSP m_lineCacheDevice; QScopedPointer m_dabExecutor; qreal m_currentUpdatePeriod = 20.0; KisRollingMeanAccumulatorWrapper m_avgSpacing; KisRollingMeanAccumulatorWrapper m_avgNumDabs; KisRollingMeanAccumulatorWrapper m_avgUpdateTimePerDab; const int m_idealNumRects; const int m_minUpdatePeriod; const int m_maxUpdatePeriod; }; #endif // KIS_BRUSHOP_H_ diff --git a/plugins/paintops/deform/kis_deform_paintop.cpp b/plugins/paintops/deform/kis_deform_paintop.cpp index b55dd59b52..1bde615ba4 100644 --- a/plugins/paintops/deform/kis_deform_paintop.cpp +++ b/plugins/paintops/deform/kis_deform_paintop.cpp @@ -1,160 +1,160 @@ /* * Copyright (c) 2008-2010 Lukáš Tvrdý * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_deform_paintop.h" #include "kis_deform_paintop_settings.h" #include #include #include #include #include #include "kis_global.h" #include "kis_paint_device.h" #include "kis_painter.h" #include "kis_selection.h" #include "kis_random_accessor_ng.h" #include "kis_lod_transform.h" #include #include "kis_deform_option.h" #include "kis_brush_size_option.h" #include "kis_paintop_plugin_utils.h" #include #include #ifdef Q_OS_WIN // quoting DRAND48(3) man-page: // These functions are declared obsolete by SVID 3, // which states that rand(3) should be used instead. #define drand48() (static_cast(qrand()) / static_cast(RAND_MAX)) #endif KisDeformPaintOp::KisDeformPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) { Q_UNUSED(image); Q_UNUSED(node); Q_ASSERT(settings); m_sizeProperties.readOptionSetting(settings); m_properties.readOptionSetting(settings); - m_airbrushOptionWidget.readOptionSetting(settings); + m_airbrushOption.readOptionSetting(settings); // sensors m_sizeOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_rateOption.readOptionSetting(settings); m_sizeOption.resetAllSensors(); m_opacityOption.resetAllSensors(); m_rotationOption.resetAllSensors(); m_rateOption.resetAllSensors(); m_deformBrush.setProperties(&m_properties); m_deformBrush.setSizeProperties(&m_sizeProperties); m_deformBrush.initDeformAction(); m_dev = source(); if ((m_sizeProperties.brush_diameter * 0.5) > 1) { m_ySpacing = m_xSpacing = m_sizeProperties.brush_diameter * 0.5 * m_sizeProperties.brush_spacing; } else { m_ySpacing = m_xSpacing = 1.0; } m_spacing = m_xSpacing; } KisDeformPaintOp::~KisDeformPaintOp() { } KisSpacingInformation KisDeformPaintOp::paintAt(const KisPaintInformation& info) { if (!painter()) return KisSpacingInformation(m_spacing); if (!m_dev) return KisSpacingInformation(m_spacing); KisFixedPaintDeviceSP dab = cachedDab(source()->compositionSourceColorSpace()); qint32 x; qreal subPixelX; qint32 y; qreal subPixelY; QPointF pt = info.pos(); if (m_sizeProperties.brush_jitter_movement_enabled) { pt.setX(pt.x() + ((m_sizeProperties.brush_diameter * drand48()) - m_sizeProperties.brush_diameter * 0.5) * m_sizeProperties.brush_jitter_movement); pt.setY(pt.y() + ((m_sizeProperties.brush_diameter * drand48()) - m_sizeProperties.brush_diameter * 0.5) * m_sizeProperties.brush_jitter_movement); } qreal rotation = m_rotationOption.apply(info); // Deform Brush is capable of working with zero scale, // so no additional checks for 'zero'ness are needed qreal scale = m_sizeOption.apply(info); rotation += m_sizeProperties.brush_rotation; scale *= m_sizeProperties.brush_scale; QPointF pos = pt - m_deformBrush.hotSpot(scale, rotation); splitCoordinate(pos.x(), &x, &subPixelX); splitCoordinate(pos.y(), &y, &subPixelY); KisFixedPaintDeviceSP mask = m_deformBrush.paintMask(dab, m_dev, scale, rotation, info.pos(), subPixelX, subPixelY, x, y ); // this happens for the first dab of the move mode, we need more information for being able to move if (!mask) { return updateSpacingImpl(info); } quint8 origOpacity = m_opacityOption.apply(painter(), info); painter()->bltFixedWithFixedSelection(x, y, dab, mask, mask->bounds().width() , mask->bounds().height()); painter()->renderMirrorMask(QRect(QPoint(x, y), QSize(mask->bounds().width() , mask->bounds().height())), dab, mask); painter()->setOpacity(origOpacity); return updateSpacingImpl(info); } KisSpacingInformation KisDeformPaintOp::updateSpacingImpl(const KisPaintInformation &info) const { return KisPaintOpPluginUtils::effectiveSpacing(1.0, 1.0, true, 0.0, false, m_spacing, false, 1.0, KisLodTransform::lodToScale(painter()->device()), - &m_airbrushOptionWidget, nullptr, info); + &m_airbrushOption, nullptr, info); } KisTimingInformation KisDeformPaintOp::updateTimingImpl(const KisPaintInformation &info) const { - return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOptionWidget, &m_rateOption, info); + return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOption, &m_rateOption, info); } diff --git a/plugins/paintops/deform/kis_deform_paintop.h b/plugins/paintops/deform/kis_deform_paintop.h index cd583837e1..0f40de3aa5 100644 --- a/plugins/paintops/deform/kis_deform_paintop.h +++ b/plugins/paintops/deform/kis_deform_paintop.h @@ -1,73 +1,73 @@ /* * Copyright (c) 2008,2010 Lukáš Tvrdý * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_DEFORMPAINTOP_H_ #define KIS_DEFORMPAINTOP_H_ #include #include #include #include #include #include #include #include "deform_brush.h" #include "kis_deform_paintop_settings.h" #include "kis_deform_option.h" class KisPainter; class KisDeformPaintOp : public KisPaintOp { public: KisDeformPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); ~KisDeformPaintOp() override; protected: KisSpacingInformation paintAt(const KisPaintInformation& info) override; KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const override; KisTimingInformation updateTimingImpl(const KisPaintInformation &info) const override; private: KisPaintDeviceSP m_dab; KisPaintDeviceSP m_dev; DeformBrush m_deformBrush; DeformOption m_properties; KisBrushSizeOptionProperties m_sizeProperties; - KisAirbrushOptionWidget m_airbrushOptionWidget; + KisAirbrushOptionProperties m_airbrushOption; KisPressureSizeOption m_sizeOption; KisPressureOpacityOption m_opacityOption; KisPressureRotationOption m_rotationOption; KisPressureRateOption m_rateOption; qreal m_xSpacing; qreal m_ySpacing; qreal m_spacing; }; #endif // KIS_DEFORMPAINTOP_H_ diff --git a/plugins/paintops/libpaintop/kis_airbrush_option_widget.cpp b/plugins/paintops/libpaintop/kis_airbrush_option_widget.cpp index cf3d5e85f2..8ea15e40ef 100644 --- a/plugins/paintops/libpaintop/kis_airbrush_option_widget.cpp +++ b/plugins/paintops/libpaintop/kis_airbrush_option_widget.cpp @@ -1,157 +1,157 @@ /* * Copyright (c) 2008 Boudewijn Rempt * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_airbrush_option_widget.h" #include "kis_paintop_settings.h" #include #include #include #include "ui_wdgairbrush.h" const qreal MINIMUM_RATE = 1.0; const qreal MAXIMUM_RATE = 1000.0; const int RATE_NUM_DECIMALS = 2; const qreal RATE_EXPONENT_RATIO = 2.0; const qreal RATE_SINGLE_STEP = 1.0; const qreal DEFAULT_RATE = 20.0; class KisAirbrushWidget: public QWidget, public Ui::WdgAirbrush { public: KisAirbrushWidget(QWidget *parent = 0, bool canIgnoreSpacing = true) : QWidget(parent) { setupUi(this); sliderRate->setRange(MINIMUM_RATE, MAXIMUM_RATE, RATE_NUM_DECIMALS); sliderRate->setExponentRatio(RATE_EXPONENT_RATIO); sliderRate->setSingleStep(RATE_SINGLE_STEP); sliderRate->setValue(DEFAULT_RATE); checkBoxIgnoreSpacing->setVisible(canIgnoreSpacing); checkBoxIgnoreSpacing->setEnabled(canIgnoreSpacing); } }; struct KisAirbrushOptionWidget::Private { public: bool ignoreSpacing; // We store the airbrush interval (in milliseconds) instead of the rate because the interval is // likely to be accessed more often. qreal airbrushInterval; QScopedPointer configPage; }; KisAirbrushOptionWidget::KisAirbrushOptionWidget(bool enabled, bool canIgnoreSpacing) : KisPaintOpOption(KisPaintOpOption::COLOR, enabled) , m_d(new Private()) { setObjectName("KisAirbrushOption"); // Initialize GUI. m_checkable = true; m_d->configPage.reset(new KisAirbrushWidget(nullptr, canIgnoreSpacing)); connect(m_d->configPage->sliderRate, SIGNAL(valueChanged(qreal)), SLOT(slotIntervalChanged())); connect(m_d->configPage->checkBoxIgnoreSpacing, SIGNAL(toggled(bool)), SLOT(slotIgnoreSpacingChanged())); setConfigurationPage(m_d->configPage.data()); // Read initial configuration from the GUI. updateIgnoreSpacing(); updateInterval(); } KisAirbrushOptionWidget::~KisAirbrushOptionWidget() { delete m_d; } void KisAirbrushOptionWidget::writeOptionSetting(KisPropertiesConfigurationSP setting) const { KIS_SAFE_ASSERT_RECOVER (m_d->airbrushInterval > 0.0) { m_d->airbrushInterval = 1.0; } setting->setProperty(AIRBRUSH_ENABLED, isChecked()); setting->setProperty(AIRBRUSH_RATE, 1000.0 / m_d->airbrushInterval); qDebug() << "writeOptionSetting. Interval:" << m_d->airbrushInterval << "Calculated rate" << 1000.0 / m_d->airbrushInterval << "Rate in widget" << m_d->configPage->sliderRate->value(); setting->setProperty(AIRBRUSH_IGNORE_SPACING, m_d->ignoreSpacing); } void KisAirbrushOptionWidget::readOptionSetting(const KisPropertiesConfigurationSP setting) { setChecked(setting->getBool(AIRBRUSH_ENABLED)); // Update settings in the widget. The widget's signals should cause the changes to be propagated // to this->m_d as well. m_d->configPage->sliderRate->setValue(setting->getDouble(AIRBRUSH_RATE, DEFAULT_RATE)); qDebug() << "readOptionSetting. Interval:" << m_d->airbrushInterval << "Rate from settings" << setting->getDouble(AIRBRUSH_RATE, DEFAULT_RATE) << "Rate in widget" << m_d->configPage->sliderRate->value(); m_d->configPage->checkBoxIgnoreSpacing->setChecked(setting->getBool(AIRBRUSH_IGNORE_SPACING, false)); } qreal KisAirbrushOptionWidget::airbrushInterval() const { return m_d->airbrushInterval; } bool KisAirbrushOptionWidget::ignoreSpacing() const { return m_d->ignoreSpacing; } void KisAirbrushOptionWidget::slotIntervalChanged() { updateInterval(); emitSettingChanged(); } void KisAirbrushOptionWidget::slotIgnoreSpacingChanged() { updateIgnoreSpacing(); emitSettingChanged(); } void KisAirbrushOptionWidget::updateInterval() { // Get rate in dabs per second, then convert to interval in milliseconds. qreal rate = m_d->configPage->sliderRate->value(); KIS_SAFE_ASSERT_RECOVER(rate > 0.0) { rate = 1.0; } m_d->airbrushInterval = 1000.0 / rate; qDebug() << "updateInterval();. Interval:" << m_d->airbrushInterval << "Rate in widget" << m_d->configPage->sliderRate->value(); } void KisAirbrushOptionWidget::updateIgnoreSpacing() { m_d->ignoreSpacing = m_d->configPage->checkBoxIgnoreSpacing->isChecked(); } void KisAirbrushOptionProperties::readOptionSettingImpl(const KisPropertiesConfiguration *setting){ enabled = setting->getBool(AIRBRUSH_ENABLED); airbrushInterval = 1000.0 / setting->getDouble(AIRBRUSH_RATE, DEFAULT_RATE); ignoreSpacing = setting->getBool(AIRBRUSH_IGNORE_SPACING, false); } -void KisAirbrushOptionProperties::writeOptionSettingImpl(KisPropertiesConfiguration *setting) const{ +void KisAirbrushOptionProperties::writeOptionSettingImpl(KisPropertiesConfiguration *setting) const { setting->setProperty(AIRBRUSH_ENABLED, enabled); setting->setProperty(AIRBRUSH_RATE, 1000.0 / airbrushInterval > 0 ? airbrushInterval : 1.0); setting->setProperty(AIRBRUSH_IGNORE_SPACING, ignoreSpacing); } diff --git a/plugins/paintops/libpaintop/kis_airbrush_option_widget.h b/plugins/paintops/libpaintop/kis_airbrush_option_widget.h index ab6d443ef0..334364d3ed 100644 --- a/plugins/paintops/libpaintop/kis_airbrush_option_widget.h +++ b/plugins/paintops/libpaintop/kis_airbrush_option_widget.h @@ -1,77 +1,78 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_AIRBRUSH_OPTION_H #define KIS_AIRBRUSH_OPTION_H #include #include /** * Allows the user to activate airbrushing of the brush mask (brush is painted at the same position over and over) * Rate is set in milliseconds. */ class PAINTOP_EXPORT KisAirbrushOptionWidget : public KisPaintOpOption { Q_OBJECT public: KisAirbrushOptionWidget(bool enabled = true, bool canIgnoreSpacing = true); ~KisAirbrushOptionWidget() override; void writeOptionSetting(KisPropertiesConfigurationSP setting) const override; void readOptionSetting(const KisPropertiesConfigurationSP setting) override; /** * Returns the airbrushing interval, in milliseconds. This value should be ignored if the * KisAirbrushOption is not checked according to isChecked(). */ qreal airbrushInterval() const; /** * Returns true if regular distance-based spacing should be ignored and overridden by time-based * spacing. This value should be ignored if the KisAirbrushOption is not checked according to * isChecked(). */ bool ignoreSpacing() const; private Q_SLOTS: void slotIntervalChanged(); void slotIgnoreSpacingChanged(); private: // Reads the airbrush interval from the GUI. void updateInterval(); // Reads the "ignore spacing" setting from the GUI. void updateIgnoreSpacing(); struct Private; Private *const m_d; }; -struct KisAirbrushOptionProperties : public KisPaintopPropertiesBase +class PAINTOP_EXPORT KisAirbrushOptionProperties : public KisPaintopPropertiesBase { +public: bool enabled {false}; qreal airbrushInterval {1000.0 / 20.0}; bool ignoreSpacing {false}; - - void readOptionSettingImpl(const KisPropertiesConfiguration *setting) override; - void writeOptionSettingImpl(KisPropertiesConfiguration *setting) const override; +protected: + void readOptionSettingImpl(const KisPropertiesConfiguration *settings) override; + void writeOptionSettingImpl(KisPropertiesConfiguration *settings) const override; }; #endif diff --git a/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp b/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp index 55f03d5da9..109e29b9ae 100644 --- a/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp +++ b/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp @@ -1,181 +1,181 @@ /* * Copyright (c) 2008 Boudewijn Rempt * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_brush_based_paintop.h" #include "kis_properties_configuration.h" #include #include "kis_brush_option.h" #include #include #include "kis_painter.h" #include #include "kis_paintop_utils.h" #include "kis_paintop_plugin_utils.h" #include #include #include #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND Q_GLOBAL_STATIC(TextBrushInitializationWorkaround, s_instance) TextBrushInitializationWorkaround *TextBrushInitializationWorkaround::instance() { return s_instance; } void TextBrushInitializationWorkaround::preinitialize(KisPropertiesConfigurationSP settings) { if (KisBrushOptionProperties::isTextBrush(settings.data())) { KisBrushOptionProperties brushOption; brushOption.readOptionSetting(settings); m_brush = brushOption.brush(); m_settings = settings; } else { m_brush = 0; m_settings = 0; } } KisBrushSP TextBrushInitializationWorkaround::tryGetBrush(const KisPropertiesConfigurationSP settings) { return (settings && settings == m_settings ? m_brush : 0); } TextBrushInitializationWorkaround::TextBrushInitializationWorkaround() : m_settings(0) {} TextBrushInitializationWorkaround::~TextBrushInitializationWorkaround() {} void KisBrushBasedPaintOp::preinitializeOpStatically(KisPaintOpSettingsSP settings) { TextBrushInitializationWorkaround::instance()->preinitialize(settings); } #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ KisBrushBasedPaintOp::KisBrushBasedPaintOp(const KisPropertiesConfigurationSP settings, KisPainter* painter) : KisPaintOp(painter), m_textureProperties(painter->device()->defaultBounds()->currentLevelOfDetail()) { Q_ASSERT(settings); #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND m_brush = TextBrushInitializationWorkaround::instance()->tryGetBrush(settings); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ if (!m_brush) { KisBrushOptionProperties brushOption; brushOption.readOptionSetting(settings); m_brush = brushOption.brush(); } m_brush->notifyStrokeStarted(); m_precisionOption.readOptionSetting(settings); m_dabCache = new KisDabCache(m_brush); m_dabCache->setPrecisionOption(&m_precisionOption); m_mirrorOption.readOptionSetting(settings); m_dabCache->setMirrorPostprocessing(&m_mirrorOption); m_textureProperties.fillProperties(settings); m_dabCache->setTexturePostprocessing(&m_textureProperties); } KisBrushBasedPaintOp::~KisBrushBasedPaintOp() { delete m_dabCache; } bool KisBrushBasedPaintOp::checkSizeTooSmall(qreal scale) { scale *= m_brush->scale(); return KisPaintOpUtils::checkSizeTooSmall(scale, m_brush->width(), m_brush->height()); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal scale) const { // we parse dab rotation separately, so don't count it QSizeF metric = m_brush->characteristicSize(KisDabShape(scale, 1.0, 0)); return effectiveSpacing(metric.width(), metric.height(), 1.0, false, 0.0, false); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal scale, qreal rotation, const KisPaintInformation &pi) const { return effectiveSpacing(scale, rotation, nullptr, nullptr, pi); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal scale, qreal rotation, const KisPressureSpacingOption &spacingOption, const KisPaintInformation &pi) const { return effectiveSpacing(scale, rotation, nullptr, &spacingOption, pi); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal scale, qreal rotation, - const KisAirbrushOptionWidget *airbrushOption, + const KisAirbrushOptionProperties *airbrushOption, const KisPressureSpacingOption *spacingOption, const KisPaintInformation &pi) const { bool isotropicSpacing = spacingOption && spacingOption->isotropicSpacing(); MirrorProperties prop = m_mirrorOption.apply(pi); const bool implicitFlipped = prop.horizontalMirror != prop.verticalMirror; // we parse dab rotation separately, so don't count it QSizeF metric = m_brush->characteristicSize(KisDabShape(scale, 1.0, 0)); return KisPaintOpPluginUtils::effectiveSpacing(metric.width(), metric.height(), isotropicSpacing, rotation, implicitFlipped, m_brush->spacing(), m_brush->autoSpacingActive(), m_brush->autoSpacingCoeff(), KisLodTransform::lodToScale(painter()->device()), airbrushOption, spacingOption, pi); } KisSpacingInformation KisBrushBasedPaintOp::effectiveSpacing(qreal dabWidth, qreal dabHeight, qreal extraScale, bool isotropicSpacing, qreal rotation, bool axesFlipped) const { return KisPaintOpUtils::effectiveSpacing(dabWidth, dabHeight, extraScale, true, isotropicSpacing, rotation, axesFlipped, m_brush->spacing(), m_brush->autoSpacingActive(), m_brush->autoSpacingCoeff(), KisLodTransform::lodToScale(painter()->device())); } bool KisBrushBasedPaintOp::canPaint() const { return m_brush != 0; } diff --git a/plugins/paintops/libpaintop/kis_brush_based_paintop.h b/plugins/paintops/libpaintop/kis_brush_based_paintop.h index 0123cd658a..c884c3be46 100644 --- a/plugins/paintops/libpaintop/kis_brush_based_paintop.h +++ b/plugins/paintops/libpaintop/kis_brush_based_paintop.h @@ -1,103 +1,103 @@ /* * Copyright (c) 2008 Boudewijn Rempt * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_BRUSH_BASED_PAINTOP_H #define KIS_BRUSH_BASED_PAINTOP_H #include "kritapaintop_export.h" #include #include "kis_dab_cache.h" #include "kis_brush.h" #include "kis_texture_option.h" #include "kis_precision_option.h" #include "kis_airbrush_option_widget.h" #include "kis_pressure_mirror_option.h" #include class KisPropertiesConfiguration; class KisPressureSpacingOption; class KisPressureRateOption; class KisDabCache; /// Internal class TextBrushInitializationWorkaround { public: TextBrushInitializationWorkaround(); ~TextBrushInitializationWorkaround(); static TextBrushInitializationWorkaround* instance(); void preinitialize(KisPropertiesConfigurationSP settings); KisBrushSP tryGetBrush(const KisPropertiesConfigurationSP settings); private: KisBrushSP m_brush; KisPropertiesConfigurationSP m_settings; }; /** * This is a base class for paintops that use a KisBrush or derived * brush to paint with. This is mainly important for the spacing * generation. */ class PAINTOP_EXPORT KisBrushBasedPaintOp : public KisPaintOp { public: KisBrushBasedPaintOp(const KisPropertiesConfigurationSP settings, KisPainter* painter); ~KisBrushBasedPaintOp() override; bool checkSizeTooSmall(qreal scale); KisSpacingInformation effectiveSpacing(qreal scale) const; KisSpacingInformation effectiveSpacing(qreal scale, qreal rotation, const KisPaintInformation &pi) const; KisSpacingInformation effectiveSpacing(qreal scale, qreal rotation, const KisPressureSpacingOption &spacingOption, const KisPaintInformation &pi) const; KisSpacingInformation effectiveSpacing(qreal scale, qreal rotation, - const KisAirbrushOptionWidget *airbrushOption, + const KisAirbrushOptionProperties *airbrushOption, const KisPressureSpacingOption *spacingOption, const KisPaintInformation &pi) const; ///Reimplemented, false if brush is 0 bool canPaint() const override; #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND typedef int needs_preinitialization; static void preinitializeOpStatically(KisPaintOpSettingsSP settings); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ private: KisSpacingInformation effectiveSpacing(qreal dabWidth, qreal dabHeight, qreal extraScale, bool isotropicSpacing, qreal rotation, bool axesFlipped) const; protected: // XXX: make private! KisDabCache *m_dabCache; KisBrushSP m_brush; private: KisTextureProperties m_textureProperties; protected: KisPressureMirrorOption m_mirrorOption; KisPrecisionOption m_precisionOption; }; #endif diff --git a/plugins/paintops/libpaintop/kis_paintop_plugin_utils.h b/plugins/paintops/libpaintop/kis_paintop_plugin_utils.h index 4419852bc0..2a8b0e839d 100644 --- a/plugins/paintops/libpaintop/kis_paintop_plugin_utils.h +++ b/plugins/paintops/libpaintop/kis_paintop_plugin_utils.h @@ -1,101 +1,101 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_PAINTOP_PLUGIN_UTILS_H #define __KIS_PAINTOP_PLUGIN_UTILS_H #include "kis_paint_information.h" #include "kis_paintop_utils.h" #include "kis_paintop_settings.h" #include "kis_airbrush_option_widget.h" #include "kis_pressure_spacing_option.h" #include "kis_pressure_rate_option.h" namespace KisPaintOpPluginUtils { /** * Similar to KisPaintOpUtils::effectiveSpacing, but some of the required parameters are obtained * from the provided configuration options. This function assumes a common configuration where * spacing and airbrush settings are configured through a KisPressureSpacingOption and * KisAirbrushOption. This type of configuration is used by several different paintops. * @param airbrushOption - The airbrushing option. Can be null for paintops that don't support * airbrushing. * @param spacingOption - The pressure-curve spacing option. Can be null for paintops that don't * support pressure-based spacing. */ KisSpacingInformation effectiveSpacing(qreal dabWidth, qreal dabHeight, bool isotropicSpacing, qreal rotation, bool axesFlipped, qreal spacingVal, bool autoSpacingActive, qreal autoSpacingCoeff, qreal lodScale, - const KisAirbrushOptionWidget *airbrushOption, + const KisAirbrushOptionProperties *airbrushOption, const KisPressureSpacingOption *spacingOption, const KisPaintInformation &pi) { // Extract required parameters. bool distanceSpacingEnabled = true; - if (airbrushOption && airbrushOption->isChecked()) { - distanceSpacingEnabled = !airbrushOption->ignoreSpacing(); + if (airbrushOption && airbrushOption->enabled) { + distanceSpacingEnabled = !airbrushOption->ignoreSpacing; } qreal extraScale = 1.0; if (spacingOption && spacingOption->isChecked()) { extraScale = spacingOption->apply(pi); } return KisPaintOpUtils::effectiveSpacing(dabWidth, dabHeight, extraScale, distanceSpacingEnabled, isotropicSpacing, rotation, axesFlipped, spacingVal, autoSpacingActive, autoSpacingCoeff, lodScale); } /** * Similar to KisPaintOpUtils::effectiveTiming, but some of the required parameters are obtained * from the provided configuration options. This function assumes a common configuration where * airbrush settings are configured through a KisAirbrushOption and KisPressureRateOption. This type * of configuration is used by several different paintops. * @param airbrushOption - The airbrushing option. Can be null for paintops that don't support * airbrushing. * @param rateOption - The pressure-curve airbrush rate option. Can be null for paintops that don't * support a pressure-based airbrush rate. */ -KisTimingInformation effectiveTiming(const KisAirbrushOptionWidget *airbrushOption, +KisTimingInformation effectiveTiming(const KisAirbrushOptionProperties *airbrushOption, const KisPressureRateOption *rateOption, const KisPaintInformation &pi) { // Extract required parameters. bool timingEnabled = false; qreal timingInterval = LONG_TIME; if (airbrushOption) { - timingEnabled = airbrushOption->isChecked(); - timingInterval = airbrushOption->airbrushInterval(); + timingEnabled = airbrushOption->enabled; + timingInterval = airbrushOption->airbrushInterval; } qreal rateExtraScale = 1.0; if (rateOption && rateOption->isChecked()) { rateExtraScale = rateOption->apply(pi); } return KisPaintOpUtils::effectiveTiming(timingEnabled, timingInterval, rateExtraScale); } } #endif /* __KIS_PAINTOP_PLUGIN_UTILS_H */ diff --git a/plugins/paintops/particle/kis_particle_paintop.cpp b/plugins/paintops/particle/kis_particle_paintop.cpp index 4aa6f5956b..54d9b233f2 100644 --- a/plugins/paintops/particle/kis_particle_paintop.cpp +++ b/plugins/paintops/particle/kis_particle_paintop.cpp @@ -1,123 +1,123 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_particle_paintop.h" #include "kis_particle_paintop_settings.h" #include #include "kis_vec.h" #include #include #include #include #include #include #include #include #include #include #include #include "kis_particleop_option.h" #include "particle_brush.h" KisParticlePaintOp::KisParticlePaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) { Q_UNUSED(image); Q_UNUSED(node); m_properties.particleCount = settings->getInt(PARTICLE_COUNT); m_properties.iterations = settings->getInt(PARTICLE_ITERATIONS); m_properties.gravity = settings->getDouble(PARTICLE_GRAVITY); m_properties.weight = settings->getDouble(PARTICLE_WEIGHT); m_properties.scale = QPointF(settings->getDouble(PARTICLE_SCALE_X), settings->getDouble(PARTICLE_SCALE_Y)); m_particleBrush.setProperties(&m_properties); m_particleBrush.initParticles(); - m_airbrushOptionWidget.readOptionSetting(settings); + m_airbrushOption.readOptionSetting(settings); m_rateOption.readOptionSetting(settings); m_rateOption.resetAllSensors(); m_first = true; } KisParticlePaintOp::~KisParticlePaintOp() { } KisSpacingInformation KisParticlePaintOp::paintAt(const KisPaintInformation& info) { doPaintLine(info, info); return updateSpacingImpl(info); } KisSpacingInformation KisParticlePaintOp::updateSpacingImpl(const KisPaintInformation &info) const { return KisPaintOpPluginUtils::effectiveSpacing(0.0, 0.0, true, 0.0, false, 0.0, false, 0.0, KisLodTransform::lodToScale(painter()->device()), - &m_airbrushOptionWidget, nullptr, info); + &m_airbrushOption, nullptr, info); } KisTimingInformation KisParticlePaintOp::updateTimingImpl(const KisPaintInformation &info) const { - return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOptionWidget, &m_rateOption, info); + return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOption, &m_rateOption, info); } void KisParticlePaintOp::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { // Use superclass behavior for lines of zero length. Otherwise, airbrushing can happen faster // than it is supposed to. if (pi1.pos() == pi2.pos()) { KisPaintOp::paintLine(pi1, pi2, currentDistance); } else { doPaintLine(pi1, pi2); } } void KisParticlePaintOp::doPaintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2) { if (!painter()) return; if (!m_dab) { m_dab = source()->createCompositionSourceDevice(); } else { m_dab->clear(); } if (m_first) { m_particleBrush.setInitialPosition(pi1.pos()); m_first = false; } m_particleBrush.draw(m_dab, painter()->paintColor(), pi2.pos()); QRect rc = m_dab->extent(); painter()->bitBlt(rc.x(), rc.y(), m_dab, rc.x(), rc.y(), rc.width(), rc.height()); painter()->renderMirrorMask(rc, m_dab); } diff --git a/plugins/paintops/particle/kis_particle_paintop.h b/plugins/paintops/particle/kis_particle_paintop.h index facbe2538a..b5c394987a 100644 --- a/plugins/paintops/particle/kis_particle_paintop.h +++ b/plugins/paintops/particle/kis_particle_paintop.h @@ -1,62 +1,62 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_PARTICLE_PAINTOP_H_ #define KIS_PARTICLE_PAINTOP_H_ #include #include #include #include #include "kis_particle_paintop_settings.h" #include "particle_brush.h" class KisPainter; class KisPaintInformation; class KisParticlePaintOp : public KisPaintOp { public: KisParticlePaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); ~KisParticlePaintOp() override; void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) override; protected: KisSpacingInformation paintAt(const KisPaintInformation& info) override; KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const override; KisTimingInformation updateTimingImpl(const KisPaintInformation &info) const override; private: void doPaintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2); private: KisParticleBrushProperties m_properties; KisPaintDeviceSP m_dab; ParticleBrush m_particleBrush; - KisAirbrushOptionWidget m_airbrushOptionWidget; + KisAirbrushOptionProperties m_airbrushOption; KisPressureRateOption m_rateOption; bool m_first; }; #endif // KIS_PARTICLE_PAINTOP_H_ diff --git a/plugins/paintops/sketch/kis_sketch_paintop.cpp b/plugins/paintops/sketch/kis_sketch_paintop.cpp index ddaca275b2..98a72c8f8c 100644 --- a/plugins/paintops/sketch/kis_sketch_paintop.cpp +++ b/plugins/paintops/sketch/kis_sketch_paintop.cpp @@ -1,325 +1,325 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2010 Ricardo Cabello * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_sketch_paintop.h" #include "kis_sketch_paintop_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_lod_transform.h" #include /* * Based on Harmony project http://github.com/mrdoob/harmony/ */ // chrome : diff 0.2, sketchy : 0.3, fur: 0.5 // fur : distance / thresholdDistance // shaded: opacity per line :/ // ((1 - (d / 1000)) * 0.1 * BRUSH_PRESSURE), offset == 0 // chrome: color per line :/ //this.context.strokeStyle = "rgba(" + Math.floor(Math.random() * COLOR[0]) + ", " + Math.floor(Math.random() * COLOR[1]) + ", " + Math.floor(Math.random() * COLOR[2]) + ", " + 0.1 * BRUSH_PRESSURE + " )"; // long fur // from: count + offset * -random // to: i point - (offset * -random) + random * 2 // probability distance / thresholdDistnace // shaded: probabity : paint always - 0.0 density KisSketchPaintOp::KisSketchPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) { Q_UNUSED(image); Q_UNUSED(node); - m_airbrushOptionWidget.readOptionSetting(settings); + m_airbrushOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_sizeOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_rateOption.readOptionSetting(settings); m_sketchProperties.readOptionSetting(settings); m_brushOption.readOptionSetting(settings); m_densityOption.readOptionSetting(settings); m_lineWidthOption.readOptionSetting(settings); m_offsetScaleOption.readOptionSetting(settings); m_brush = m_brushOption.brush(); m_dabCache = new KisDabCache(m_brush); m_opacityOption.resetAllSensors(); m_sizeOption.resetAllSensors(); m_rotationOption.resetAllSensors(); m_rateOption.resetAllSensors(); m_painter = 0; m_count = 0; } KisSketchPaintOp::~KisSketchPaintOp() { delete m_painter; delete m_dabCache; } void KisSketchPaintOp::drawConnection(const QPointF& start, const QPointF& end, double lineWidth) { if (lineWidth == 1.0) { m_painter->drawThickLine(start, end, lineWidth, lineWidth); } else { m_painter->drawLine(start, end, lineWidth, true); } } void KisSketchPaintOp::updateBrushMask(const KisPaintInformation& info, qreal scale, qreal rotation) { QRect dstRect; m_maskDab = m_dabCache->fetchDab(m_dab->colorSpace(), painter()->paintColor(), info.pos(), KisDabShape(scale, 1.0, rotation), info, 1.0, &dstRect); m_brushBoundingBox = dstRect; m_hotSpot = QPointF(0.5 * m_brushBoundingBox.width(), 0.5 * m_brushBoundingBox.height()); } void KisSketchPaintOp::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { // Use superclass behavior for lines of zero length. Otherwise, airbrushing can happen faster // than it is supposed to. if (pi1.pos() == pi2.pos()) { KisPaintOp::paintLine(pi1, pi2, currentDistance); } else { doPaintLine(pi1, pi2); } -} +} void KisSketchPaintOp::doPaintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2) { if (!m_brush || !painter()) return; if (!m_dab) { m_dab = source()->createCompositionSourceDevice(); m_painter = new KisPainter(m_dab); m_painter->setPaintColor(painter()->paintColor()); } else { m_dab->clear(); } QPointF prevMouse = pi1.pos(); QPointF mousePosition = pi2.pos(); m_points.append(mousePosition); const qreal lodAdditionalScale = KisLodTransform::lodToScale(painter()->device()); const qreal scale = lodAdditionalScale * m_sizeOption.apply(pi2); if ((scale * m_brush->width()) <= 0.01 || (scale * m_brush->height()) <= 0.01) return; const qreal currentLineWidth = qMax(0.9, lodAdditionalScale * m_lineWidthOption.apply(pi2, m_sketchProperties.lineWidth)); const qreal currentOffsetScale = m_offsetScaleOption.apply(pi2, m_sketchProperties.offset); const double rotation = m_rotationOption.apply(pi2); const double currentProbability = m_densityOption.apply(pi2, m_sketchProperties.probability); // shaded: does not draw this line, chrome does, fur does if (m_sketchProperties.makeConnection) { drawConnection(prevMouse, mousePosition, currentLineWidth); } qreal thresholdDistance = 0.0; // update the mask for simple mode only once // determine the radius if (m_count == 0 && m_sketchProperties.simpleMode) { updateBrushMask(pi2, 1.0, 0.0); //m_radius = qMax(m_maskDab->bounds().width(),m_maskDab->bounds().height()) * 0.5; m_radius = 0.5 * qMax(m_brush->width(), m_brush->height()); } if (!m_sketchProperties.simpleMode) { updateBrushMask(pi2, scale, rotation); m_radius = qMax(m_maskDab->bounds().width(), m_maskDab->bounds().height()) * 0.5; thresholdDistance = pow(m_radius, 2); } if (m_sketchProperties.simpleMode) { // update the radius according scale in simple mode thresholdDistance = pow(m_radius * scale, 2); } // determine density const qreal density = thresholdDistance * currentProbability; // probability behaviour qreal probability = 1.0 - currentProbability; QColor painterColor = painter()->paintColor().toQColor(); QColor randomColor; KoColor color(m_dab->colorSpace()); int w = m_maskDab->bounds().width(); quint8 opacityU8 = 0; quint8 * pixel; qreal distance; QPoint positionInMask; QPointF diff; int size = m_points.size(); // MAIN LOOP for (int i = 0; i < size; i++) { diff = m_points.at(i) - mousePosition; distance = diff.x() * diff.x() + diff.y() * diff.y(); // circle test bool makeConnection = false; if (m_sketchProperties.simpleMode) { if (distance < thresholdDistance) { makeConnection = true; } // mask test } else { if (m_brushBoundingBox.contains(m_points.at(i))) { positionInMask = (diff + m_hotSpot).toPoint(); uint pos = ((positionInMask.y() * w + positionInMask.x()) * m_maskDab->pixelSize()); if (pos < m_maskDab->allocatedPixels() * m_maskDab->pixelSize()) { pixel = m_maskDab->data() + pos; opacityU8 = m_maskDab->colorSpace()->opacityU8(pixel); if (opacityU8 != 0) { makeConnection = true; } } } } if (!makeConnection) { // check next point continue; } if (m_sketchProperties.distanceDensity) { probability = distance / density; } KisRandomSourceSP randomSource = pi2.randomSource(); // density check if (randomSource->generateNormalized() >= probability) { QPointF offsetPt = diff * currentOffsetScale; if (m_sketchProperties.randomRGB) { /** * Since the order of calculation of function * parameters is not defined by C++ standard, we * should generate values in an external code snippet * which has a definite order of execution. */ qreal r1 = randomSource->generateNormalized(); qreal r2 = randomSource->generateNormalized(); qreal r3 = randomSource->generateNormalized(); // some color transformation per line goes here randomColor.setRgbF(r1 * painterColor.redF(), r2 * painterColor.greenF(), r3 * painterColor.blueF()); color.fromQColor(randomColor); m_painter->setPaintColor(color); } // distance based opacity quint8 opacity = OPACITY_OPAQUE_U8; if (m_sketchProperties.distanceOpacity) { opacity *= qRound((1.0 - (distance / thresholdDistance))); } if (m_sketchProperties.randomOpacity) { opacity *= randomSource->generateNormalized(); } m_painter->setOpacity(opacity); if (m_sketchProperties.magnetify) { drawConnection(mousePosition + offsetPt, m_points.at(i) - offsetPt, currentLineWidth); } else { drawConnection(mousePosition + offsetPt, mousePosition - offsetPt, currentLineWidth); } } }// end of MAIN LOOP m_count++; QRect rc = m_dab->extent(); quint8 origOpacity = m_opacityOption.apply(painter(), pi2); painter()->bitBlt(rc.x(), rc.y(), m_dab, rc.x(), rc.y(), rc.width(), rc.height()); painter()->renderMirrorMask(rc, m_dab); painter()->setOpacity(origOpacity); } KisSpacingInformation KisSketchPaintOp::paintAt(const KisPaintInformation& info) { doPaintLine(info, info); return updateSpacingImpl(info); } KisSpacingInformation KisSketchPaintOp::updateSpacingImpl(const KisPaintInformation &info) const { return KisPaintOpPluginUtils::effectiveSpacing(0.0, 0.0, true, 0.0, false, 0.0, false, 0.0, KisLodTransform::lodToScale(painter()->device()), - &m_airbrushOptionWidget, nullptr, info); + &m_airbrushOption, nullptr, info); } KisTimingInformation KisSketchPaintOp::updateTimingImpl(const KisPaintInformation &info) const { - return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOptionWidget, &m_rateOption, info); + return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOption, &m_rateOption, info); } diff --git a/plugins/paintops/sketch/kis_sketch_paintop.h b/plugins/paintops/sketch/kis_sketch_paintop.h index 8c46e79a44..f760983b95 100644 --- a/plugins/paintops/sketch/kis_sketch_paintop.h +++ b/plugins/paintops/sketch/kis_sketch_paintop.h @@ -1,94 +1,94 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_SKETCH_PAINTOP_H_ #define KIS_SKETCH_PAINTOP_H_ #include #include #include "kis_density_option.h" #include "kis_sketchop_option.h" #include "kis_sketch_paintop_settings.h" #include "kis_painter.h" #include #include #include #include #include #include "kis_linewidth_option.h" #include "kis_offset_scale_option.h" class KisDabCache; class KisSketchPaintOp : public KisPaintOp { public: KisSketchPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image); ~KisSketchPaintOp() override; void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) override; protected: KisSpacingInformation paintAt(const KisPaintInformation& info) override; KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const override; KisTimingInformation updateTimingImpl(const KisPaintInformation &info) const override; private: // pixel buffer KisPaintDeviceSP m_dab; // mask detection area KisFixedPaintDeviceSP m_maskDab; QRectF m_brushBoundingBox; QPointF m_hotSpot; // simple mode qreal m_radius; KisPressureOpacityOption m_opacityOption; KisPressureSizeOption m_sizeOption; KisPressureRotationOption m_rotationOption; KisPressureRateOption m_rateOption; KisDensityOption m_densityOption; KisLineWidthOption m_lineWidthOption; KisOffsetScaleOption m_offsetScaleOption; - KisAirbrushOptionWidget m_airbrushOptionWidget; + KisAirbrushOptionProperties m_airbrushOption; KisBrushOptionProperties m_brushOption; SketchProperties m_sketchProperties; QVector m_points; int m_count; KisPainter * m_painter; KisBrushSP m_brush; KisDabCache *m_dabCache; private: void drawConnection(const QPointF &start, const QPointF &end, double lineWidth); void updateBrushMask(const KisPaintInformation& info, qreal scale, qreal rotation); void doPaintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2); }; #endif // KIS_SKETCH_PAINTOP_H_ diff --git a/plugins/paintops/spray/kis_spray_paintop.cpp b/plugins/paintops/spray/kis_spray_paintop.cpp index d104069f4a..ff83355007 100644 --- a/plugins/paintops/spray/kis_spray_paintop.cpp +++ b/plugins/paintops/spray/kis_spray_paintop.cpp @@ -1,153 +1,153 @@ /* * Copyright (c) 2008-2012 Lukáš Tvrdý * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_spray_paintop.h" #include "kis_spray_paintop_settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include KisSprayPaintOp::KisSprayPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) : KisPaintOp(painter) , m_isPresetValid(true) , m_node(node) { Q_ASSERT(settings); Q_ASSERT(painter); Q_UNUSED(image); - m_airbrushOptionWidget.readOptionSetting(settings); + m_airbrushOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_sizeOption.readOptionSetting(settings); m_rateOption.readOptionSetting(settings); m_rotationOption.resetAllSensors(); m_opacityOption.resetAllSensors(); m_sizeOption.resetAllSensors(); m_rateOption.resetAllSensors(); m_brushOption.readOptionSetting(settings); m_colorProperties.fillProperties(settings); m_properties.readOptionSetting(settings); // first load tip properties as shape properties are dependent on diameter/scale/aspect m_shapeProperties.loadSettings(settings, m_properties.diameter * m_properties.scale, m_properties.diameter * m_properties.aspect * m_properties.scale); // TODO: what to do with proportional sizes? m_shapeDynamicsProperties.loadSettings(settings); if (!m_shapeProperties.enabled && !m_brushOption.brush()) { // in case the preset does not contain the definition for KisBrush m_isPresetValid = false; dbgKrita << "Preset is not valid. Painting is not possible. Use the preset editor to fix current brush engine preset."; } m_sprayBrush.setProperties(&m_properties, &m_colorProperties, &m_shapeProperties, &m_shapeDynamicsProperties, m_brushOption.brush()); m_sprayBrush.setFixedDab(cachedDab()); // spacing if ((m_properties.diameter * 0.5) > 1) { m_ySpacing = m_xSpacing = m_properties.diameter * 0.5 * m_properties.spacing; } else { m_ySpacing = m_xSpacing = 1.0; } m_spacing = m_xSpacing; } KisSprayPaintOp::~KisSprayPaintOp() { } KisSpacingInformation KisSprayPaintOp::paintAt(const KisPaintInformation& info) { if (!painter() || !m_isPresetValid) { return KisSpacingInformation(m_spacing); } if (!m_dab) { m_dab = source()->createCompositionSourceDevice(); } else { m_dab->clear(); } qreal rotation = m_rotationOption.apply(info); quint8 origOpacity = m_opacityOption.apply(painter(), info); // Spray Brush is capable of working with zero scale, // so no additional checks for 'zero'ness are needed const qreal scale = m_sizeOption.apply(info); const qreal lodScale = KisLodTransform::lodToScale(painter()->device()); m_sprayBrush.paint(m_dab, m_node->paintDevice(), info, rotation, scale, lodScale, painter()->paintColor(), painter()->backgroundColor()); QRect rc = m_dab->extent(); painter()->bitBlt(rc.topLeft(), m_dab, rc); painter()->renderMirrorMask(rc, m_dab); painter()->setOpacity(origOpacity); return computeSpacing(info, lodScale); } KisSpacingInformation KisSprayPaintOp::updateSpacingImpl(const KisPaintInformation &info) const { return computeSpacing(info, KisLodTransform::lodToScale(painter()->device())); } KisTimingInformation KisSprayPaintOp::updateTimingImpl(const KisPaintInformation &info) const { - return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOptionWidget, &m_rateOption, info); + return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOption, &m_rateOption, info); } KisSpacingInformation KisSprayPaintOp::computeSpacing(const KisPaintInformation &info, qreal lodScale) const { return KisPaintOpPluginUtils::effectiveSpacing(1.0, 1.0, true, 0.0, false, m_spacing * lodScale, false, 1.0, lodScale, - &m_airbrushOptionWidget, nullptr, info); + &m_airbrushOption, nullptr, info); } diff --git a/plugins/paintops/spray/kis_spray_paintop.h b/plugins/paintops/spray/kis_spray_paintop.h index 6b6e8c7c59..600f6bcf48 100644 --- a/plugins/paintops/spray/kis_spray_paintop.h +++ b/plugins/paintops/spray/kis_spray_paintop.h @@ -1,75 +1,75 @@ /* * Copyright (c) 2008-2012 Lukáš Tvrdý * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_SPRAY_PAINTOP_H_ #define KIS_SPRAY_PAINTOP_H_ #include #include #include "spray_brush.h" #include "kis_spray_paintop_settings.h" #include "kis_brush_option.h" #include #include #include #include #include class KisPainter; class KisSprayPaintOp : public KisPaintOp { public: KisSprayPaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image); ~KisSprayPaintOp() override; protected: KisSpacingInformation paintAt(const KisPaintInformation& info) override; KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const override; KisTimingInformation updateTimingImpl(const KisPaintInformation &info) const override; private: KisSpacingInformation computeSpacing(const KisPaintInformation &info, qreal lodScale) const; private: KisShapeProperties m_shapeProperties; KisSprayOptionProperties m_properties; KisShapeDynamicsProperties m_shapeDynamicsProperties; KisColorProperties m_colorProperties; KisBrushOptionProperties m_brushOption; KisPaintDeviceSP m_dab; SprayBrush m_sprayBrush; qreal m_xSpacing, m_ySpacing, m_spacing; bool m_isPresetValid; - KisAirbrushOptionWidget m_airbrushOptionWidget; + KisAirbrushOptionProperties m_airbrushOption; KisPressureRotationOption m_rotationOption; KisPressureSizeOption m_sizeOption; KisPressureOpacityOption m_opacityOption; KisPressureRateOption m_rateOption; KisNodeSP m_node; }; #endif // KIS_SPRAY_PAINTOP_H_ diff --git a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.cpp b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.cpp index e0bcbfe695..6534935056 100644 --- a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.cpp +++ b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.cpp @@ -1,253 +1,253 @@ /* * Copyright (C) 2015 Wolthera van Hövell tot Westerflier * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tangent_normal_paintop.h" #include #include #include #include #include #include #include #include #include #include #include #include KisTangentNormalPaintOp::KisTangentNormalPaintOp(const KisPaintOpSettingsSP settings, KisPainter* painter, KisNodeSP node, KisImageSP image): KisBrushBasedPaintOp(settings, painter), m_opacityOption(node), m_tempDev(painter->device()->createCompositionSourceDevice()) { Q_UNUSED(image); //Init, read settings, etc// m_tangentTiltOption.readOptionSetting(settings); - m_airbrushOptionWidget.readOptionSetting(settings); + m_airbrushOption.readOptionSetting(settings); m_sizeOption.readOptionSetting(settings); m_opacityOption.readOptionSetting(settings); m_flowOption.readOptionSetting(settings); m_spacingOption.readOptionSetting(settings); m_rateOption.readOptionSetting(settings); m_softnessOption.readOptionSetting(settings); m_sharpnessOption.readOptionSetting(settings); m_rotationOption.readOptionSetting(settings); m_scatterOption.readOptionSetting(settings); m_sizeOption.resetAllSensors(); m_opacityOption.resetAllSensors(); m_flowOption.resetAllSensors(); m_spacingOption.resetAllSensors(); m_rateOption.resetAllSensors(); m_softnessOption.resetAllSensors(); m_sharpnessOption.resetAllSensors(); m_rotationOption.resetAllSensors(); m_scatterOption.resetAllSensors(); m_dabCache->setSharpnessPostprocessing(&m_sharpnessOption); m_rotationOption.applyFanCornersInfo(this); } KisTangentNormalPaintOp::~KisTangentNormalPaintOp() { //destroy things here// } KisSpacingInformation KisTangentNormalPaintOp::paintAt(const KisPaintInformation& info) { /* * For the color, the precision of tilt is only 60x60, and the precision of direction and rotation are 360 and 360*90. * You can't get more precise than 8bit. Therefore, we will check if the current space is RGB, * if so we request a profile with that space and 8bit bit depth, if not, just sRGB */ KoColor currentColor = painter()->paintColor(); QString currentSpace = currentColor.colorSpace()->colorModelId().id(); const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); if (currentSpace != "RGBA") { rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); } else { rgbColorSpace = currentColor.colorSpace(); } QVector channelValues(4); qreal r, g, b; if (currentColor.colorSpace()->colorDepthId().id()=="F16" || currentColor.colorSpace()->colorDepthId().id()=="F32"){ channelValues[0] = 0.5;//red channelValues[1] = 0.5;//green channelValues[2] = 1.0;//blue channelValues[3] = 1.0;//alpha, leave alone. m_tangentTiltOption.apply(info, &r, &g, &b); channelValues[0] = r;//red channelValues[1] = g;//green channelValues[2] = b;//blue } else { channelValues[0] = 1.0;//blue channelValues[1] = 0.5;//green channelValues[2] = 0.5;//red channelValues[3] = 1.0;//alpha, leave alone. m_tangentTiltOption.apply(info, &r, &g, &b); channelValues[0] = b;//blue channelValues[1] = g;//green channelValues[2] = r;//red } quint8 data[4]; rgbColorSpace->fromNormalisedChannelsValue(data, channelValues); KoColor color(data, rgbColorSpace);//Should be default RGB(0.5,0.5,1.0) //draw stuff here, return kisspacinginformation. KisBrushSP brush = m_brush; if (!painter()->device() || !brush || !brush->canPaintFor(info)) { return KisSpacingInformation(1.0); } qreal scale = m_sizeOption.apply(info); scale *= KisLodTransform::lodToScale(painter()->device()); qreal rotation = m_rotationOption.apply(info); if (checkSizeTooSmall(scale)) return KisSpacingInformation(); KisDabShape shape(scale, 1.0, rotation); QPointF cursorPos = m_scatterOption.apply(info, brush->maskWidth(shape, 0, 0, info), brush->maskHeight(shape, 0, 0, info)); m_maskDab = m_dabCache->fetchDab(rgbColorSpace, color, cursorPos, shape, info, m_softnessOption.apply(info), &m_dstDabRect); if (m_dstDabRect.isEmpty()) return KisSpacingInformation(1.0); QRect dabRect = m_maskDab->bounds(); // sanity check Q_ASSERT(m_dstDabRect.size() == dabRect.size()); Q_UNUSED(dabRect); quint8 oldOpacity = painter()->opacity(); QString oldCompositeOpId = painter()->compositeOp()->id(); m_opacityOption.setFlow(m_flowOption.apply(info)); m_opacityOption.apply(painter(), info); //paint with the default color? Copied this from color smudge.// //painter()->setCompositeOp(COMPOSITE_COPY); //painter()->fill(0, 0, m_dstDabRect.width(), m_dstDabRect.height(), color); painter()->bltFixed(m_dstDabRect.topLeft(), m_maskDab, m_maskDab->bounds()); painter()->renderMirrorMaskSafe(m_dstDabRect, m_maskDab, !m_dabCache->needSeparateOriginal()); // restore original opacity and composite mode values painter()->setOpacity(oldOpacity); painter()->setCompositeOp(oldCompositeOpId); return computeSpacing(info, scale, rotation); } KisSpacingInformation KisTangentNormalPaintOp::updateSpacingImpl(const KisPaintInformation &info) const { qreal scale = m_sizeOption.apply(info) * KisLodTransform::lodToScale(painter()->device()); qreal rotation = m_rotationOption.apply(info); return computeSpacing(info, scale, rotation); } KisTimingInformation KisTangentNormalPaintOp::updateTimingImpl(const KisPaintInformation &info) const { - return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOptionWidget, &m_rateOption, info); + return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushOption, &m_rateOption, info); } KisSpacingInformation KisTangentNormalPaintOp::computeSpacing(const KisPaintInformation &info, qreal scale, qreal rotation) const { - return effectiveSpacing(scale, rotation, &m_airbrushOptionWidget, &m_spacingOption, info); + return effectiveSpacing(scale, rotation, &m_airbrushOption, &m_spacingOption, info); } void KisTangentNormalPaintOp::paintLine(const KisPaintInformation& pi1, const KisPaintInformation& pi2, KisDistanceInformation *currentDistance) { if (m_sharpnessOption.isChecked() && m_brush && (m_brush->width() == 1) && (m_brush->height() == 1)) { if (!m_lineCacheDevice) { m_lineCacheDevice = m_tempDev; } else { m_lineCacheDevice->clear(); } KisPainter p(m_lineCacheDevice); KoColor currentColor = painter()->paintColor(); QString currentSpace = currentColor.colorSpace()->colorModelId().id(); const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); if (currentSpace != "RGBA") { rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); } else { rgbColorSpace = currentColor.colorSpace(); } QVector channelValues(4); qreal r, g, b; if (currentColor.colorSpace()->colorDepthId().id()=="F16" || currentColor.colorSpace()->colorDepthId().id()=="F32"){ channelValues[0] = 0.5;//red channelValues[1] = 0.5;//green channelValues[2] = 1.0;//blue channelValues[3] = 1.0;//alpha, leave alone. m_tangentTiltOption.apply(pi2, &r, &g, &b); channelValues[0] = r;//red channelValues[1] = g;//green channelValues[2] = b;//blue } else { channelValues[0] = 1.0;//blue channelValues[1] = 0.5;//green channelValues[2] = 0.5;//red channelValues[3] = 1.0;//alpha, leave alone. m_tangentTiltOption.apply(pi2, &r, &g, &b); channelValues[0] = b;//blue channelValues[1] = g;//green channelValues[2] = r;//red } quint8 data[4]; rgbColorSpace->fromNormalisedChannelsValue(data, channelValues); KoColor color(data, rgbColorSpace); p.setPaintColor(color); p.drawDDALine(pi1.pos(), pi2.pos()); QRect rc = m_lineCacheDevice->extent(); painter()->bitBlt(rc.x(), rc.y(), m_lineCacheDevice, rc.x(), rc.y(), rc.width(), rc.height()); painter()->renderMirrorMask(rc, m_lineCacheDevice); } else { KisPaintOp::paintLine(pi1, pi2, currentDistance); } } diff --git a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.h b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.h index 943594f021..58e53ee966 100644 --- a/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.h +++ b/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.h @@ -1,85 +1,85 @@ /* * Copyright (C) 2015 Wolthera van Hövell tot Westerflier * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_TANGENTNORMALPAINTOP_H_ #define _KIS_TANGENTNORMALPAINTOP_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include class KisBrushBasedPaintOpSettings; class KisPainter; class KisTangentNormalPaintOp: public KisBrushBasedPaintOp { public: //public functions// /* Create a Tangent Normal Brush Operator*/ KisTangentNormalPaintOp(const KisPaintOpSettingsSP settings, KisPainter* painter, KisNodeSP node, KisImageSP image); ~KisTangentNormalPaintOp() override; void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) override; protected: /*paint the dabs*/ KisSpacingInformation paintAt(const KisPaintInformation& info) override; KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const override; KisTimingInformation updateTimingImpl(const KisPaintInformation &info) const override; private: KisSpacingInformation computeSpacing(const KisPaintInformation &info, qreal scale, qreal rotation) const; private: //private functions// KisPressureSizeOption m_sizeOption; KisFlowOpacityOption m_opacityOption; KisPressureSpacingOption m_spacingOption; KisPressureRateOption m_rateOption; KisPressureRotationOption m_rotationOption; KisPressureScatterOption m_scatterOption; KisTangentTiltOption m_tangentTiltOption; - KisAirbrushOptionWidget m_airbrushOptionWidget; + KisAirbrushOptionProperties m_airbrushOption; KisPressureSoftnessOption m_softnessOption; KisPressureSharpnessOption m_sharpnessOption; KisPressureFlowOption m_flowOption; KisFixedPaintDeviceSP m_maskDab; KisPaintDeviceSP m_tempDev; QRect m_dstDabRect; KisPaintDeviceSP m_lineCacheDevice; }; #endif // _KIS_TANGENTNORMALPAINTOP_H_