File indexing completed on 2025-02-02 04:15:56

0001 /*
0002  *  SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
0003  *  SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org>
0004  *  SPDX-FileCopyrightText: 2004 Clarence Dang <dang@kde.org>
0005  *  SPDX-FileCopyrightText: 2004 Adrian Page <adrian@pagenet.plus.com>
0006  *  SPDX-FileCopyrightText: 2004, 2007, 2010 Cyrille Berger <cberger@cberger.net>
0007  *
0008  *  SPDX-License-Identifier: GPL-2.0-or-later
0009  */
0010 
0011 #include "kis_paintop.h"
0012 
0013 #include <QtMath>
0014 
0015 #include <KoColor.h>
0016 #include <KoColorSpace.h>
0017 #include <KoPointerEvent.h>
0018 
0019 #include "kis_painter.h"
0020 #include "kis_layer.h"
0021 
0022 #include "kis_image.h"
0023 #include "kis_paint_device.h"
0024 #include "kis_global.h"
0025 #include "kis_datamanager.h"
0026 #include <brushengine/kis_paintop_preset.h>
0027 #include <brushengine/kis_paint_information.h>
0028 #include "kis_vec.h"
0029 #include "kis_perspective_math.h"
0030 #include "kis_fixed_paint_device.h"
0031 #include "kis_paintop_utils.h"
0032 
0033 
0034 #define BEZIER_FLATNESS_THRESHOLD 0.5
0035 #include <kis_distance_information.h>
0036 
0037 #include <qnumeric.h>
0038 
0039 struct Q_DECL_HIDDEN KisPaintOp::Private {
0040     Private(KisPaintOp *_q)
0041         : q(_q) {}
0042 
0043     KisPaintOp *q {nullptr};
0044 
0045     KisFixedPaintDeviceSP dab;
0046     KisPainter* painter {nullptr};
0047 
0048     bool fanCornersEnabled {false};
0049     qreal fanCornersStep {1.0};
0050 };
0051 
0052 
0053 KisPaintOp::KisPaintOp(KisPainter * painter) : d(new Private(this))
0054 {
0055     d->painter = painter;
0056 }
0057 
0058 KisPaintOp::~KisPaintOp()
0059 {
0060     d->dab.clear();
0061     delete d;
0062 }
0063 
0064 KisFixedPaintDeviceSP KisPaintOp::cachedDab()
0065 {
0066     return cachedDab(d->painter->device()->colorSpace());
0067 }
0068 
0069 KisFixedPaintDeviceSP KisPaintOp::cachedDab(const KoColorSpace *cs)
0070 {
0071     if (!d->dab || *d->dab->colorSpace() != *cs) {
0072         d->dab = new KisFixedPaintDevice(cs);
0073     }
0074     return d->dab;
0075 }
0076 
0077 void KisPaintOp::setFanCornersInfo(bool fanCornersEnabled, qreal fanCornersStep)
0078 {
0079     d->fanCornersEnabled = fanCornersEnabled;
0080     d->fanCornersStep = fanCornersStep;
0081 }
0082 
0083 void KisPaintOp::splitCoordinate(qreal coordinate, qint32 *whole, qreal *fraction)
0084 {
0085     const qint32 i = qFloor(coordinate);
0086     const qreal f = coordinate - i;
0087 
0088     *whole = i;
0089     *fraction = f;
0090 }
0091 
0092 std::pair<int, bool> KisPaintOp::doAsynchronousUpdate(QVector<KisRunnableStrokeJobData *> &jobs)
0093 {
0094     Q_UNUSED(jobs);
0095     return std::make_pair(40, false);
0096 }
0097 
0098 static void paintBezierCurve(KisPaintOp *paintOp,
0099                              const KisPaintInformation &pi1,
0100                              const KisVector2D &control1,
0101                              const KisVector2D &control2,
0102                              const KisPaintInformation &pi2,
0103                              KisDistanceInformation *currentDistance)
0104 {
0105     LineEquation line = LineEquation::Through(toKisVector2D(pi1.pos()), toKisVector2D(pi2.pos()));
0106     qreal d1 = line.absDistance(control1);
0107     qreal d2 = line.absDistance(control2);
0108 
0109     if ((d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD)
0110             || qIsNaN(d1) || qIsNaN(d2)) {
0111         paintOp->paintLine(pi1, pi2, currentDistance);
0112     } else {
0113         // Midpoint subdivision. See Foley & Van Dam Computer Graphics P.508
0114         KisVector2D l2 = (toKisVector2D(pi1.pos()) + control1) / 2;
0115         KisVector2D h = (control1 + control2) / 2;
0116         KisVector2D l3 = (l2 + h) / 2;
0117         KisVector2D r3 = (control2 + toKisVector2D(pi2.pos())) / 2;
0118         KisVector2D r2 = (h + r3) / 2;
0119         KisVector2D l4 = (l3 + r2) / 2;
0120 
0121         KisPaintInformation middlePI = KisPaintInformation::mix(toQPointF(l4), 0.5, pi1, pi2);
0122 
0123         paintBezierCurve(paintOp, pi1, l2, l3, middlePI, currentDistance);
0124         paintBezierCurve(paintOp, middlePI, r2, r3, pi2, currentDistance);
0125     }
0126 }
0127 
0128 void KisPaintOp::paintBezierCurve(const KisPaintInformation &pi1,
0129                                   const QPointF &control1,
0130                                   const QPointF &control2,
0131                                   const KisPaintInformation &pi2,
0132                                   KisDistanceInformation *currentDistance)
0133 {
0134     return ::paintBezierCurve(this, pi1, toKisVector2D(control1), toKisVector2D(control2), pi2, currentDistance);
0135 }
0136 
0137 
0138 void KisPaintOp::paintLine(const KisPaintInformation &pi1,
0139                            const KisPaintInformation &pi2,
0140                            KisDistanceInformation *currentDistance)
0141 {
0142     KisPaintOpUtils::paintLine(*this, pi1, pi2, currentDistance,
0143                                d->fanCornersEnabled,
0144                                d->fanCornersStep);
0145 }
0146 
0147 void KisPaintOp::paintAt(const KisPaintInformation& info, KisDistanceInformation *currentDistance)
0148 {
0149     Q_ASSERT(currentDistance);
0150 
0151     KisPaintInformation pi(info);
0152     pi.paintAt(*this, currentDistance);
0153 }
0154 
0155 void KisPaintOp::updateSpacing(const KisPaintInformation &info,
0156                                KisDistanceInformation &currentDistance) const
0157 {
0158     KisPaintInformation pi(info);
0159     KisSpacingInformation spacingInfo;
0160     {
0161         KisPaintInformation::DistanceInformationRegistrar r
0162             = pi.registerDistanceInformation(&currentDistance);
0163         spacingInfo = updateSpacingImpl(pi);
0164     }
0165 
0166     currentDistance.updateSpacing(spacingInfo);
0167 }
0168 
0169 void KisPaintOp::updateTiming(const KisPaintInformation &info,
0170                               KisDistanceInformation &currentDistance) const
0171 {
0172     KisPaintInformation pi(info);
0173     KisTimingInformation timingInfo;
0174     {
0175         KisPaintInformation::DistanceInformationRegistrar r
0176             = pi.registerDistanceInformation(&currentDistance);
0177         timingInfo = updateTimingImpl(pi);
0178     }
0179 
0180     currentDistance.updateTiming(timingInfo);
0181 }
0182 
0183 KisTimingInformation KisPaintOp::updateTimingImpl(const KisPaintInformation &info) const
0184 {
0185     Q_UNUSED(info);
0186     return KisTimingInformation();
0187 }
0188 
0189 KisPainter* KisPaintOp::painter() const
0190 {
0191     return d->painter;
0192 }
0193 
0194 KisPaintDeviceSP KisPaintOp::source() const
0195 {
0196     return d->painter->device();
0197 }