comparison Resources/Graveyard/Deprecated/Platforms/Wasm/Defaults.cpp @ 1503:553084468225

moving /Deprecated/ to /Resources/Graveyard/Deprecated/
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 30 Jun 2020 11:38:13 +0200
parents Deprecated/Platforms/Wasm/Defaults.cpp@fbc5bfde6c95
children
comparison
equal deleted inserted replaced
1502:e5729dab3f67 1503:553084468225
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 "Defaults.h"
23
24 #include "WasmWebService.h"
25 #include "WasmDelayedCallExecutor.h"
26 #include "../../../Framework/Deprecated/Widgets/TestCairoWidget.h"
27 #include "../../../Framework/Deprecated/Viewport/WidgetViewport.h"
28 #include <Applications/Wasm/StartupParametersBuilder.h>
29 #include <Platforms/Wasm/WasmPlatformApplicationAdapter.h>
30 #include <Framework/StoneInitialization.h>
31 #include <Core/Logging.h>
32 #include <sstream>
33
34 #include <algorithm>
35
36
37 static unsigned int width_ = 0;
38 static unsigned int height_ = 0;
39
40 /**********************************/
41
42 static std::unique_ptr<OrthancStone::IStoneApplication> application;
43 static std::unique_ptr<OrthancStone::WasmPlatformApplicationAdapter> applicationWasmAdapter = NULL;
44 static std::unique_ptr<OrthancStone::StoneApplicationContext> context;
45 static OrthancStone::StartupParametersBuilder startupParametersBuilder;
46 static OrthancStone::MessageBroker broker;
47
48 static OrthancStone::ViewportContentChangedObserver viewportContentChangedObserver_(broker);
49 static OrthancStone::StatusBar statusBar_;
50
51 static std::list<std::shared_ptr<Deprecated::WidgetViewport>> viewports_;
52
53 std::shared_ptr<Deprecated::WidgetViewport> FindViewportSharedPtr(ViewportHandle viewport) {
54 for (const auto& v : viewports_) {
55 if (v.get() == viewport) {
56 return v;
57 }
58 }
59 assert(false);
60 return std::shared_ptr<Deprecated::WidgetViewport>();
61 }
62
63 #ifdef __cplusplus
64 extern "C" {
65 #endif
66
67 #if 0
68 // rewrite malloc/free in order to monitor allocations. We actually only monitor large allocations (like images ...)
69
70 size_t bigChunksTotalSize = 0;
71 std::map<void*, size_t> allocatedBigChunks;
72
73 extern void* emscripten_builtin_malloc(size_t bytes);
74 extern void emscripten_builtin_free(void* mem);
75
76 void * __attribute__((noinline)) malloc(size_t size)
77 {
78 void *ptr = emscripten_builtin_malloc(size);
79 if (size > 100000)
80 {
81 bigChunksTotalSize += size;
82 printf("++ Allocated %zu bytes, got %p. (%zu MB consumed by big chunks)\n", size, ptr, bigChunksTotalSize/(1024*1024));
83 allocatedBigChunks[ptr] = size;
84 }
85 return ptr;
86 }
87
88 void __attribute__((noinline)) free(void *ptr)
89 {
90 emscripten_builtin_free(ptr);
91
92 std::map<void*, size_t>::iterator it = allocatedBigChunks.find(ptr);
93 if (it != allocatedBigChunks.end())
94 {
95 bigChunksTotalSize -= it->second;
96 printf("-- Freed %zu bytes at %p. (%zu MB consumed by big chunks)\n", it->second, ptr, bigChunksTotalSize/(1024*1024));
97 allocatedBigChunks.erase(it);
98 }
99 }
100 #endif // 0
101
102 using namespace OrthancStone;
103
104 // when WASM needs a C++ viewport
105 ViewportHandle EMSCRIPTEN_KEEPALIVE CreateCppViewport() {
106
107 std::shared_ptr<Deprecated::WidgetViewport> viewport(new Deprecated::WidgetViewport(broker));
108 printf("viewport %x\n", (int)viewport.get());
109
110 viewports_.push_back(viewport);
111
112 printf("There are now %lu viewports in C++\n", viewports_.size());
113
114 viewport->SetStatusBar(statusBar_);
115
116 viewport->RegisterObserverCallback(
117 new Callable<ViewportContentChangedObserver, Deprecated::IViewport::ViewportChangedMessage>
118 (viewportContentChangedObserver_, &ViewportContentChangedObserver::OnViewportChanged));
119
120 return viewport.get();
121 }
122
123 // when WASM does not need a viewport anymore, it should release it
124 void EMSCRIPTEN_KEEPALIVE ReleaseCppViewport(ViewportHandle viewport) {
125 viewports_.remove_if([viewport](const std::shared_ptr<Deprecated::WidgetViewport>& v) { return v.get() == viewport;});
126
127 printf("There are now %lu viewports in C++\n", viewports_.size());
128 }
129
130 void EMSCRIPTEN_KEEPALIVE CreateWasmApplication(ViewportHandle viewport) {
131 printf("Initializing Stone\n");
132 OrthancStone::StoneInitialize();
133 printf("CreateWasmApplication\n");
134
135 application.reset(CreateUserApplication(broker));
136 applicationWasmAdapter.reset(CreateWasmApplicationAdapter(broker, application.get()));
137 Deprecated::WasmWebService::SetBroker(broker);
138 Deprecated::WasmDelayedCallExecutor::SetBroker(broker);
139
140 startupParametersBuilder.Clear();
141 }
142
143 void EMSCRIPTEN_KEEPALIVE SetStartupParameter(const char* keyc,
144 const char* value) {
145 startupParametersBuilder.SetStartupParameter(keyc, value);
146 }
147
148 void EMSCRIPTEN_KEEPALIVE StartWasmApplication(const char* baseUri) {
149
150 printf("StartWasmApplication\n");
151
152 Orthanc::Logging::SetErrorWarnInfoTraceLoggingFunctions(
153 stone_console_error, stone_console_warning,
154 stone_console_info, stone_console_trace);
155
156 // recreate a command line from uri arguments and parse it
157 boost::program_options::variables_map parameters;
158 boost::program_options::options_description options;
159 application->DeclareStartupOptions(options);
160 startupParametersBuilder.GetStartupParameters(parameters, options);
161
162 context.reset(new OrthancStone::StoneApplicationContext(broker));
163 context->SetOrthancBaseUrl(baseUri);
164 printf("Base URL to Orthanc API: [%s]\n", baseUri);
165 context->SetWebService(Deprecated::WasmWebService::GetInstance());
166 context->SetDelayedCallExecutor(Deprecated::WasmDelayedCallExecutor::GetInstance());
167 application->Initialize(context.get(), statusBar_, parameters);
168 application->InitializeWasm();
169
170 // viewport->SetSize(width_, height_);
171 printf("StartWasmApplication - completed\n");
172 }
173
174 bool EMSCRIPTEN_KEEPALIVE WasmIsTraceLevelEnabled()
175 {
176 return Orthanc::Logging::IsTraceLevelEnabled();
177 }
178
179 bool EMSCRIPTEN_KEEPALIVE WasmIsInfoLevelEnabled()
180 {
181 return Orthanc::Logging::IsInfoLevelEnabled();
182 }
183
184 void EMSCRIPTEN_KEEPALIVE WasmDoAnimation()
185 {
186 for (auto viewport : viewports_) {
187 // TODO Only launch the JavaScript timer if "HasAnimation()"
188 if (viewport->HasAnimation())
189 {
190 viewport->DoAnimation();
191 }
192
193 }
194
195 }
196
197
198 void EMSCRIPTEN_KEEPALIVE ViewportSetSize(ViewportHandle viewport, unsigned int width, unsigned int height)
199 {
200 width_ = width;
201 height_ = height;
202
203 viewport->SetSize(width, height);
204 }
205
206 int EMSCRIPTEN_KEEPALIVE ViewportRender(ViewportHandle viewport,
207 unsigned int width,
208 unsigned int height,
209 uint8_t* data)
210 {
211 viewportContentChangedObserver_.Reset();
212
213 //printf("ViewportRender called %dx%d\n", width, height);
214 if (width == 0 ||
215 height == 0)
216 {
217 return 1;
218 }
219
220 Orthanc::ImageAccessor surface;
221 surface.AssignWritable(Orthanc::PixelFormat_BGRA32, width, height, 4 * width, data);
222
223 viewport->Render(surface);
224
225 // Convert from BGRA32 memory layout (only color mode supported by
226 // Cairo, which corresponds to CAIRO_FORMAT_ARGB32) to RGBA32 (as
227 // expected by HTML5 canvas). This simply amounts to swapping the
228 // B and R channels.
229 uint8_t* p = data;
230 for (unsigned int y = 0; y < height; y++) {
231 for (unsigned int x = 0; x < width; x++) {
232 uint8_t tmp = p[0];
233 p[0] = p[2];
234 p[2] = tmp;
235
236 p += 4;
237 }
238 }
239
240 return 1;
241 }
242
243
244 void EMSCRIPTEN_KEEPALIVE ViewportMouseDown(ViewportHandle viewport,
245 unsigned int rawButton,
246 int x,
247 int y,
248 unsigned int rawModifiers)
249 {
250 OrthancStone::MouseButton button;
251 switch (rawButton)
252 {
253 case 0:
254 button = OrthancStone::MouseButton_Left;
255 break;
256
257 case 1:
258 button = OrthancStone::MouseButton_Middle;
259 break;
260
261 case 2:
262 button = OrthancStone::MouseButton_Right;
263 break;
264
265 default:
266 return; // Unknown button
267 }
268
269 viewport->MouseDown(button, x, y, OrthancStone::KeyboardModifiers_None, std::vector<Deprecated::Touch>());
270 }
271
272
273 void EMSCRIPTEN_KEEPALIVE ViewportMouseWheel(ViewportHandle viewport,
274 int deltaY,
275 int x,
276 int y,
277 int isControl)
278 {
279 if (deltaY != 0)
280 {
281 OrthancStone::MouseWheelDirection direction = (deltaY < 0 ?
282 OrthancStone::MouseWheelDirection_Up :
283 OrthancStone::MouseWheelDirection_Down);
284 OrthancStone::KeyboardModifiers modifiers = OrthancStone::KeyboardModifiers_None;
285
286 if (isControl != 0)
287 {
288 modifiers = OrthancStone::KeyboardModifiers_Control;
289 }
290
291 viewport->MouseWheel(direction, x, y, modifiers);
292 }
293 }
294
295
296 void EMSCRIPTEN_KEEPALIVE ViewportMouseMove(ViewportHandle viewport,
297 int x,
298 int y)
299 {
300 viewport->MouseMove(x, y, std::vector<Deprecated::Touch>());
301 }
302
303 void GetTouchVector(std::vector<Deprecated::Touch>& output,
304 int touchCount,
305 float x0,
306 float y0,
307 float x1,
308 float y1,
309 float x2,
310 float y2)
311 {
312 // TODO: it might be nice to try to pass all the x0,y0 coordinates as arrays but that's not so easy to pass array between JS and C++
313 if (touchCount > 0)
314 {
315 output.push_back(Deprecated::Touch(x0, y0));
316 }
317 if (touchCount > 1)
318 {
319 output.push_back(Deprecated::Touch(x1, y1));
320 }
321 if (touchCount > 2)
322 {
323 output.push_back(Deprecated::Touch(x2, y2));
324 }
325
326 }
327
328 void EMSCRIPTEN_KEEPALIVE ViewportTouchStart(ViewportHandle viewport,
329 int touchCount,
330 float x0,
331 float y0,
332 float x1,
333 float y1,
334 float x2,
335 float y2)
336 {
337 // printf("touch start with %d touches\n", touchCount);
338
339 std::vector<Deprecated::Touch> touches;
340 GetTouchVector(touches, touchCount, x0, y0, x1, y1, x2, y2);
341 viewport->TouchStart(touches);
342 }
343
344 void EMSCRIPTEN_KEEPALIVE ViewportTouchMove(ViewportHandle viewport,
345 int touchCount,
346 float x0,
347 float y0,
348 float x1,
349 float y1,
350 float x2,
351 float y2)
352 {
353 // printf("touch move with %d touches\n", touchCount);
354
355 std::vector<Deprecated::Touch> touches;
356 GetTouchVector(touches, touchCount, x0, y0, x1, y1, x2, y2);
357 viewport->TouchMove(touches);
358 }
359
360 void EMSCRIPTEN_KEEPALIVE ViewportTouchEnd(ViewportHandle viewport,
361 int touchCount,
362 float x0,
363 float y0,
364 float x1,
365 float y1,
366 float x2,
367 float y2)
368 {
369 // printf("touch end with %d touches remaining\n", touchCount);
370
371 std::vector<Deprecated::Touch> touches;
372 GetTouchVector(touches, touchCount, x0, y0, x1, y1, x2, y2);
373 viewport->TouchEnd(touches);
374 }
375
376 void EMSCRIPTEN_KEEPALIVE ViewportKeyPressed(ViewportHandle viewport,
377 int key,
378 const char* keyChar,
379 bool isShiftPressed,
380 bool isControlPressed,
381 bool isAltPressed)
382
383 {
384 OrthancStone::KeyboardModifiers modifiers = OrthancStone::KeyboardModifiers_None;
385 if (isShiftPressed) {
386 modifiers = static_cast<OrthancStone::KeyboardModifiers>(modifiers + OrthancStone::KeyboardModifiers_Shift);
387 }
388 if (isControlPressed) {
389 modifiers = static_cast<OrthancStone::KeyboardModifiers>(modifiers + OrthancStone::KeyboardModifiers_Control);
390 }
391 if (isAltPressed) {
392 modifiers = static_cast<OrthancStone::KeyboardModifiers>(modifiers + OrthancStone::KeyboardModifiers_Alt);
393 }
394
395 char c = 0;
396 if (keyChar != NULL && key == OrthancStone::KeyboardKeys_Generic) {
397 c = keyChar[0];
398 }
399 viewport->KeyPressed(static_cast<OrthancStone::KeyboardKeys>(key), c, modifiers);
400 }
401
402
403 void EMSCRIPTEN_KEEPALIVE ViewportMouseUp(ViewportHandle viewport)
404 {
405 viewport->MouseUp();
406 }
407
408
409 void EMSCRIPTEN_KEEPALIVE ViewportMouseEnter(ViewportHandle viewport)
410 {
411 viewport->MouseEnter();
412 }
413
414
415 void EMSCRIPTEN_KEEPALIVE ViewportMouseLeave(ViewportHandle viewport)
416 {
417 viewport->MouseLeave();
418 }
419
420 const char* EMSCRIPTEN_KEEPALIVE SendSerializedMessageToStoneApplication(const char* message)
421 {
422 static std::string output; // we don't want the string to be deallocated when we return to JS code so we always use the same string (this is fine since JS is single-thread)
423
424 //printf("SendSerializedMessageToStoneApplication\n");
425 //printf("%s", message);
426
427 if (applicationWasmAdapter.get() != NULL) {
428 applicationWasmAdapter->HandleSerializedMessageFromWeb(output, std::string(message));
429 return output.c_str();
430 }
431 printf("This Stone application does not have a Web Adapter, unable to send messages");
432 return NULL;
433 }
434
435 #ifdef __cplusplus
436 }
437 #endif