0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
authorkgv <kgv@opencascade.com>
Thu, 16 Jul 2020 13:15:22 +0000 (16:15 +0300)
committerbugmaster <bugmaster@opencascade.com>
Wed, 22 Jul 2020 16:24:38 +0000 (19:24 +0300)
OpenGl_Context now skips loading functions related to mapping buffer,
which are required by OpenGL ES 3.0 specs but not provided by WebGL 2.0.
Message_PrinterSystemLog does not use a broken emscripten_log() anymore, which corrupted UNICODE strings.

WasmOcctView::initWindow() - callbacks now set using EMSCRIPTEN_EVENT_TARGET_WINDOW
instead of 0 used by older Emscripten API.

Mouse callbacks now track canvas element and use
EmscriptenMouseEvent::targetX/targetY instead of ::canvasX/canvasY
as the latter was broken.

Added emscripten_set_main_loop() setup to shut up eglSwapInterval() error message.
Fixed missing \0 at the end of string converted by toUtf8Array().

samples/webgl/WasmOcctView.cpp
samples/webgl/main.cpp
samples/webgl/occt-webgl-sample.html
src/Message/Message_PrinterSystemLog.cxx
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_GlCore30.hxx

index 68a8b86..aa5e672 100644 (file)
@@ -109,13 +109,13 @@ void WasmOcctView::initWindow()
 {
   myDevicePixelRatio = jsDevicePixelRatio();
   myCanvasId = THE_CANVAS_ID;
-  const char* aTargetId = !myCanvasId.IsEmpty() ? myCanvasId.ToCString() : NULL;
+  const char* aTargetId = !myCanvasId.IsEmpty() ? myCanvasId.ToCString() : EMSCRIPTEN_EVENT_TARGET_WINDOW;
   const EM_BOOL toUseCapture = EM_TRUE;
-  emscripten_set_resize_callback     (NULL,      this, toUseCapture, onResizeCallback);
+  emscripten_set_resize_callback     (EMSCRIPTEN_EVENT_TARGET_WINDOW, this, toUseCapture, onResizeCallback);
 
-  emscripten_set_mousedown_callback  (NULL,      this, toUseCapture, onMouseCallback);
-  emscripten_set_mouseup_callback    (NULL,      this, toUseCapture, onMouseCallback);
-  emscripten_set_mousemove_callback  (NULL,      this, toUseCapture, onMouseCallback);
+  emscripten_set_mousedown_callback  (aTargetId, this, toUseCapture, onMouseCallback);
+  emscripten_set_mouseup_callback    (aTargetId, this, toUseCapture, onMouseCallback);
+  emscripten_set_mousemove_callback  (aTargetId, this, toUseCapture, onMouseCallback);
   emscripten_set_dblclick_callback   (aTargetId, this, toUseCapture, onMouseCallback);
   emscripten_set_click_callback      (aTargetId, this, toUseCapture, onMouseCallback);
   emscripten_set_mouseenter_callback (aTargetId, this, toUseCapture, onMouseCallback);
@@ -127,9 +127,9 @@ void WasmOcctView::initWindow()
   emscripten_set_touchmove_callback  (aTargetId, this, toUseCapture, onTouchCallback);
   emscripten_set_touchcancel_callback(aTargetId, this, toUseCapture, onTouchCallback);
 
-  //emscripten_set_keypress_callback   (NULL,      this, toUseCapture, onKeyCallback);
-  emscripten_set_keydown_callback    (NULL,      this, toUseCapture, onKeyDownCallback);
-  emscripten_set_keyup_callback      (NULL,      this, toUseCapture, onKeyUpCallback);
+  //emscripten_set_keypress_callback   (EMSCRIPTEN_EVENT_TARGET_WINDOW, this, toUseCapture, onKeyCallback);
+  emscripten_set_keydown_callback    (EMSCRIPTEN_EVENT_TARGET_WINDOW, this, toUseCapture, onKeyDownCallback);
+  emscripten_set_keyup_callback      (EMSCRIPTEN_EVENT_TARGET_WINDOW, this, toUseCapture, onKeyUpCallback);
 }
 
 // ================================================================
@@ -396,7 +396,7 @@ EM_BOOL WasmOcctView::onMouseEvent (int theEventType, const EmscriptenMouseEvent
 
   Graphic3d_Vec2i aWinSize;
   myView->Window()->Size (aWinSize.x(), aWinSize.y());
-  const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (theEvent->canvasX, theEvent->canvasY));
+  const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (theEvent->targetX, theEvent->targetY));
   Aspect_VKeyFlags aFlags = 0;
   if (theEvent->ctrlKey  == EM_TRUE) { aFlags |= Aspect_VKeyFlags_CTRL;  }
   if (theEvent->shiftKey == EM_TRUE) { aFlags |= Aspect_VKeyFlags_SHIFT; }
@@ -477,7 +477,7 @@ EM_BOOL WasmOcctView::onWheelEvent (int theEventType, const EmscriptenWheelEvent
 
   Graphic3d_Vec2i aWinSize;
   myView->Window()->Size (aWinSize.x(), aWinSize.y());
-  const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (theEvent->mouse.canvasX, theEvent->mouse.canvasY));
+  const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (theEvent->mouse.targetX, theEvent->mouse.targetY));
   if (aNewPos.x() < 0 || aNewPos.x() > aWinSize.x()
    || aNewPos.y() < 0 || aNewPos.y() > aWinSize.y())
   {
index 8f55322..fd7b94d 100644 (file)
 //! Global viewer instance.
 static WasmOcctView aViewer;
 
+//! Dummy main loop callback for a single shot.
+extern "C" void onMainLoop()
+{
+  // do nothing here - viewer updates are handled on demand
+  emscripten_cancel_main_loop();
+}
+
 //! File data read event.
 extern "C" void onFileDataRead (void* theOpaque, void* theBuffer, int theDataLen)
 {
@@ -60,6 +67,10 @@ int main()
   Handle(Message_PrinterSystemLog) aJSConsolePrinter = new Message_PrinterSystemLog ("webgl-sample", Message_Trace);
   Message::DefaultMessenger()->AddPrinter (aJSConsolePrinter); // open JavaScript console within the Browser to see this output
   Message::DefaultMessenger()->Send (TCollection_AsciiString("NbLogicalProcessors: ") + OSD_Parallel::NbLogicalProcessors(), Message_Trace);
+
+  // setup a dummy single-shot main loop callback just to shut up a useless Emscripten error message on calling eglSwapInterval()
+  emscripten_set_main_loop (onMainLoop, -1, 0);
+
   aViewer.run();
   Message::DefaultMessenger()->Send (OSD_MemInfo::PrintInfo(), Message_Trace);
 
index 80f7e6f..efec7db 100644 (file)
@@ -69,6 +69,7 @@ var Module =
   printErr: function(theText) {\r
     //var anElement = document.getElementById('output');\r
     //anElement.innerHTML += theText + "<br>";\r
+    console.warn(theText);\r
   },\r
   canvas: (function() {\r
     var aCanvas = document.getElementById('canvas');\r
@@ -85,11 +86,12 @@ fileInput.onchange = function()
   var aReader = new FileReader();\r
   aReader.onload = function()\r
   {\r
+    var aNameLenBytes = lengthBytesUTF8(aFile.name) + 1;\r
+    const aNameBuffer = Module._malloc(aNameLenBytes);\r
+    stringToUTF8(aFile.name, aNameBuffer, aNameLenBytes);\r
+\r
     var aDataArray = new Uint8Array (aReader.result);\r
-    var aNameArray = new Uint8Array (toUtf8Array (aFile.name));\r
     const aDataBuffer = Module._malloc(aDataArray.length);\r
-    const aNameBuffer = Module._malloc(aNameArray.length);\r
-    Module.HEAPU8.set(aNameArray, aNameBuffer);\r
     Module.HEAPU8.set(aDataArray, aDataBuffer);\r
     Module.ccall('onFileDataRead', null, ['number', 'number', 'number'], [aNameBuffer, aDataBuffer, aDataArray.length]);\r
     Module._free(aDataBuffer);\r
@@ -98,35 +100,6 @@ fileInput.onchange = function()
   };\r
   aReader.readAsArrayBuffer(aFile);\r
 };\r
-\r
-//! Convert string into UTF-8 array.\r
-function toUtf8Array (theText)\r
-{\r
-  var aRes = [];\r
-  for (var aCharIter = 0; aCharIter < theText.length; ++aCharIter)\r
-  {\r
-    var aCharCode = theText.charCodeAt (aCharIter);\r
-    if (aCharCode < 0x80)\r
-    {\r
-      aRes.push (aCharCode);\r
-    }\r
-    else if (aCharCode < 0x800)\r
-    {\r
-      aRes.push (0xc0 | (aCharCode >> 6), 0x80 | (aCharCode & 0x3f));\r
-    }\r
-    else if (aCharCode < 0xd800 || aCharCode >= 0xe000)\r
-    {\r
-      aRes.push (0xe0 | (aCharCode >> 12), 0x80 | ((aCharCode>>6) & 0x3f), 0x80 | (aCharCode & 0x3f));\r
-    }\r
-    else\r
-    {\r
-      ++aCharIter;\r
-      aCharCode = 0x10000 + (((aCharCode & 0x3ff)<<10) | (theText.charCodeAt (aCharIter) & 0x3ff));\r
-      aRes.push(0xf0 | (aCharCode >>18), 0x80 | ((aCharCode>>12) & 0x3f), 0x80 | ((aCharCode>>6) & 0x3f), 0x80 | (aCharCode & 0x3f));\r
-    }\r
-  }\r
-  return aRes;\r
-}\r
 </script>\r
 <script type="text/javascript" src="occt-webgl-sample.js" charset="utf-8"></script>\r
 </body>\r
index e17b7df..0c82c21 100644 (file)
 #elif defined(__EMSCRIPTEN__)
   #include <emscripten/emscripten.h>
 
-  // actual version of Emscripten does not define these yet
-  #ifndef EM_LOG_INFO
-    #define EM_LOG_INFO 0
-  #endif
-  #ifndef EM_LOG_DEBUG
-    #define EM_LOG_DEBUG 0
-  #endif
-
-  //! Convert message gravity into emscripten_log() flags.
-  static int getEmscriptenPriority (const Message_Gravity theGravity)
-  {
-    switch (theGravity)
-    {
-      case Message_Trace:   return EM_LOG_CONSOLE | EM_LOG_DEBUG;
-      case Message_Info:    return EM_LOG_CONSOLE | EM_LOG_INFO;
-      case Message_Warning: return EM_LOG_CONSOLE | EM_LOG_WARN;
-      case Message_Alarm:   return EM_LOG_CONSOLE | EM_LOG_ERROR;
-      case Message_Fail:    return EM_LOG_CONSOLE | EM_LOG_ERROR;
-    }
-    return EM_LOG_CONSOLE;
-  }
-
   //! Print message to console.debug().
-  EM_JS(void, debugMsgToConsole, (const char* theStr), {
+  EM_JS(void, occJSConsoleDebug, (const char* theStr), {
     console.debug(UTF8ToString(theStr));
   });
+
+  //! Print message to console.info().
+  EM_JS(void, occJSConsoleInfo, (const char* theStr), {
+    console.info(UTF8ToString(theStr));
+  });
+
+  //! Print message to console.warn().
+  EM_JS(void, occJSConsoleWarn, (const char* theStr), {
+    console.warn(UTF8ToString(theStr));
+  });
+
+  //! Print message to console.error().
+  EM_JS(void, occJSConsoleError, (const char* theStr), {
+    console.error(UTF8ToString(theStr));
+  });
 #else
   #include <syslog.h>
 
@@ -176,14 +169,16 @@ void Message_PrinterSystemLog::send (const TCollection_AsciiString& theString,
 #elif defined(__ANDROID__)
   __android_log_write (getAndroidLogPriority (theGravity), myEventSourceName.ToCString(), theString.ToCString());
 #elif defined(__EMSCRIPTEN__)
-  if (theGravity == Message_Trace)
-  {
-    debugMsgToConsole (theString.ToCString());
-  }
-  else
+  // don't use bogus emscripten_log() corrupting UNICODE strings
+  switch (theGravity)
   {
-    emscripten_log (getEmscriptenPriority (theGravity), "%s", theString.ToCString());
+    case Message_Trace:   occJSConsoleDebug(theString.ToCString()); return;
+    case Message_Info:    occJSConsoleInfo (theString.ToCString()); return;
+    case Message_Warning: occJSConsoleWarn (theString.ToCString()); return;
+    case Message_Alarm:   occJSConsoleError(theString.ToCString()); return;
+    case Message_Fail:    occJSConsoleError(theString.ToCString()); return;
   }
+  occJSConsoleWarn (theString.ToCString());
 #else
   syslog (getSysLogPriority (theGravity), "%s", theString.ToCString());
 #endif
index 36933dd..01413d5 100644 (file)
@@ -1577,14 +1577,20 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glDeleteVertexArrays)
        && FindProcShort (glGenVertexArrays)
        && FindProcShort (glIsVertexArray);
+#ifndef __EMSCRIPTEN__ // latest Emscripten does not pretend having / simulating mapping buffer functions
   const bool hasMapBufferRange = IsGlGreaterEqual (3, 0)
        && FindProcShort (glMapBufferRange)
+       && FindProcShort (glUnmapBuffer)
+       && FindProcShort (glGetBufferPointerv)
        && FindProcShort (glFlushMappedBufferRange);
+#endif
 
   // load OpenGL ES 3.0 new functions
   const bool has30es = IsGlGreaterEqual (3, 0)
        && hasVAO
+    #ifndef __EMSCRIPTEN__
        && hasMapBufferRange
+    #endif
        && hasInstanced
        && arbSamplerObject != NULL
        && arbFBOBlit != NULL
@@ -1602,8 +1608,6 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glEndQuery)
        && FindProcShort (glGetQueryiv)
        && FindProcShort (glGetQueryObjectuiv)
-       && FindProcShort (glUnmapBuffer)
-       && FindProcShort (glGetBufferPointerv)
        && FindProcShort (glDrawBuffers)
        && FindProcShort (glUniformMatrix2x3fv)
        && FindProcShort (glUniformMatrix3x2fv)
index f9cb9ad..3c24b4b 100644 (file)
@@ -60,8 +60,10 @@ public: //! @name GL_ARB_vertex_array_object (added to OpenGL 3.0 core)
 
 public: //! @name GL_ARB_map_buffer_range (added to OpenGL 3.0 core)
 
+#ifndef __EMSCRIPTEN__
   using theBaseClass_t::glMapBufferRange;
   using theBaseClass_t::glFlushMappedBufferRange;
+#endif
 
 public: //! @name OpenGL 3.0 additives to 2.1
 
@@ -142,8 +144,10 @@ public: //! @name OpenGL 3.0 additives to 2.1
   using theBaseClass_t::glEndQuery;
   using theBaseClass_t::glGetQueryiv;
   using theBaseClass_t::glGetQueryObjectuiv;
+#ifndef __EMSCRIPTEN__
   using theBaseClass_t::glUnmapBuffer;
 #endif
+#endif
 };
 
 //! OpenGL 3.0 core based on 2.1 version.