comparison Applications/Platforms/WebAssembly/WebGLViewportsRegistry.cpp @ 1591:5887a4f8594b

moving platform-specific files out of the "OrthancStone" folder
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 23 Oct 2020 13:15:03 +0200
parents OrthancStone/Sources/Viewport/WebGLViewportsRegistry.cpp@314b6dc507d9
children 9ac2a65d4172
comparison
equal deleted inserted replaced
1590:7b963bccafef 1591:5887a4f8594b
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21
22 #include "WebGLViewportsRegistry.h"
23
24 #include "../../../OrthancStone/Sources/Scene2DViewport/ViewportController.h"
25 #include "../../../OrthancStone/Sources/Toolbox/GenericToolbox.h"
26
27 #include <OrthancException.h>
28
29 #include <boost/make_shared.hpp>
30
31
32 static double viewportsTimeout_ = 1000;
33 static std::unique_ptr<OrthancStone::WebGLViewportsRegistry> globalRegistry_;
34
35
36 namespace OrthancStone
37 {
38 void WebGLViewportsRegistry::LaunchTimer()
39 {
40 timeOutID_ = emscripten_set_timeout(
41 OnTimeoutCallback,
42 timeoutMS_,
43 reinterpret_cast<void*>(this));
44 }
45
46 void WebGLViewportsRegistry::OnTimeout()
47 {
48 for (Viewports::iterator it = viewports_.begin();
49 it != viewports_.end();
50 ++it)
51 {
52 if (it->second == NULL ||
53 it->second->IsContextLost())
54 {
55 LOG(INFO) << "WebGL context lost for canvas: " << it->first;
56
57 // Try and duplicate the HTML5 canvas in the DOM
58 EM_ASM({
59 var canvas = document.getElementById(UTF8ToString($0));
60 if (canvas) {
61 var parent = canvas.parentElement;
62 if (parent) {
63 var cloned = canvas.cloneNode(true /* deep copy */);
64 parent.insertBefore(cloned, canvas);
65 parent.removeChild(canvas);
66 }
67 }
68 },
69 it->first.c_str() // $0 = ID of the canvas
70 );
71
72 // At this point, the old canvas is removed from the DOM and
73 // replaced by a fresh one with the same ID: Recreate the
74 // WebGL context on the new canvas
75 boost::shared_ptr<WebGLViewport> viewport;
76
77 // we need to steal the properties from the old viewport
78 // and set them to the new viewport
79 {
80 std::unique_ptr<IViewport::ILock> lock(it->second->Lock());
81
82 // TODO: remove ViewportController
83 Scene2D* scene = lock->GetController().ReleaseScene();
84 viewport = WebGLViewport::Create(it->first);
85
86 {
87 std::unique_ptr<IViewport::ILock> newLock(viewport->Lock());
88 newLock->GetController().AcquireScene(scene);
89 }
90 }
91
92 // Replace the old WebGL viewport by the new one
93 it->second = viewport;
94
95 // Tag the fresh canvas as needing a repaint
96 {
97 std::unique_ptr<IViewport::ILock> lock(it->second->Lock());
98 lock->Invalidate();
99 }
100 }
101 }
102
103 LaunchTimer();
104 }
105
106 void WebGLViewportsRegistry::OnTimeoutCallback(void *userData)
107 {
108 // This object dies with the process or tab.
109 WebGLViewportsRegistry* that =
110 reinterpret_cast<WebGLViewportsRegistry*>(userData);
111 that->OnTimeout();
112 }
113
114 WebGLViewportsRegistry::WebGLViewportsRegistry(double timeoutMS) :
115 timeoutMS_(timeoutMS),
116 timeOutID_(0)
117 {
118 if (timeoutMS <= 0)
119 {
120 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
121 }
122
123 LaunchTimer();
124 }
125
126 WebGLViewportsRegistry::~WebGLViewportsRegistry()
127 {
128 emscripten_clear_timeout(timeOutID_);
129 Clear();
130 }
131
132 boost::shared_ptr<WebGLViewport> WebGLViewportsRegistry::Add(
133 const std::string& canvasId)
134 {
135 if (viewports_.find(canvasId) != viewports_.end())
136 {
137 LOG(ERROR) << "Canvas was already registered: " << canvasId;
138 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
139 }
140 else
141 {
142 boost::shared_ptr<WebGLViewport> viewport =
143 WebGLViewport::Create(canvasId);
144 viewports_[canvasId] = viewport;
145 return viewport;
146 }
147 }
148
149 void WebGLViewportsRegistry::Remove(const std::string& canvasId)
150 {
151 Viewports::iterator found = viewports_.find(canvasId);
152
153 if (found == viewports_.end())
154 {
155 LOG(ERROR) << "Cannot remove unregistered canvas: " << canvasId;
156 }
157 else
158 {
159 viewports_.erase(found);
160 }
161 }
162
163 void WebGLViewportsRegistry::Clear()
164 {
165 viewports_.clear();
166 }
167
168 WebGLViewportsRegistry::Accessor::Accessor(WebGLViewportsRegistry& that,
169 const std::string& canvasId) :
170 that_(that)
171 {
172 Viewports::iterator viewport = that.viewports_.find(canvasId);
173 if (viewport != that.viewports_.end() &&
174 viewport->second != NULL)
175 {
176 lock_.reset(viewport->second->Lock());
177 }
178 }
179
180 IViewport::ILock& WebGLViewportsRegistry::Accessor::GetViewport() const
181 {
182 if (IsValid())
183 {
184 return *lock_;
185 }
186 else
187 {
188 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
189 }
190 }
191
192
193 void WebGLViewportsRegistry::FinalizeGlobalRegistry()
194 {
195 globalRegistry_.reset();
196 }
197
198
199 void WebGLViewportsRegistry::SetGlobalRegistryTimeout(double timeout)
200 {
201 if (globalRegistry_.get())
202 {
203 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
204 }
205 else
206 {
207 viewportsTimeout_ = timeout;
208 }
209 }
210
211
212 WebGLViewportsRegistry& WebGLViewportsRegistry::GetGlobalRegistry()
213 {
214 if (globalRegistry_.get() == NULL)
215 {
216 globalRegistry_.reset(new WebGLViewportsRegistry(viewportsTimeout_));
217 }
218
219 return *globalRegistry_;
220 }
221 }