File indexing completed on 2024-06-16 04:17:34

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_particle_paintop.h"
0008 #include "kis_particle_paintop_settings.h"
0009 
0010 #include <cmath>
0011 
0012 #include "kis_vec.h"
0013 
0014 #include <KoCompositeOp.h>
0015 
0016 #include <kis_image.h>
0017 #include <kis_debug.h>
0018 
0019 #include <kis_global.h>
0020 #include <kis_paint_device.h>
0021 #include <kis_painter.h>
0022 #include <kis_lod_transform.h>
0023 #include <kis_types.h>
0024 #include <kis_paintop_plugin_utils.h>
0025 #include <brushengine/kis_paintop.h>
0026 #include <brushengine/kis_paint_information.h>
0027 
0028 #include "KisParticleOpOptionData.h"
0029 
0030 #include "particle_brush.h"
0031 
0032 KisParticlePaintOp::KisParticlePaintOp(const KisPaintOpSettingsSP settings, KisPainter * painter, KisNodeSP node, KisImageSP image)
0033     : KisPaintOp(painter)
0034     , m_rateOption(settings.data())
0035     , m_first(true)
0036 {
0037     Q_UNUSED(image);
0038     Q_UNUSED(node);
0039 
0040     m_particleOpData.read(settings.data());
0041 
0042     m_particleBrush.setProperties(&m_particleOpData);
0043     m_particleBrush.initParticles();
0044 
0045     m_airbrushData.read(settings.data());
0046 }
0047 
0048 KisParticlePaintOp::~KisParticlePaintOp()
0049 {
0050 }
0051 
0052 KisSpacingInformation KisParticlePaintOp::paintAt(const KisPaintInformation& info)
0053 {
0054     doPaintLine(info, info);
0055     return updateSpacingImpl(info);
0056 }
0057 
0058 KisSpacingInformation KisParticlePaintOp::updateSpacingImpl(const KisPaintInformation &info) const
0059 {
0060     return KisPaintOpPluginUtils::effectiveSpacing(0.0, 0.0, true, 0.0, false, 0.0, false, 0.0,
0061                                                    KisLodTransform::lodToScale(painter()->device()),
0062                                                    &m_airbrushData, nullptr, info);
0063 }
0064 
0065 KisTimingInformation KisParticlePaintOp::updateTimingImpl(const KisPaintInformation &info) const
0066 {
0067     return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushData, &m_rateOption, info);
0068 }
0069 
0070 void KisParticlePaintOp::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2,
0071                                    KisDistanceInformation *currentDistance)
0072 {
0073     // Use superclass behavior for lines of zero length. Otherwise, airbrushing can happen faster
0074     // than it is supposed to.
0075     if (pi1.pos() == pi2.pos()) {
0076         KisPaintOp::paintLine(pi1, pi2, currentDistance);
0077     } else {
0078         doPaintLine(pi1, pi2);
0079     }
0080 }
0081 
0082 void KisParticlePaintOp::doPaintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2)
0083 {
0084     if (!painter()) return;
0085 
0086     if (!m_dab) {
0087         m_dab = source()->createCompositionSourceDevice();
0088     }
0089     else {
0090         m_dab->clear();
0091     }
0092 
0093 
0094     if (m_first) {
0095         m_particleBrush.setInitialPosition(pi1.pos());
0096         m_first = false;
0097     }
0098 
0099     m_particleBrush.draw(m_dab, painter()->paintColor(), pi2.pos());
0100     QRect rc = m_dab->extent();
0101 
0102     painter()->bitBlt(rc.x(), rc.y(), m_dab, rc.x(), rc.y(), rc.width(), rc.height());
0103     painter()->renderMirrorMask(rc, m_dab);
0104 }