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 }