comparison OrthancStone/Sources/Viewport/WebAssemblyViewport.cpp @ 1512:244ad1e4e76a

reorganization of folders
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 07 Jul 2020 16:21:02 +0200
parents Framework/Viewport/WebAssemblyViewport.cpp@6e43cac7833c
children a48ae10857b1
comparison
equal deleted inserted replaced
1511:9dfeee74c1e6 1512:244ad1e4e76a
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 "WebAssemblyViewport.h"
23
24 #include "../Toolbox/GenericToolbox.h"
25
26 #include <OrthancException.h>
27
28 #include <boost/make_shared.hpp>
29 #include <boost/enable_shared_from_this.hpp>
30
31 namespace OrthancStone
32 {
33 static void ConvertMouseEvent(PointerEvent& target,
34 const EmscriptenMouseEvent& source,
35 const ICompositor& compositor)
36 {
37 int x = static_cast<int>(source.targetX);
38 int y = static_cast<int>(source.targetY);
39
40 switch (source.button)
41 {
42 case 0:
43 target.SetMouseButton(MouseButton_Left);
44 break;
45
46 case 1:
47 target.SetMouseButton(MouseButton_Middle);
48 break;
49
50 case 2:
51 target.SetMouseButton(MouseButton_Right);
52 break;
53
54 default:
55 target.SetMouseButton(MouseButton_None);
56 break;
57 }
58
59 target.AddPosition(compositor.GetPixelCenterCoordinates(x, y));
60 target.SetAltModifier(source.altKey);
61 target.SetControlModifier(source.ctrlKey);
62 target.SetShiftModifier(source.shiftKey);
63 }
64
65
66 class WebAssemblyViewport::WasmLock : public ILock
67 {
68 private:
69 WebAssemblyViewport& that_;
70
71 public:
72 WasmLock(WebAssemblyViewport& that) :
73 that_(that)
74 {
75 }
76
77 virtual bool HasCompositor() const ORTHANC_OVERRIDE
78 {
79 return that_.compositor_.get() != NULL;
80 }
81
82 virtual ICompositor& GetCompositor() ORTHANC_OVERRIDE
83 {
84 if (that_.compositor_.get() == NULL)
85 {
86 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
87 }
88 else
89 {
90 return *that_.compositor_;
91 }
92 }
93
94 virtual ViewportController& GetController() ORTHANC_OVERRIDE
95 {
96 assert(that_.controller_);
97 return *that_.controller_;
98 }
99
100 virtual void Invalidate() ORTHANC_OVERRIDE
101 {
102 that_.Invalidate();
103 }
104 };
105
106
107 EM_BOOL WebAssemblyViewport::OnRequestAnimationFrame(double time, void *userData)
108 {
109 LOG(TRACE) << __func__;
110 WebAssemblyViewport* that = reinterpret_cast<WebAssemblyViewport*>(userData);
111
112 if (that->compositor_.get() != NULL &&
113 that->controller_ /* should always be true */)
114 {
115 that->Paint(*that->compositor_, *that->controller_);
116 }
117
118 LOG(TRACE) << "Exiting: " << __func__;
119 return true;
120 }
121
122 EM_BOOL WebAssemblyViewport::OnResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
123 {
124 LOG(TRACE) << __func__;
125 WebAssemblyViewport* that = reinterpret_cast<WebAssemblyViewport*>(userData);
126
127 if (that->compositor_.get() != NULL)
128 {
129 that->UpdateSize(*that->compositor_);
130 that->Invalidate();
131 }
132
133 LOG(TRACE) << "Exiting: " << __func__;
134 return true;
135 }
136
137
138 EM_BOOL WebAssemblyViewport::OnMouseDown(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
139 {
140 WebAssemblyViewport* that = reinterpret_cast<WebAssemblyViewport*>(userData);
141
142 LOG(TRACE) << "mouse down: " << that->GetCanvasCssSelector();
143
144 if (that->compositor_.get() != NULL &&
145 that->interactor_.get() != NULL)
146 {
147 PointerEvent pointer;
148 ConvertMouseEvent(pointer, *mouseEvent, *that->compositor_);
149
150 that->controller_->HandleMousePress(*that->interactor_, pointer,
151 that->compositor_->GetCanvasWidth(),
152 that->compositor_->GetCanvasHeight());
153 that->Invalidate();
154 }
155
156 LOG(TRACE) << "Exiting: " << __func__;
157 return true;
158 }
159
160
161 EM_BOOL WebAssemblyViewport::OnMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
162 {
163 WebAssemblyViewport* that = reinterpret_cast<WebAssemblyViewport*>(userData);
164
165 if (that->compositor_.get() != NULL &&
166 that->controller_->HasActiveTracker())
167 {
168 PointerEvent pointer;
169 ConvertMouseEvent(pointer, *mouseEvent, *that->compositor_);
170 if (that->controller_->HandleMouseMove(pointer))
171 {
172 that->Invalidate();
173 }
174 }
175
176 LOG(TRACE) << "Exiting: " << __func__;
177 return true;
178 }
179
180 EM_BOOL WebAssemblyViewport::OnMouseUp(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
181 {
182 LOG(TRACE) << __func__;
183 WebAssemblyViewport* that = reinterpret_cast<WebAssemblyViewport*>(userData);
184
185 if (that->compositor_.get() != NULL)
186 {
187 PointerEvent pointer;
188 ConvertMouseEvent(pointer, *mouseEvent, *that->compositor_);
189 that->controller_->HandleMouseRelease(pointer);
190 that->Invalidate();
191 }
192
193 LOG(TRACE) << "Exiting: " << __func__;
194 return true;
195 }
196
197 void WebAssemblyViewport::Invalidate()
198 {
199 emscripten_request_animation_frame(OnRequestAnimationFrame, reinterpret_cast<void*>(this));
200 }
201
202 void WebAssemblyViewport::AcquireCompositor(ICompositor* compositor /* takes ownership */)
203 {
204 if (compositor == NULL)
205 {
206 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
207 }
208 else
209 {
210 compositor_.reset(compositor);
211 }
212 }
213
214 #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1
215 // everything OK..... we're using the new setting
216 #else
217 #pragma message("WARNING: DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR is not defined or equal to 0. Stone will use the OLD Emscripten rules for DOM element selection.")
218 #endif
219
220 WebAssemblyViewport::WebAssemblyViewport(
221 const std::string& canvasId, bool enableEmscriptenMouseEvents) :
222 canvasId_(canvasId),
223 #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR == 1
224 canvasCssSelector_("#" + canvasId),
225 #else
226 canvasCssSelector_(canvasId),
227 #endif
228 interactor_(new DefaultViewportInteractor),
229 enableEmscriptenMouseEvents_(enableEmscriptenMouseEvents)
230 {
231 }
232
233 void WebAssemblyViewport::PostConstructor()
234 {
235 boost::shared_ptr<IViewport> viewport = shared_from_this();
236 controller_.reset(new ViewportController(viewport));
237
238 LOG(INFO) << "Initializing Stone viewport on HTML canvas: "
239 << canvasId_;
240
241 if (canvasId_.empty() ||
242 canvasId_[0] == '#')
243 {
244 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
245 "The canvas identifier must not start with '#'");
246 }
247
248 // Disable right-click on the canvas (i.e. context menu)
249 EM_ASM({
250 document.getElementById(UTF8ToString($0)).oncontextmenu =
251 function(event)
252 {
253 event.preventDefault();
254 }
255 },
256 canvasId_.c_str() // $0
257 );
258
259 // It is not possible to monitor the resizing of individual
260 // canvas, so we track the full window of the browser
261 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW,
262 reinterpret_cast<void*>(this),
263 false,
264 OnResize);
265
266 if (enableEmscriptenMouseEvents_)
267 {
268
269 // if any of this function causes an error in the console, please
270 // make sure you are using the new (as of 1.39.x) version of
271 // emscripten element lookup rules( pass
272 // "-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1" to the linker.
273
274 emscripten_set_mousedown_callback(canvasCssSelector_.c_str(),
275 reinterpret_cast<void*>(this),
276 false,
277 OnMouseDown);
278
279 emscripten_set_mousemove_callback(canvasCssSelector_.c_str(),
280 reinterpret_cast<void*>(this),
281 false,
282 OnMouseMove);
283
284 emscripten_set_mouseup_callback(canvasCssSelector_.c_str(),
285 reinterpret_cast<void*>(this),
286 false,
287 OnMouseUp);
288 }
289 }
290
291 void WebAssemblyViewport::UpdateCanvasSize()
292 {
293 UpdateSize(*compositor_);
294 }
295
296 WebAssemblyViewport::~WebAssemblyViewport()
297 {
298 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW,
299 reinterpret_cast<void*>(this),
300 false,
301 NULL);
302
303 if (enableEmscriptenMouseEvents_)
304 {
305
306 emscripten_set_mousedown_callback(canvasCssSelector_.c_str(),
307 reinterpret_cast<void*>(this),
308 false,
309 NULL);
310
311 emscripten_set_mousemove_callback(canvasCssSelector_.c_str(),
312 reinterpret_cast<void*>(this),
313 false,
314 NULL);
315
316 emscripten_set_mouseup_callback(canvasCssSelector_.c_str(),
317 reinterpret_cast<void*>(this),
318 false,
319 NULL);
320 }
321 }
322
323 IViewport::ILock* WebAssemblyViewport::Lock()
324 {
325 return new WasmLock(*this);
326 }
327
328 void WebAssemblyViewport::AcquireInteractor(IViewportInteractor* interactor)
329 {
330 if (interactor == NULL)
331 {
332 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
333 }
334 else
335 {
336 interactor_.reset(interactor);
337 }
338 }
339 }