File indexing completed on 2024-06-09 04:28:10

0001 /*
0002  *  SPDX-FileCopyrightText: 2012 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_dab_cache.h"
0008 
0009 #include <KoColor.h>
0010 #include "kis_paint_device.h"
0011 #include "kis_brush.h"
0012 #include <kis_fixed_paint_device.h>
0013 #include "kis_color_source.h"
0014 #include "KisSharpnessOption.h"
0015 #include "kis_texture_option.h"
0016 
0017 #include <kundo2command.h>
0018 
0019 struct KisDabCache::Private {
0020 
0021     Private(KisBrushSP brush)
0022         : brush(brush)
0023     {}
0024 
0025     int seqNo = 0;
0026 
0027     KisFixedPaintDeviceSP dab;
0028     KisFixedPaintDeviceSP dabOriginal;
0029 
0030     KisBrushSP brush;
0031     KisPaintDeviceSP colorSourceDevice;
0032 
0033     KisSharpnessOption *sharpnessOption = 0;
0034     KisTextureOption *textureOption = 0;
0035 };
0036 
0037 
0038 
0039 KisDabCache::KisDabCache(KisBrushSP brush)
0040     : m_d(new Private(brush))
0041 {
0042 }
0043 
0044 KisDabCache::~KisDabCache()
0045 {
0046     delete m_d;
0047 }
0048 
0049 void KisDabCache::setSharpnessPostprocessing(KisSharpnessOption *option)
0050 {
0051     m_d->sharpnessOption = option;
0052 }
0053 
0054 void KisDabCache::setTexturePostprocessing(KisTextureOption *option)
0055 {
0056     m_d->textureOption = option;
0057 }
0058 
0059 bool KisDabCache::needSeparateOriginal() const
0060 {
0061     return KisDabCacheBase::needSeparateOriginal(m_d->textureOption, m_d->sharpnessOption);
0062 }
0063 
0064 
0065 KisFixedPaintDeviceSP KisDabCache::fetchDab(const KoColorSpace *cs,
0066         KisColorSource *colorSource,
0067         const QPointF &cursorPoint,
0068         KisDabShape const& shape,
0069         const KisPaintInformation& info,
0070         qreal softnessFactor,
0071         QRect *dstDabRect,
0072         qreal lightnessStrength)
0073 {
0074     //Q_UNUSED(lightnessStrength);
0075 
0076     return fetchDabCommon(cs, colorSource, KoColor(),
0077                           cursorPoint,
0078                           shape,
0079                           info,
0080                           softnessFactor,
0081                           dstDabRect,
0082                           lightnessStrength);
0083 }
0084 
0085 KisFixedPaintDeviceSP KisDabCache::fetchDab(const KoColorSpace *cs,
0086         const KoColor& color,
0087         const QPointF &cursorPoint,
0088         KisDabShape const& shape,
0089         const KisPaintInformation& info,
0090         qreal softnessFactor,
0091         QRect *dstDabRect,
0092         qreal lightnessStrength)
0093 {
0094     return fetchDabCommon(cs, 0, color,
0095                           cursorPoint,
0096                           shape,
0097                           info,
0098                           softnessFactor,
0099                           dstDabRect,
0100                           lightnessStrength);
0101 }
0102 
0103 KisFixedPaintDeviceSP KisDabCache::fetchNormalizedImageDab(const KoColorSpace *cs,
0104                                                            const QPointF &cursorPoint,
0105                                                            KisDabShape const& shape,
0106                                                            const KisPaintInformation& info,
0107                                                            qreal softnessFactor,
0108                                                            QRect *dstDabRect)
0109 {
0110     return fetchDabCommon(cs, 0, KoColor(),
0111                           cursorPoint,
0112                           shape,
0113                           info,
0114                           softnessFactor,
0115                           dstDabRect,
0116                           1.0,
0117                           true);
0118 }
0119 
0120 inline
0121 KisFixedPaintDeviceSP KisDabCache::fetchFromCache(KisDabCacheUtils::DabRenderingResources *resources,
0122                                                   const KisPaintInformation& info,
0123                                                   QRect *dstDabRect)
0124 {
0125     if (needSeparateOriginal()) {
0126         *m_d->dab = *m_d->dabOriginal;
0127         *dstDabRect = KisDabCacheUtils::correctDabRectWhenFetchedFromCache(*dstDabRect, m_d->dab->bounds().size());
0128         KisDabCacheUtils::postProcessDab(m_d->dab, dstDabRect->topLeft(), info, resources);
0129     }
0130     else {
0131         *dstDabRect = KisDabCacheUtils::correctDabRectWhenFetchedFromCache(*dstDabRect, m_d->dab->bounds().size());
0132     }
0133 
0134     return m_d->dab;
0135 }
0136 
0137 /**
0138  * A special hack class that allows creation of temporary object with resources
0139  * without taking ownership over the option classes
0140  */
0141 struct TemporaryResourcesWithoutOwning : public KisDabCacheUtils::DabRenderingResources
0142 {
0143     ~TemporaryResourcesWithoutOwning() override {
0144         // we do not own these resources, so just
0145         // release them before destruction
0146         colorSource.take();
0147         sharpnessOption.take();
0148         textureOption.take();
0149     }
0150 };
0151 
0152 inline
0153 KisFixedPaintDeviceSP KisDabCache::fetchDabCommon(const KoColorSpace *cs,
0154         KisColorSource *colorSource,
0155         const KoColor& color,
0156         const QPointF &cursorPoint,
0157         KisDabShape shape,
0158         const KisPaintInformation& info,
0159         qreal softnessFactor,
0160         QRect *dstDabRect,
0161         qreal lightnessStrength,
0162         bool forceNormalizedRGBAImageStamp)
0163 {
0164     Q_ASSERT(dstDabRect);
0165     //Q_UNUSED(lightnessStrength);
0166 
0167     bool hasDabInCache = true;
0168 
0169     if (!m_d->dab || *m_d->dab->colorSpace() != *cs) {
0170         m_d->dab = new KisFixedPaintDevice(cs);
0171         hasDabInCache = false;
0172     }
0173 
0174     using namespace KisDabCacheUtils;
0175 
0176     // 0. Notify brush that we ar going to paint a new dab
0177 
0178     m_d->brush->prepareForSeqNo(info, m_d->seqNo);
0179     m_d->seqNo++;
0180 
0181     // 1. Calculate new dab parameters and whether we can reuse the cache
0182 
0183     TemporaryResourcesWithoutOwning resources;
0184     resources.brush = m_d->brush;
0185     resources.colorSourceDevice = m_d->colorSourceDevice;
0186 
0187     // NOTE: we use a special subclass of resources that will NOT
0188     //       delete options on destruction!
0189     resources.colorSource.reset(colorSource);
0190     resources.sharpnessOption.reset(m_d->sharpnessOption);
0191     resources.textureOption.reset(m_d->textureOption);
0192 
0193 
0194     DabGenerationInfo di;
0195     bool shouldUseCache = false;
0196 
0197     fetchDabGenerationInfo(hasDabInCache,
0198                            &resources,
0199                            DabRequestInfo(
0200                                color,
0201                                cursorPoint,
0202                                shape,
0203                                info,
0204                                softnessFactor,
0205                                lightnessStrength),
0206                            &di,
0207                            &shouldUseCache);
0208 
0209     *dstDabRect = di.dstDabRect;
0210 
0211 
0212     // 2. Try return a saved dab from the cache
0213 
0214     if (shouldUseCache) {
0215         return fetchFromCache(&resources, info, dstDabRect);
0216     }
0217 
0218     // 3. Generate new dab
0219 
0220     generateDab(di, &resources, &m_d->dab, forceNormalizedRGBAImageStamp);
0221 
0222     // 4. Do postprocessing
0223     if (di.needsPostprocessing) {
0224         if (!m_d->dabOriginal || *cs != *m_d->dabOriginal->colorSpace()) {
0225             m_d->dabOriginal = new KisFixedPaintDevice(cs);
0226         }
0227 
0228         *m_d->dabOriginal = *m_d->dab;
0229 
0230         postProcessDab(m_d->dab, di.dstDabRect.topLeft(), info, &resources);
0231     }
0232 
0233     return m_d->dab;
0234 }