diff Samples/Sdl/RtViewer/RtViewerSdl.cpp @ 1404:3e644f6fadd4

Three-viewport is now OK in SDL and Wasm
author Benjamin Golinvaux <bgo@osimis.io>
date Wed, 29 Apr 2020 22:06:24 +0200
parents 27e0a00bd3e8
children 5d7ee14dc1eb
line wrap: on
line diff
--- a/Samples/Sdl/RtViewer/RtViewerSdl.cpp	Wed Apr 29 18:11:49 2020 +0200
+++ b/Samples/Sdl/RtViewer/RtViewerSdl.cpp	Wed Apr 29 22:06:24 2020 +0200
@@ -18,7 +18,8 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
 
-#include "RtViewer.h"
+#include "RtViewerApp.h"
+#include "RtViewerView.h"
 #include "../SdlHelpers.h"
 
 // Stone of Orthanc includes
@@ -61,10 +62,16 @@
 
 namespace OrthancStone
 {
-  void RtViewerApp::CreateViewport()
+  void RtViewerView::EnableGLDebugOutput()
+  {
+    glEnable(GL_DEBUG_OUTPUT);
+    glDebugMessageCallback(OpenGLMessageCallback, 0);
+  }
+
+  boost::shared_ptr<IViewport> RtViewerView::CreateViewport(const std::string& canvasId)
   {
     // False means we do NOT let Windows treat this as a legacy application that needs to be scaled
-    viewport_ = SdlOpenGLViewport::Create("CT RTDOSE RTSTRUCT viewer", 1024, 1024, false);
+    return SdlOpenGLViewport::Create(canvasId, 1024, 1024, false);
   }
 
   void RtViewerApp::ProcessOptions(int argc, char* argv[])
@@ -113,25 +120,6 @@
   {
     ProcessOptions(argc, argv);
 
-    {
-      std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
-      ViewportController& controller = lock->GetController();
-      Scene2D& scene = controller.GetScene();
-      ICompositor& compositor = lock->GetCompositor();
-
-      // False means we do NOT let a hi-DPI aware desktop managedr treat this as a legacy application that requires
-      // scaling.
-      controller.FitContent(compositor.GetCanvasWidth(), compositor.GetCanvasHeight());
-
-      glEnable(GL_DEBUG_OUTPUT);
-      glDebugMessageCallback(OpenGLMessageCallback, 0);
-
-      compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
-                         FONT_SIZE_0, Orthanc::Encoding_Latin1);
-      compositor.SetFont(1, Orthanc::EmbeddedResources::UBUNTU_FONT,
-                         FONT_SIZE_1, Orthanc::Encoding_Latin1);
-    }
-
     /**
     Create the shared loaders context
     */
@@ -170,22 +158,44 @@
 
     loadersContext->StartOracle();
 
+    CreateLoaders();
+
+    /**
+    Create viewports
+    */
+    CreateView("RtViewer Axial", VolumeProjection_Axial);
+    CreateView("RtViewer Coronal", VolumeProjection_Coronal);
+    CreateView("RtViewer Sagittal", VolumeProjection_Sagittal);
+
+    for (size_t i = 0; i < views_.size(); ++i)
+    {
+      views_[i]->PrepareViewport();
+      views_[i]->EnableGLDebugOutput();
+    }
+
+    DefaultViewportInteractor interactor;
+
     /**
     It is very important that the Oracle (responsible for network I/O) be started before creating and firing the 
     loaders, for any command scheduled by the loader before the oracle is started will be lost.
     */
-    PrepareLoadersAndSlicers();
+    StartLoaders();
 
-    DefaultViewportInteractor interactor;
 
-    boost::shared_ptr<SdlViewport> viewport = boost::dynamic_pointer_cast<SdlViewport>(viewport_);
-
-    OrthancStoneHelpers::SdlRunLoop(viewport, interactor);
-
+    std::vector<boost::shared_ptr<SdlViewport>> sdlViewports;
+    for(size_t i = 0; i < views_.size(); ++i)
+    {
+      boost::shared_ptr<RtViewerView> view = views_[i];
+      boost::shared_ptr<IViewport> viewport = view->GetViewport();
+      boost::shared_ptr<SdlViewport> sdlViewport = 
+        boost::dynamic_pointer_cast<SdlViewport>(viewport);
+      sdlViewports.push_back(sdlViewport);
+    }
+    OrthancStoneHelpers::SdlRunLoop(sdlViewports, interactor);
     loadersContext->StopOracle();
   }
 
-  void RtViewerApp::TakeScreenshot(const std::string& target,
+  void RtViewerView::TakeScreenshot(const std::string& target,
                                    unsigned int canvasWidth,
                                    unsigned int canvasHeight)
   {
@@ -206,328 +216,6 @@
     Orthanc::PngWriter writer;
     writer.WriteToFile(target, png);
   }
-
-
-#if 0
-  void RtViewerApp::HandleApplicationEvent(
-    const SDL_Event& event)
-  {
-    //DisplayInfoText();
-
-    std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
-    ViewportController& controller = lock->GetController();
-    Scene2D& scene = controller.GetScene();
-    ICompositor& compositor = lock->GetCompositor();
-
-    if (event.type == SDL_MOUSEMOTION)
-    {
-      int scancodeCount = 0;
-      const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount);
-
-      if (activeTracker_.get() == NULL &&
-          SDL_SCANCODE_LALT < scancodeCount &&
-          keyboardState[SDL_SCANCODE_LALT])
-      {
-        // The "left-ctrl" key is down, while no tracker is present
-        // Let's display the info text
-        PointerEvent e;
-        e.AddPosition(compositor.GetPixelCenterCoordinates(
-          event.button.x, event.button.y));
-
-        DisplayFloatingCtrlInfoText(e);
-      }
-      else
-      {
-        HideInfoText();
-        //LOG(TRACE) << "(event.type == SDL_MOUSEMOTION)";
-        if (activeTracker_.get() != NULL)
-        {
-          //LOG(TRACE) << "(activeTracker_.get() != NULL)";
-          PointerEvent e;
-          e.AddPosition(compositor.GetPixelCenterCoordinates(
-            event.button.x, event.button.y));
-
-          //LOG(TRACE) << "event.button.x = " << event.button.x << "     " <<
-          //  "event.button.y = " << event.button.y;
-          LOG(TRACE) << "activeTracker_->PointerMove(e); " <<
-            e.GetMainPosition().GetX() << " " << e.GetMainPosition().GetY();
-
-          activeTracker_->PointerMove(e);
-          if (!activeTracker_->IsAlive())
-            activeTracker_.reset();
-        }
-      }
-    }
-    else if (event.type == SDL_MOUSEBUTTONUP)
-    {
-      if (activeTracker_)
-      {
-        PointerEvent e;
-        e.AddPosition(compositor.GetPixelCenterCoordinates(event.button.x, event.button.y));
-        activeTracker_->PointerUp(e);
-        if (!activeTracker_->IsAlive())
-          activeTracker_.reset();
-      }
-    }
-    else if (event.type == SDL_MOUSEBUTTONDOWN)
-    {
-      PointerEvent e;
-      e.AddPosition(compositor.GetPixelCenterCoordinates(
-        event.button.x, event.button.y));
-      if (activeTracker_)
-      {
-        activeTracker_->PointerDown(e);
-        if (!activeTracker_->IsAlive())
-          activeTracker_.reset();
-      }
-      else
-      {
-        // we ATTEMPT to create a tracker if need be
-        activeTracker_ = CreateSuitableTracker(event, e);
-      }
-    }
-    else if (event.type == SDL_KEYDOWN &&
-             event.key.repeat == 0 /* Ignore key bounce */)
-    {
-      switch (event.key.keysym.sym)
-      {
-      case SDLK_ESCAPE:
-        if (activeTracker_)
-        {
-          activeTracker_->Cancel();
-          if (!activeTracker_->IsAlive())
-            activeTracker_.reset();
-        }
-        break;
-
-      case SDLK_r:
-        UpdateLayers();
-        {
-          std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
-          lock->Invalidate();
-        }
-        break;
-
-      case SDLK_s:
-        compositor.FitContent(scene);
-        break;
-
-      case SDLK_t:
-        if (!activeTracker_)
-          SelectNextTool();
-        else
-        {
-          LOG(WARNING) << "You cannot change the active tool when an interaction"
-            " is taking place";
-        }
-        break;
-
-      case SDLK_z:
-        LOG(TRACE) << "SDLK_z has been pressed. event.key.keysym.mod == " << event.key.keysym.mod;
-        if (event.key.keysym.mod & KMOD_CTRL)
-        {
-          if (controller.CanUndo())
-          {
-            LOG(TRACE) << "Undoing...";
-            controller.Undo();
-          }
-          else
-          {
-            LOG(WARNING) << "Nothing to undo!!!";
-          }
-        }
-        break;
-
-      case SDLK_y:
-        LOG(TRACE) << "SDLK_y has been pressed. event.key.keysym.mod == " << event.key.keysym.mod;
-        if (event.key.keysym.mod & KMOD_CTRL)
-        {
-          if (controller.CanRedo())
-          {
-            LOG(TRACE) << "Redoing...";
-            controller.Redo();
-          }
-          else
-          {
-            LOG(WARNING) << "Nothing to redo!!!";
-          }
-        }
-        break;
-
-      case SDLK_c:
-        TakeScreenshot(
-          "screenshot.png",
-          compositor.GetCanvasWidth(),
-          compositor.GetCanvasHeight());
-        break;
-
-      default:
-        break;
-      }
-    }
-    else if (viewport_->IsRefreshEvent(event))
-    {
-      // the viewport has been invalidated and requires repaint
-      viewport_->Paint();
-    }
-  }
-#endif 
-
-#if 0
-  void RtViewerApp::RunSdl(int argc, char* argv[])
-  {
-    ProcessOptions(argc, argv);
-
-    {
-      std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
-      ViewportController& controller = lock->GetController();
-      Scene2D& scene = controller.GetScene();
-      ICompositor& compositor = lock->GetCompositor();
-
-      // False means we do NOT let a hi-DPI aware desktop managedr treat this as a legacy application that requires
-      // scaling.
-      controller.FitContent(compositor.GetCanvasWidth(), compositor.GetCanvasHeight());
-
-      glEnable(GL_DEBUG_OUTPUT);
-      glDebugMessageCallback(OpenGLMessageCallback, 0);
-
-      compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
-                         FONT_SIZE_0, Orthanc::Encoding_Latin1);
-      compositor.SetFont(1, Orthanc::EmbeddedResources::UBUNTU_FONT,
-                         FONT_SIZE_1, Orthanc::Encoding_Latin1);
-    }
-                     //////// from loader
-    
-    loadersContext_.reset(new GenericLoadersContext(1, 4, 1));
-    loadersContext_->StartOracle();
-
-    /**
-    It is very important that the Oracle (responsible for network I/O) be started before creating and firing the 
-    loaders, for any command scheduled by the loader before the oracle is started will be lost.
-    */
-    PrepareLoadersAndSlicers();
-
-    bool stopApplication = false;
-
-    while (!stopApplication)
-    {
-      SDL_Event event;
-      while (!stopApplication && SDL_PollEvent(&event))
-      {
-        if (event.type == SDL_QUIT)
-        {
-          stopApplication = true;
-          break;
-        }
-        else if (event.type == SDL_WINDOWEVENT &&
-                 event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
-        {
-          DisableTracker();
-        }
-        else if (event.type == SDL_KEYDOWN &&
-                 event.key.repeat == 0 /* Ignore key bounce */)
-        {
-          switch (event.key.keysym.sym)
-          {
-          case SDLK_f:
-            // TODO: implement GetWindow to be able to do:
-            // viewport_->GetWindow().ToggleMaximize();
-            ORTHANC_ASSERT(false, "Please implement GetWindow()");
-            break;
-          case SDLK_q:
-            stopApplication = true;
-            break;
-          default:
-            break;
-          }
-        }
-        // the code above is rather application-neutral.
-        // the following call handles events specific to the application
-        HandleApplicationEvent(event);
-      }
-      SDL_Delay(1);
-    }
-    loadersContext_->StopOracle();
-  }
-#endif
-
-#if 0
-  boost::shared_ptr<IFlexiblePointerTracker> RtViewerApp::CreateSuitableTracker(
-    const SDL_Event& event,
-    const PointerEvent& e)
-  {
-    std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
-    ViewportController& controller = lock->GetController();
-    Scene2D& scene = controller.GetScene();
-    ICompositor& compositor = lock->GetCompositor();
-
-    using namespace Orthanc;
-
-    switch (event.button.button)
-    {
-    case SDL_BUTTON_MIDDLE:
-      return boost::shared_ptr<IFlexiblePointerTracker>(new PanSceneTracker
-      (viewport_, e));
-
-    case SDL_BUTTON_RIGHT:
-      return boost::shared_ptr<IFlexiblePointerTracker>(new ZoomSceneTracker
-      (viewport_, e, compositor.GetCanvasHeight()));
-
-    case SDL_BUTTON_LEFT:
-    {
-      //LOG(TRACE) << "CreateSuitableTracker: case SDL_BUTTON_LEFT:";
-      // TODO: we need to iterate on the set of measuring tool and perform
-      // a hit test to check if a tracker needs to be created for edition.
-      // Otherwise, depending upon the active tool, we might want to create
-      // a "measuring tool creation" tracker
-
-      // TODO: if there are conflicts, we should prefer a tracker that 
-      // pertains to the type of measuring tool currently selected (TBD?)
-      boost::shared_ptr<IFlexiblePointerTracker> hitTestTracker = TrackerHitTest(e);
-
-      if (hitTestTracker != NULL)
-      {
-        //LOG(TRACE) << "hitTestTracker != NULL";
-        return hitTestTracker;
-      }
-      else
-      {
-        switch (currentTool_)
-        {
-        case RtViewerGuiTool_Rotate:
-          //LOG(TRACE) << "Creating RotateSceneTracker";
-          return boost::shared_ptr<IFlexiblePointerTracker>(new RotateSceneTracker(viewport_, e));
-        case RtViewerGuiTool_Pan:
-          return boost::shared_ptr<IFlexiblePointerTracker>(new PanSceneTracker(viewport_, e));
-        case RtViewerGuiTool_Zoom:
-          return boost::shared_ptr<IFlexiblePointerTracker>(new ZoomSceneTracker(viewport_, e, compositor.GetCanvasHeight()));
-        //case GuiTool_AngleMeasure:
-        //  return new AngleMeasureTracker(GetScene(), e);
-        //case GuiTool_CircleMeasure:
-        //  return new CircleMeasureTracker(GetScene(), e);
-        //case GuiTool_EllipseMeasure:
-        //  return new EllipseMeasureTracker(GetScene(), e);
-        case RtViewerGuiTool_LineMeasure:
-          return boost::shared_ptr<IFlexiblePointerTracker>(new CreateLineMeasureTracker(viewport_, e));
-        case RtViewerGuiTool_AngleMeasure:
-          return boost::shared_ptr<IFlexiblePointerTracker>(new CreateAngleMeasureTracker(viewport_, e));
-        case RtViewerGuiTool_CircleMeasure:
-          LOG(ERROR) << "Not implemented yet!";
-          return boost::shared_ptr<IFlexiblePointerTracker>();
-        case RtViewerGuiTool_EllipseMeasure:
-          LOG(ERROR) << "Not implemented yet!";
-          return boost::shared_ptr<IFlexiblePointerTracker>();
-        default:
-          throw OrthancException(ErrorCode_InternalError, "Wrong tool!");
-        }
-      }
-    }
-    default:
-      return boost::shared_ptr<IFlexiblePointerTracker>();
-    }
-  }
-#endif
-
 }
 
 boost::weak_ptr<OrthancStone::RtViewerApp> g_app;