# HG changeset patch # User Sebastien Jodogne # Date 1559141336 -7200 # Node ID 2de01660debe1e17876ba636c665fbefa41539e6 # Parent 9a6c7a5dcb7606975a78268da9979b377f5a73ff reorganization diff -r 9a6c7a5dcb76 -r 2de01660debe Samples/WebAssembly/BasicMPR.cpp --- a/Samples/WebAssembly/BasicMPR.cpp Wed May 29 15:45:15 2019 +0200 +++ b/Samples/WebAssembly/BasicMPR.cpp Wed May 29 16:48:56 2019 +0200 @@ -20,273 +20,21 @@ +#include "dev.h" + #include -#include -#include #include "../../Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h" -#include "../../Framework/OpenGL/WebAssemblyOpenGLContext.h" #include "../../Framework/Oracle/SleepOracleCommand.h" #include "../../Framework/Oracle/WebAssemblyOracle.h" #include "../../Framework/Scene2D/GrayscaleStyleConfigurator.h" -#include "../../Framework/Scene2D/OpenGLCompositor.h" -#include "../../Framework/Scene2D/PanSceneTracker.h" -#include "../../Framework/Scene2D/RotateSceneTracker.h" -#include "../../Framework/Scene2D/ZoomSceneTracker.h" -#include "../../Framework/Scene2DViewport/IFlexiblePointerTracker.h" -#include "../../Framework/Scene2DViewport/ViewportController.h" #include "../../Framework/StoneInitialization.h" #include "../../Framework/Volumes/VolumeSceneLayerSource.h" -#include -#include - - -static const unsigned int FONT_SIZE = 32; - namespace OrthancStone { - class WebAssemblyViewport : public boost::noncopyable - { - private: - // the construction order is important because compositor_ - // will hold a reference to the scene that belong to the - // controller_ object - OpenGL::WebAssemblyOpenGLContext context_; - boost::shared_ptr controller_; - OpenGLCompositor compositor_; - - void SetupEvents(const std::string& canvas); - - public: - WebAssemblyViewport(MessageBroker& broker, - const std::string& canvas) : - context_(canvas), - controller_(new ViewportController(broker)), - compositor_(context_, *controller_->GetScene()) - { - compositor_.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, - FONT_SIZE, Orthanc::Encoding_Latin1); - SetupEvents(canvas); - } - - Scene2D& GetScene() - { - return *controller_->GetScene(); - } - - const boost::shared_ptr& GetController() - { - return controller_; - } - - void UpdateSize() - { - context_.UpdateSize(); - compositor_.UpdateSize(); - Refresh(); - } - - void Refresh() - { - compositor_.Refresh(); - } - - void FitContent() - { - GetScene().FitContent(context_.GetCanvasWidth(), context_.GetCanvasHeight()); - } - - const std::string& GetCanvasIdentifier() const - { - return context_.GetCanvasIdentifier(); - } - - ScenePoint2D GetPixelCenterCoordinates(int x, int y) const - { - return compositor_.GetPixelCenterCoordinates(x, y); - } - - unsigned int GetCanvasWidth() const - { - return context_.GetCanvasWidth(); - } - - unsigned int GetCanvasHeight() const - { - return context_.GetCanvasHeight(); - } - }; - - class ActiveTracker : public boost::noncopyable - { - private: - boost::shared_ptr tracker_; - std::string canvasIdentifier_; - bool insideCanvas_; - - public: - ActiveTracker(const boost::shared_ptr& tracker, - const WebAssemblyViewport& viewport) : - tracker_(tracker), - canvasIdentifier_(viewport.GetCanvasIdentifier()), - insideCanvas_(true) - { - if (tracker_.get() == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - } - - bool IsAlive() const - { - return tracker_->IsAlive(); - } - - void PointerMove(const PointerEvent& event) - { - tracker_->PointerMove(event); - } - - void PointerUp(const PointerEvent& event) - { - tracker_->PointerUp(event); - } - }; -} - -static OrthancStone::PointerEvent* ConvertMouseEvent( - const EmscriptenMouseEvent& source, - OrthancStone::WebAssemblyViewport& viewport) -{ - std::auto_ptr target( - new OrthancStone::PointerEvent); - - target->AddPosition(viewport.GetPixelCenterCoordinates( - source.targetX, source.targetY)); - target->SetAltModifier(source.altKey); - target->SetControlModifier(source.ctrlKey); - target->SetShiftModifier(source.shiftKey); - - return target.release(); -} - -std::auto_ptr tracker_; - -EM_BOOL OnMouseEvent(int eventType, - const EmscriptenMouseEvent *mouseEvent, - void *userData) -{ - if (mouseEvent != NULL && - userData != NULL) - { - OrthancStone::WebAssemblyViewport& viewport = - *reinterpret_cast(userData); - - switch (eventType) - { - case EMSCRIPTEN_EVENT_CLICK: - { - static unsigned int count = 0; - char buf[64]; - sprintf(buf, "click %d", count++); - - std::auto_ptr layer(new OrthancStone::TextSceneLayer); - layer->SetText(buf); - viewport.GetScene().SetLayer(100, layer.release()); - viewport.Refresh(); - break; - } - - case EMSCRIPTEN_EVENT_MOUSEDOWN: - { - boost::shared_ptr t; - - { - std::auto_ptr event( - ConvertMouseEvent(*mouseEvent, viewport)); - - switch (mouseEvent->button) - { - case 0: // Left button - emscripten_console_log("Creating RotateSceneTracker"); - t.reset(new OrthancStone::RotateSceneTracker( - viewport.GetController(), *event)); - break; - - case 1: // Middle button - emscripten_console_log("Creating PanSceneTracker"); - LOG(INFO) << "Creating PanSceneTracker" ; - t.reset(new OrthancStone::PanSceneTracker( - viewport.GetController(), *event)); - break; - - case 2: // Right button - emscripten_console_log("Creating ZoomSceneTracker"); - t.reset(new OrthancStone::ZoomSceneTracker( - viewport.GetController(), *event, viewport.GetCanvasWidth())); - break; - - default: - break; - } - } - - if (t.get() != NULL) - { - tracker_.reset( - new OrthancStone::ActiveTracker(t, viewport)); - viewport.Refresh(); - } - - break; - } - - case EMSCRIPTEN_EVENT_MOUSEMOVE: - if (tracker_.get() != NULL) - { - std::auto_ptr event( - ConvertMouseEvent(*mouseEvent, viewport)); - tracker_->PointerMove(*event); - viewport.Refresh(); - } - break; - - case EMSCRIPTEN_EVENT_MOUSEUP: - if (tracker_.get() != NULL) - { - std::auto_ptr event( - ConvertMouseEvent(*mouseEvent, viewport)); - tracker_->PointerUp(*event); - viewport.Refresh(); - if (!tracker_->IsAlive()) - tracker_.reset(); - } - break; - - default: - break; - } - } - - return true; -} - - -void OrthancStone::WebAssemblyViewport::SetupEvents(const std::string& canvas) -{ - emscripten_set_mousedown_callback(canvas.c_str(), this, false, OnMouseEvent); - emscripten_set_mousemove_callback(canvas.c_str(), this, false, OnMouseEvent); - emscripten_set_mouseup_callback(canvas.c_str(), this, false, OnMouseEvent); -} - - - - -namespace OrthancStone -{ - class VolumeSlicerViewport : public IObserver + class VolumeSlicerWidget : public IObserver { private: OrthancStone::WebAssemblyViewport viewport_; @@ -317,7 +65,7 @@ } public: - VolumeSlicerViewport(MessageBroker& broker, + VolumeSlicerWidget(MessageBroker& broker, const std::string& canvas, VolumeProjection projection) : IObserver(broker), @@ -344,8 +92,8 @@ } loader.RegisterObserverCallback( - new Callable - (*this, &VolumeSlicerViewport::Handle)); + new Callable + (*this, &VolumeSlicerWidget::Handle)); source_.reset(new VolumeSceneLayerSource(viewport_.GetScene(), layerDepth, slicer)); @@ -365,6 +113,11 @@ } } + size_t GetSlicesCount() const + { + return planes_.size(); + } + void Scroll(int delta) { if (!planes_.empty()) @@ -402,9 +155,9 @@ boost::shared_ptr loader_; -std::auto_ptr viewport1_; -std::auto_ptr viewport2_; -std::auto_ptr viewport3_; +std::auto_ptr widget1_; +std::auto_ptr widget2_; +std::auto_ptr widget3_; OrthancStone::MessageBroker broker_; OrthancStone::WebAssemblyOracle oracle_(broker_); @@ -414,19 +167,19 @@ { try { - if (viewport1_.get() != NULL) + if (widget1_.get() != NULL) { - viewport1_->UpdateSize(); + widget1_->UpdateSize(); } - if (viewport2_.get() != NULL) + if (widget2_.get() != NULL) { - viewport2_->UpdateSize(); + widget2_->UpdateSize(); } - if (viewport3_.get() != NULL) + if (widget3_.get() != NULL) { - viewport3_->UpdateSize(); + widget3_->UpdateSize(); } } catch (Orthanc::OrthancException& e) @@ -444,19 +197,19 @@ { try { - if (viewport1_.get() != NULL) + if (widget1_.get() != NULL) { - viewport1_->Refresh(); + widget1_->Refresh(); } - if (viewport2_.get() != NULL) + if (widget2_.get() != NULL) { - viewport2_->Refresh(); + widget2_->Refresh(); } - if (viewport3_.get() != NULL) + if (widget3_.get() != NULL) { - viewport3_->Refresh(); + widget3_->Refresh(); } return true; @@ -492,12 +245,15 @@ delta = 1; } + OrthancStone::VolumeSlicerWidget& widget = + *reinterpret_cast(userData); + if (ctrlDown_) { - delta *= 10; + delta *= static_cast(widget.GetSlicesCount() / 10); } - - reinterpret_cast(userData)->Scroll(delta); + + widget.Scroll(delta); } } catch (Orthanc::OrthancException& e) @@ -509,15 +265,24 @@ } -EM_BOOL OnKey(int eventType, - const EmscriptenKeyboardEvent *keyEvent, - void *userData) +EM_BOOL OnKeyDown(int eventType, + const EmscriptenKeyboardEvent *keyEvent, + void *userData) { ctrlDown_ = keyEvent->ctrlKey; return false; } +EM_BOOL OnKeyUp(int eventType, + const EmscriptenKeyboardEvent *keyEvent, + void *userData) +{ + ctrlDown_ = false; + return false; +} + + namespace OrthancStone @@ -574,26 +339,26 @@ { loader_.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(ct_, oracle_, oracle_)); - viewport1_.reset(new OrthancStone::VolumeSlicerViewport(broker_, "mycanvas1", OrthancStone::VolumeProjection_Axial)); - viewport1_->SetSlicer(0, loader_, *loader_, new OrthancStone::GrayscaleStyleConfigurator); - viewport1_->UpdateSize(); + widget1_.reset(new OrthancStone::VolumeSlicerWidget(broker_, "mycanvas1", OrthancStone::VolumeProjection_Axial)); + widget1_->SetSlicer(0, loader_, *loader_, new OrthancStone::GrayscaleStyleConfigurator); + widget1_->UpdateSize(); - viewport2_.reset(new OrthancStone::VolumeSlicerViewport(broker_, "mycanvas2", OrthancStone::VolumeProjection_Coronal)); - viewport2_->SetSlicer(0, loader_, *loader_, new OrthancStone::GrayscaleStyleConfigurator); - viewport2_->UpdateSize(); + widget2_.reset(new OrthancStone::VolumeSlicerWidget(broker_, "mycanvas2", OrthancStone::VolumeProjection_Coronal)); + widget2_->SetSlicer(0, loader_, *loader_, new OrthancStone::GrayscaleStyleConfigurator); + widget2_->UpdateSize(); - viewport3_.reset(new OrthancStone::VolumeSlicerViewport(broker_, "mycanvas3", OrthancStone::VolumeProjection_Sagittal)); - viewport3_->SetSlicer(0, loader_, *loader_, new OrthancStone::GrayscaleStyleConfigurator); - viewport3_->UpdateSize(); + widget3_.reset(new OrthancStone::VolumeSlicerWidget(broker_, "mycanvas3", OrthancStone::VolumeProjection_Sagittal)); + widget3_->SetSlicer(0, loader_, *loader_, new OrthancStone::GrayscaleStyleConfigurator); + widget3_->UpdateSize(); emscripten_set_resize_callback("#window", NULL, false, OnWindowResize); - emscripten_set_wheel_callback("mycanvas1", viewport1_.get(), false, OnMouseWheel); - emscripten_set_wheel_callback("mycanvas2", viewport2_.get(), false, OnMouseWheel); - emscripten_set_wheel_callback("mycanvas3", viewport3_.get(), false, OnMouseWheel); + emscripten_set_wheel_callback("mycanvas1", widget1_.get(), false, OnMouseWheel); + emscripten_set_wheel_callback("mycanvas2", widget2_.get(), false, OnMouseWheel); + emscripten_set_wheel_callback("mycanvas3", widget3_.get(), false, OnMouseWheel); - emscripten_set_keydown_callback("#window", NULL, false, OnKey); - emscripten_set_keyup_callback("#window", NULL, false, OnKey); + emscripten_set_keydown_callback("#window", NULL, false, OnKeyDown); + emscripten_set_keyup_callback("#window", NULL, false, OnKeyUp); emscripten_request_animation_frame_loop(OnAnimationFrame, NULL); diff -r 9a6c7a5dcb76 -r 2de01660debe Samples/WebAssembly/BasicScene.cpp --- a/Samples/WebAssembly/BasicScene.cpp Wed May 29 15:45:15 2019 +0200 +++ b/Samples/WebAssembly/BasicScene.cpp Wed May 29 16:48:56 2019 +0200 @@ -19,38 +19,21 @@ **/ +#include "dev.h" #include #include // From Stone -#include "../../Applications/Sdl/SdlOpenGLWindow.h" -#include "../../Framework/Scene2D/CairoCompositor.h" #include "../../Framework/Scene2D/ColorTextureSceneLayer.h" -#include "../../Framework/Scene2D/OpenGLCompositor.h" -#include "../../Framework/Scene2D/PanSceneTracker.h" -#include "../../Framework/Scene2D/RotateSceneTracker.h" -#include "../../Framework/Scene2D/Scene2D.h" -#include "../../Framework/Scene2D/ZoomSceneTracker.h" -#include "../../Framework/Scene2DViewport/ViewportController.h" #include "../../Framework/StoneInitialization.h" -#include "../../Framework/OpenGL/WebAssemblyOpenGLContext.h" // From Orthanc framework #include #include #include -#include - -#include - -static const unsigned int FONT_SIZE = 32; - -using boost::shared_ptr; -using boost::make_shared; - -void PrepareScene(OrthancStone::Scene2DPtr scene) +void PrepareScene(OrthancStone::Scene2D& scene) { using namespace OrthancStone; @@ -77,13 +60,13 @@ p[4] = 0; p[5] = 0; - scene->SetLayer(12, new ColorTextureSceneLayer(i)); + scene.SetLayer(12, new ColorTextureSceneLayer(i)); std::auto_ptr l(new ColorTextureSceneLayer(i)); l->SetOrigin(-3, 2); l->SetPixelSpacing(1.5, 1); l->SetAngle(20.0 / 180.0 * M_PI); - scene->SetLayer(14, l.release()); + scene.SetLayer(14, l.release()); } // Texture of 1x1 size @@ -99,7 +82,7 @@ std::auto_ptr l(new ColorTextureSceneLayer(i)); l->SetOrigin(-2, 1); l->SetAngle(20.0 / 180.0 * M_PI); - scene->SetLayer(13, l.release()); + scene.SetLayer(13, l.release()); } // Some lines @@ -130,7 +113,7 @@ chain.push_back(ScenePoint2D(4, 2)); layer->AddChain(chain, false, 0, 0, 255); - scene->SetLayer(50, layer.release()); + scene.SetLayer(50, layer.release()); } // Some text @@ -138,243 +121,10 @@ { std::auto_ptr layer(new TextSceneLayer); layer->SetText("Hello"); - scene->SetLayer(100, layer.release()); + scene.SetLayer(100, layer.release()); } } -namespace OrthancStone -{ - class WebAssemblyViewport : public boost::noncopyable - { - private: - // the construction order is important because compositor_ - // will hold a reference to the scene that belong to the - // controller_ object - OpenGL::WebAssemblyOpenGLContext context_; - ViewportControllerPtr controller_; - OpenGLCompositor compositor_; - - void SetupEvents(const std::string& canvas); - - public: - WebAssemblyViewport(MessageBroker& broker, const std::string& canvas) : - context_(canvas), - controller_(make_shared(broker)), - compositor_(context_, *controller_->GetScene()) - { - compositor_.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, - FONT_SIZE, Orthanc::Encoding_Latin1); - SetupEvents(canvas); - } - - Scene2DPtr GetScene() - { - return controller_->GetScene(); - } - - ViewportControllerPtr GetController() - { - return controller_; - } - - void UpdateSize() - { - context_.UpdateSize(); - compositor_.UpdateSize(); - Refresh(); - } - - void Refresh() - { - compositor_.Refresh(); - } - - const std::string& GetCanvasIdentifier() const - { - return context_.GetCanvasIdentifier(); - } - - ScenePoint2D GetPixelCenterCoordinates(int x, int y) const - { - return compositor_.GetPixelCenterCoordinates(x, y); - } - - unsigned int GetCanvasWidth() const - { - return context_.GetCanvasWidth(); - } - - unsigned int GetCanvasHeight() const - { - return context_.GetCanvasHeight(); - } - }; - - class ActiveTracker : public boost::noncopyable - { - private: - OrthancStone::FlexiblePointerTrackerPtr tracker_; - std::string canvasIdentifier_; - bool insideCanvas_; - - public: - ActiveTracker(FlexiblePointerTrackerPtr tracker, - const WebAssemblyViewport& viewport) : - tracker_(tracker), - canvasIdentifier_(viewport.GetCanvasIdentifier()), - insideCanvas_(true) - { - if (tracker_.get() == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - } - - bool IsAlive() const - { - return tracker_->IsAlive(); - } - - void PointerMove(const PointerEvent& event) - { - tracker_->PointerMove(event); - } - - void PointerUp(const PointerEvent& event) - { - tracker_->PointerUp(event); - } - }; -} - -static OrthancStone::PointerEvent* ConvertMouseEvent( - const EmscriptenMouseEvent& source, - OrthancStone::WebAssemblyViewport& viewport) -{ - std::auto_ptr target( - new OrthancStone::PointerEvent); - - target->AddPosition(viewport.GetPixelCenterCoordinates( - source.targetX, source.targetY)); - target->SetAltModifier(source.altKey); - target->SetControlModifier(source.ctrlKey); - target->SetShiftModifier(source.shiftKey); - - return target.release(); -} - -std::auto_ptr tracker_; - -EM_BOOL OnMouseEvent(int eventType, - const EmscriptenMouseEvent *mouseEvent, - void *userData) -{ - if (mouseEvent != NULL && - userData != NULL) - { - OrthancStone::WebAssemblyViewport& viewport = - *reinterpret_cast(userData); - - switch (eventType) - { - case EMSCRIPTEN_EVENT_CLICK: - { - static unsigned int count = 0; - char buf[64]; - sprintf(buf, "click %d", count++); - - std::auto_ptr layer(new OrthancStone::TextSceneLayer); - layer->SetText(buf); - viewport.GetScene()->SetLayer(100, layer.release()); - viewport.Refresh(); - break; - } - - case EMSCRIPTEN_EVENT_MOUSEDOWN: - { - OrthancStone::FlexiblePointerTrackerPtr t; - - { - std::auto_ptr event( - ConvertMouseEvent(*mouseEvent, viewport)); - - switch (mouseEvent->button) - { - case 0: // Left button - emscripten_console_log("Creating RotateSceneTracker"); - t.reset(new OrthancStone::RotateSceneTracker( - viewport.GetController(), *event)); - break; - - case 1: // Middle button - emscripten_console_log("Creating PanSceneTracker"); - LOG(INFO) << "Creating PanSceneTracker" ; - t.reset(new OrthancStone::PanSceneTracker( - viewport.GetController(), *event)); - break; - - case 2: // Right button - emscripten_console_log("Creating ZoomSceneTracker"); - t.reset(new OrthancStone::ZoomSceneTracker( - viewport.GetController(), *event, viewport.GetCanvasWidth())); - break; - - default: - break; - } - } - - if (t.get() != NULL) - { - tracker_.reset( - new OrthancStone::ActiveTracker(t, viewport)); - viewport.Refresh(); - } - - break; - } - - case EMSCRIPTEN_EVENT_MOUSEMOVE: - if (tracker_.get() != NULL) - { - std::auto_ptr event( - ConvertMouseEvent(*mouseEvent, viewport)); - tracker_->PointerMove(*event); - viewport.Refresh(); - } - break; - - case EMSCRIPTEN_EVENT_MOUSEUP: - if (tracker_.get() != NULL) - { - std::auto_ptr event( - ConvertMouseEvent(*mouseEvent, viewport)); - tracker_->PointerUp(*event); - viewport.Refresh(); - if (!tracker_->IsAlive()) - tracker_.reset(); - } - break; - - default: - break; - } - } - - return true; -} - - -void OrthancStone::WebAssemblyViewport::SetupEvents(const std::string& canvas) -{ -#if 0 - emscripten_set_click_callback(canvas.c_str(), this, false, OnMouseEvent); -#else - emscripten_set_mousedown_callback(canvas.c_str(), this, false, OnMouseEvent); - emscripten_set_mousemove_callback(canvas.c_str(), this, false, OnMouseEvent); - emscripten_set_mouseup_callback(canvas.c_str(), this, false, OnMouseEvent); -#endif -} std::auto_ptr viewport1_; std::auto_ptr viewport2_; diff -r 9a6c7a5dcb76 -r 2de01660debe Samples/WebAssembly/CMakeLists.txt --- a/Samples/WebAssembly/CMakeLists.txt Wed May 29 15:45:15 2019 +0200 +++ b/Samples/WebAssembly/CMakeLists.txt Wed May 29 16:48:56 2019 +0200 @@ -70,7 +70,7 @@ ) -if (OFF) +if (ON) add_executable(BasicScene BasicScene.cpp ) diff -r 9a6c7a5dcb76 -r 2de01660debe Samples/WebAssembly/ConfigurationLocalSJO.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Samples/WebAssembly/ConfigurationLocalSJO.json Wed May 29 16:48:56 2019 +0200 @@ -0,0 +1,20 @@ +{ + "Plugins": [ + "/home/jodogne/Subversion/orthanc-webviewer/r/libOrthancWebViewer.so", + "/home/jodogne/Subversion/orthanc/r/libServeFolders.so" + ], + "StorageDirectory" : "/tmp/orthanc-db", + "IndexDirectory" : "/tmp/orthanc-db", + "RemoteAccessAllowed" : true, + "AuthenticationEnabled" : false, + "ServeFolders" : { + "AllowCache" : false, + "GenerateETag" : true, + "Folders" : { + "/stone" : "/tmp/stone" + } + }, + "WebViewer" : { + "CachePath" : "/tmp/orthanc-db/WebViewerCache" + } +} diff -r 9a6c7a5dcb76 -r 2de01660debe Samples/WebAssembly/NOTES.txt --- a/Samples/WebAssembly/NOTES.txt Wed May 29 15:45:15 2019 +0200 +++ b/Samples/WebAssembly/NOTES.txt Wed May 29 16:48:56 2019 +0200 @@ -1,9 +1,19 @@ +Docker +------ + $ source ~/Downloads/emsdk/emsdk_env.sh $ cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DALLOW_DOWNLOADS=ON .. -DCMAKE_INSTALL_PREFIX=/tmp/stone $ ninja install -$ docker run -p 4242:4242 -p 8042:8042 --rm -v /tmp/stone:/root/stone:ro -v /tmp/stone-db/:/var/lib/orthanc/db/ jodogne/orthanc-plugins:1.5.6 /root/stone/Configuration.json --verbose +$ docker run -p 4242:4242 -p 8042:8042 --rm -v /tmp/stone:/root/stone:ro -v /tmp/stone-db/:/var/lib/orthanc/db/ jodogne/orthanc-plugins:latest /root/stone/Configuration.json --verbose + +WARNING: This won't work using "orthanc-plugins:1.5.6", as support for +PAM is mandatatory in "/instances/.../image-uint16". -notes BGO : + + +notes BGO +--------- + source ~/apps/emsdk/emsdk_env.sh cd /mnt/c/osi/dev/orthanc-stone/Samples/WebAssembly mkdir build @@ -12,3 +22,18 @@ ninja install docker run -p 4242:4242 -p 8042:8042 --rm -v "C:/osi/dev/orthanc-stone/Samples/WebAssembly/installDir:/root/stone:ro" jodogne/orthanc-plugins:1.5.6 /root/stone/Configuration.json --verbose + + + + +Local SJO +--------- + +$ source ~/Downloads/emsdk/emsdk_env.sh +$ cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DALLOW_DOWNLOADS=ON .. -DCMAKE_INSTALL_PREFIX=/tmp/stone +$ ninja install + +$ make -C ~/Subversion/orthanc/r -j4 +$ make -C ~/Subversion/orthanc-webviewer/r -j4 +$ ~/Subversion/orthanc/r/Orthanc ../ConfigurationLocalSJO.json + diff -r 9a6c7a5dcb76 -r 2de01660debe Samples/WebAssembly/dev.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Samples/WebAssembly/dev.h Wed May 29 16:48:56 2019 +0200 @@ -0,0 +1,271 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "../../Framework/OpenGL/WebAssemblyOpenGLContext.h" +#include "../../Framework/Scene2D/OpenGLCompositor.h" +#include "../../Framework/Scene2D/PanSceneTracker.h" +#include "../../Framework/Scene2D/RotateSceneTracker.h" +#include "../../Framework/Scene2D/ZoomSceneTracker.h" +#include "../../Framework/Scene2DViewport/ViewportController.h" + +#include + +#include + +static const unsigned int FONT_SIZE = 32; + +namespace OrthancStone +{ + class WebAssemblyViewport : public boost::noncopyable + { + private: + // the construction order is important because compositor_ + // will hold a reference to the scene that belong to the + // controller_ object + OpenGL::WebAssemblyOpenGLContext context_; + boost::shared_ptr controller_; + OpenGLCompositor compositor_; + + void SetupEvents(const std::string& canvas); + + public: + WebAssemblyViewport(MessageBroker& broker, + const std::string& canvas) : + context_(canvas), + controller_(new ViewportController(broker)), + compositor_(context_, *controller_->GetScene()) + { + compositor_.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, + FONT_SIZE, Orthanc::Encoding_Latin1); + SetupEvents(canvas); + } + + Scene2D& GetScene() + { + return *controller_->GetScene(); + } + + const boost::shared_ptr& GetController() + { + return controller_; + } + + void UpdateSize() + { + context_.UpdateSize(); + compositor_.UpdateSize(); + Refresh(); + } + + void Refresh() + { + compositor_.Refresh(); + } + + void FitContent() + { + GetScene().FitContent(context_.GetCanvasWidth(), context_.GetCanvasHeight()); + } + + const std::string& GetCanvasIdentifier() const + { + return context_.GetCanvasIdentifier(); + } + + ScenePoint2D GetPixelCenterCoordinates(int x, int y) const + { + return compositor_.GetPixelCenterCoordinates(x, y); + } + + unsigned int GetCanvasWidth() const + { + return context_.GetCanvasWidth(); + } + + unsigned int GetCanvasHeight() const + { + return context_.GetCanvasHeight(); + } + }; + + class ActiveTracker : public boost::noncopyable + { + private: + boost::shared_ptr tracker_; + std::string canvasIdentifier_; + bool insideCanvas_; + + public: + ActiveTracker(const boost::shared_ptr& tracker, + const WebAssemblyViewport& viewport) : + tracker_(tracker), + canvasIdentifier_(viewport.GetCanvasIdentifier()), + insideCanvas_(true) + { + if (tracker_.get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + } + + bool IsAlive() const + { + return tracker_->IsAlive(); + } + + void PointerMove(const PointerEvent& event) + { + tracker_->PointerMove(event); + } + + void PointerUp(const PointerEvent& event) + { + tracker_->PointerUp(event); + } + }; +} + +static OrthancStone::PointerEvent* ConvertMouseEvent( + const EmscriptenMouseEvent& source, + OrthancStone::WebAssemblyViewport& viewport) +{ + std::auto_ptr target( + new OrthancStone::PointerEvent); + + target->AddPosition(viewport.GetPixelCenterCoordinates( + source.targetX, source.targetY)); + target->SetAltModifier(source.altKey); + target->SetControlModifier(source.ctrlKey); + target->SetShiftModifier(source.shiftKey); + + return target.release(); +} + +std::auto_ptr tracker_; + +EM_BOOL OnMouseEvent(int eventType, + const EmscriptenMouseEvent *mouseEvent, + void *userData) +{ + if (mouseEvent != NULL && + userData != NULL) + { + OrthancStone::WebAssemblyViewport& viewport = + *reinterpret_cast(userData); + + switch (eventType) + { + case EMSCRIPTEN_EVENT_CLICK: + { + static unsigned int count = 0; + char buf[64]; + sprintf(buf, "click %d", count++); + + std::auto_ptr layer(new OrthancStone::TextSceneLayer); + layer->SetText(buf); + viewport.GetScene().SetLayer(100, layer.release()); + viewport.Refresh(); + break; + } + + case EMSCRIPTEN_EVENT_MOUSEDOWN: + { + boost::shared_ptr t; + + { + std::auto_ptr event( + ConvertMouseEvent(*mouseEvent, viewport)); + + switch (mouseEvent->button) + { + case 0: // Left button + emscripten_console_log("Creating RotateSceneTracker"); + t.reset(new OrthancStone::RotateSceneTracker( + viewport.GetController(), *event)); + break; + + case 1: // Middle button + emscripten_console_log("Creating PanSceneTracker"); + LOG(INFO) << "Creating PanSceneTracker" ; + t.reset(new OrthancStone::PanSceneTracker( + viewport.GetController(), *event)); + break; + + case 2: // Right button + emscripten_console_log("Creating ZoomSceneTracker"); + t.reset(new OrthancStone::ZoomSceneTracker( + viewport.GetController(), *event, viewport.GetCanvasWidth())); + break; + + default: + break; + } + } + + if (t.get() != NULL) + { + tracker_.reset( + new OrthancStone::ActiveTracker(t, viewport)); + viewport.Refresh(); + } + + break; + } + + case EMSCRIPTEN_EVENT_MOUSEMOVE: + if (tracker_.get() != NULL) + { + std::auto_ptr event( + ConvertMouseEvent(*mouseEvent, viewport)); + tracker_->PointerMove(*event); + viewport.Refresh(); + } + break; + + case EMSCRIPTEN_EVENT_MOUSEUP: + if (tracker_.get() != NULL) + { + std::auto_ptr event( + ConvertMouseEvent(*mouseEvent, viewport)); + tracker_->PointerUp(*event); + viewport.Refresh(); + if (!tracker_->IsAlive()) + tracker_.reset(); + } + break; + + default: + break; + } + } + + return true; +} + + +void OrthancStone::WebAssemblyViewport::SetupEvents(const std::string& canvas) +{ + emscripten_set_mousedown_callback(canvas.c_str(), this, false, OnMouseEvent); + emscripten_set_mousemove_callback(canvas.c_str(), this, false, OnMouseEvent); + emscripten_set_mouseup_callback(canvas.c_str(), this, false, OnMouseEvent); +}