1// Aseprite
2// Copyright (C) 2019-2022 Igara Studio S.A.
3// Copyright (C) 2001-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/commands/filters/filter_preview.h"
13
14#include "app/commands/filters/filter_manager_impl.h"
15#include "app/ui/editor/editor.h"
16#include "app/ui/editor/editor_render.h"
17#include "doc/layer.h"
18#include "doc/sprite.h"
19#include "ui/manager.h"
20#include "ui/message.h"
21#include "ui/widget.h"
22
23namespace app {
24
25using namespace ui;
26using namespace filters;
27
28FilterPreview::FilterPreview(FilterManagerImpl* filterMgr)
29 : Widget(kGenericWidget)
30 , m_filterMgr(filterMgr)
31 , m_timer(1, this)
32 , m_filterThread(nullptr)
33 , m_filterIsDone(false)
34{
35 setVisible(false);
36}
37
38FilterPreview::~FilterPreview()
39{
40 stop();
41}
42
43void FilterPreview::setEnablePreview(bool state)
44{
45 if (state) {
46 Editor::renderEngine().setPreviewImage(
47 m_filterMgr->layer(),
48 m_filterMgr->frame(),
49 m_filterMgr->destinationImage(),
50 nullptr,
51 m_filterMgr->position(),
52 static_cast<doc::LayerImage*>(m_filterMgr->layer())->blendMode());
53 }
54 else {
55 Editor::renderEngine().removePreviewImage();
56 }
57}
58
59void FilterPreview::stop()
60{
61 {
62 std::scoped_lock lock(m_filterMgrMutex);
63 if (m_timer.isRunning()) {
64 ASSERT(m_filterMgr);
65 m_filterMgr->end();
66 }
67 }
68
69 m_timer.stop();
70
71 if (m_filterThread) {
72 m_filterThread->join();
73 m_filterThread.reset();
74 }
75}
76
77void FilterPreview::restartPreview()
78{
79 stop();
80
81 std::scoped_lock lock(m_filterMgrMutex);
82
83 m_filterMgr->beginForPreview();
84 m_filterIsDone = false;
85 m_timer.start();
86 m_filterThread.reset(
87 new base::thread([this]{ onFilterThread(); }));
88}
89
90bool FilterPreview::onProcessMessage(Message* msg)
91{
92 switch (msg->type()) {
93
94 case kOpenMessage:
95 setEnablePreview(true);
96 break;
97
98 case kCloseMessage:
99 setEnablePreview(false);
100
101 // Stop the preview timer.
102 {
103 std::scoped_lock lock(m_filterMgrMutex);
104 m_timer.stop();
105 }
106 break;
107
108 case kTimerMessage: {
109 std::scoped_lock lock(m_filterMgrMutex);
110 if (m_filterMgr) {
111 m_filterMgr->flush();
112 if (m_filterIsDone)
113 m_timer.stop();
114 }
115 break;
116 }
117 }
118
119 return Widget::onProcessMessage(msg);
120}
121
122// This is executed in other thread.
123void FilterPreview::onFilterThread()
124{
125 bool running = true;
126 while (running) {
127 {
128 std::scoped_lock lock(m_filterMgrMutex);
129 m_filterIsDone = !m_filterMgr->applyStep();
130 running = (!m_filterIsDone && m_timer.isRunning());
131 }
132 base::this_thread::yield();
133 }
134}
135
136} // namespace app
137