File indexing completed on 2024-12-22 04:16:22
0001 /* 0002 * SPDX-FileCopyrightText: 2008-2012 Lukáš Tvrdý <lukast.dev@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_spray_paintop.h" 0008 #include "kis_spray_paintop_settings.h" 0009 0010 #include <cmath> 0011 0012 #include <QRect> 0013 #include <kis_global.h> 0014 #include <kis_paint_device.h> 0015 #include <kis_painter.h> 0016 #include <kis_types.h> 0017 #include <brushengine/kis_paintop.h> 0018 #include <kis_node.h> 0019 0020 #include <kis_fixed_paint_device.h> 0021 #include <kis_brush_option.h> 0022 #include <kis_lod_transform.h> 0023 #include <kis_paintop_plugin_utils.h> 0024 #include <KoResourceLoadResult.h> 0025 0026 0027 KisSprayPaintOp::KisSprayPaintOp(const KisPaintOpSettingsSP settings, KisPainter *painter, KisNodeSP node, KisImageSP image) 0028 : KisPaintOp(painter) 0029 , m_sprayOpOption(settings.data()) 0030 , m_isPresetValid(true) 0031 , m_rotationOption(settings.data()) 0032 , m_sizeOption(settings.data()) 0033 , m_opacityOption(settings.data()) 0034 , m_rateOption(settings.data()) 0035 , m_node(node) 0036 0037 { 0038 Q_ASSERT(settings); 0039 Q_ASSERT(painter); 0040 Q_UNUSED(image); 0041 0042 m_airbrushData.read(settings.data()); 0043 0044 m_brushOption.readOptionSetting(settings, settings->resourcesInterface(), settings->canvasResourcesInterface()); 0045 0046 m_colorProperties.read(settings.data()); 0047 // create the actual distribution objects 0048 m_sprayOpOption.updateDistributions(); 0049 // first load tip properties as shape properties are dependent on diameter/scale/aspect 0050 m_shapeProperties.read(settings.data()); 0051 0052 // TODO: what to do with proportional sizes? 0053 m_shapeDynamicsProperties.read(settings.data()); 0054 0055 if (!m_shapeProperties.enabled && !m_brushOption.brush()) { 0056 // in case the preset does not contain the definition for KisBrush 0057 m_isPresetValid = false; 0058 dbgKrita << "Preset is not valid. Painting is not possible. Use the preset editor to fix current brush engine preset."; 0059 } 0060 0061 m_sprayBrush.setProperties(&m_sprayOpOption.data, &m_colorProperties, 0062 &m_shapeProperties, &m_shapeDynamicsProperties, m_brushOption.brush()); 0063 0064 m_sprayBrush.setFixedDab(cachedDab()); 0065 0066 // spacing 0067 if ((m_sprayOpOption.data.diameter * 0.5) > 1) { 0068 m_ySpacing = m_xSpacing = m_sprayOpOption.data.diameter * 0.5 * m_sprayOpOption.data.spacing; 0069 } 0070 else { 0071 m_ySpacing = m_xSpacing = 1.0; 0072 } 0073 m_spacing = m_xSpacing; 0074 } 0075 0076 KisSprayPaintOp::~KisSprayPaintOp() 0077 { 0078 } 0079 0080 QList<KoResourceLoadResult> KisSprayPaintOp::prepareLinkedResources(const KisPaintOpSettingsSP settings, KisResourcesInterfaceSP resourcesInterface) 0081 { 0082 KisBrushOptionProperties brushOption; 0083 return brushOption.prepareLinkedResources(settings, resourcesInterface); 0084 } 0085 0086 KisSpacingInformation KisSprayPaintOp::paintAt(const KisPaintInformation& info) 0087 { 0088 if (!painter() || !m_isPresetValid) { 0089 return KisSpacingInformation(m_spacing); 0090 } 0091 0092 if (!m_dab) { 0093 m_dab = source()->createCompositionSourceDevice(); 0094 } 0095 else { 0096 m_dab->clear(); 0097 } 0098 0099 qreal rotation = m_rotationOption.apply(info); 0100 quint8 origOpacity = m_opacityOption.apply(painter(), info); 0101 // Spray Brush is capable of working with zero scale, 0102 // so no additional checks for 'zero'ness are needed 0103 const qreal scale = m_sizeOption.apply(info); 0104 const qreal lodScale = KisLodTransform::lodToScale(painter()->device()); 0105 0106 0107 m_sprayBrush.paint(m_dab, 0108 m_node->paintDevice(), 0109 info, 0110 rotation, 0111 scale, lodScale, 0112 painter()->paintColor(), 0113 painter()->backgroundColor()); 0114 0115 QRect rc = m_dab->extent(); 0116 painter()->bitBlt(rc.topLeft(), m_dab, rc); 0117 painter()->renderMirrorMask(rc, m_dab); 0118 painter()->setOpacity(origOpacity); 0119 0120 return computeSpacing(info, lodScale); 0121 } 0122 0123 KisSpacingInformation KisSprayPaintOp::updateSpacingImpl(const KisPaintInformation &info) const 0124 { 0125 return computeSpacing(info, KisLodTransform::lodToScale(painter()->device())); 0126 } 0127 0128 KisTimingInformation KisSprayPaintOp::updateTimingImpl(const KisPaintInformation &info) const 0129 { 0130 return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushData, &m_rateOption, info); 0131 } 0132 0133 KisSpacingInformation KisSprayPaintOp::computeSpacing(const KisPaintInformation &info, 0134 qreal lodScale) const 0135 { 0136 return KisPaintOpPluginUtils::effectiveSpacing(1.0, 1.0, true, 0.0, false, 0137 m_spacing * lodScale, false, 1.0, lodScale, 0138 &m_airbrushData, nullptr, info); 0139 }