diff Framework/Viewport/WebGLViewportsRegistry.cpp @ 1232:a28861abf888 broker

viewports for WebAssembly
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 09 Dec 2019 17:46:33 +0100
parents
children e71ee3e88448
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Viewport/WebGLViewportsRegistry.cpp	Mon Dec 09 17:46:33 2019 +0100
@@ -0,0 +1,173 @@
+/**
+ * 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 <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "WebGLViewportsRegistry.h"
+
+#include <Core/OrthancException.h>
+
+namespace OrthancStone
+{
+  void WebGLViewportsRegistry::LaunchTimer()
+  {
+    emscripten_set_timeout(OnTimeoutCallback, 1000.0 * static_cast<double>(timeoutSeconds_), this);
+  }
+
+  
+  void WebGLViewportsRegistry::OnTimeout()
+  {
+    for (Viewports::iterator it = viewports_.begin(); it != viewports_.end(); ++it)
+    {
+      if (it->second == NULL ||
+          it->second->IsContextLost())
+      {
+        LOG(INFO) << "WebGL context lost for canvas: " << it->first;
+
+        // Try and duplicate the HTML5 canvas in the DOM
+        EM_ASM({
+            var canvas = document.getElementById(UTF8ToString($0));
+            if (canvas) {
+              var parent = canvas.parentElement;
+              if (parent) {
+                var cloned = canvas.cloneNode(true /* deep copy */);
+                parent.insertBefore(cloned, canvas);
+                parent.removeChild(canvas);
+              }
+            }
+          },
+          it->first.c_str()  // $0 = ID of the canvas
+          );
+
+        // At this point, the old canvas is removed from the DOM and
+        // replaced by a fresh one with the same ID: Recreate the
+        // WebGL context on the new canvas
+        std::auto_ptr<WebGLViewport> viewport;
+          
+        {
+          std::auto_ptr<IViewport::ILock> lock(it->second->Lock());
+          viewport.reset(new WebGLViewport(it->first, lock->GetController().GetScene()));
+        }
+
+        // Replace the old WebGL viewport by the new one
+        delete it->second;
+        it->second = viewport.release();
+
+        // Tag the fresh canvas as needing a repaint
+        {
+          std::auto_ptr<IViewport::ILock> lock(it->second->Lock());
+          lock->Invalidate();
+        }
+      }
+    }
+      
+    LaunchTimer();
+  }
+
+    
+  void WebGLViewportsRegistry::OnTimeoutCallback(void *userData)
+  {
+    WebGLViewportsRegistry& that = *reinterpret_cast<WebGLViewportsRegistry*>(userData);
+    that.OnTimeout();
+  }
+
+    
+  WebGLViewportsRegistry::WebGLViewportsRegistry(unsigned int timeoutSeconds) :
+    timeoutSeconds_(timeoutSeconds)
+  {
+    if (timeoutSeconds <= 0)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }          
+
+    LaunchTimer();
+  }
+
+    
+  WebGLViewportsRegistry::~WebGLViewportsRegistry()
+  {
+    for (Viewports::iterator it = viewports_.begin(); it != viewports_.end(); ++it)
+    {
+      if (it->second != NULL)
+      {
+        delete it->second;
+      }
+    }
+  }
+
+    
+  void WebGLViewportsRegistry::Add(const std::string& canvasId)
+  {
+    if (viewports_.find(canvasId) != viewports_.end())
+    {
+      LOG(ERROR) << "Canvas was already registered: " << canvasId;
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      viewports_[canvasId] = new WebGLViewport(canvasId);
+    }
+  }
+
+    
+  void WebGLViewportsRegistry::Remove(const std::string& canvasId)
+  {
+    Viewports::iterator found = viewports_.find(canvasId);
+
+    if (found == viewports_.end())
+    {
+      LOG(ERROR) << "Cannot remove unregistered canvas: " << canvasId;
+    }
+    else
+    {
+      if (found->second != NULL)
+      {
+        delete found->second;
+      }
+
+      viewports_.erase(found);
+    }
+  }
+
+    
+  WebGLViewportsRegistry::Accessor::Accessor(WebGLViewportsRegistry& that,
+                                             const std::string& canvasId) :
+    that_(that)
+  {
+    Viewports::iterator viewport = that.viewports_.find(canvasId);
+    if (viewport != that.viewports_.end() &&
+        viewport->second != NULL)
+    {
+      lock_.reset(viewport->second->Lock());
+    }
+  }
+
+
+  IViewport::ILock& WebGLViewportsRegistry::Accessor::GetViewport() const
+  {
+    if (IsValid())
+    {
+      return *lock_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+}