Mercurial > hg > orthanc-stone
annotate Samples/WebAssembly/BasicMPR.cpp @ 824:15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 29 May 2019 15:26:47 +0200 |
parents | 467d58a59718 |
children | 9a6c7a5dcb76 |
rev | line source |
---|---|
820 | 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-2019 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 | |
23 #include <emscripten.h> | |
24 #include <emscripten/fetch.h> | |
25 #include <emscripten/html5.h> | |
26 | |
27 #include "../../Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h" | |
28 #include "../../Framework/OpenGL/WebAssemblyOpenGLContext.h" | |
824
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
29 #include "../../Framework/Oracle/SleepOracleCommand.h" |
820 | 30 #include "../../Framework/Scene2D/GrayscaleStyleConfigurator.h" |
31 #include "../../Framework/Scene2D/OpenGLCompositor.h" | |
32 #include "../../Framework/Scene2D/PanSceneTracker.h" | |
33 #include "../../Framework/Scene2D/RotateSceneTracker.h" | |
34 #include "../../Framework/Scene2D/ZoomSceneTracker.h" | |
35 #include "../../Framework/Scene2DViewport/IFlexiblePointerTracker.h" | |
36 #include "../../Framework/Scene2DViewport/ViewportController.h" | |
37 #include "../../Framework/StoneInitialization.h" | |
38 #include "../../Framework/Volumes/VolumeSceneLayerSource.h" | |
39 | |
40 #include <Core/OrthancException.h> | |
41 #include <Core/Toolbox.h> | |
42 | |
43 | |
44 static const unsigned int FONT_SIZE = 32; | |
45 | |
46 | |
47 namespace OrthancStone | |
48 { | |
49 class WebAssemblyViewport : public boost::noncopyable | |
50 { | |
51 private: | |
52 // the construction order is important because compositor_ | |
53 // will hold a reference to the scene that belong to the | |
54 // controller_ object | |
55 OpenGL::WebAssemblyOpenGLContext context_; | |
56 boost::shared_ptr<ViewportController> controller_; | |
57 OpenGLCompositor compositor_; | |
58 | |
59 void SetupEvents(const std::string& canvas); | |
60 | |
61 public: | |
62 WebAssemblyViewport(MessageBroker& broker, | |
63 const std::string& canvas) : | |
64 context_(canvas), | |
65 controller_(new ViewportController(broker)), | |
66 compositor_(context_, *controller_->GetScene()) | |
67 { | |
68 compositor_.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, | |
69 FONT_SIZE, Orthanc::Encoding_Latin1); | |
70 SetupEvents(canvas); | |
71 } | |
72 | |
73 Scene2D& GetScene() | |
74 { | |
75 return *controller_->GetScene(); | |
76 } | |
77 | |
78 const boost::shared_ptr<ViewportController>& GetController() | |
79 { | |
80 return controller_; | |
81 } | |
82 | |
83 void UpdateSize() | |
84 { | |
85 context_.UpdateSize(); | |
86 compositor_.UpdateSize(); | |
87 Refresh(); | |
88 } | |
89 | |
90 void Refresh() | |
91 { | |
92 compositor_.Refresh(); | |
93 } | |
94 | |
822 | 95 void FitContent() |
96 { | |
97 GetScene().FitContent(context_.GetCanvasWidth(), context_.GetCanvasHeight()); | |
98 } | |
99 | |
820 | 100 const std::string& GetCanvasIdentifier() const |
101 { | |
102 return context_.GetCanvasIdentifier(); | |
103 } | |
104 | |
105 ScenePoint2D GetPixelCenterCoordinates(int x, int y) const | |
106 { | |
107 return compositor_.GetPixelCenterCoordinates(x, y); | |
108 } | |
109 | |
110 unsigned int GetCanvasWidth() const | |
111 { | |
112 return context_.GetCanvasWidth(); | |
113 } | |
114 | |
115 unsigned int GetCanvasHeight() const | |
116 { | |
117 return context_.GetCanvasHeight(); | |
118 } | |
119 }; | |
120 | |
121 class ActiveTracker : public boost::noncopyable | |
122 { | |
123 private: | |
124 boost::shared_ptr<IFlexiblePointerTracker> tracker_; | |
125 std::string canvasIdentifier_; | |
126 bool insideCanvas_; | |
127 | |
128 public: | |
129 ActiveTracker(const boost::shared_ptr<IFlexiblePointerTracker>& tracker, | |
130 const WebAssemblyViewport& viewport) : | |
131 tracker_(tracker), | |
132 canvasIdentifier_(viewport.GetCanvasIdentifier()), | |
133 insideCanvas_(true) | |
134 { | |
135 if (tracker_.get() == NULL) | |
136 { | |
137 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
138 } | |
139 } | |
140 | |
141 bool IsAlive() const | |
142 { | |
143 return tracker_->IsAlive(); | |
144 } | |
145 | |
146 void PointerMove(const PointerEvent& event) | |
147 { | |
148 tracker_->PointerMove(event); | |
149 } | |
150 | |
151 void PointerUp(const PointerEvent& event) | |
152 { | |
153 tracker_->PointerUp(event); | |
154 } | |
155 }; | |
156 } | |
157 | |
158 static OrthancStone::PointerEvent* ConvertMouseEvent( | |
159 const EmscriptenMouseEvent& source, | |
160 OrthancStone::WebAssemblyViewport& viewport) | |
161 { | |
162 std::auto_ptr<OrthancStone::PointerEvent> target( | |
163 new OrthancStone::PointerEvent); | |
164 | |
165 target->AddPosition(viewport.GetPixelCenterCoordinates( | |
166 source.targetX, source.targetY)); | |
167 target->SetAltModifier(source.altKey); | |
168 target->SetControlModifier(source.ctrlKey); | |
169 target->SetShiftModifier(source.shiftKey); | |
170 | |
171 return target.release(); | |
172 } | |
173 | |
174 std::auto_ptr<OrthancStone::ActiveTracker> tracker_; | |
175 | |
176 EM_BOOL OnMouseEvent(int eventType, | |
177 const EmscriptenMouseEvent *mouseEvent, | |
178 void *userData) | |
179 { | |
180 if (mouseEvent != NULL && | |
181 userData != NULL) | |
182 { | |
183 OrthancStone::WebAssemblyViewport& viewport = | |
184 *reinterpret_cast<OrthancStone::WebAssemblyViewport*>(userData); | |
185 | |
186 switch (eventType) | |
187 { | |
188 case EMSCRIPTEN_EVENT_CLICK: | |
189 { | |
190 static unsigned int count = 0; | |
191 char buf[64]; | |
192 sprintf(buf, "click %d", count++); | |
193 | |
194 std::auto_ptr<OrthancStone::TextSceneLayer> layer(new OrthancStone::TextSceneLayer); | |
195 layer->SetText(buf); | |
196 viewport.GetScene().SetLayer(100, layer.release()); | |
197 viewport.Refresh(); | |
198 break; | |
199 } | |
200 | |
201 case EMSCRIPTEN_EVENT_MOUSEDOWN: | |
202 { | |
203 boost::shared_ptr<OrthancStone::IFlexiblePointerTracker> t; | |
204 | |
205 { | |
206 std::auto_ptr<OrthancStone::PointerEvent> event( | |
207 ConvertMouseEvent(*mouseEvent, viewport)); | |
208 | |
209 switch (mouseEvent->button) | |
210 { | |
211 case 0: // Left button | |
212 emscripten_console_log("Creating RotateSceneTracker"); | |
213 t.reset(new OrthancStone::RotateSceneTracker( | |
214 viewport.GetController(), *event)); | |
215 break; | |
216 | |
217 case 1: // Middle button | |
218 emscripten_console_log("Creating PanSceneTracker"); | |
219 LOG(INFO) << "Creating PanSceneTracker" ; | |
220 t.reset(new OrthancStone::PanSceneTracker( | |
221 viewport.GetController(), *event)); | |
222 break; | |
223 | |
224 case 2: // Right button | |
225 emscripten_console_log("Creating ZoomSceneTracker"); | |
226 t.reset(new OrthancStone::ZoomSceneTracker( | |
227 viewport.GetController(), *event, viewport.GetCanvasWidth())); | |
228 break; | |
229 | |
230 default: | |
231 break; | |
232 } | |
233 } | |
234 | |
235 if (t.get() != NULL) | |
236 { | |
237 tracker_.reset( | |
238 new OrthancStone::ActiveTracker(t, viewport)); | |
239 viewport.Refresh(); | |
240 } | |
241 | |
242 break; | |
243 } | |
244 | |
245 case EMSCRIPTEN_EVENT_MOUSEMOVE: | |
246 if (tracker_.get() != NULL) | |
247 { | |
248 std::auto_ptr<OrthancStone::PointerEvent> event( | |
249 ConvertMouseEvent(*mouseEvent, viewport)); | |
250 tracker_->PointerMove(*event); | |
251 viewport.Refresh(); | |
252 } | |
253 break; | |
254 | |
255 case EMSCRIPTEN_EVENT_MOUSEUP: | |
256 if (tracker_.get() != NULL) | |
257 { | |
258 std::auto_ptr<OrthancStone::PointerEvent> event( | |
259 ConvertMouseEvent(*mouseEvent, viewport)); | |
260 tracker_->PointerUp(*event); | |
261 viewport.Refresh(); | |
262 if (!tracker_->IsAlive()) | |
263 tracker_.reset(); | |
264 } | |
265 break; | |
266 | |
267 default: | |
268 break; | |
269 } | |
270 } | |
271 | |
272 return true; | |
273 } | |
274 | |
275 | |
276 void OrthancStone::WebAssemblyViewport::SetupEvents(const std::string& canvas) | |
277 { | |
278 emscripten_set_mousedown_callback(canvas.c_str(), this, false, OnMouseEvent); | |
279 emscripten_set_mousemove_callback(canvas.c_str(), this, false, OnMouseEvent); | |
280 emscripten_set_mouseup_callback(canvas.c_str(), this, false, OnMouseEvent); | |
281 } | |
282 | |
283 | |
284 | |
285 | |
286 namespace OrthancStone | |
287 { | |
288 class VolumeSlicerViewport : public IObserver | |
289 { | |
290 private: | |
291 OrthancStone::WebAssemblyViewport viewport_; | |
292 std::auto_ptr<VolumeSceneLayerSource> source_; | |
293 VolumeProjection projection_; | |
294 std::vector<CoordinateSystem3D> planes_; | |
295 size_t currentPlane_; | |
296 | |
297 void Handle(const DicomVolumeImage::GeometryReadyMessage& message) | |
298 { | |
299 LOG(INFO) << "Geometry is available"; | |
300 | |
301 const VolumeImageGeometry& geometry = message.GetOrigin().GetGeometry(); | |
302 | |
303 const unsigned int depth = geometry.GetProjectionDepth(projection_); | |
304 currentPlane_ = depth / 2; | |
305 | |
306 planes_.resize(depth); | |
307 | |
308 for (unsigned int z = 0; z < depth; z++) | |
309 { | |
310 planes_[z] = geometry.GetProjectionSlice(projection_, z); | |
311 } | |
822 | 312 |
313 Refresh(); | |
314 | |
315 viewport_.FitContent(); | |
820 | 316 } |
317 | |
318 public: | |
319 VolumeSlicerViewport(MessageBroker& broker, | |
320 const std::string& canvas, | |
321 VolumeProjection projection) : | |
322 IObserver(broker), | |
323 viewport_(broker, canvas), | |
324 projection_(projection), | |
325 currentPlane_(0) | |
326 { | |
327 } | |
328 | |
329 void UpdateSize() | |
330 { | |
331 viewport_.UpdateSize(); | |
332 } | |
333 | |
334 void SetSlicer(int layerDepth, | |
335 const boost::shared_ptr<IVolumeSlicer>& slicer, | |
336 IObservable& loader, | |
337 ILayerStyleConfigurator* configurator) | |
338 { | |
339 if (source_.get() != NULL) | |
340 { | |
341 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls, | |
342 "Only one slicer can be registered"); | |
343 } | |
344 | |
345 loader.RegisterObserverCallback( | |
346 new Callable<VolumeSlicerViewport, DicomVolumeImage::GeometryReadyMessage> | |
347 (*this, &VolumeSlicerViewport::Handle)); | |
348 | |
349 source_.reset(new VolumeSceneLayerSource(viewport_.GetScene(), layerDepth, slicer)); | |
350 | |
351 if (configurator != NULL) | |
352 { | |
353 source_->SetConfigurator(configurator); | |
354 } | |
355 } | |
356 | |
357 void Refresh() | |
358 { | |
359 if (source_.get() != NULL && | |
360 currentPlane_ < planes_.size()) | |
361 { | |
362 source_->Update(planes_[currentPlane_]); | |
822 | 363 viewport_.Refresh(); |
820 | 364 } |
365 } | |
823 | 366 |
367 void Scroll(int delta) | |
368 { | |
369 if (!planes_.empty()) | |
370 { | |
371 int tmp = static_cast<int>(currentPlane_) + delta; | |
372 unsigned int next; | |
373 | |
374 if (tmp < 0) | |
375 { | |
376 next = 0; | |
377 } | |
378 else if (tmp >= static_cast<int>(planes_.size())) | |
379 { | |
380 next = planes_.size() - 1; | |
381 } | |
382 else | |
383 { | |
384 next = static_cast<size_t>(tmp); | |
385 } | |
386 | |
387 if (next != currentPlane_) | |
388 { | |
389 currentPlane_ = next; | |
390 Refresh(); | |
391 } | |
392 } | |
393 } | |
820 | 394 }; |
395 | |
396 | |
397 | |
398 | |
399 class WebAssemblyOracle : | |
400 public IOracle, | |
401 public IObservable | |
402 { | |
403 private: | |
404 typedef std::map<std::string, std::string> HttpHeaders; | |
405 | |
824
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
406 class Emitter : public IMessageEmitter |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
407 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
408 private: |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
409 WebAssemblyOracle& oracle_; |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
410 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
411 public: |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
412 Emitter(WebAssemblyOracle& oracle) : |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
413 oracle_(oracle) |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
414 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
415 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
416 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
417 virtual void EmitMessage(const IObserver& receiver, |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
418 const IMessage& message) |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
419 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
420 oracle_.EmitMessage(receiver, message); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
421 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
422 }; |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
423 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
424 |
820 | 425 class FetchContext : public boost::noncopyable |
426 { | |
427 private: | |
428 Emitter emitter_; | |
429 const IObserver& receiver_; | |
430 std::auto_ptr<IOracleCommand> command_; | |
431 std::string expectedContentType_; | |
432 | |
433 public: | |
434 FetchContext(WebAssemblyOracle& oracle, | |
435 const IObserver& receiver, | |
436 IOracleCommand* command, | |
437 const std::string& expectedContentType) : | |
438 emitter_(oracle), | |
439 receiver_(receiver), | |
440 command_(command), | |
441 expectedContentType_(expectedContentType) | |
442 { | |
443 if (command == NULL) | |
444 { | |
445 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
446 } | |
447 } | |
448 | |
449 const std::string& GetExpectedContentType() const | |
450 { | |
451 return expectedContentType_; | |
452 } | |
453 | |
454 void EmitMessage(const IMessage& message) | |
455 { | |
456 emitter_.EmitMessage(receiver_, message); | |
457 } | |
458 | |
459 IMessageEmitter& GetEmitter() | |
460 { | |
461 return emitter_; | |
462 } | |
463 | |
464 const IObserver& GetReceiver() const | |
465 { | |
466 return receiver_; | |
467 } | |
468 | |
469 IOracleCommand& GetCommand() const | |
470 { | |
471 return *command_; | |
472 } | |
473 | |
474 template <typename T> | |
475 const T& GetTypedCommand() const | |
476 { | |
477 return dynamic_cast<T&>(*command_); | |
478 } | |
479 }; | |
480 | |
481 static void FetchSucceeded(emscripten_fetch_t *fetch) | |
482 { | |
483 /** | |
484 * Firstly, make a local copy of the fetched information, and | |
485 * free data associated with the fetch. | |
486 **/ | |
487 | |
488 std::auto_ptr<FetchContext> context(reinterpret_cast<FetchContext*>(fetch->userData)); | |
489 | |
490 std::string answer; | |
491 if (fetch->numBytes > 0) | |
492 { | |
493 answer.assign(fetch->data, fetch->numBytes); | |
494 } | |
495 | |
496 /** | |
497 * TODO - HACK - As of emscripten-1.38.31, the fetch API does | |
498 * not contain a way to retrieve the HTTP headers of the | |
499 * answer. We make the assumption that the "Content-Type" header | |
500 * of the response is the same as the "Accept" header of the | |
501 * query. This should be fixed in future versions of emscripten. | |
502 * https://github.com/emscripten-core/emscripten/pull/8486 | |
503 **/ | |
504 | |
505 HttpHeaders headers; | |
506 if (!context->GetExpectedContentType().empty()) | |
507 { | |
508 headers["Content-Type"] = context->GetExpectedContentType(); | |
509 } | |
510 | |
511 | |
512 emscripten_fetch_close(fetch); | |
513 | |
514 | |
515 /** | |
516 * Secondly, use the retrieved data. | |
517 **/ | |
518 | |
519 try | |
520 { | |
521 if (context.get() == NULL) | |
522 { | |
523 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
524 } | |
525 else | |
526 { | |
527 switch (context->GetCommand().GetType()) | |
528 { | |
529 case IOracleCommand::Type_OrthancRestApi: | |
530 { | |
531 OrthancRestApiCommand::SuccessMessage message | |
532 (context->GetTypedCommand<OrthancRestApiCommand>(), headers, answer); | |
533 context->EmitMessage(message); | |
534 break; | |
535 } | |
536 | |
537 case IOracleCommand::Type_GetOrthancImage: | |
538 { | |
539 context->GetTypedCommand<GetOrthancImageCommand>().ProcessHttpAnswer | |
540 (context->GetEmitter(), context->GetReceiver(), answer, headers); | |
541 break; | |
542 } | |
543 | |
544 case IOracleCommand::Type_GetOrthancWebViewerJpeg: | |
545 { | |
546 context->GetTypedCommand<GetOrthancWebViewerJpegCommand>().ProcessHttpAnswer | |
547 (context->GetEmitter(), context->GetReceiver(), answer); | |
548 break; | |
549 } | |
550 | |
551 default: | |
552 LOG(ERROR) << "Command type not implemented by the WebAssembly Oracle: " | |
553 << context->GetCommand().GetType(); | |
554 } | |
555 } | |
556 } | |
557 catch (Orthanc::OrthancException& e) | |
558 { | |
559 LOG(ERROR) << "Error while processing a fetch answer in the oracle: " << e.What(); | |
560 } | |
561 } | |
562 | |
563 static void FetchFailed(emscripten_fetch_t *fetch) | |
564 { | |
565 std::auto_ptr<FetchContext> context(reinterpret_cast<FetchContext*>(fetch->userData)); | |
566 | |
567 LOG(ERROR) << "Fetching " << fetch->url << " failed, HTTP failure status code: " << fetch->status; | |
568 | |
569 /** | |
570 * TODO - The following code leads to an infinite recursion, at | |
571 * least with Firefox running on incognito mode => WHY? | |
572 **/ | |
573 //emscripten_fetch_close(fetch); // Also free data on failure. | |
574 } | |
575 | |
576 | |
577 class FetchCommand : public boost::noncopyable | |
578 { | |
579 private: | |
580 WebAssemblyOracle& oracle_; | |
581 const IObserver& receiver_; | |
582 std::auto_ptr<IOracleCommand> command_; | |
583 Orthanc::HttpMethod method_; | |
584 std::string uri_; | |
585 std::string body_; | |
586 HttpHeaders headers_; | |
587 unsigned int timeout_; | |
588 std::string expectedContentType_; | |
589 | |
590 public: | |
591 FetchCommand(WebAssemblyOracle& oracle, | |
592 const IObserver& receiver, | |
593 IOracleCommand* command) : | |
594 oracle_(oracle), | |
595 receiver_(receiver), | |
596 command_(command), | |
597 method_(Orthanc::HttpMethod_Get), | |
598 timeout_(0) | |
599 { | |
600 if (command == NULL) | |
601 { | |
602 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
603 } | |
604 } | |
605 | |
606 void SetMethod(Orthanc::HttpMethod method) | |
607 { | |
608 method_ = method; | |
609 } | |
610 | |
611 void SetUri(const std::string& uri) | |
612 { | |
613 uri_ = uri; | |
614 } | |
615 | |
616 void SetBody(std::string& body /* will be swapped */) | |
617 { | |
618 body_.swap(body); | |
619 } | |
620 | |
621 void SetHttpHeaders(const HttpHeaders& headers) | |
622 { | |
623 headers_ = headers; | |
624 } | |
625 | |
626 void SetTimeout(unsigned int timeout) | |
627 { | |
628 timeout_ = timeout; | |
629 } | |
630 | |
631 void Execute() | |
632 { | |
633 if (command_.get() == NULL) | |
634 { | |
635 // Cannot call Execute() twice | |
636 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
637 } | |
638 | |
639 emscripten_fetch_attr_t attr; | |
640 emscripten_fetch_attr_init(&attr); | |
641 | |
642 const char* method; | |
643 | |
644 switch (method_) | |
645 { | |
646 case Orthanc::HttpMethod_Get: | |
647 method = "GET"; | |
648 break; | |
649 | |
650 case Orthanc::HttpMethod_Post: | |
651 method = "POST"; | |
652 break; | |
653 | |
654 case Orthanc::HttpMethod_Delete: | |
655 method = "DELETE"; | |
656 break; | |
657 | |
658 case Orthanc::HttpMethod_Put: | |
659 method = "PUT"; | |
660 break; | |
661 | |
662 default: | |
663 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
664 } | |
665 | |
666 strcpy(attr.requestMethod, method); | |
667 | |
668 attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY; | |
669 attr.onsuccess = FetchSucceeded; | |
670 attr.onerror = FetchFailed; | |
671 attr.timeoutMSecs = timeout_ * 1000; | |
672 | |
673 std::vector<const char*> headers; | |
674 headers.reserve(2 * headers_.size() + 1); | |
675 | |
676 std::string expectedContentType; | |
677 | |
678 for (HttpHeaders::const_iterator it = headers_.begin(); it != headers_.end(); ++it) | |
679 { | |
680 std::string key; | |
681 Orthanc::Toolbox::ToLowerCase(key, it->first); | |
682 | |
683 if (key == "accept") | |
684 { | |
685 expectedContentType = it->second; | |
686 } | |
687 | |
688 if (key != "accept-encoding") // Web browsers forbid the modification of this HTTP header | |
689 { | |
690 headers.push_back(it->first.c_str()); | |
691 headers.push_back(it->second.c_str()); | |
692 } | |
693 } | |
694 | |
695 headers.push_back(NULL); // Termination of the array of HTTP headers | |
696 | |
697 attr.requestHeaders = &headers[0]; | |
698 | |
699 if (!body_.empty()) | |
700 { | |
701 attr.requestDataSize = body_.size(); | |
702 attr.requestData = body_.c_str(); | |
703 } | |
704 | |
705 // Must be the last call to prevent memory leak on error | |
706 attr.userData = new FetchContext(oracle_, receiver_, command_.release(), expectedContentType); | |
707 emscripten_fetch(&attr, uri_.c_str()); | |
708 } | |
709 }; | |
710 | |
711 | |
712 void Execute(const IObserver& receiver, | |
713 OrthancRestApiCommand* command) | |
714 { | |
715 FetchCommand fetch(*this, receiver, command); | |
716 | |
717 fetch.SetMethod(command->GetMethod()); | |
718 fetch.SetUri(command->GetUri()); | |
719 fetch.SetHttpHeaders(command->GetHttpHeaders()); | |
720 fetch.SetTimeout(command->GetTimeout()); | |
721 | |
722 if (command->GetMethod() == Orthanc::HttpMethod_Put || | |
723 command->GetMethod() == Orthanc::HttpMethod_Put) | |
724 { | |
725 std::string body; | |
726 command->SwapBody(body); | |
727 fetch.SetBody(body); | |
728 } | |
729 | |
730 fetch.Execute(); | |
731 } | |
732 | |
733 | |
734 void Execute(const IObserver& receiver, | |
735 GetOrthancImageCommand* command) | |
736 { | |
737 FetchCommand fetch(*this, receiver, command); | |
738 | |
739 fetch.SetUri(command->GetUri()); | |
740 fetch.SetHttpHeaders(command->GetHttpHeaders()); | |
741 fetch.SetTimeout(command->GetTimeout()); | |
742 | |
743 fetch.Execute(); | |
744 } | |
745 | |
746 | |
747 void Execute(const IObserver& receiver, | |
748 GetOrthancWebViewerJpegCommand* command) | |
749 { | |
750 FetchCommand fetch(*this, receiver, command); | |
751 | |
752 fetch.SetUri(command->GetUri()); | |
753 fetch.SetHttpHeaders(command->GetHttpHeaders()); | |
754 fetch.SetTimeout(command->GetTimeout()); | |
755 | |
756 fetch.Execute(); | |
757 } | |
758 | |
824
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
759 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
760 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
761 class TimeoutContext |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
762 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
763 private: |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
764 WebAssemblyOracle& oracle_; |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
765 const IObserver& receiver_; |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
766 std::auto_ptr<SleepOracleCommand> command_; |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
767 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
768 public: |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
769 TimeoutContext(WebAssemblyOracle& oracle, |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
770 const IObserver& receiver, |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
771 IOracleCommand* command) : |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
772 oracle_(oracle), |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
773 receiver_(receiver) |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
774 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
775 if (command == NULL) |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
776 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
777 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
778 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
779 else |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
780 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
781 command_.reset(dynamic_cast<SleepOracleCommand*>(command)); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
782 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
783 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
784 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
785 void EmitMessage() |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
786 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
787 SleepOracleCommand::TimeoutMessage message(*command_); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
788 oracle_.EmitMessage(receiver_, message); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
789 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
790 }; |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
791 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
792 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
793 static void TimeoutCallback(void *userData) |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
794 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
795 std::auto_ptr<TimeoutContext> context(reinterpret_cast<TimeoutContext*>(userData)); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
796 context->EmitMessage(); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
797 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
798 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
799 |
820 | 800 |
801 public: | |
802 WebAssemblyOracle(MessageBroker& broker) : | |
803 IObservable(broker) | |
804 { | |
805 } | |
806 | |
807 virtual void Schedule(const IObserver& receiver, | |
808 IOracleCommand* command) | |
809 { | |
810 std::auto_ptr<IOracleCommand> protection(command); | |
811 | |
812 if (command == NULL) | |
813 { | |
814 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
815 } | |
816 | |
817 switch (command->GetType()) | |
818 { | |
819 case IOracleCommand::Type_OrthancRestApi: | |
820 Execute(receiver, dynamic_cast<OrthancRestApiCommand*>(protection.release())); | |
821 break; | |
822 | |
823 case IOracleCommand::Type_GetOrthancImage: | |
824 Execute(receiver, dynamic_cast<GetOrthancImageCommand*>(protection.release())); | |
825 break; | |
826 | |
827 case IOracleCommand::Type_GetOrthancWebViewerJpeg: | |
828 Execute(receiver, dynamic_cast<GetOrthancWebViewerJpegCommand*>(protection.release())); | |
829 break; | |
830 | |
824
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
831 case IOracleCommand::Type_Sleep: |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
832 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
833 unsigned int timeoutMS = dynamic_cast<SleepOracleCommand*>(command)->GetDelay(); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
834 emscripten_set_timeout(TimeoutCallback, timeoutMS, new TimeoutContext(*this, receiver, protection.release())); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
835 break; |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
836 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
837 |
820 | 838 default: |
839 LOG(ERROR) << "Command type not implemented by the WebAssembly Oracle: " << command->GetType(); | |
840 } | |
841 } | |
842 | |
843 virtual void Start() | |
844 { | |
845 } | |
846 | |
847 virtual void Stop() | |
848 { | |
849 } | |
850 }; | |
851 } | |
852 | |
853 | |
854 | |
855 | |
856 boost::shared_ptr<OrthancStone::DicomVolumeImage> ct_(new OrthancStone::DicomVolumeImage); | |
857 | |
858 boost::shared_ptr<OrthancStone::OrthancSeriesVolumeProgressiveLoader> loader_; | |
859 | |
860 std::auto_ptr<OrthancStone::VolumeSlicerViewport> viewport1_; | |
861 std::auto_ptr<OrthancStone::VolumeSlicerViewport> viewport2_; | |
862 std::auto_ptr<OrthancStone::VolumeSlicerViewport> viewport3_; | |
863 | |
864 OrthancStone::MessageBroker broker_; | |
865 OrthancStone::WebAssemblyOracle oracle_(broker_); | |
866 | |
867 | |
868 EM_BOOL OnWindowResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData) | |
869 { | |
870 try | |
871 { | |
872 if (viewport1_.get() != NULL) | |
873 { | |
874 viewport1_->UpdateSize(); | |
875 } | |
876 | |
877 if (viewport2_.get() != NULL) | |
878 { | |
879 viewport2_->UpdateSize(); | |
880 } | |
881 | |
882 if (viewport3_.get() != NULL) | |
883 { | |
884 viewport3_->UpdateSize(); | |
885 } | |
886 } | |
887 catch (Orthanc::OrthancException& e) | |
888 { | |
889 LOG(ERROR) << "Exception while updating canvas size: " << e.What(); | |
890 } | |
891 | |
892 return true; | |
893 } | |
894 | |
895 | |
896 | |
897 | |
898 EM_BOOL OnAnimationFrame(double time, void *userData) | |
899 { | |
900 try | |
901 { | |
902 if (viewport1_.get() != NULL) | |
903 { | |
904 viewport1_->Refresh(); | |
905 } | |
906 | |
907 if (viewport2_.get() != NULL) | |
908 { | |
909 viewport2_->Refresh(); | |
910 } | |
911 | |
912 if (viewport3_.get() != NULL) | |
913 { | |
914 viewport3_->Refresh(); | |
915 } | |
916 | |
917 return true; | |
918 } | |
919 catch (Orthanc::OrthancException& e) | |
920 { | |
921 LOG(ERROR) << "Exception in the animation loop, stopping now: " << e.What(); | |
922 return false; | |
923 } | |
924 } | |
925 | |
926 | |
823 | 927 static bool ctrlDown_ = false; |
928 | |
929 | |
930 EM_BOOL OnMouseWheel(int eventType, | |
931 const EmscriptenWheelEvent *wheelEvent, | |
932 void *userData) | |
933 { | |
934 try | |
935 { | |
936 if (userData != NULL) | |
937 { | |
938 int delta = 0; | |
939 | |
940 if (wheelEvent->deltaY < 0) | |
941 { | |
942 delta = -1; | |
943 } | |
944 | |
945 if (wheelEvent->deltaY > 0) | |
946 { | |
947 delta = 1; | |
948 } | |
949 | |
950 if (ctrlDown_) | |
951 { | |
952 delta *= 10; | |
953 } | |
954 | |
955 reinterpret_cast<OrthancStone::VolumeSlicerViewport*>(userData)->Scroll(delta); | |
956 } | |
957 } | |
958 catch (Orthanc::OrthancException& e) | |
959 { | |
960 LOG(ERROR) << "Exception in the wheel event: " << e.What(); | |
961 } | |
962 | |
963 return true; | |
964 } | |
965 | |
966 | |
967 EM_BOOL OnKey(int eventType, | |
968 const EmscriptenKeyboardEvent *keyEvent, | |
969 void *userData) | |
970 { | |
971 ctrlDown_ = keyEvent->ctrlKey; | |
972 return false; | |
973 } | |
974 | |
975 | |
976 | |
977 | |
824
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
978 namespace OrthancStone |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
979 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
980 class TestSleep : public IObserver |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
981 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
982 private: |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
983 WebAssemblyOracle& oracle_; |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
984 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
985 void Schedule() |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
986 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
987 oracle_.Schedule(*this, new OrthancStone::SleepOracleCommand(2000)); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
988 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
989 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
990 void Handle(const SleepOracleCommand::TimeoutMessage& message) |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
991 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
992 LOG(INFO) << "TIMEOUT"; |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
993 Schedule(); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
994 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
995 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
996 public: |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
997 TestSleep(MessageBroker& broker, |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
998 WebAssemblyOracle& oracle) : |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
999 IObserver(broker), |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1000 oracle_(oracle) |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1001 { |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1002 oracle.RegisterObserverCallback( |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1003 new Callable<TestSleep, SleepOracleCommand::TimeoutMessage> |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1004 (*this, &TestSleep::Handle)); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1005 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1006 LOG(INFO) << "STARTING"; |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1007 Schedule(); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1008 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1009 }; |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1010 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1011 //static TestSleep testSleep(broker_, oracle_); |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1012 } |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1013 |
15d493101c1e
support of SleepOracleCommand in WebAssemblyOracle
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
823
diff
changeset
|
1014 |
820 | 1015 extern "C" |
1016 { | |
1017 int main(int argc, char const *argv[]) | |
1018 { | |
1019 OrthancStone::StoneInitialize(); | |
1020 Orthanc::Logging::EnableInfoLevel(true); | |
1021 // Orthanc::Logging::EnableTraceLevel(true); | |
1022 EM_ASM(window.dispatchEvent(new CustomEvent("WebAssemblyLoaded"));); | |
1023 } | |
1024 | |
1025 EMSCRIPTEN_KEEPALIVE | |
1026 void Initialize() | |
1027 { | |
1028 try | |
1029 { | |
1030 loader_.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(ct_, oracle_, oracle_)); | |
1031 | |
1032 viewport1_.reset(new OrthancStone::VolumeSlicerViewport(broker_, "mycanvas1", OrthancStone::VolumeProjection_Axial)); | |
1033 viewport1_->SetSlicer(0, loader_, *loader_, new OrthancStone::GrayscaleStyleConfigurator); | |
1034 viewport1_->UpdateSize(); | |
1035 | |
1036 viewport2_.reset(new OrthancStone::VolumeSlicerViewport(broker_, "mycanvas2", OrthancStone::VolumeProjection_Coronal)); | |
1037 viewport2_->SetSlicer(0, loader_, *loader_, new OrthancStone::GrayscaleStyleConfigurator); | |
1038 viewport2_->UpdateSize(); | |
1039 | |
1040 viewport3_.reset(new OrthancStone::VolumeSlicerViewport(broker_, "mycanvas3", OrthancStone::VolumeProjection_Sagittal)); | |
1041 viewport3_->SetSlicer(0, loader_, *loader_, new OrthancStone::GrayscaleStyleConfigurator); | |
1042 viewport3_->UpdateSize(); | |
1043 | |
1044 emscripten_set_resize_callback("#window", NULL, false, OnWindowResize); | |
823 | 1045 |
1046 emscripten_set_wheel_callback("mycanvas1", viewport1_.get(), false, OnMouseWheel); | |
1047 emscripten_set_wheel_callback("mycanvas2", viewport2_.get(), false, OnMouseWheel); | |
1048 emscripten_set_wheel_callback("mycanvas3", viewport3_.get(), false, OnMouseWheel); | |
1049 | |
1050 emscripten_set_keydown_callback("#window", NULL, false, OnKey); | |
1051 emscripten_set_keyup_callback("#window", NULL, false, OnKey); | |
820 | 1052 |
1053 emscripten_request_animation_frame_loop(OnAnimationFrame, NULL); | |
1054 | |
1055 oracle_.Start(); | |
1056 loader_->LoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); | |
1057 } | |
1058 catch (Orthanc::OrthancException& e) | |
1059 { | |
1060 LOG(ERROR) << "Exception during Initialize(): " << e.What(); | |
1061 } | |
1062 } | |
1063 } |