diff OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyOpenGLContext.cpp @ 1899:917500c46fe0

moved the Platform folder from the Applications folder to the Stone library itself
author Alain Mazy <am@osimis.io>
date Sat, 29 Jan 2022 12:47:32 +0100
parents
children 184b0aeae1af
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyOpenGLContext.cpp	Sat Jan 29 12:47:32 2022 +0100
@@ -0,0 +1,202 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2022 Osimis S.A., Belgium
+ * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "WebAssemblyOpenGLContext.h"
+
+#include "../../../OrthancStone/Sources/StoneException.h"
+
+#include <Logging.h>
+#include <OrthancException.h>
+
+#include <emscripten/html5.h>
+#include <emscripten/em_asm.h>
+
+#include <boost/math/special_functions/round.hpp>
+
+namespace OrthancStone
+{
+  namespace OpenGL
+  {
+    class WebAssemblyOpenGLContext::PImpl
+    {
+    private:
+      std::string                     canvasSelector_;
+      EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context_;
+      bool                            isContextLost_;
+
+    public:
+      explicit PImpl(const std::string& canvasSelector) :
+        canvasSelector_(canvasSelector),
+        isContextLost_(false)
+      {
+        // Context configuration
+        EmscriptenWebGLContextAttributes attr; 
+        emscripten_webgl_init_context_attributes(&attr);
+
+        // The next line might be necessary to print using
+        // WebGL. Sometimes, if set to "false" (the default value),
+        // the canvas was rendered as a fully white or black
+        // area. UNCONFIRMED.
+        attr.preserveDrawingBuffer = true;
+
+        context_ = emscripten_webgl_create_context(canvasSelector.c_str(), &attr);
+        if (context_ == 0)
+        {
+          std::string message("Cannot create an OpenGL context for the element with the following CSS selector: \"");
+          message += canvasSelector;
+          message += "\"  Please make sure the -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 flag has been passed to Emscripten when building.";
+          LOG(ERROR) << message;
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, message);
+        }
+      }
+
+      void* DebugGetInternalContext() const
+      {
+        return reinterpret_cast<void*>(context_);
+      }
+
+      bool IsContextLost()
+      {
+        //LOG(TRACE) << "IsContextLost() for context " << std::hex << context_ << std::dec;
+        bool apiFlag = (emscripten_is_webgl_context_lost(context_) != 0);
+        isContextLost_ = apiFlag;
+        return isContextLost_;
+      }
+
+      void SetLostContext()
+      {
+        isContextLost_ = true;
+      }
+
+      ~PImpl()
+      {
+        try
+        {
+          EMSCRIPTEN_RESULT result = emscripten_webgl_destroy_context(context_);
+          if (result != EMSCRIPTEN_RESULT_SUCCESS)
+          {
+            LOG(ERROR) << "emscripten_webgl_destroy_context returned code " << result;
+          }
+        }
+        catch (const Orthanc::OrthancException& e)
+        {
+          if (e.HasDetails())
+          {
+            LOG(ERROR) << "OrthancException in WebAssemblyOpenGLContext::~PImpl: " << e.What() << " Details: " << e.GetDetails();
+          }
+          else
+          {
+            LOG(ERROR) << "OrthancException in WebAssemblyOpenGLContext::~PImpl: " << e.What();
+          }
+        }
+        catch (const std::exception& e)
+        {
+          LOG(ERROR) << "std::exception in WebAssemblyOpenGLContext::~PImpl: " << e.what();
+        }
+        catch (...)
+        {
+          LOG(ERROR) << "Unknown exception in WebAssemblyOpenGLContext::~PImpl";
+        }
+      }
+
+      const std::string& GetCanvasSelector() const
+      {
+        return canvasSelector_;
+      }
+
+      void MakeCurrent()
+      {
+        if (IsContextLost())
+        {
+          LOG(ERROR) << "MakeCurrent() called on lost context " << context_;
+          throw StoneException(ErrorCode_WebGLContextLost);
+        }
+
+        if (emscripten_is_webgl_context_lost(context_))
+        {
+          LOG(ERROR) << "OpenGL context has been lost for canvas selector: " << canvasSelector_;
+          SetLostContext();
+          throw StoneException(ErrorCode_WebGLContextLost);
+        }
+
+        if (emscripten_webgl_make_context_current(context_) != EMSCRIPTEN_RESULT_SUCCESS)
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
+                                          "Cannot set the OpenGL context");
+        }
+      }
+
+      void SwapBuffer() 
+      {
+        /**
+         * "Rendered WebGL content is implicitly presented (displayed to
+         * the user) on the canvas when the event handler that renders with
+         * WebGL returns back to the browser event loop."
+         * https://emscripten.org/docs/api_reference/html5.h.html#webgl-context
+         *
+         * Could call "emscripten_webgl_commit_frame()" if
+         * "explicitSwapControl" option were set to "true".
+         **/
+      }
+    };
+
+
+    WebAssemblyOpenGLContext::WebAssemblyOpenGLContext(const std::string& canvasSelector) :
+      pimpl_(new PImpl(canvasSelector))
+    {
+    }
+
+    bool WebAssemblyOpenGLContext::IsContextLost()
+    {
+      return pimpl_->IsContextLost();
+    }
+
+    void WebAssemblyOpenGLContext::SetLostContext()
+    {
+      pimpl_->SetLostContext();
+    }
+
+    void* WebAssemblyOpenGLContext::DebugGetInternalContext() const
+    {
+      return pimpl_->DebugGetInternalContext();
+    }
+    
+    void WebAssemblyOpenGLContext::MakeCurrent()
+    {
+      assert(pimpl_.get() != NULL);
+      pimpl_->MakeCurrent();
+    }
+
+    void WebAssemblyOpenGLContext::SwapBuffer() 
+    {
+      assert(pimpl_.get() != NULL);
+      pimpl_->SwapBuffer();
+    }
+
+    const std::string& WebAssemblyOpenGLContext::GetCanvasSelector() const
+    {
+      assert(pimpl_.get() != NULL);
+      return pimpl_->GetCanvasSelector();
+    }
+  }
+}