Warning, file /graphics/krita/plugins/paintops/tangentnormal/kis_tangent_normal_paintop.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  *  SPDX-FileCopyrightText: 2015 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_tangent_normal_paintop.h"
0008 
0009 #include <QRect>
0010 
0011 #include <KoColorSpaceRegistry.h>
0012 #include <KoColor.h>
0013 
0014 #include <kis_brush.h>
0015 #include <kis_paint_device.h>
0016 #include <kis_painter.h>
0017 #include <kis_node.h>
0018 #include <kis_brush_based_paintop_settings.h>
0019 #include <kis_fixed_paint_device.h>
0020 #include <kis_image.h>
0021 #include <kis_lod_transform.h>
0022 #include <kis_paintop_plugin_utils.h>
0023 
0024 
0025 KisTangentNormalPaintOp::KisTangentNormalPaintOp(const KisPaintOpSettingsSP settings, KisPainter* painter, KisNodeSP node, KisImageSP image)
0026     : KisBrushBasedPaintOp(settings, painter)
0027     , m_tangentTiltOption(settings.data())
0028     , m_opacityOption(settings.data(), node)
0029     , m_flowOption(settings.data())
0030     , m_sizeOption(settings.data())
0031     , m_spacingOption(settings.data())
0032     , m_softnessOption(settings.data())
0033     , m_sharpnessOption(settings.data())
0034     , m_scatterOption(settings.data())
0035     , m_rotationOption(settings.data())
0036     , m_rateOption(settings.data())
0037     , m_tempDev(painter->device()->createCompositionSourceDevice())
0038 
0039 {
0040     Q_UNUSED(image);
0041     //Init, read settings, etc//
0042     m_airbrushData.read(settings.data());
0043 
0044     m_dabCache->setSharpnessPostprocessing(&m_sharpnessOption);
0045     m_rotationOption.applyFanCornersInfo(this);
0046 }
0047 
0048 KisTangentNormalPaintOp::~KisTangentNormalPaintOp()
0049 {
0050     //destroy things here//
0051 }
0052 
0053 KisSpacingInformation KisTangentNormalPaintOp::paintAt(const KisPaintInformation& info)
0054 {
0055     /*
0056      * For the color, the precision of tilt is only 60x60, and the precision of direction and rotation are 360 and 360*90.
0057      * You can't get more precise than 8bit. Therefore, we will check if the current space is RGB,
0058      * if so we request a profile with that space and 8bit bit depth, if not, just sRGB
0059      */
0060     KoColor currentColor = painter()->paintColor();
0061     QString currentSpace = currentColor.colorSpace()->colorModelId().id();
0062     const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8();
0063     if (currentSpace != "RGBA") {
0064         rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8();
0065     } else {
0066         rgbColorSpace = currentColor.colorSpace();
0067     }
0068     QVector <float> channelValues(4);
0069     qreal r, g, b;
0070 
0071     if (currentColor.colorSpace()->colorDepthId().id()=="F16" || currentColor.colorSpace()->colorDepthId().id()=="F32"){
0072         channelValues[0] = 0.5;//red
0073         channelValues[1] = 0.5;//green
0074         channelValues[2] = 1.0;//blue
0075         channelValues[3] = 1.0;//alpha, leave alone.
0076 
0077 
0078         m_tangentTiltOption.apply(info, &r, &g, &b);
0079 
0080         channelValues[0] = r;//red
0081         channelValues[1] = g;//green
0082         channelValues[2] = b;//blue
0083     } else {
0084         channelValues[0] = 1.0;//blue
0085         channelValues[1] = 0.5;//green
0086         channelValues[2] = 0.5;//red
0087         channelValues[3] = 1.0;//alpha, leave alone.
0088 
0089         m_tangentTiltOption.apply(info, &r, &g, &b);
0090 
0091         channelValues[0] = b;//blue
0092         channelValues[1] = g;//green
0093         channelValues[2] = r;//red
0094     }
0095 
0096     quint8 data[MAX_PIXEL_SIZE];
0097     rgbColorSpace->fromNormalisedChannelsValue(data, channelValues);
0098     KoColor color(data, rgbColorSpace);//Should be default RGB(0.5,0.5,1.0)
0099     //draw stuff here, return kisspacinginformation.
0100     KisBrushSP brush = m_brush;
0101 
0102     if (!painter()->device() || !brush || !brush->canPaintFor(info)) {
0103         return KisSpacingInformation(1.0);
0104     }
0105 
0106     qreal scale    = m_sizeOption.apply(info);
0107     scale *= KisLodTransform::lodToScale(painter()->device());
0108     qreal rotation = m_rotationOption.apply(info);
0109     if (checkSizeTooSmall(scale)) return KisSpacingInformation();
0110     KisDabShape shape(scale, 1.0, rotation);
0111 
0112 
0113     QPointF cursorPos =
0114             m_scatterOption.apply(info,
0115                                   brush->maskWidth(shape, 0, 0, info),
0116                                   brush->maskHeight(shape, 0, 0, info));
0117 
0118     m_maskDab =
0119             m_dabCache->fetchDab(rgbColorSpace, color, cursorPos,
0120                                  shape,
0121                                  info, m_softnessOption.apply(info),
0122                                  &m_dstDabRect);
0123 
0124     if (m_dstDabRect.isEmpty()) return KisSpacingInformation(1.0);
0125 
0126     QRect dabRect = m_maskDab->bounds();
0127 
0128     // sanity check
0129     Q_ASSERT(m_dstDabRect.size() == dabRect.size());
0130     Q_UNUSED(dabRect);
0131 
0132     quint8  oldOpacity = painter()->opacity();
0133     QString oldCompositeOpId = painter()->compositeOpId();
0134 
0135 
0136     m_opacityOption.apply(painter(), info);
0137     //paint with the default color? Copied this from color smudge.//
0138     //painter()->setCompositeOp(COMPOSITE_COPY);
0139     //painter()->fill(0, 0, m_dstDabRect.width(), m_dstDabRect.height(), color);
0140     painter()->bltFixed(m_dstDabRect.topLeft(), m_maskDab, m_maskDab->bounds());
0141     painter()->renderMirrorMaskSafe(m_dstDabRect, m_maskDab, !m_dabCache->needSeparateOriginal());
0142 
0143     // restore original opacity and composite mode values
0144     painter()->setOpacity(oldOpacity);
0145     painter()->setCompositeOpId(oldCompositeOpId);
0146 
0147     return computeSpacing(info, scale, rotation);
0148 }
0149 
0150 KisSpacingInformation KisTangentNormalPaintOp::updateSpacingImpl(const KisPaintInformation &info) const
0151 {
0152     qreal scale = m_sizeOption.apply(info) * KisLodTransform::lodToScale(painter()->device());
0153     qreal rotation = m_rotationOption.apply(info);
0154     return computeSpacing(info, scale, rotation);
0155 }
0156 
0157 KisTimingInformation KisTangentNormalPaintOp::updateTimingImpl(const KisPaintInformation &info) const
0158 {
0159     return KisPaintOpPluginUtils::effectiveTiming(&m_airbrushData, &m_rateOption, info);
0160 }
0161 
0162 KisSpacingInformation KisTangentNormalPaintOp::computeSpacing(const KisPaintInformation &info,
0163                                                               qreal scale, qreal rotation) const
0164 {
0165     return effectiveSpacing(scale, rotation, &m_airbrushData, &m_spacingOption, info);
0166 }
0167 
0168 void KisTangentNormalPaintOp::paintLine(const KisPaintInformation& pi1, const KisPaintInformation& pi2, KisDistanceInformation *currentDistance)
0169 {
0170     if (m_sharpnessOption.isChecked() && m_brush && (m_brush->width() == 1) && (m_brush->height() == 1)) {
0171 
0172         if (!m_lineCacheDevice) {
0173             m_lineCacheDevice = m_tempDev;
0174         }
0175         else {
0176             m_lineCacheDevice->clear();
0177         }
0178 
0179         KisPainter p(m_lineCacheDevice);
0180         KoColor currentColor = painter()->paintColor();
0181         QString currentSpace = currentColor.colorSpace()->colorModelId().id();
0182         const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8();
0183         if (currentSpace != "RGBA") {
0184             rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8();
0185         } else {
0186             rgbColorSpace = currentColor.colorSpace();
0187         }
0188         QVector <float> channelValues(4);
0189         qreal r, g, b;
0190 
0191         if (currentColor.colorSpace()->colorDepthId().id()=="F16" || currentColor.colorSpace()->colorDepthId().id()=="F32"){
0192             channelValues[0] = 0.5;//red
0193             channelValues[1] = 0.5;//green
0194             channelValues[2] = 1.0;//blue
0195             channelValues[3] = 1.0;//alpha, leave alone.
0196 
0197 
0198             m_tangentTiltOption.apply(pi2, &r, &g, &b);
0199 
0200             channelValues[0] = r;//red
0201             channelValues[1] = g;//green
0202             channelValues[2] = b;//blue
0203         } else {
0204             channelValues[0] = 1.0;//blue
0205             channelValues[1] = 0.5;//green
0206             channelValues[2] = 0.5;//red
0207             channelValues[3] = 1.0;//alpha, leave alone.
0208 
0209             m_tangentTiltOption.apply(pi2, &r, &g, &b);
0210 
0211             channelValues[0] = b;//blue
0212             channelValues[1] = g;//green
0213             channelValues[2] = r;//red
0214         }
0215 
0216         quint8 data[4];
0217         rgbColorSpace->fromNormalisedChannelsValue(data, channelValues);
0218         KoColor color(data, rgbColorSpace);
0219         p.setPaintColor(color);
0220         p.drawDDALine(pi1.pos(), pi2.pos());
0221 
0222         QRect rc = m_lineCacheDevice->extent();
0223         painter()->bitBlt(rc.x(), rc.y(), m_lineCacheDevice, rc.x(), rc.y(), rc.width(), rc.height());
0224         painter()->renderMirrorMask(rc, m_lineCacheDevice);
0225     }
0226     else {
0227         KisPaintOp::paintLine(pi1, pi2, currentDistance);
0228     }
0229 }