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 | |
23 | namespace app { |
24 | |
25 | using namespace ui; |
26 | using namespace filters; |
27 | |
28 | FilterPreview::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 | |
38 | FilterPreview::~FilterPreview() |
39 | { |
40 | stop(); |
41 | } |
42 | |
43 | void 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 | |
59 | void 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 | |
77 | void 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 | |
90 | bool 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. |
123 | void 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 | |