Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_regenerate_frame_stroke_strategy.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <KisRegion.h>
12#include "kis_node.h"
13#include "kis_image.h"
14#include "krita_utils.h"
15
17#include "kis_async_merger.h"
20
21
23{
30 std::optional<KisLockFrameGenerationLock> frameGenerationLock;
31
32 class Data : public KisStrokeJobData {
33 public:
34 Data(KisNodeSP _root, const QRect &_rect, const QRect &_cropRect)
36 root(_root), rect(_rect), cropRect(_cropRect)
37 {}
38
39 KisStrokeJobData* createLodClone(int levelOfDetail) override {
40 Q_UNUSED(levelOfDetail);
41 return new KisStrokeJobData(CONCURRENT);
42 }
43
45 QRect rect;
46 QRect cropRect;
47 };
48
51 if (!image) {
52 return;
53 }
54
57 }
58 }
59
62 if (!image) {
63 return;
64 }
65
66 while (!prevUpdatesFilters.isEmpty()) {
68 }
69 }
70};
71
73 const KisRegion &dirtyRegion,
74 bool isCancellable,
76 KisLockFrameGenerationLock &&frameGenerationLock)
77 : KisSimpleStrokeStrategy(QLatin1String("regenerate_external_frame_stroke")),
78 m_d(new Private)
79{
80 m_d->type = EXTERNAL_FRAME;
81
82 m_d->frameId = frameId;
83 m_d->dirtyRegion = dirtyRegion;
84 m_d->interface = interface;
85 m_d->frameGenerationLock = std::move(frameGenerationLock);
86
90
92
95
98 setCanForgetAboutMe(isCancellable);
99}
100
102 : KisSimpleStrokeStrategy(QLatin1String("regenerate_current_frame_stroke"), kundo2_i18n("Render Animation")),
103 m_d(new Private)
104{
105 m_d->type = CURRENT_FRAME;
106
107 m_d->frameId = 0;
108 m_d->dirtyRegion = KisRegion();
109 m_d->interface = interface;
110
114
117
118 // switching frames is a distinct user action, so it should
119 // cancel the playback or any action easily
122}
123
127
129{
130 KisImageSP image = m_d->interface->image().toStrongRef();
131 if (!image) {
132 return;
133 }
134 if (m_d->type == EXTERNAL_FRAME) {
135 if (!image->animationInterface()->hasAnimation()) {
136 warnKrita << "KisRegenerateFrameStrokeStrategy::initStrokeCallback(): WARNING: trying to"
137 << "regenerate an external frame on a non-animated image, that will cause"
138 << "a useless consumption of memory";
139 }
140
141 m_d->saveAndResetUpdatesFilter();
142 image->disableUIUpdates();
143 m_d->interface->saveAndResetCurrentTime(m_d->frameId, &m_d->previousFrameId);
144 } else if (m_d->type == CURRENT_FRAME) {
145 m_d->interface->blockFrameInvalidation(true);
146 m_d->interface->updatesFacade()->refreshGraphAsync(KisNodeSP(), KisProjectionUpdateFlag::DontInvalidateFrames);
147 }
148}
149
151{
152 Private::Data *d = dynamic_cast<Private::Data*>(data);
153 KIS_ASSERT(d);
154 KIS_ASSERT(!m_d->dirtyRegion.isEmpty());
155 KIS_ASSERT(m_d->type == EXTERNAL_FRAME);
156
157 const bool skipNonRenderableNodes = m_d->type == EXTERNAL_FRAME;
158 KisBaseRectsWalkerSP walker = new KisFullRefreshWalker(d->cropRect,
160 walker->collectRects(d->root, d->rect);
161
162 KisAsyncMerger merger;
163 merger.startMerge(*walker);
164}
165
167{
168 KisImageSP image = m_d->interface->image().toStrongRef();
169 if (!image) {
170 return;
171 }
172
173
174 if (m_d->type == EXTERNAL_FRAME) {
175 m_d->interface->notifyFrameReady();
176 m_d->interface->restoreCurrentTime(&m_d->previousFrameId);
177 image->enableUIUpdates();
178 m_d->restoreUpdatesFilter();
179 } else if (m_d->type == CURRENT_FRAME) {
180 m_d->interface->notifyFrameRegenerated();
181 m_d->interface->blockFrameInvalidation(false);
182 }
183}
184
186{
187 KisImageSP image = m_d->interface->image().toStrongRef();
188 if (!image) {
189 return;
190 }
191 if (m_d->type == EXTERNAL_FRAME) {
192 m_d->interface->notifyFrameCancelled();
193 m_d->interface->restoreCurrentTime(&m_d->previousFrameId);
194 image->enableUIUpdates();
195 m_d->restoreUpdatesFilter();
196 } else if (m_d->type == CURRENT_FRAME) {
197 m_d->interface->blockFrameInvalidation(false);
198 }
199}
200
202{
203 Q_UNUSED(levelOfDetail);
204
209 return m_d->type == CURRENT_FRAME ?
210 new KisRegenerateFrameStrokeStrategy(m_d->interface) :
211 new KisSimpleStrokeStrategy(QLatin1String("dumb-lodn-KisRegenerateFrameStrokeStrategy"));
212}
213
215{
216 KisImageSP image = m_d->interface->image().toStrongRef();
217 if (!image) {
218 return;
219 }
220 if (m_d->type == EXTERNAL_FRAME) {
221 m_d->interface->restoreCurrentTime(&m_d->previousFrameId);
222 image->enableUIUpdates();
223 m_d->restoreUpdatesFilter();
224 } else if (m_d->type == CURRENT_FRAME) {
225 m_d->interface->blockFrameInvalidation(false);
226 }
227}
228
230{
231 KisImageSP image = m_d->interface->image().toStrongRef();
232 if (!image) {
233 return;
234 }
235 if (m_d->type == EXTERNAL_FRAME) {
236 m_d->saveAndResetUpdatesFilter();
237 image->disableUIUpdates();
238 m_d->interface->saveAndResetCurrentTime(m_d->frameId, &m_d->previousFrameId);
239 } else if (m_d->type == CURRENT_FRAME) {
240 m_d->interface->blockFrameInvalidation(true);
241 }
242}
243
245{
248 KisImageSP image = _image;
249
250 const QRect cropRect = image->bounds();
251 QVector<QRect> rects = splitRectIntoPatches(image->bounds(), optimalPatchSize());
253
254 Q_FOREACH (const QRect &rc, rects) {
255 jobsData << new Private::Data(image->root(), rc, cropRect);
256 }
257
258 return jobsData;
259}
void startMerge(KisBaseRectsWalker &walker, bool notifyClones=true)
void collectRects(KisNodeSP node, const QRect &requestedRect)
void disableUIUpdates() override
KisImageAnimationInterface * animationInterface() const
KisProjectionUpdatesFilterSP removeProjectionUpdatesFilter(KisProjectionUpdatesFilterCookie cookie) override
removes already installed filter from the stack of updates filers
KisProjectionUpdatesFilterCookie currentProjectionUpdatesFilter() const override
QVector< QRect > enableUIUpdates() override
QRect bounds() const override
KisProjectionUpdatesFilterCookie addProjectionUpdatesFilter(KisProjectionUpdatesFilterSP filter) override
KisStrokeJobData * createLodClone(int levelOfDetail) override
Data(KisNodeSP _root, const QRect &_rect, const QRect &_cropRect)
KisRegenerateFrameStrokeStrategy(int frameId, const KisRegion &dirtyRegion, bool isCancellable, KisImageAnimationInterface *interface, KisLockFrameGenerationLock &&frameGenerationLock)
static QList< KisStrokeJobData * > createJobsData(KisImageWSP image)
void doStrokeCallback(KisStrokeJobData *data) override
KisStrokeStrategy * createLodClone(int levelOfDetail) override
void enableJob(JobType type, bool enable=true, KisStrokeJobData::Sequentiality sequentiality=KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::Exclusivity exclusivity=KisStrokeJobData::NORMAL)
KisSimpleStrokeStrategy(const QLatin1String &id, const KUndo2MagicString &name=KUndo2MagicString())
KisStrokeJobData(Sequentiality sequentiality=SEQUENTIAL, Exclusivity exclusivity=NORMAL)
void setClearsRedoOnStart(bool value)
void setRequestsOtherStrokesToEnd(bool value)
void setCanForgetAboutMe(bool value)
KisSharedPtr< T > toStrongRef() const
toStrongRef returns a KisSharedPtr which may be dereferenced.
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
#define warnKrita
Definition kis_debug.h:87
void * KisProjectionUpdatesFilterCookie
Definition kis_types.h:285
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
KUndo2MagicString kundo2_i18n(const char *text)
QVector< QRect > splitRectIntoPatches(const QRect &rc, const QSize &patchSize)
QSize optimalPatchSize()
std::optional< KisLockFrameGenerationLock > frameGenerationLock