Mercurial > hg > orthanc-stone
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 |