changeset 1216:5147277850cf broker

better abstraction for IViewport
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 05 Dec 2019 16:36:40 +0100
parents 9efa66d8d3f8
children c04d0aa40f73
files Framework/Scene2DViewport/MeasureCommands.h Framework/Scene2DViewport/ViewportController.cpp Framework/Scene2DViewport/ViewportController.h Framework/Viewport/IViewport.h Framework/Viewport/SdlViewport.cpp Framework/Viewport/SdlViewport.h
diffstat 6 files changed, 168 insertions(+), 135 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Scene2DViewport/MeasureCommands.h	Wed Dec 04 20:12:15 2019 +0100
+++ b/Framework/Scene2DViewport/MeasureCommands.h	Thu Dec 05 16:36:40 2019 +0100
@@ -47,6 +47,8 @@
 
   protected:
     boost::shared_ptr<ViewportController>  GetController();
+
+  private:
     boost::weak_ptr<ViewportController> controllerW_;
   };
 
--- a/Framework/Scene2DViewport/ViewportController.cpp	Wed Dec 04 20:12:15 2019 +0100
+++ b/Framework/Scene2DViewport/ViewportController.cpp	Thu Dec 05 16:36:40 2019 +0100
@@ -64,6 +64,12 @@
   }
 
 
+  ViewportController::ViewportController() :
+    undoStackW_(boost::make_shared<OrthancStone::UndoStack>()),
+    canvasToSceneFactor_(1)
+  {
+  }
+
   ViewportController::ViewportController(boost::weak_ptr<UndoStack> undoStackW)
     : undoStackW_(undoStackW)
     , canvasToSceneFactor_(1)
--- a/Framework/Scene2DViewport/ViewportController.h	Wed Dec 04 20:12:15 2019 +0100
+++ b/Framework/Scene2DViewport/ViewportController.h	Thu Dec 05 16:36:40 2019 +0100
@@ -109,6 +109,8 @@
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, \
                                         SceneTransformChanged, ViewportController);
 
+    ViewportController();
+
     ViewportController(boost::weak_ptr<UndoStack> undoStackW);
 
     ~ViewportController();
--- a/Framework/Viewport/IViewport.h	Wed Dec 04 20:12:15 2019 +0100
+++ b/Framework/Viewport/IViewport.h	Thu Dec 05 16:36:40 2019 +0100
@@ -21,8 +21,7 @@
 #pragma once
 
 #include "../Scene2D/ICompositor.h"
-#include "../Scene2D/Scene2D.h"
-#include "../Scene2D/ScenePoint2D.h"
+#include "../Scene2DViewport/ViewportController.h"
 
 namespace OrthancStone
 {
@@ -50,22 +49,16 @@
       virtual bool HasCompositor() const = 0;
 
       virtual ICompositor& GetCompositor() = 0;
+
+      virtual ViewportController& GetController() = 0;
+
+      virtual void Invalidate() = 0;
     };   
     
     virtual ~IViewport()
     {
     }
 
-    // Can be invoked from any thread (notably from the thread of the
-    // Stone context)
-    virtual void Invalidate() = 0;
-
-    // Must be invoked from the main (GUI) thread
-    virtual void Paint(const Scene2D& scene) = 0;
-
-    virtual void UpdateSize(unsigned int width,
-                            unsigned int height) = 0;
-
     virtual ILock* Lock() = 0;
   };
 }
--- a/Framework/Viewport/SdlViewport.cpp	Wed Dec 04 20:12:15 2019 +0100
+++ b/Framework/Viewport/SdlViewport.cpp	Thu Dec 05 16:36:40 2019 +0100
@@ -24,7 +24,33 @@
 
 namespace OrthancStone
 {
-  SdlViewport::SdlViewport()
+  ICompositor& SdlViewport::SdlLock::GetCompositor()
+  {
+    if (that_.compositor_.get() == NULL)
+    {
+      // The derived class should have called "AcquireCompositor()"
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+    else
+    {
+      return *that_.compositor_;
+    }
+  }
+
+
+  void SdlViewport::AcquireCompositor(ICompositor* compositor /* takes ownership */)
+  {
+    if (compositor == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+
+    compositor_.reset(compositor);
+  }
+
+
+  SdlViewport::SdlViewport() :
+    controller_(new ViewportController)
   {
     refreshEvent_ = SDL_RegisterEvents(1);
     
@@ -50,29 +76,52 @@
                                        bool allowDpiScaling) :
     context_(title, width, height, allowDpiScaling)
   {
-    compositor_.reset(new OpenGLCompositor(context_));
+    AcquireCompositor(new OpenGLCompositor(context_));  // (*)
+  }
+
+
+  SdlOpenGLViewport::~SdlOpenGLViewport()
+  {
+    // Make sure that the "OpenGLCompositor" is destroyed BEFORE the
+    // "OpenGLContext" it references (*)
+    ClearCompositor();
+  }
+
+
+  void SdlOpenGLViewport::Paint()
+  {
+    SdlLock lock(*this);
+    lock.GetCompositor().Refresh(lock.GetController().GetScene());
   }
 
-  void SdlOpenGLViewport::Invalidate()
+
+  void SdlOpenGLViewport::UpdateSize(unsigned int width, 
+                                     unsigned int height)
   {
-    SendRefreshEvent();
+    // nothing to do in OpenGL, the OpenGLCompositor::UpdateSize will be called automatically
+    SdlLock lock(*this);
+    lock.Invalidate();
   }
 
-  void SdlOpenGLViewport::Paint(const Scene2D& scene)
+
+  void SdlOpenGLViewport::ToggleMaximize()
   {
-    boost::mutex::scoped_lock lock(mutex_);
-    compositor_->Refresh(scene);
+    // No need to call "Invalidate()" here, as "UpdateSize()" will
+    // be invoked after event "SDL_WINDOWEVENT_SIZE_CHANGED"
+    SdlLock lock(*this);
+    context_.ToggleMaximize();
   }
 
 
+
   SdlCairoViewport::SdlCairoViewport(const char* title,
                                      unsigned int width,
                                      unsigned int height,
                                      bool allowDpiScaling) :
     window_(title, width, height, false /* enable OpenGL */, allowDpiScaling),
-    compositor_(width, height),
     sdlSurface_(NULL)
   {
+    AcquireCompositor(new CairoCompositor(width, height));
   }
 
   SdlCairoViewport::~SdlCairoViewport()
@@ -83,50 +132,56 @@
     }
   }
   
-  void SdlCairoViewport::Paint(const Scene2D& scene)
+  void SdlCairoViewport::Paint()
   {
-    boost::mutex::scoped_lock lock(mutex_);
+    SdlLock lock(*this);
 
-    compositor_.Refresh(scene);
-    CreateSdlSurfaceFromCompositor();
+    lock.GetCompositor().Refresh(lock.GetController().GetScene());
+    CreateSdlSurfaceFromCompositor(dynamic_cast<CairoCompositor&>(lock.GetCompositor()));
     
     if (sdlSurface_ != NULL)
     {
       window_.Render(sdlSurface_);
-    }    
+    }
   }
 
-  void SdlCairoViewport::Invalidate()
-  {
-    SendRefreshEvent();
-  }
 
   void SdlCairoViewport::UpdateSize(unsigned int width,
                                     unsigned int height)
   {
-    {
-      boost::mutex::scoped_lock lock(mutex_);
-      compositor_.UpdateSize(width, height);
-    }
-
-    Invalidate();
+    SdlLock lock(*this);
+    dynamic_cast<CairoCompositor&>(lock.GetCompositor()).UpdateSize(width, height);
+    lock.Invalidate();
   }
   
-  void SdlCairoViewport::CreateSdlSurfaceFromCompositor()  // Assumes that the mutex is locked
+
+  void SdlCairoViewport::ToggleMaximize()
+  {
+    // No need to call "Invalidate()" here, as "UpdateSize()" will
+    // be invoked after event "SDL_WINDOWEVENT_SIZE_CHANGED"
+    SdlLock lock(*this);
+    window_.ToggleMaximize();
+  }
+
+  
+  // Assumes that the mutex is locked
+  void SdlCairoViewport::CreateSdlSurfaceFromCompositor(CairoCompositor& compositor)
   {
     static const uint32_t rmask = 0x00ff0000;
     static const uint32_t gmask = 0x0000ff00;
     static const uint32_t bmask = 0x000000ff;
 
-    const unsigned int width = compositor_.GetCanvas().GetWidth();
-    const unsigned int height = compositor_.GetCanvas().GetHeight();
+    const unsigned int width = compositor.GetCanvas().GetWidth();
+    const unsigned int height = compositor.GetCanvas().GetHeight();
+
+    printf("%dx%d\n", width, height);
     
     if (sdlSurface_ != NULL)
     {
-      if (sdlSurface_->pixels == compositor_.GetCanvas().GetBuffer() &&
+      if (sdlSurface_->pixels == compositor.GetCanvas().GetBuffer() &&
           sdlSurface_->w == static_cast<int>(width) &&
           sdlSurface_->h == static_cast<int>(height) &&
-          sdlSurface_->pitch == static_cast<int>(compositor_.GetCanvas().GetPitch()))
+          sdlSurface_->pitch == static_cast<int>(compositor.GetCanvas().GetPitch()))
       {
         // The image from the compositor has not changed, no need to update the surface
         return;
@@ -137,8 +192,8 @@
       }
     }
 
-    sdlSurface_ = SDL_CreateRGBSurfaceFrom((void*)(compositor_.GetCanvas().GetBuffer()), width, height, 32,
-                                           compositor_.GetCanvas().GetPitch(), rmask, gmask, bmask, 0);
+    sdlSurface_ = SDL_CreateRGBSurfaceFrom((void*)(compositor.GetCanvas().GetBuffer()), width, height, 32,
+                                           compositor.GetCanvas().GetPitch(), rmask, gmask, bmask, 0);
     if (!sdlSurface_)
     {
       LOG(ERROR) << "Cannot create a SDL surface from a Cairo surface";
--- a/Framework/Viewport/SdlViewport.h	Wed Dec 04 20:12:15 2019 +0100
+++ b/Framework/Viewport/SdlViewport.h	Thu Dec 05 16:36:40 2019 +0100
@@ -48,43 +48,24 @@
   class SdlViewport : public IViewport
   {
   private:
-    uint32_t  refreshEvent_;
+    boost::mutex                           mutex_;
+    uint32_t                               refreshEvent_;
+    boost::shared_ptr<ViewportController>  controller_;
+    std::auto_ptr<ICompositor>             compositor_;
+
+    void SendRefreshEvent();
 
   protected:
-    void SendRefreshEvent();
-    
-  public:
-    SdlViewport();
-
-    bool IsRefreshEvent(const SDL_Event& event) const
-    {
-      return (event.type == refreshEvent_);
-    }
-
-    virtual void UpdateSize(unsigned int width,
-                            unsigned int height) = 0;
-
-    virtual void ToggleMaximize() = 0;
-  };
-
-
-  class SdlOpenGLViewport : public SdlViewport
-  {
-  private:
-    boost::mutex                     mutex_;
-    SdlOpenGLContext                 context_;
-    std::auto_ptr<OpenGLCompositor>  compositor_;
-
     class SdlLock : public ILock
     {
     private:
-      SdlOpenGLViewport&         that_;
-      boost::mutex::scoped_lock  lock_;
-      
+      SdlViewport&                that_;
+      boost::mutex::scoped_lock   lock_;
+
     public:
-      SdlLock(SdlOpenGLViewport& viewport) :
-        that_(viewport),
-        lock_(viewport.mutex_)
+      SdlLock(SdlViewport& that) :
+      that_(that),
+      lock_(that.mutex_)
       {
       }
 
@@ -93,73 +74,78 @@
         return true;
       }
 
-      virtual ICompositor& GetCompositor() ORTHANC_OVERRIDE
+      virtual ICompositor& GetCompositor() ORTHANC_OVERRIDE;
+      
+      virtual ViewportController& GetController() ORTHANC_OVERRIDE
       {
-        return *that_.compositor_;
+        return *that_.controller_;
+      }
+
+      virtual void Invalidate() ORTHANC_OVERRIDE
+      {
+        that_.SendRefreshEvent();
       }
     };
-    
+
+    void ClearCompositor()
+    {
+      compositor_.reset();
+    }
+
+    void AcquireCompositor(ICompositor* compositor /* takes ownership */);
+
   public:
-    SdlOpenGLViewport(const char* title,
-                      unsigned int width,
-                      unsigned int height,
-                      bool allowDpiScaling = true);
+    SdlViewport();
 
-    virtual void Invalidate() ORTHANC_OVERRIDE;
-
-    virtual void Paint(const Scene2D& scene) ORTHANC_OVERRIDE;
+    bool IsRefreshEvent(const SDL_Event& event) const
+    {
+      return (event.type == refreshEvent_);
+    }
 
     virtual ILock* Lock() ORTHANC_OVERRIDE
     {
       return new SdlLock(*this);
     }
 
-    virtual void UpdateSize(unsigned int width, unsigned int height) ORTHANC_OVERRIDE
-    {
-      // nothing to do in OpenGL, the OpenGLCompositor::UpdateSize will be called automatically
-    }
+    virtual void UpdateSize(unsigned int width,
+                            unsigned int height) = 0;
+
+    virtual void ToggleMaximize() = 0;
+
+    // Must be invoked from the main SDL thread
+    virtual void Paint() = 0;
+  };
+
+
+  class SdlOpenGLViewport : public SdlViewport
+  {
+  private:
+    SdlOpenGLContext  context_;
 
-    virtual void ToggleMaximize() ORTHANC_OVERRIDE
-    {
-      boost::mutex::scoped_lock lock(mutex_);
-      context_.ToggleMaximize();
-    }
+  public:
+    SdlOpenGLViewport(const char* title,
+                      unsigned int width,
+                      unsigned int height,
+                      bool allowDpiScaling = true);
+
+    virtual ~SdlOpenGLViewport();
+
+    virtual void Paint() ORTHANC_OVERRIDE;
+
+    virtual void UpdateSize(unsigned int width, 
+                            unsigned int height) ORTHANC_OVERRIDE;
+
+    virtual void ToggleMaximize() ORTHANC_OVERRIDE;
   };
 
 
   class SdlCairoViewport : public SdlViewport
   {
   private:
-    class SdlLock : public ILock
-    {
-    private:
-      SdlCairoViewport&          that_;
-      boost::mutex::scoped_lock  lock_;
-      
-    public:
-      SdlLock(SdlCairoViewport& viewport) :
-        that_(viewport),
-        lock_(viewport.mutex_)
-      {
-      }
+    SdlWindow     window_;
+    SDL_Surface*  sdlSurface_;
 
-      virtual bool HasCompositor() const ORTHANC_OVERRIDE
-      {
-        return true;
-      }
-
-      virtual ICompositor& GetCompositor() ORTHANC_OVERRIDE
-      {
-        return that_.compositor_;
-      }
-    };
- 
-    boost::mutex      mutex_;
-    SdlWindow         window_;
-    CairoCompositor   compositor_;
-    SDL_Surface*      sdlSurface_;
-
-    void CreateSdlSurfaceFromCompositor();
+    void CreateSdlSurfaceFromCompositor(CairoCompositor& compositor);
 
   public:
     SdlCairoViewport(const char* title,
@@ -167,24 +153,13 @@
                      unsigned int height,
                      bool allowDpiScaling = true);
 
-    ~SdlCairoViewport();
-
-    virtual void Invalidate() ORTHANC_OVERRIDE;
+    virtual ~SdlCairoViewport();
 
-    virtual void Paint(const Scene2D& scene) ORTHANC_OVERRIDE;
-
-    virtual ILock* Lock() ORTHANC_OVERRIDE
-    {
-      return new SdlLock(*this);
-    }
+    virtual void Paint() ORTHANC_OVERRIDE;
 
     virtual void UpdateSize(unsigned int width,
                             unsigned int height) ORTHANC_OVERRIDE;
 
-    virtual void ToggleMaximize() ORTHANC_OVERRIDE
-    {
-      boost::mutex::scoped_lock lock(mutex_);
-      window_.ToggleMaximize();
-    }
+    virtual void ToggleMaximize() ORTHANC_OVERRIDE;
   };
 }