comparison Deprecated/Platforms/Wasm/Defaults.cpp @ 1400:419d0320c344

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