From 089998169de3efeb81786393b0898d0c94e4e7e2 Mon Sep 17 00:00:00 2001
From: Joseph Mirabel <jmirabel@laas.fr>
Date: Sat, 9 Feb 2019 17:52:55 +0100
Subject: [PATCH] Add WindowsManager::refresh and provide asynchronous refresh.

---
 idl/gepetto/viewer/graphical-interface.idl |  5 ++
 include/gepetto/gui/windows-manager.hh     | 13 ++++-
 src/graphical-interface.impl.cpp           |  2 +
 src/graphical-interface.impl.hh            |  1 +
 src/gui/windows-manager.cc                 | 63 ++++++++++++++++++++++
 5 files changed, 82 insertions(+), 2 deletions(-)

diff --git a/idl/gepetto/viewer/graphical-interface.idl b/idl/gepetto/viewer/graphical-interface.idl
index 782ec99..2fc2306 100644
--- a/idl/gepetto/viewer/graphical-interface.idl
+++ b/idl/gepetto/viewer/graphical-interface.idl
@@ -351,6 +351,11 @@ typedef sequence<Transform> TransformSeq;
 
     /// Change configurations according to the last applyConfigurations.d
     void refresh() raises (Error);
+
+    /// Set to false if you do not want refresh to be synchronized
+    /// with the rendering loop.
+    /// \note This is an experimental features.
+    void setRefreshIsSynchronous (in boolean synchonous) raises (Error);
     
     /// Return the Position + Quaternion orientation of an object in the global frame
     /// \param input nodeName : name of the node.
diff --git a/include/gepetto/gui/windows-manager.hh b/include/gepetto/gui/windows-manager.hh
index 1b3eaf6..080e406 100644
--- a/include/gepetto/gui/windows-manager.hh
+++ b/include/gepetto/gui/windows-manager.hh
@@ -54,8 +54,13 @@ namespace gepetto {
             const std::string& extension);
         bool stopCapture (const WindowID windowId);
 
-        public slots:
-          int createWindow(QString windowName);
+        void refresh ();
+        void setRefreshIsSynchronous (bool synchonous);
+
+      public slots:
+        int createWindow(QString windowName);
+        void asyncRefresh ();
+
       protected:
         WindowsManager (BodyTreeWidget* bodyTree);
 
@@ -75,6 +80,10 @@ namespace gepetto {
         void deleteBodyItem(const std::string& nodeName);
 
         std::vector<OSGWidget*> widgets_;
+
+        bool refreshIsSynchronous_;
+        graphics::Mutex configsAsyncMtx_;
+        NodeConfigurations_t configsAsync_;
     };
   } // namespace gui
 } // namespace gepetto
diff --git a/src/graphical-interface.impl.cpp b/src/graphical-interface.impl.cpp
index 6ee2959..eb1b01c 100644
--- a/src/graphical-interface.impl.cpp
+++ b/src/graphical-interface.impl.cpp
@@ -292,6 +292,8 @@ namespace graphics {
 
       BIND_TO_WINDOWS_MANAGER_0(VOID, refresh)
 
+      BIND_TO_WINDOWS_MANAGER_1(VOID, setRefreshIsSynchronous, BOOL)
+
       BIND_TO_WINDOWS_MANAGER_1(VOID, createScene, STRING)
 
       BIND_TO_WINDOWS_MANAGER_1(VOID, createSceneWithFloor, STRING)
diff --git a/src/graphical-interface.impl.hh b/src/graphical-interface.impl.hh
index 68968fa..3b70e61 100644
--- a/src/graphical-interface.impl.hh
+++ b/src/graphical-interface.impl.hh
@@ -56,6 +56,7 @@ public:
   virtual Names_t* getWindowList() throw (Error);
 
   virtual void refresh() throw (Error);
+  virtual void setRefreshIsSynchronous(bool synchronous) throw (Error);
 
   virtual WindowID createWindow(const char* windowNameCorba) throw (Error);
   virtual WindowID getWindowID (const char* windowNameCorba) throw (Error);
diff --git a/src/gui/windows-manager.cc b/src/gui/windows-manager.cc
index b0fffac..1589747 100644
--- a/src/gui/windows-manager.cc
+++ b/src/gui/windows-manager.cc
@@ -26,6 +26,8 @@
 
 namespace gepetto {
   namespace gui {
+    using graphics::ScopedLock;
+
     Qt::ConnectionType connectionType (QObject* o, int blocking)
     {
       if (o->thread() == QThread::currentThread())
@@ -72,6 +74,7 @@ namespace gepetto {
     WindowsManager::WindowsManager(BodyTreeWidget* bodyTree)
       : Parent_t ()
       , bodyTree_ (bodyTree)
+      , refreshIsSynchronous_ (true)
     {
     }
 
@@ -244,5 +247,65 @@ namespace gepetto {
           Q_RETURN_ARG (bool, res));
       return res;
     }
+
+    struct ApplyConfigurationFunctor
+    {
+      void operator() (const graphics::NodeConfiguration& nc) const
+      {
+        nc.node->applyConfiguration ( nc.position, nc.quat);
+      }
+    };
+
+    void WindowsManager::refresh ()
+    {
+      if (refreshIsSynchronous_) {
+        {
+          ScopedLock lock(configListMtx_);
+          {
+            ScopedLock lock(osgFrameMutex());
+            //refresh scene with the new configuration
+            std::for_each(newNodeConfigurations_.begin(),
+                newNodeConfigurations_.end(), ApplyConfigurationFunctor());
+          }
+          newNodeConfigurations_.resize (0);
+        }
+        if (autoCaptureTransform_) captureTransform ();
+      } else {
+        {
+          ScopedLock lock1(configsAsyncMtx_);
+          ScopedLock lock2(configListMtx_);
+          if (configsAsync_.size() == 0) {
+            configsAsync_.swap (newNodeConfigurations_);
+            QMetaObject::invokeMethod (this, "asyncRefresh", Qt::QueuedConnection);
+          } else {
+            configsAsync_.insert (configsAsync_.end(),
+                newNodeConfigurations_.begin(),
+                newNodeConfigurations_.end());
+            newNodeConfigurations_.resize(0);
+            // No need to reinvoke asyncRefresh as it hasn't been ran yet.
+          }
+        }
+      }
+    }
+
+    void WindowsManager::asyncRefresh ()
+    {
+      NodeConfigurations_t& cfgs = configsAsync_;
+      {
+        ScopedLock lock(configsAsyncMtx_);
+        {
+          ScopedLock lock(osgFrameMutex());
+          //refresh scene with the new configuration
+          std::for_each(cfgs.begin(), cfgs.end(), ApplyConfigurationFunctor());
+        }
+        cfgs.resize (0);
+      }
+      if (autoCaptureTransform_) captureTransform ();
+    }
+
+    void WindowsManager::setRefreshIsSynchronous (bool synchonous)
+    {
+      refreshIsSynchronous_ = synchonous;
+    }
   } // namespace gui
 } // namespace gepetto
-- 
GitLab