0031070: Configuration - fix building issues when using Emscripten toolchain IR-2019-10-25
authorkgv <kgv@opencascade.com>
Tue, 15 Oct 2019 23:42:33 +0000 (02:42 +0300)
committerapn <apn@opencascade.com>
Sat, 26 Oct 2019 21:43:07 +0000 (00:43 +0300)
Handled __EMSCRIPTEN__ macros to:
- Workaround atomics (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 is undefined, but GCC atomics are provided).
- Suppress non-standard header <sys/signal.h> warning.
- Return OSD_LinuxREDHAT.
- Avoid inclusion of XLib headers.
- Skip fontconfig library.
- Enable EGL+GLES path (translated by Emscripten into WebGL).
- Skip eglCreatePbufferSurface() not implemented by Emscripten EGL.

Fixed Graphic3d_Vec4.hxx usage within Quantity_ColorRGBA.hxx.

OpenGl_ShaderManager::defaultGlslVersion() now prefers GLSL 300 es when WebGL 2.0 is available,
as there no any OpenGL ES greater than 3.0 emulation so far.

Shaders_Declarations.glsl - added workaround for GLSL compilation on WebGL 1.0
by defining Light properties accessors as macros instead of functions
('[]' : Index expression must be constant).

OpenGl_FrameBuffer::Init() - added workaround for initialization of GL_DEPTH24_STENCIL8
depth-stencil attachment on WebGL 1.0 + GL_WEBGL_depth_texture extension.

OpenGl_Context::Vec4FromQuantityColor() now considers myIsSRgbActive flag
to handle use case, when Immediate Layer is drawn directly into window buffer,
which is not sRGB-ready.

Added new sample - OCCT WebGL viewer.

37 files changed:
dox/FILES_HTML.txt
dox/overview/images/sample_webgl.png [new file with mode: 0644]
dox/overview/overview.md
samples/webgl/.gitignore [new file with mode: 0644]
samples/webgl/CMakeLists.txt [new file with mode: 0644]
samples/webgl/ReadMe.md [new file with mode: 0644]
samples/webgl/WasmOcctView.cpp [new file with mode: 0644]
samples/webgl/WasmOcctView.h [new file with mode: 0644]
samples/webgl/WasmVKeys.h [new file with mode: 0644]
samples/webgl/main.cpp [new file with mode: 0644]
samples/webgl/occt-webgl-sample.html [new file with mode: 0644]
src/Aspect/Aspect_DisplayConnection.cxx
src/Aspect/Aspect_DisplayConnection.hxx
src/Aspect/Aspect_FBConfig.hxx
src/Aspect/Aspect_XWD.hxx
src/Font/Font_FontMgr.cxx
src/InterfaceGraphic/InterfaceGraphic.hxx
src/OSD/OSD_Chronometer.cxx
src/OSD/OSD_MemInfo.cxx
src/OSD/OSD_Path.cxx
src/OSD/OSD_signal.cxx
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_FrameBuffer.cxx
src/OpenGl/OpenGl_GlFunctions.hxx
src/OpenGl/OpenGl_GraphicDriver.cxx
src/OpenGl/OpenGl_GraphicDriver.hxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_Window.cxx
src/Quantity/Quantity_ColorRGBA.cxx
src/Shaders/Declarations.glsl
src/Shaders/DeclarationsImpl.glsl
src/Shaders/Shaders_DeclarationsImpl_glsl.pxx
src/Shaders/Shaders_Declarations_glsl.pxx
src/Standard/Standard_Atomic.hxx
src/Xw/Xw_Window.cxx
src/Xw/Xw_Window.hxx

index 2c1be0e..2accb66 100644 (file)
@@ -14,6 +14,7 @@ overview/overview.md
 ../samples/qt/AndroidQt/ReadMe.md
 ../samples/java/jniviewer/ReadMe.md
 ../samples/ios/UIKitSample/ReadMe.md
+../samples/webgl/ReadMe.md
 
 tutorial/tutorial.md
 
diff --git a/dox/overview/images/sample_webgl.png b/dox/overview/images/sample_webgl.png
new file mode 100644 (file)
index 0000000..7d3781f
Binary files /dev/null and b/dox/overview/images/sample_webgl.png differ
index 289c0e6..6096a2d 100644 (file)
@@ -214,6 +214,7 @@ for which OCCT is certified to work.
 | Linux     | GNU gcc 4.3+ <br> LLVM CLang 3.6+ |
 | OS X / macOS | XCode 6 or newer |
 | Android   | NDK r10, GNU gcc 4.8 or newer |
+| Web       | Emscripten SDK 1.39 or newer (CLang) |
 
 1) VC++ 141 64-bit is used for regular testing and for building binary package of official release of OCCT on Windows.
 
@@ -572,3 +573,11 @@ There is a sample demonstrating usage of OCCT on iOS with Apple UIKit framework.
 @figure{/overview/images/sample_ios_uikit.png}
 
 See \subpage occt_samples_ios_uikit "iOS sample Readme" for details.
+
+@subsubsection OCCT_OVW_SECTION_7_3_6 Web
+
+WebGL Viewer sample demonstrating usage of OCCT 3D Viewer in Web browser with Emscripten SDK can be found in `samples/webgl`.
+
+@figure{/overview/images/sample_webgl.png}
+
+See \subpage occt_samples_webgl "WebGL sample Readme" for details.
diff --git a/samples/webgl/.gitignore b/samples/webgl/.gitignore
new file mode 100644 (file)
index 0000000..ecdfdf7
--- /dev/null
@@ -0,0 +1,2 @@
+/build
+/work
diff --git a/samples/webgl/CMakeLists.txt b/samples/webgl/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ee35d9d
--- /dev/null
@@ -0,0 +1,66 @@
+cmake_minimum_required(VERSION 3.2)
+
+project(occt-webgl-sample)
+
+set(CMAKE_CXX_STANDARD 11)
+set(APP_VERSION_MAJOR 1)
+set(APP_VERSION_MINOR 0)
+set(APP_TARGET occt-webgl-sample)
+
+# customize build
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s WASM=1")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_WEBGL2=1")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s ALLOW_MEMORY_GROWTH=1")
+#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s SAFE_HEAP=1")
+#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s NO_EXIT_RUNTIME=1")
+#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s TOTAL_MEMORY=16MB")
+#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s ABORTING_MALLOC=0")
+#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s FORCE_FILESYSTEM=1")
+#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --preload-file myFile")
+
+INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})
+file(GLOB SOURCES
+  *.h
+  *.cpp
+)
+source_group ("Headers" FILES
+  WasmOcctView.h)
+source_group ("Sources" FILES
+  WasmOcctView.cpp
+  main.cpp)
+
+# FreeType
+find_package(freetype REQUIRED NO_DEFAULT_PATH)
+if(freetype_FOUND)
+  message (STATUS "Using FreeType from \"${freetype_DIR}\"" )
+else()
+  message(WARNING "Could not find FreeType, please set freetype_DIR variable." )
+endif()
+
+# Open CASCADE Technology
+find_package(OpenCASCADE REQUIRED NO_DEFAULT_PATH)
+if(OpenCASCADE_FOUND)
+  message (STATUS "Using OpenCASCADE from \"${OpenCASCADE_DIR}\"" )
+  INCLUDE_DIRECTORIES(${OpenCASCADE_INCLUDE_DIR})
+  LINK_DIRECTORIES(${OpenCASCADE_LIBRARY_DIR})
+else()
+  message(WARNING "Could not find OpenCASCADE, please set OpenCASCADE_DIR variable." )
+  set(OCCT_LIBRARY_DIR)
+  set(OCCT_BIN_DIR)
+endif()
+
+set(OpenCASCADE_LIBS TKRWMesh TKBinXCAF TKBin TKBinL TKOpenGl TKXCAF TKVCAF TKCAF TKV3d TKHLR TKMesh TKService TKShHealing TKPrim TKTopAlgo TKGeomAlgo TKBRep TKGeomBase TKG3d TKG2d TKMath TKLCAF TKCDF TKernel)
+
+add_executable(${APP_TARGET} ${SOURCES})
+target_link_libraries(
+  ${APP_TARGET}
+  ${OpenCASCADE_LIBS}
+  freetype
+)
+set_target_properties(${APP_TARGET} PROPERTIES LINK_FLAGS "-s EXPORTED_FUNCTIONS=['_main','_onFileDataRead'] -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap']")
+
+install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}")
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.wasm DESTINATION ${CMAKE_INSTALL_PREFIX})
+install(FILES occt-webgl-sample.html DESTINATION ${CMAKE_INSTALL_PREFIX})
+install(FILES ${OpenCASCADE_RESOURCE_DIR}/DrawResources/OCC_logo.png DESTINATION ${CMAKE_INSTALL_PREFIX})
+install(FILES ${OpenCASCADE_RESOURCE_DIR}/DrawResources/lamp.ico DESTINATION ${CMAKE_INSTALL_PREFIX})
diff --git a/samples/webgl/ReadMe.md b/samples/webgl/ReadMe.md
new file mode 100644 (file)
index 0000000..7e748eb
--- /dev/null
@@ -0,0 +1,28 @@
+OCCT WebGL Viewer sample {#occt_samples_webgl}
+================== 
+
+This sample demonstrates simple way of using OCCT libraries in Web application written in C++ and translated into WebAssembly module using Emscripten SDK (emsdk):
+https://emscripten.org/
+
+Sample consists of the Open CASCADE 3D Viewer with a button for opening a model in BREP format.
+The sample requires a WebGL 2.0 capable browser supporting WebAssembly 1.0 (Wasm).
+
+Installation and configuration:
+ 1. Install Emscripten SDK and activate minimal configuration (Python, Java and CLang) following *emsdk* documentation. Activate also MinGW when building sample on Windows host.
+ 2. Build (using *emsdk*) or download FreeType static library.
+ 3. Configure CMake for building Open CASCADE Technology (OCCT) static libraries (BUILD_LIBRARY_TYPE="Static").
+    For this, activate *emsdk* command prompt, configure CMake for building OCCT using cross-compilation toolchain, disable *BUILD_MODULE_Draw*. 
+ 4. Perform building and installation steps.
+~~~~~
+    > ${EMSDK}/fastcomp/emscripten/cmake/Modules/Platform/Emscripten.cmake
+~~~~~
+ 5. Configure CMake for building this WebGL sample using *emsdk* with paths to OCCT and FreeType. Perform building and installation steps.
+ 6. Copy data/occ/Ball.brep from OCCT into "samples" folder within WebGL sample installation path.
+ 7. Navigate to installation folder and start web server from it; Python coming with *emsdk* can be used for this purpose:
+~~~~~
+    > python -m SimpleHTTPServer 8080
+~~~~~
+ 8. Open compatible browser and enter path taking into account your web server settings:
+~~~~~
+    > http://localhost:8080/occt-webgl-sample.html
+~~~~~
diff --git a/samples/webgl/WasmOcctView.cpp b/samples/webgl/WasmOcctView.cpp
new file mode 100644 (file)
index 0000000..68a8b86
--- /dev/null
@@ -0,0 +1,678 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of the examples of the Open CASCADE Technology software library.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
+
+#include "WasmOcctView.h"
+
+#include "WasmVKeys.h"
+
+#include <AIS_Shape.hxx>
+#include <AIS_ViewCube.hxx>
+#include <Aspect_Handle.hxx>
+#include <Aspect_DisplayConnection.hxx>
+#include <Aspect_NeutralWindow.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <OpenGl_GraphicDriver.hxx>
+#include <Prs3d_DatumAspect.hxx>
+
+#include <iostream>
+
+#define THE_CANVAS_ID "canvas"
+
+namespace
+{
+  EM_JS(int, jsCanvasGetWidth, (), {
+    return canvas.width;
+  });
+
+  EM_JS(int, jsCanvasGetHeight, (), {
+    return canvas.height;
+  });
+
+  EM_JS(float, jsDevicePixelRatio, (), {
+    var aDevicePixelRatio = window.devicePixelRatio || 1;
+    return aDevicePixelRatio;
+  });
+
+  //! Return cavas size in pixels.
+  static Graphic3d_Vec2i jsCanvasSize()
+  {
+    return Graphic3d_Vec2i (jsCanvasGetWidth(), jsCanvasGetHeight());
+  }
+}
+
+// ================================================================
+// Function : WasmOcctView
+// Purpose  :
+// ================================================================
+WasmOcctView::WasmOcctView()
+: myDevicePixelRatio (1.0f),
+  myUpdateRequests (0)
+{
+}
+
+// ================================================================
+// Function : ~WasmOcctView
+// Purpose  :
+// ================================================================
+WasmOcctView::~WasmOcctView()
+{
+}
+
+// ================================================================
+// Function : run
+// Purpose  :
+// ================================================================
+void WasmOcctView::run()
+{
+  initWindow();
+  initViewer();
+  initDemoScene();
+  if (myView.IsNull())
+  {
+    return;
+  }
+
+  myView->MustBeResized();
+  myView->Redraw();
+
+  // There is no inifinite message loop, main() will return from here immediately.
+  // Tell that our Module should be left loaded and handle events through callbacks.
+  //emscripten_set_main_loop (redrawView, 60, 1);
+  //emscripten_set_main_loop (redrawView, -1, 1);
+  EM_ASM(Module['noExitRuntime'] = true);
+}
+
+// ================================================================
+// Function : initWindow
+// Purpose  :
+// ================================================================
+void WasmOcctView::initWindow()
+{
+  myDevicePixelRatio = jsDevicePixelRatio();
+  myCanvasId = THE_CANVAS_ID;
+  const char* aTargetId = !myCanvasId.IsEmpty() ? myCanvasId.ToCString() : NULL;
+  const EM_BOOL toUseCapture = EM_TRUE;
+  emscripten_set_resize_callback     (NULL,      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_dblclick_callback   (aTargetId, this, toUseCapture, onMouseCallback);
+  emscripten_set_click_callback      (aTargetId, this, toUseCapture, onMouseCallback);
+  emscripten_set_mouseenter_callback (aTargetId, this, toUseCapture, onMouseCallback);
+  emscripten_set_mouseleave_callback (aTargetId, this, toUseCapture, onMouseCallback);
+  emscripten_set_wheel_callback      (aTargetId, this, toUseCapture, onWheelCallback);
+
+  emscripten_set_touchstart_callback (aTargetId, this, toUseCapture, onTouchCallback);
+  emscripten_set_touchend_callback   (aTargetId, this, toUseCapture, onTouchCallback);
+  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);
+}
+
+// ================================================================
+// Function : dumpGlInfo
+// Purpose  :
+// ================================================================
+void WasmOcctView::dumpGlInfo (bool theIsBasic)
+{
+  TColStd_IndexedDataMapOfStringString aGlCapsDict;
+  myView->DiagnosticInformation (aGlCapsDict, theIsBasic ? Graphic3d_DiagnosticInfo_Basic : Graphic3d_DiagnosticInfo_Complete);
+  if (theIsBasic)
+  {
+    TCollection_AsciiString aViewport;
+    aGlCapsDict.FindFromKey ("Viewport", aViewport);
+    aGlCapsDict.Clear();
+    aGlCapsDict.Add ("Viewport", aViewport);
+  }
+  aGlCapsDict.Add ("Display scale", TCollection_AsciiString(myDevicePixelRatio));
+
+  // beautify output
+  {
+    TCollection_AsciiString* aGlVer   = aGlCapsDict.ChangeSeek ("GLversion");
+    TCollection_AsciiString* aGlslVer = aGlCapsDict.ChangeSeek ("GLSLversion");
+    if (aGlVer   != NULL
+     && aGlslVer != NULL)
+    {
+      *aGlVer = *aGlVer + " [GLSL: " + *aGlslVer + "]";
+      aGlslVer->Clear();
+    }
+  }
+
+  TCollection_AsciiString anInfo;
+  for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aGlCapsDict); aValueIter.More(); aValueIter.Next())
+  {
+    if (!aValueIter.Value().IsEmpty())
+    {
+      if (!anInfo.IsEmpty())
+      {
+        anInfo += "\n";
+      }
+      anInfo += aValueIter.Key() + ": " + aValueIter.Value();
+    }
+  }
+
+  ::Message::DefaultMessenger()->Send (anInfo, Message_Warning);
+}
+
+// ================================================================
+// Function : initPixelScaleRatio
+// Purpose  :
+// ================================================================
+void WasmOcctView::initPixelScaleRatio()
+{
+  SetTouchToleranceScale (myDevicePixelRatio);
+  if (!myView.IsNull())
+  {
+    myView->ChangeRenderingParams().Resolution = (unsigned int )(96.0 * myDevicePixelRatio + 0.5);
+  }
+  if (!myContext.IsNull())
+  {
+    myContext->SetPixelTolerance (int(myDevicePixelRatio * 6.0));
+    if (!myViewCube.IsNull())
+    {
+      static const double THE_CUBE_SIZE = 60.0;
+      myViewCube->SetSize (myDevicePixelRatio * THE_CUBE_SIZE, false);
+      myViewCube->SetBoxFacetExtension (myViewCube->Size() * 0.15);
+      myViewCube->SetAxesPadding (myViewCube->Size() * 0.10);
+      myViewCube->SetFontHeight  (THE_CUBE_SIZE * 0.16);
+      if (myViewCube->HasInteractiveContext())
+      {
+        myContext->Redisplay (myViewCube, false);
+      }
+    }
+  }
+}
+
+// ================================================================
+// Function : initViewer
+// Purpose  :
+// ================================================================
+bool WasmOcctView::initViewer()
+{
+  // Build with "--preload-file MyFontFile.ttf" option
+  // and register font in Font Manager to use custom font(s).
+  /*const char* aFontPath = "MyFontFile.ttf";
+  if (Handle(Font_SystemFont) aFont = Font_FontMgr::GetInstance()->CheckFont (aFontPath))
+  {
+    Font_FontMgr::GetInstance()->RegisterFont (aFont, true);
+  }
+  else
+  {
+    Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: font '") + aFontPath + "' is not found", Message_Fail);
+  }*/
+
+  Handle(Aspect_DisplayConnection) aDisp;
+  Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver (aDisp, false);
+  aDriver->ChangeOptions().buffersNoSwap = true; // swap has no effect in WebGL
+  if (!aDriver->InitContext())
+  {
+    Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: EGL initialization failed"), Message_Fail);
+    return false;
+  }
+
+  Handle(V3d_Viewer) aViewer = new V3d_Viewer (aDriver);
+  aViewer->SetComputedMode (false);
+  aViewer->SetDefaultShadingModel (Graphic3d_TOSM_FRAGMENT);
+  aViewer->SetDefaultLights();
+  aViewer->SetLightOn();
+
+  Handle(Aspect_NeutralWindow) aWindow = new Aspect_NeutralWindow();
+  Graphic3d_Vec2i aWinSize = jsCanvasSize();
+  if (aWinSize.x() < 10 || aWinSize.y() < 10)
+  {
+    Message::DefaultMessenger()->Send (TCollection_AsciiString ("Warning: invalid canvas size"), Message_Warning);
+  }
+  aWindow->SetSize (aWinSize.x(), aWinSize.y());
+
+  myTextStyle = new Prs3d_TextAspect();
+  myTextStyle->SetFont (Font_NOF_ASCII_MONO);
+  myTextStyle->SetHeight (12);
+  myTextStyle->Aspect()->SetColor (Quantity_NOC_GRAY95);
+  myTextStyle->Aspect()->SetColorSubTitle (Quantity_NOC_BLACK);
+  myTextStyle->Aspect()->SetDisplayType (Aspect_TODT_SHADOW);
+  myTextStyle->Aspect()->SetTextFontAspect (Font_FA_Bold);
+  myTextStyle->Aspect()->SetTextZoomable (false);
+  myTextStyle->SetHorizontalJustification (Graphic3d_HTA_LEFT);
+  myTextStyle->SetVerticalJustification (Graphic3d_VTA_BOTTOM);
+
+  myView = new V3d_View (aViewer);
+  myView->SetImmediateUpdate (false);
+  myView->ChangeRenderingParams().Resolution = (unsigned int )(96.0 * myDevicePixelRatio + 0.5);
+  myView->ChangeRenderingParams().ToShowStats = true;
+  myView->ChangeRenderingParams().StatsTextAspect = myTextStyle->Aspect();
+  myView->ChangeRenderingParams().StatsTextHeight = (int )myTextStyle->Height();
+  myView->SetWindow (aWindow);
+  dumpGlInfo (false);
+
+  myContext = new AIS_InteractiveContext (aViewer);
+  initPixelScaleRatio();
+  return true;
+}
+
+// ================================================================
+// Function : initDemoScene
+// Purpose  :
+// ================================================================
+void WasmOcctView::initDemoScene()
+{
+  if (myContext.IsNull())
+  {
+    return;
+  }
+
+  //myView->TriedronDisplay (Aspect_TOTP_LEFT_LOWER, Quantity_NOC_GOLD, 0.08, V3d_WIREFRAME);
+
+  myViewCube = new AIS_ViewCube();
+  // presentation parameters
+  initPixelScaleRatio();
+  myViewCube->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_RIGHT_LOWER, Graphic3d_Vec2i (100, 100)));
+  myViewCube->Attributes()->SetDatumAspect (new Prs3d_DatumAspect());
+  myViewCube->Attributes()->DatumAspect()->SetTextAspect (myTextStyle);
+  // animation parameters
+  myViewCube->SetViewAnimation (myViewAnimation);
+  myViewCube->SetFixedAnimationLoop (false);
+  myViewCube->SetAutoStartAnimation (true);
+  myContext->Display (myViewCube, false);
+
+  // Build with "--preload-file MySampleFile.brep" option to load some shapes here.
+}
+
+
+// ================================================================
+// Function : updateView
+// Purpose  :
+// ================================================================
+void WasmOcctView::updateView()
+{
+  if (!myView.IsNull())
+  {
+    if (++myUpdateRequests == 1)
+    {
+      emscripten_async_call (onRedrawView, this, 0);
+    }
+  }
+}
+
+// ================================================================
+// Function : redrawView
+// Purpose  :
+// ================================================================
+void WasmOcctView::redrawView()
+{
+  if (!myView.IsNull())
+  {
+    FlushViewEvents (myContext, myView, true);
+  }
+}
+
+// ================================================================
+// Function : handleViewRedraw
+// Purpose  :
+// ================================================================
+void WasmOcctView::handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
+                                     const Handle(V3d_View)& theView)
+{
+  myUpdateRequests = 0;
+  AIS_ViewController::handleViewRedraw (theCtx, theView);
+  if (myToAskNextFrame)
+  {
+    // ask more frames
+    ++myUpdateRequests;
+    emscripten_async_call (onRedrawView, this, 0);
+  }
+}
+
+// ================================================================
+// Function : onResizeEvent
+// Purpose  :
+// ================================================================
+EM_BOOL WasmOcctView::onResizeEvent (int theEventType, const EmscriptenUiEvent* theEvent)
+{
+  (void )theEventType; // EMSCRIPTEN_EVENT_RESIZE or EMSCRIPTEN_EVENT_CANVASRESIZED
+  (void )theEvent;
+  if (myView.IsNull())
+  {
+    return EM_FALSE;
+  }
+
+  Handle(Aspect_NeutralWindow) aWindow = Handle(Aspect_NeutralWindow)::DownCast (myView->Window());
+  Graphic3d_Vec2i aWinSizeOld, aWinSizeNew (jsCanvasSize());
+  if (aWinSizeNew.x() < 10 || aWinSizeNew.y() < 10)
+  {
+    Message::DefaultMessenger()->Send (TCollection_AsciiString ("Warning: invalid canvas size"), Message_Warning);
+  }
+  aWindow->Size (aWinSizeOld.x(), aWinSizeOld.y());
+  const float aPixelRatio = jsDevicePixelRatio();
+  if (aWinSizeNew != aWinSizeOld
+   || aPixelRatio != myDevicePixelRatio)
+  {
+    if (myDevicePixelRatio != aPixelRatio)
+    {
+      myDevicePixelRatio = aPixelRatio;
+      initPixelScaleRatio();
+    }
+    aWindow->SetSize (aWinSizeNew.x(), aWinSizeNew.y());
+    myView->MustBeResized();
+    myView->Invalidate();
+    myView->Redraw();
+    dumpGlInfo (true);
+  }
+  return EM_TRUE;
+}
+
+// ================================================================
+// Function : onMouseEvent
+// Purpose  :
+// ================================================================
+EM_BOOL WasmOcctView::onMouseEvent (int theEventType, const EmscriptenMouseEvent* theEvent)
+{
+  if (myView.IsNull())
+  {
+    return EM_FALSE;
+  }
+
+  Graphic3d_Vec2i aWinSize;
+  myView->Window()->Size (aWinSize.x(), aWinSize.y());
+  const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (theEvent->canvasX, theEvent->canvasY));
+  Aspect_VKeyFlags aFlags = 0;
+  if (theEvent->ctrlKey  == EM_TRUE) { aFlags |= Aspect_VKeyFlags_CTRL;  }
+  if (theEvent->shiftKey == EM_TRUE) { aFlags |= Aspect_VKeyFlags_SHIFT; }
+  if (theEvent->altKey   == EM_TRUE) { aFlags |= Aspect_VKeyFlags_ALT;   }
+  if (theEvent->metaKey  == EM_TRUE) { aFlags |= Aspect_VKeyFlags_META;  }
+
+  const bool isEmulated = false;
+  const Aspect_VKeyMouse aButtons = WasmVKeys_MouseButtonsFromNative (theEvent->buttons);
+  switch (theEventType)
+  {
+    case EMSCRIPTEN_EVENT_MOUSEMOVE:
+    {
+      if ((aNewPos.x() < 0 || aNewPos.x() > aWinSize.x()
+        || aNewPos.y() < 0 || aNewPos.y() > aWinSize.y())
+        && PressedMouseButtons() == Aspect_VKeyMouse_NONE)
+      {
+        return EM_FALSE;
+      }
+      if (UpdateMousePosition (aNewPos, aButtons, aFlags, isEmulated))
+      {
+        updateView();
+      }
+      break;
+    }
+    case EMSCRIPTEN_EVENT_MOUSEDOWN:
+    case EMSCRIPTEN_EVENT_MOUSEUP:
+    {
+      if (aNewPos.x() < 0 || aNewPos.x() > aWinSize.x()
+       || aNewPos.y() < 0 || aNewPos.y() > aWinSize.y())
+      {
+        return EM_FALSE;
+      }
+      if (UpdateMouseButtons (aNewPos, aButtons, aFlags, isEmulated))
+      {
+        updateView();
+      }
+      break;
+    }
+    case EMSCRIPTEN_EVENT_CLICK:
+    case EMSCRIPTEN_EVENT_DBLCLICK:
+    {
+      if (aNewPos.x() < 0 || aNewPos.x() > aWinSize.x()
+       || aNewPos.y() < 0 || aNewPos.y() > aWinSize.y())
+      {
+        return EM_FALSE;
+      }
+      break;
+    }
+    case EMSCRIPTEN_EVENT_MOUSEENTER:
+    {
+      break;
+    }
+    case EMSCRIPTEN_EVENT_MOUSELEAVE:
+    {
+      // there is no SetCapture() support, so that mouse unclick events outside canvas will not arrive,
+      // so we have to forget current state...
+      if (UpdateMouseButtons (aNewPos, Aspect_VKeyMouse_NONE, aFlags, isEmulated))
+      {
+        updateView();
+      }
+      break;
+    }
+  }
+  return EM_TRUE;
+}
+
+// ================================================================
+// Function : onWheelEvent
+// Purpose  :
+// ================================================================
+EM_BOOL WasmOcctView::onWheelEvent (int theEventType, const EmscriptenWheelEvent* theEvent)
+{
+  if (myView.IsNull()
+   || theEventType != EMSCRIPTEN_EVENT_WHEEL)
+  {
+    return EM_FALSE;
+  }
+
+  Graphic3d_Vec2i aWinSize;
+  myView->Window()->Size (aWinSize.x(), aWinSize.y());
+  const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (theEvent->mouse.canvasX, theEvent->mouse.canvasY));
+  if (aNewPos.x() < 0 || aNewPos.x() > aWinSize.x()
+   || aNewPos.y() < 0 || aNewPos.y() > aWinSize.y())
+  {
+    return EM_FALSE;
+  }
+
+  double aDelta = 0.0;
+  switch (theEvent->deltaMode)
+  {
+    case DOM_DELTA_PIXEL:
+    {
+      aDelta = theEvent->deltaY / (5.0 * myDevicePixelRatio);
+      break;
+    }
+    case DOM_DELTA_LINE:
+    {
+      aDelta = theEvent->deltaY * 8.0;
+      break;
+    }
+    case DOM_DELTA_PAGE:
+    {
+      aDelta = theEvent->deltaY >= 0.0 ? 24.0 : -24.0;
+      break;
+    }
+  }
+
+  if (UpdateZoom (Aspect_ScrollDelta (aNewPos, -aDelta)))
+  {
+    updateView();
+  }
+  return EM_TRUE;
+}
+
+// ================================================================
+// Function : onTouchEvent
+// Purpose  :
+// ================================================================
+EM_BOOL WasmOcctView::onTouchEvent (int theEventType, const EmscriptenTouchEvent* theEvent)
+{
+  const double aClickTolerance = 5.0;
+  if (myView.IsNull())
+  {
+    return EM_FALSE;
+  }
+
+  Graphic3d_Vec2i aWinSize;
+  myView->Window()->Size (aWinSize.x(), aWinSize.y());
+  bool hasUpdates = false;
+  for (int aTouchIter = 0; aTouchIter < theEvent->numTouches; ++aTouchIter)
+  {
+    const EmscriptenTouchPoint& aTouch = theEvent->touches[aTouchIter];
+    if (!aTouch.isChanged)
+    {
+      continue;
+    }
+
+    const Standard_Size aTouchId = (Standard_Size )aTouch.identifier;
+    const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (aTouch.canvasX, aTouch.canvasY));
+    switch (theEventType)
+    {
+      case EMSCRIPTEN_EVENT_TOUCHSTART:
+      {
+        if (aNewPos.x() >= 0 && aNewPos.x() < aWinSize.x()
+         && aNewPos.y() >= 0 && aNewPos.y() < aWinSize.y())
+        {
+          hasUpdates = true;
+          AddTouchPoint (aTouchId, Graphic3d_Vec2d (aNewPos));
+          myClickTouch.From.SetValues (-1.0, -1.0);
+          if (myTouchPoints.Extent() == 1)
+          {
+            myClickTouch.From = Graphic3d_Vec2d (aNewPos);
+          }
+        }
+        break;
+      }
+      case EMSCRIPTEN_EVENT_TOUCHMOVE:
+      {
+        const int anOldIndex = myTouchPoints.FindIndex (aTouchId);
+        if (anOldIndex != 0)
+        {
+          hasUpdates = true;
+          UpdateTouchPoint (aTouchId, Graphic3d_Vec2d (aNewPos));
+          if (myTouchPoints.Extent() == 1
+           && (myClickTouch.From - Graphic3d_Vec2d (aNewPos)).cwiseAbs().maxComp() > aClickTolerance)
+          {
+            myClickTouch.From.SetValues (-1.0, -1.0);
+          }
+        }
+        break;
+      }
+      case EMSCRIPTEN_EVENT_TOUCHEND:
+      case EMSCRIPTEN_EVENT_TOUCHCANCEL:
+      {
+        if (RemoveTouchPoint (aTouchId))
+        {
+          if (myTouchPoints.IsEmpty()
+           && myClickTouch.From.minComp() >= 0.0)
+          {
+            if (myDoubleTapTimer.IsStarted()
+             && myDoubleTapTimer.ElapsedTime() <= myMouseDoubleClickInt)
+            {
+              myView->FitAll (0.01, false);
+              myView->Invalidate();
+            }
+            else
+            {
+              myDoubleTapTimer.Stop();
+              myDoubleTapTimer.Reset();
+              myDoubleTapTimer.Start();
+              SelectInViewer (Graphic3d_Vec2i (myClickTouch.From), false);
+            }
+          }
+          hasUpdates = true;
+        }
+        break;
+      }
+    }
+  }
+  if (hasUpdates)
+  {
+    updateView();
+  }
+  return hasUpdates || !myTouchPoints.IsEmpty() ? EM_TRUE : EM_FALSE;
+}
+
+// ================================================================
+// Function : onKeyDownEvent
+// Purpose  :
+// ================================================================
+EM_BOOL WasmOcctView::onKeyDownEvent (int theEventType, const EmscriptenKeyboardEvent* theEvent)
+{
+  if (myView.IsNull()
+   || theEventType != EMSCRIPTEN_EVENT_KEYDOWN) // EMSCRIPTEN_EVENT_KEYPRESS
+  {
+    return EM_FALSE;
+  }
+
+  const double aTimeStamp = EventTime();
+  const Aspect_VKey aVKey = WasmVKeys_VirtualKeyFromNative (theEvent->keyCode);
+  if (aVKey == Aspect_VKey_UNKNOWN)
+  {
+    return EM_FALSE;
+  }
+
+  if (theEvent->repeat == EM_FALSE)
+  {
+    myKeys.KeyDown (aVKey, aTimeStamp);
+  }
+
+  if (Aspect_VKey2Modifier (aVKey) == 0)
+  {
+    // normal key
+  }
+  return EM_FALSE;
+}
+
+// ================================================================
+// Function : onKeyUpEvent
+// Purpose  :
+// ================================================================
+EM_BOOL WasmOcctView::onKeyUpEvent (int theEventType, const EmscriptenKeyboardEvent* theEvent)
+{
+  if (myView.IsNull()
+   || theEventType != EMSCRIPTEN_EVENT_KEYUP)
+  {
+    return EM_FALSE;
+  }
+
+  const double aTimeStamp = EventTime();
+  const Aspect_VKey aVKey = WasmVKeys_VirtualKeyFromNative (theEvent->keyCode);
+  if (aVKey == Aspect_VKey_UNKNOWN)
+  {
+    return EM_FALSE;
+  }
+
+  if (theEvent->repeat == EM_TRUE)
+  {
+    return EM_FALSE;
+  }
+
+  const unsigned int aModif = myKeys.Modifiers();
+  myKeys.KeyUp (aVKey, aTimeStamp);
+  if (Aspect_VKey2Modifier (aVKey) == 0)
+  {
+    // normal key released
+    switch (aVKey | aModif)
+    {
+      case Aspect_VKey_F:
+      {
+        myView->FitAll (0.01, false);
+        myView->Invalidate();
+        updateView();
+        return EM_TRUE;
+      }
+    }
+  }
+  return EM_FALSE;
+}
diff --git a/samples/webgl/WasmOcctView.h b/samples/webgl/WasmOcctView.h
new file mode 100644 (file)
index 0000000..0715e7c
--- /dev/null
@@ -0,0 +1,157 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of the examples of the Open CASCADE Technology software library.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
+
+#ifndef _WasmOcctView_HeaderFile
+#define _WasmOcctView_HeaderFile
+
+#include <AIS_InteractiveContext.hxx>
+#include <AIS_ViewController.hxx>
+#include <V3d_View.hxx>
+
+#include <emscripten.h>
+#include <emscripten/html5.h>
+
+class AIS_ViewCube;
+
+//! Sample class creating 3D Viewer within Emscripten canvas.
+class WasmOcctView : protected AIS_ViewController
+{
+public:
+  //! Default constructor.
+  WasmOcctView();
+
+  //! Destructor.
+  virtual ~WasmOcctView();
+
+  //! Main application entry point.
+  void run();
+
+  //! Return interactive context.
+  const Handle(AIS_InteractiveContext)& Context() const { return myContext; }
+
+  //! Return view.
+  const Handle(V3d_View)& View() const { return myView; }
+
+  //! Return device pixel ratio for handling high DPI displays.
+  float DevicePixelRatio() const { return myDevicePixelRatio; }
+
+private:
+
+  //! Create window.
+  void initWindow();
+
+  //! Create 3D Viewer.
+  bool initViewer();
+
+  //! Fill 3D Viewer with a DEMO items.
+  void initDemoScene();
+
+  //! Application event loop.
+  void mainloop();
+
+  //! Request view redrawing.
+  void updateView();
+
+  //! Flush events and redraw view.
+  void redrawView();
+
+  //! Handle view redraw.
+  virtual void handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
+                                 const Handle(V3d_View)& theView) override;
+
+  //! Dump WebGL context information.
+  void dumpGlInfo (bool theIsBasic);
+
+  //! Initialize pixel scale ratio.
+  void initPixelScaleRatio();
+
+  //! Return point from logical units to backing store.
+  Graphic3d_Vec2d convertPointToBacking (const Graphic3d_Vec2d& thePnt) const
+  {
+    return thePnt * myDevicePixelRatio;
+  }
+
+  //! Return point from logical units to backing store.
+  Graphic3d_Vec2i convertPointToBacking (const Graphic3d_Vec2i& thePnt) const
+  {
+    Graphic3d_Vec2d aPnt = Graphic3d_Vec2d (thePnt) * myDevicePixelRatio + Graphic3d_Vec2d (0.5);
+    return Graphic3d_Vec2i (aPnt);
+  }
+
+//! @name Emscripten callbacks
+private:
+  //! Window resize event.
+  EM_BOOL onResizeEvent (int theEventType, const EmscriptenUiEvent* theEvent);
+
+  //! Mouse event.
+  EM_BOOL onMouseEvent (int theEventType, const EmscriptenMouseEvent* theEvent);
+
+  //! Scroll event.
+  EM_BOOL onWheelEvent (int theEventType, const EmscriptenWheelEvent* theEvent);
+
+  //! Touch event.
+  EM_BOOL onTouchEvent (int theEventType, const EmscriptenTouchEvent* theEvent);
+
+  //! Key down event.
+  EM_BOOL onKeyDownEvent (int theEventType, const EmscriptenKeyboardEvent* theEvent);
+
+  //! Key up event.
+  EM_BOOL onKeyUpEvent (int theEventType, const EmscriptenKeyboardEvent* theEvent);
+
+//! @name Emscripten callbacks (static functions)
+private:
+
+  static EM_BOOL onResizeCallback (int theEventType, const EmscriptenUiEvent* theEvent, void* theView)
+  { return ((WasmOcctView* )theView)->onResizeEvent (theEventType, theEvent); }
+
+  static void onRedrawView (void* theView)
+  { return ((WasmOcctView* )theView)->redrawView(); }
+
+  static EM_BOOL onMouseCallback (int theEventType, const EmscriptenMouseEvent* theEvent, void* theView)
+  { return ((WasmOcctView* )theView)->onMouseEvent (theEventType, theEvent); }
+
+  static EM_BOOL onWheelCallback (int theEventType, const EmscriptenWheelEvent* theEvent, void* theView)
+  { return ((WasmOcctView* )theView)->onWheelEvent (theEventType, theEvent); }
+
+  static EM_BOOL onTouchCallback (int theEventType, const EmscriptenTouchEvent* theEvent, void* theView)
+  { return ((WasmOcctView* )theView)->onTouchEvent (theEventType, theEvent); }
+
+  static EM_BOOL onKeyDownCallback (int theEventType, const EmscriptenKeyboardEvent* theEvent, void* theView)
+  { return ((WasmOcctView* )theView)->onKeyDownEvent (theEventType, theEvent); }
+
+  static EM_BOOL onKeyUpCallback (int theEventType, const EmscriptenKeyboardEvent* theEvent, void* theView)
+  { return ((WasmOcctView* )theView)->onKeyUpEvent (theEventType, theEvent); }
+
+private:
+
+  Handle(AIS_InteractiveContext) myContext;          //!< interactive context
+  Handle(V3d_View)               myView;             //!< 3D view
+  Handle(Prs3d_TextAspect)       myTextStyle;        //!< text style for OSD elements
+  Handle(AIS_ViewCube)           myViewCube;         //!< view cube object
+  TCollection_AsciiString        myCanvasId;         //!< canvas element id on HTML page
+  Aspect_Touch                   myClickTouch;       //!< single touch position for handling clicks
+  OSD_Timer                      myDoubleTapTimer;   //!< timer for handling double tap
+  float                          myDevicePixelRatio; //!< device pixel ratio for handling high DPI displays
+  unsigned int                   myUpdateRequests;   //!< counter for unhandled update requests
+
+};
+
+#endif // _WasmOcctView_HeaderFile
diff --git a/samples/webgl/WasmVKeys.h b/samples/webgl/WasmVKeys.h
new file mode 100644 (file)
index 0000000..3c8bb32
--- /dev/null
@@ -0,0 +1,264 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of the examples of the Open CASCADE Technology software library.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
+
+#ifndef _WasmVKeys_HeaderFile
+#define _WasmVKeys_HeaderFile
+
+#include <Aspect_VKey.hxx>
+
+#include <emscripten/key_codes.h>
+
+//! Convert Emscripten mouse buttons into Aspect_VKeyMouse.
+inline Aspect_VKeyMouse WasmVKeys_MouseButtonsFromNative (unsigned short theButtons)
+{
+  Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
+  if ((theButtons & 0x1) != 0)
+  {
+    aButtons |= Aspect_VKeyMouse_LeftButton;
+  }
+  if ((theButtons & 0x2) != 0)
+  {
+    aButtons |= Aspect_VKeyMouse_RightButton;
+  }
+  if ((theButtons & 0x4) != 0)
+  {
+    aButtons |= Aspect_VKeyMouse_MiddleButton;
+  }
+  return aButtons;
+}
+
+//! Convert DOM virtual key into Aspect_VKey.
+inline Aspect_VKey WasmVKeys_VirtualKeyFromNative (Standard_Integer theKey)
+{
+  if (theKey >= DOM_VK_0
+   && theKey <= DOM_VK_9)
+  {
+    // numpad keys
+    return Aspect_VKey((theKey - DOM_VK_0) + Aspect_VKey_0);
+  }
+  if (theKey >= DOM_VK_A
+   && theKey <= DOM_VK_Z)
+  {
+    // main latin alphabet keys
+    return Aspect_VKey((theKey - DOM_VK_A) + Aspect_VKey_A);
+  }
+  if (theKey >= DOM_VK_F1
+   && theKey <= DOM_VK_F24)
+  {
+    // special keys
+    if (theKey <= DOM_VK_F12)
+    {
+      return Aspect_VKey((theKey - DOM_VK_F1) + Aspect_VKey_F1);
+    }
+    return Aspect_VKey_UNKNOWN;
+  }
+  if (theKey >= DOM_VK_NUMPAD0
+   && theKey <= DOM_VK_NUMPAD9)
+  {
+    // numpad keys
+    return Aspect_VKey((theKey - DOM_VK_NUMPAD0) + Aspect_VKey_Numpad0);
+  }
+
+  switch (theKey)
+  {
+    case DOM_VK_CANCEL:
+    case DOM_VK_HELP:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_BACK_SPACE:
+      return Aspect_VKey_Backspace;
+    case DOM_VK_TAB:
+      return Aspect_VKey_Tab;
+    case DOM_VK_CLEAR:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_RETURN:
+    case DOM_VK_ENTER:
+      return Aspect_VKey_Enter;
+    case DOM_VK_SHIFT:
+      return Aspect_VKey_Shift;
+    case DOM_VK_CONTROL:
+      return Aspect_VKey_Control;
+    case DOM_VK_ALT:
+      return Aspect_VKey_Alt;
+    case DOM_VK_PAUSE:
+    case DOM_VK_CAPS_LOCK:
+    case DOM_VK_KANA:
+    //case DOM_VK_HANGUL:
+    case DOM_VK_EISU:
+    case DOM_VK_JUNJA:
+    case DOM_VK_FINAL:
+    case DOM_VK_HANJA:
+    //case DOM_VK_KANJI:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_ESCAPE:
+      return Aspect_VKey_Escape;
+    case DOM_VK_CONVERT:
+    case DOM_VK_NONCONVERT:
+    case DOM_VK_ACCEPT:
+    case DOM_VK_MODECHANGE:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_SPACE:
+      return Aspect_VKey_Space;
+    case DOM_VK_PAGE_UP:
+      return Aspect_VKey_PageUp;
+    case DOM_VK_PAGE_DOWN:
+      return Aspect_VKey_PageDown;
+    case DOM_VK_END:
+      return Aspect_VKey_End;
+    case DOM_VK_HOME:
+      return Aspect_VKey_Home;
+    case DOM_VK_LEFT:
+      return Aspect_VKey_Left;
+    case DOM_VK_UP:
+      return Aspect_VKey_Up;
+    case DOM_VK_RIGHT:
+      return Aspect_VKey_Right;
+    case DOM_VK_DOWN:
+      return Aspect_VKey_Down;
+    case DOM_VK_SELECT:
+    case DOM_VK_PRINT:
+    case DOM_VK_EXECUTE:
+    case DOM_VK_PRINTSCREEN:
+    case DOM_VK_INSERT:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_DELETE:
+      return Aspect_VKey_Delete;
+    case DOM_VK_COLON:
+      return Aspect_VKey_Comma;
+    case DOM_VK_SEMICOLON:
+      return Aspect_VKey_Semicolon;
+    case DOM_VK_LESS_THAN:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_EQUALS:
+      return Aspect_VKey_Equal;
+    case DOM_VK_GREATER_THAN:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_QUESTION_MARK:
+      return Aspect_VKey_Slash;
+    case DOM_VK_AT: // @ key
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_WIN:
+      return Aspect_VKey_Meta;
+    case DOM_VK_CONTEXT_MENU:
+    case DOM_VK_SLEEP:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_MULTIPLY:
+      return Aspect_VKey_NumpadMultiply;
+    case DOM_VK_ADD:
+      return Aspect_VKey_NumpadAdd;
+    case DOM_VK_SEPARATOR:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_SUBTRACT:
+      return Aspect_VKey_NumpadSubtract;
+    case DOM_VK_DECIMAL:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_DIVIDE:
+      return Aspect_VKey_NumpadDivide;
+    case DOM_VK_NUM_LOCK:
+      return Aspect_VKey_Numlock;
+    case DOM_VK_SCROLL_LOCK:
+      return Aspect_VKey_Scroll;
+    case DOM_VK_WIN_OEM_FJ_JISHO:
+    case DOM_VK_WIN_OEM_FJ_MASSHOU:
+    case DOM_VK_WIN_OEM_FJ_TOUROKU:
+    case DOM_VK_WIN_OEM_FJ_LOYA:
+    case DOM_VK_WIN_OEM_FJ_ROYA:
+    case DOM_VK_CIRCUMFLEX:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_EXCLAMATION:
+    case DOM_VK_DOUBLE_QUOTE:
+    //case DOM_VK_HASH:
+    case DOM_VK_DOLLAR:
+    case DOM_VK_PERCENT:
+    case DOM_VK_AMPERSAND:
+    case DOM_VK_UNDERSCORE:
+    case DOM_VK_OPEN_PAREN:
+    case DOM_VK_CLOSE_PAREN:
+    case DOM_VK_ASTERISK:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_PLUS:
+      return Aspect_VKey_Plus;
+    case DOM_VK_PIPE:
+    case DOM_VK_HYPHEN_MINUS:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_OPEN_CURLY_BRACKET:
+      return Aspect_VKey_BracketLeft;
+    case DOM_VK_CLOSE_CURLY_BRACKET:
+      return Aspect_VKey_BracketRight;
+    case DOM_VK_TILDE:
+      return Aspect_VKey_Tilde;
+    case DOM_VK_VOLUME_MUTE:
+      return Aspect_VKey_VolumeMute;
+    case DOM_VK_VOLUME_DOWN:
+      return Aspect_VKey_VolumeDown;
+    case DOM_VK_VOLUME_UP:
+      return Aspect_VKey_VolumeUp;
+    case DOM_VK_COMMA:
+      return Aspect_VKey_Comma;
+    case DOM_VK_PERIOD:
+      return Aspect_VKey_Period;
+    case DOM_VK_SLASH:
+      return Aspect_VKey_Slash;
+    case DOM_VK_BACK_QUOTE:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_OPEN_BRACKET:
+      return Aspect_VKey_BracketLeft;
+    case DOM_VK_BACK_SLASH:
+      return Aspect_VKey_Backslash;
+    case DOM_VK_CLOSE_BRACKET:
+      return Aspect_VKey_BracketRight;
+    case DOM_VK_QUOTE:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_META:
+      return Aspect_VKey_Meta;
+    case DOM_VK_ALTGR:
+      return Aspect_VKey_Alt;
+    case DOM_VK_WIN_ICO_HELP:
+    case DOM_VK_WIN_ICO_00:
+    case DOM_VK_WIN_ICO_CLEAR:
+    case DOM_VK_WIN_OEM_RESET:
+    case DOM_VK_WIN_OEM_JUMP:
+    case DOM_VK_WIN_OEM_PA1:
+    case DOM_VK_WIN_OEM_PA2:
+    case DOM_VK_WIN_OEM_PA3:
+    case DOM_VK_WIN_OEM_WSCTRL:
+    case DOM_VK_WIN_OEM_CUSEL:
+    case DOM_VK_WIN_OEM_ATTN:
+    case DOM_VK_WIN_OEM_FINISH:
+    case DOM_VK_WIN_OEM_COPY:
+    case DOM_VK_WIN_OEM_AUTO:
+    case DOM_VK_WIN_OEM_ENLW:
+    case DOM_VK_WIN_OEM_BACKTAB:
+    case DOM_VK_ATTN:
+    case DOM_VK_CRSEL:
+    case DOM_VK_EXSEL:
+    case DOM_VK_EREOF:
+      return Aspect_VKey_UNKNOWN;
+    case DOM_VK_PLAY:
+      return Aspect_VKey_MediaPlayPause;
+    case DOM_VK_ZOOM:
+    case DOM_VK_PA1:
+    case DOM_VK_WIN_OEM_CLEAR:
+      return Aspect_VKey_UNKNOWN;
+  }
+  return Aspect_VKey_UNKNOWN;
+}
+
+#endif // _WasmVKeys_HeaderFile
diff --git a/samples/webgl/main.cpp b/samples/webgl/main.cpp
new file mode 100644 (file)
index 0000000..44206bb
--- /dev/null
@@ -0,0 +1,66 @@
+#include <iostream>
+
+#include "WasmOcctView.h"
+
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <OSD_MemInfo.hxx>
+#include <OSD_Parallel.hxx>
+
+#include <AIS_Shape.hxx>
+#include <BRepTools.hxx>
+#include <BRep_Builder.hxx>
+#include <Standard_ArrayStreamBuffer.hxx>
+
+#include <emscripten.h>
+#include <emscripten/html5.h>
+
+//! Global viewer instance.
+static WasmOcctView aViewer;
+
+//! File data read event.
+extern "C" void onFileDataRead (void* theOpaque, void* theBuffer, int theDataLen)
+{
+  const char* aName = theOpaque != NULL ? (const char* )theOpaque : "";
+  {
+    AIS_ListOfInteractive aShapes;
+    aViewer.Context()->DisplayedObjects (AIS_KOI_Shape, -1, aShapes);
+    for (AIS_ListOfInteractive::Iterator aShapeIter (aShapes); aShapeIter.More(); aShapeIter.Next())
+    {
+      aViewer.Context()->Remove (aShapeIter.Value(), false);
+    }
+  }
+
+  Standard_ArrayStreamBuffer aStreamBuffer ((const char* )theBuffer, theDataLen);
+  std::istream aStream (&aStreamBuffer);
+  TopoDS_Shape aShape;
+  BRep_Builder aBuilder;
+  BRepTools::Read (aShape, aStream, aBuilder);
+
+  Handle(AIS_Shape) aShapePrs = new AIS_Shape (aShape);
+  aShapePrs->SetMaterial (Graphic3d_NOM_SILVER);
+  aViewer.Context()->Display (aShapePrs, AIS_Shaded, 0, false);
+  aViewer.View()->FitAll (0.01, false);
+  aViewer.View()->Redraw();
+  Message::DefaultMessenger()->Send (TCollection_AsciiString("Loaded file ") + aName, Message_Info);
+  Message::DefaultMessenger()->Send (OSD_MemInfo::PrintInfo(), Message_Trace);
+}
+
+//! File read error event.
+static void onFileReadFailed (void* theOpaque)
+{
+  const char* aName = (const char* )theOpaque;
+  Message::DefaultMessenger()->Send (TCollection_AsciiString("Error: unable to load file ") + aName, Message_Fail);
+}
+
+int main()
+{
+  Message::DefaultMessenger()->Printers().First()->SetTraceLevel (Message_Trace);
+  Message::DefaultMessenger()->Send (TCollection_AsciiString("NbLogicalProcessors: ") + OSD_Parallel::NbLogicalProcessors(), Message_Trace);
+  aViewer.run();
+  Message::DefaultMessenger()->Send (OSD_MemInfo::PrintInfo(), Message_Trace);
+
+  // load some file
+  emscripten_async_wget_data ("samples/Ball.brep", (void* )"samples/Ball.brep", onFileDataRead, onFileReadFailed);
+  return 0;
+}
diff --git a/samples/webgl/occt-webgl-sample.html b/samples/webgl/occt-webgl-sample.html
new file mode 100644 (file)
index 0000000..80f7e6f
--- /dev/null
@@ -0,0 +1,133 @@
+<!DOCTYPE html>\r
+<html lang=en-us>\r
+<head>\r
+<meta charset=utf-8><meta content="text/html; charset=utf-8" http-equiv=Content-Type>\r
+<link rel="shortcut icon" href="lamp.ico" type="image/x-icon" />\r
+<title>OCCT WebGL Viewer Sample</title>\r
+</head>\r
+<body>\r
+\r
+<h2>OCCT WebGL Viewer Sample</h2>\r
+<div>\r
+  <canvas id=canvas oncontextmenu=event.preventDefault() tabindex=-1 style="border:0 none;background-color:#000" width="409" height="409"></canvas>\r
+  <img id=occlogo src="OCC_logo.png" style="position: absolute; left: 20px; top: 0px; z-index: 2;" />\r
+</div>\r
+\r
+<div><label for="fileInput">Choose BREP file to upload: </label><input type="file" id="fileInput" accept=".brep"></div>\r
+<h4>Console output:</h4>\r
+<p id="output"></p>\r
+<script>\r
+//! Resize canvas to fit into window.\r
+function updateCanvasSize()\r
+{\r
+  // size of canvas in logical (density-independent) units\r
+  var aSizeX = Math.min (window.innerWidth,  window.screen.availWidth);\r
+  var aSizeY = Math.min (window.innerHeight, window.screen.availHeight);\r
+  aSizeX = Math.max (300, aSizeX - 30);\r
+  aSizeY = Math.max (300, aSizeY / 2);\r
+  canvas.style.width  = aSizeX + "px";\r
+  canvas.style.height = aSizeY + "px";\r
+\r
+  // drawing buffer size (aka backing store)\r
+  var aDevicePixelRatio = window.devicePixelRatio || 1;\r
+  canvas.width  = aSizeX * aDevicePixelRatio;\r
+  canvas.height = aSizeY * aDevicePixelRatio;\r
+\r
+  occlogo.style.top = (aSizeY - 30) + "px";\r
+}\r
+window.onresize = updateCanvasSize;\r
+updateCanvasSize();\r
+\r
+//! Check browser support.\r
+function isWasmSupported()\r
+{\r
+  try {\r
+    if (typeof WebAssembly === "object"\r
+     && typeof WebAssembly.instantiate === "function") {\r
+      const aDummyModule = new WebAssembly.Module (Uint8Array.of (0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));\r
+      if (aDummyModule instanceof WebAssembly.Module)\r
+      {\r
+        return new WebAssembly.Instance(aDummyModule) instanceof WebAssembly.Instance;\r
+      }\r
+    }\r
+  } catch (e) {}\r
+  return false;\r
+}\r
+if (!isWasmSupported())\r
+{\r
+  var anElement = document.getElementById('output');\r
+  anElement.innerHTML += "Browser is too old - WebAssembly support is missing!<br>Please check updates or install a modern browser.<br>";\r
+}\r
+\r
+//! Define OCCT WebGL Viewer module.\r
+var Module =\r
+{\r
+  print: (function() {\r
+    var anElement = document.getElementById('output');\r
+    return function(theText) { anElement.innerHTML += theText + "<br>"; };\r
+  })(),\r
+  printErr: function(theText) {\r
+    //var anElement = document.getElementById('output');\r
+    //anElement.innerHTML += theText + "<br>";\r
+  },\r
+  canvas: (function() {\r
+    var aCanvas = document.getElementById('canvas');\r
+    return aCanvas;\r
+  })()\r
+};\r
+\r
+//! Handle file uploading.\r
+fileInput.onchange = function()\r
+{\r
+  if (fileInput.files.length == 0) { return; }\r
+  // Warning! Entire file is pre-loaded into memory.\r
+  var aFile = fileInput.files[0];\r
+  var aReader = new FileReader();\r
+  aReader.onload = function()\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
+    Module._free(aNameBuffer);\r
+    fileInput.value = '';\r
+  };\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
+</html>\r
index 1d5a53b..d6643b3 100755 (executable)
@@ -25,7 +25,7 @@ IMPLEMENT_STANDARD_RTTIEXT(Aspect_DisplayConnection,Standard_Transient)
 // =======================================================================
 Aspect_DisplayConnection::Aspect_DisplayConnection()
 {
-#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
+#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
   myDisplay = NULL;
   myIsOwnDisplay = false;
   OSD_Environment anEnv ("DISPLAY");
@@ -40,7 +40,7 @@ Aspect_DisplayConnection::Aspect_DisplayConnection()
 // =======================================================================
 Aspect_DisplayConnection::~Aspect_DisplayConnection()
 {
-#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
+#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
   if (myDisplay != NULL
    && myIsOwnDisplay)
   {
@@ -49,7 +49,7 @@ Aspect_DisplayConnection::~Aspect_DisplayConnection()
 #endif
 }
 
-#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
+#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
 // =======================================================================
 // function : Aspect_DisplayConnection
 // purpose  :
index 1377495..e31f0f2 100755 (executable)
@@ -20,7 +20,7 @@
 #include <TCollection_AsciiString.hxx>
 #include <NCollection_DataMap.hxx>
 
-#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
+#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
   #include <InterfaceGraphic.hxx>
 #endif
 
@@ -39,7 +39,7 @@ public:
   //! Destructor. Close opened connection.
   Standard_EXPORT ~Aspect_DisplayConnection();
 
-#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
+#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
   //! Constructor. Creates connection with display specified in theDisplayName.
   //! Display name should be in format "hostname:number" or "hostname:number.screen_number", where:
   //! hostname      - Specifies the name of the host machine on which the display is physically attached.
index ffdb65b..bbed1e4 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef _Aspect_FBConfig_HeaderFile
 #define _Aspect_FBConfig_HeaderFile
 
-#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
+#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
   typedef struct __GLXFBConfigRec* GLXFBConfig;
   typedef GLXFBConfig Aspect_FBConfig; // GLXFBConfig* under UNIX
 #else
index 46fed65..7d24840 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef __Aspect_WNTXWD_HXX
 # define __Aspect_WNTXWD_HXX
 
-#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
+#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
 #  include <X11/XWDFile.h>
 # else
 
index 530237a..0032a43 100644 (file)
@@ -81,7 +81,7 @@ IMPLEMENT_STANDARD_RTTIEXT(Font_FontMgr,Standard_Transient)
       NULL
     };
 
-  #if !defined(__ANDROID__) && !defined(__APPLE__)
+  #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
     // X11 configuration file in plain text format (obsolete - doesn't exists in modern distributives)
     static Standard_CString myFontServiceConf[] = {"/etc/X11/fs/config",
                                                    "/usr/X11R6/lib/X11/fs/config",
@@ -483,7 +483,7 @@ void Font_FontMgr::InitFontDataBase()
 #else
 
   NCollection_Map<TCollection_AsciiString> aMapOfFontsDirs;
-#if !defined(__ANDROID__) && !defined(__APPLE__)
+#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
   if (FcConfig* aFcCfg = FcInitLoadConfig())
   {
     if (FcStrList* aFcFontDir = FcConfigGetFontDirs (aFcCfg))
@@ -586,7 +586,7 @@ void Font_FontMgr::InitFontDataBase()
   for (NCollection_Map<TCollection_AsciiString>::Iterator anIter (aMapOfFontsDirs);
        anIter.More(); anIter.Next())
   {
-  #if !defined(__ANDROID__) && !defined(__APPLE__)
+  #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
     OSD_File aReadFile (anIter.Value() + "/fonts.dir");
     if (!aReadFile.Exists())
     {
@@ -607,7 +607,7 @@ void Font_FontMgr::InitFontDataBase()
         }
       }
 
-  #if !defined(__ANDROID__) && !defined(__APPLE__)
+  #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
       continue;
     }
 
index 43ab88a..c533f68 100644 (file)
@@ -23,7 +23,7 @@
   #undef DrawText
 #endif
 
-#elif !defined(__ANDROID__) && !defined(__QNX__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
+#elif !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
 
 #include <stdio.h>
 
index b2de7b0..24b1cad 100644 (file)
@@ -51,7 +51,7 @@
 void OSD_Chronometer::GetProcessCPU (Standard_Real& theUserSeconds,
                                      Standard_Real& theSystemSeconds)
 {
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__ANDROID__) || defined(__QNX__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__)
   static const long aCLK_TCK = sysconf(_SC_CLK_TCK);
 #else
   static const long aCLK_TCK = CLK_TCK;
index 277804e..8a1f6f8 100644 (file)
@@ -116,7 +116,15 @@ void OSD_MemInfo::Update()
       myCounters[MemHeapUsage] += hinfo._size;
   }
 
-#elif (defined(__linux__) || defined(__linux))
+#elif (defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__))
+  const struct mallinfo aMI = mallinfo();
+  myCounters[MemHeapUsage] = aMI.uordblks;
+#if defined(__EMSCRIPTEN__)
+  // /proc/%d/status is not emulated - get more info from mallinfo()
+  myCounters[MemWorkingSet]     = aMI.uordblks;
+  myCounters[MemWorkingSetPeak] = aMI.usmblks;
+#endif
+
   // use procfs on Linux
   char aBuff[4096];
   snprintf (aBuff, sizeof(aBuff), "/proc/%d/status", getpid());
@@ -162,10 +170,6 @@ void OSD_MemInfo::Update()
     }
   }
   aFile.close();
-
-  struct mallinfo aMI = mallinfo();
-  myCounters[MemHeapUsage] = aMI.uordblks;
-
 #elif (defined(__APPLE__))
   struct task_basic_info aTaskInfo;
   mach_msg_type_number_t aTaskInfoCount = TASK_BASIC_INFO_COUNT;
index cca6172..6e5c583 100644 (file)
@@ -39,6 +39,8 @@ static OSD_SysType whereAmI()
   return OSD_VMS;
 #elif defined(__linux__) || defined(__linux)
   return OSD_LinuxREDHAT;
+#elif defined(__EMSCRIPTEN__)
+  return OSD_LinuxREDHAT;
 #elif defined(_AIX) || defined(AIX)
   return OSD_Aix;
 #else
index 654523a..af86c67 100644 (file)
@@ -703,7 +703,7 @@ typedef void (* SIG_PFV) (int);
 
 #include <signal.h>
 
-#if !defined(__ANDROID__) && !defined(__QNX__)
+#if !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
   #include <sys/signal.h>
 #endif
 
index 89a5ca6..40ec4b5 100644 (file)
@@ -63,6 +63,29 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Context,Standard_Transient)
   #include <GL/glx.h> // glXGetProcAddress()
 #endif
 
+#ifdef __EMSCRIPTEN__
+  #include <emscripten/html5.h>
+
+  //! Check if WebGL extension is available and activate it
+  //! (usage of extension without activation will generate errors).
+  static bool checkEnableWebGlExtension (const OpenGl_Context& theCtx,
+                                         const char* theExtName)
+  {
+    if (!theCtx.CheckExtension (theExtName))
+    {
+      return false;
+    }
+    if (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE aWebGlCtx = emscripten_webgl_get_current_context())
+    {
+      if (emscripten_webgl_enable_extension (aWebGlCtx, theExtName))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+#endif
+
 namespace
 {
   static const Handle(OpenGl_Resource) NULL_GL_RESOURCE;
@@ -1399,6 +1422,13 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   extAnis = CheckExtension ("GL_EXT_texture_filter_anisotropic");
   extPDS  = IsGlGreaterEqual (3, 0)
          || CheckExtension ("GL_OES_packed_depth_stencil");
+#ifdef __EMSCRIPTEN__
+  if (!extPDS
+    && checkEnableWebGlExtension (*this, "GL_WEBGL_depth_texture"))
+  {
+    extPDS = true; // WebGL 1.0 extension (in WebGL 2.0 core)
+  }
+#endif
 
   core11fwd = (OpenGl_GlCore11Fwd* )(&(*myFuncs));
   if (IsGlGreaterEqual (2, 0))
@@ -3129,6 +3159,20 @@ void OpenGl_Context::DiagnosticInformation (TColStd_IndexedDataMapOfStringString
     ReadGlVersion (aDriverVer[0], aDriverVer[1]);
     addInfo (theDict, "GLvendor",    (const char*)::glGetString (GL_VENDOR));
     addInfo (theDict, "GLdevice",    (const char*)::glGetString (GL_RENDERER));
+  #ifdef __EMSCRIPTEN__
+    if (checkEnableWebGlExtension (*this, "GL_WEBGL_debug_renderer_info"))
+    {
+      if (const char* aVendor = (const char*)::glGetString (0x9245))
+      {
+        addInfo (theDict, "GLunmaskedVendor", aVendor);
+      }
+      if (const char* aDevice = (const char*)::glGetString (0x9246))
+      {
+        addInfo (theDict, "GLunmaskedDevice", aDevice);
+      }
+    }
+  #endif
+
     addInfo (theDict, "GLversion",   (const char*)::glGetString (GL_VERSION));
     if (myGlVerMajor != aDriverVer[0]
      || myGlVerMinor != aDriverVer[1])
index e9471d8..747c872 100644 (file)
@@ -572,7 +572,7 @@ public:
   //! basing on ToRenderSRGB() flag.
   OpenGl_Vec4 Vec4FromQuantityColor (const OpenGl_Vec4& theColor) const
   {
-    return ToRenderSRGB()
+    return myIsSRgbActive
          ? Vec4LinearFromQuantityColor(theColor)
          : Vec4sRGBFromQuantityColor  (theColor);
   }
index f65a9ab..e9344f9 100644 (file)
@@ -38,6 +38,26 @@ namespace
     }
     return true;
   }
+
+  //! Return TRUE if GL_DEPTH_STENCIL_ATTACHMENT can be used.
+  static bool hasDepthStencilAttach (const Handle(OpenGl_Context)& theCtx)
+  {
+  #ifdef __EMSCRIPTEN__
+    // supported since WebGL 2.0,
+    // while WebGL 1.0 + GL_WEBGL_depth_texture needs GL_DEPTH_STENCIL_ATTACHMENT
+    // and NOT separate GL_DEPTH_ATTACHMENT+GL_STENCIL_ATTACHMENT calls which is different to OpenGL ES 2.0 + extension
+    return theCtx->IsGlGreaterEqual (3, 0) || theCtx->extPDS;
+  #elif defined(GL_ES_VERSION_2_0)
+    // supported since OpenGL ES 3.0,
+    // while OpenGL ES 2.0 + GL_EXT_packed_depth_stencil needs separate GL_DEPTH_ATTACHMENT+GL_STENCIL_ATTACHMENT calls
+    return theCtx->IsGlGreaterEqual (3, 0);
+  #else
+    // available on desktop since OpenGL 3.0
+    // or OpenGL 2.0 + GL_ARB_framebuffer_object (GL_EXT_framebuffer_object is unsupported by OCCT)
+    (void )theCtx;
+    return true;
+  #endif
+  }
 }
 
 // =======================================================================
@@ -188,15 +208,18 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
   }
   if (myDepthStencilTexture->IsValid())
   {
-  #ifdef GL_DEPTH_STENCIL_ATTACHMENT
-    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
-                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
-  #else
-    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
-    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
-                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
-  #endif
+    if (hasDepthStencilAttach (theGlContext))
+    {
+      theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+                                                    myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+    }
+    else
+    {
+      theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                                    myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+      theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                                    myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+    }
   }
   if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
   {
@@ -332,32 +355,39 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
                                                     aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
     }
   }
+
   if (myDepthStencilTexture->IsValid())
   {
-  #ifdef GL_DEPTH_STENCIL_ATTACHMENT
-    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
-                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
-  #else
-    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
-    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
-                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
-  #endif
+    if (hasDepthStencilAttach (theGlContext))
+    {
+      theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+                                                    myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+    }
+    else
+    {
+      theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                                    myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+      theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                                    myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+    }
   }
   else if (myGlDepthRBufferId != NO_RENDERBUFFER)
   {
-  #ifdef GL_DEPTH_STENCIL_ATTACHMENT
-    theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
-                                                     GL_RENDERBUFFER, myGlDepthRBufferId);
-  #else
-    theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                                     GL_RENDERBUFFER, myGlDepthRBufferId);
-    if (hasStencilRB)
+    if (hasDepthStencilAttach (theGlContext) && hasStencilRB)
     {
-      theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+      theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
                                                        GL_RENDERBUFFER, myGlDepthRBufferId);
     }
-  #endif
+    else
+    {
+      theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                                       GL_RENDERBUFFER, myGlDepthRBufferId);
+      if (hasStencilRB)
+      {
+        theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                                         GL_RENDERBUFFER, myGlDepthRBufferId);
+      }
+    }
   }
   if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
   {
@@ -486,18 +516,21 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t
                                                GL_RENDERBUFFER, myGlColorRBufferId);
   if (myGlDepthRBufferId != NO_RENDERBUFFER)
   {
-  #ifdef GL_DEPTH_STENCIL_ATTACHMENT
-    theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
-                                                 GL_RENDERBUFFER, myGlDepthRBufferId);
-  #else
-    theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                                 GL_RENDERBUFFER, myGlDepthRBufferId);
-    if (hasStencilRB)
+    if (hasDepthStencilAttach (theGlCtx) && hasStencilRB)
     {
-      theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+      theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
                                                    GL_RENDERBUFFER, myGlDepthRBufferId);
     }
-  #endif
+    else
+    {
+      theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                                   GL_RENDERBUFFER, myGlDepthRBufferId);
+      if (hasStencilRB)
+      {
+        theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                                     GL_RENDERBUFFER, myGlDepthRBufferId);
+      }
+    }
   }
   if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
   {
index 20e6eaa..ec2f93d 100644 (file)
@@ -54,7 +54,7 @@
     #include <OpenGL/gl.h>
   #endif
   #define __X_GL_H // prevent chaotic gl.h inclusions to avoid compile errors
-#elif defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__)
+#elif defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__)
   #if defined(_WIN32)
     // Angle OpenGL ES headers do not define function prototypes even for core functions,
     // however OCCT is expected to be linked against libGLESv2
   #define GL_DEPTH_STENCIL                  0x84F9
   #define GL_UNSIGNED_INT_24_8              0x84FA
   #define GL_DEPTH24_STENCIL8               0x88F0
+  #define GL_DEPTH_STENCIL_ATTACHMENT       0x821A
 
   // OpenGL ES 3.0+
   #define GL_DEPTH_COMPONENT24              0x81A6
   #define GL_PATCHES                    0x000E
 #endif
 
-#if !defined(HAVE_EGL) && (defined(__ANDROID__) || defined(__QNX__) || defined(HAVE_GLES2) || defined(OCCT_UWP))
+#if !defined(HAVE_EGL) && (defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(HAVE_GLES2) || defined(OCCT_UWP))
   #define HAVE_EGL
 #endif
 
index 1dddb00..1694e17 100644 (file)
@@ -44,11 +44,11 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_GraphicDriver,Graphic3d_GraphicDriver)
   #include <Xw_Window.hxx>
 #endif
 
-#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNX__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
+#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
   #include <X11/Xlib.h> // XOpenDisplay()
 #endif
 
-#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__)
+#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__)
   #include <EGL/egl.h>
   #ifndef EGL_OPENGL_ES3_BIT
     #define EGL_OPENGL_ES3_BIT 0x00000040
@@ -59,7 +59,7 @@ namespace
 {
   static const Handle(OpenGl_Context) TheNullGlCtx;
 
-#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__)
+#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__)
   //! Wrapper over eglChooseConfig() called with preferred defaults.
   static EGLConfig chooseEglSurfConfig (EGLDisplay theDisplay)
   {
@@ -120,7 +120,7 @@ OpenGl_GraphicDriver::OpenGl_GraphicDriver (const Handle(Aspect_DisplayConnectio
                                             const Standard_Boolean                  theToInitialize)
 : Graphic3d_GraphicDriver (theDisp),
   myIsOwnContext (Standard_False),
-#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__)
+#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__)
   myEglDisplay ((Aspect_Display )EGL_NO_DISPLAY),
   myEglContext ((Aspect_RenderingContext )EGL_NO_CONTEXT),
   myEglConfig  (NULL),
@@ -129,7 +129,7 @@ OpenGl_GraphicDriver::OpenGl_GraphicDriver (const Handle(Aspect_DisplayConnectio
   myMapOfView      (1, NCollection_BaseAllocator::CommonBaseAllocator()),
   myMapOfStructure (1, NCollection_BaseAllocator::CommonBaseAllocator())
 {
-#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNX__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
+#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
   if (myDisplayConnection.IsNull())
   {
     //throw Aspect_GraphicDeviceDefinitionError("OpenGl_GraphicDriver: cannot connect to X server!");
@@ -228,7 +228,7 @@ void OpenGl_GraphicDriver::ReleaseContext()
     aWindow->GetGlContext()->forcedRelease();
   }
 
-#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__)
+#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__)
   if (myIsOwnContext)
   {
     if (myEglContext != (Aspect_RenderingContext )EGL_NO_CONTEXT)
@@ -263,9 +263,9 @@ void OpenGl_GraphicDriver::ReleaseContext()
 Standard_Boolean OpenGl_GraphicDriver::InitContext()
 {
   ReleaseContext();
-#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__)
+#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__)
 
-#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNX__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
+#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
   if (myDisplayConnection.IsNull())
   {
     return Standard_False;
@@ -337,7 +337,7 @@ Standard_Boolean OpenGl_GraphicDriver::InitContext()
   return Standard_True;
 }
 
-#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__)
+#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__)
 // =======================================================================
 // function : InitEglContext
 // purpose  :
@@ -347,7 +347,7 @@ Standard_Boolean OpenGl_GraphicDriver::InitEglContext (Aspect_Display          t
                                                        void*                   theEglConfig)
 {
   ReleaseContext();
-#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNX__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
+#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
   if (myDisplayConnection.IsNull())
   {
     return Standard_False;
@@ -733,7 +733,7 @@ Standard_Boolean OpenGl_GraphicDriver::ViewExists (const Handle(Aspect_Window)&
   #else
     NSView* TheSpecifiedWindowId = THEWindow->HView();
   #endif
-#elif defined(__ANDROID__) || defined(__QNX__) || defined(OCCT_UWP)
+#elif defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(OCCT_UWP)
   (void )AWindow;
   int TheSpecifiedWindowId = -1;
 #else
@@ -759,7 +759,7 @@ Standard_Boolean OpenGl_GraphicDriver::ViewExists (const Handle(Aspect_Window)&
       #else
         NSView* TheWindowIdOfView = theWindow->HView();
       #endif
-#elif defined(__ANDROID__) || defined(__QNX__) || defined(OCCT_UWP)
+#elif defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(OCCT_UWP)
       int TheWindowIdOfView = 0;
 #else
       const Handle(Xw_Window) theWindow = Handle(Xw_Window)::DownCast (AspectWindow);
index 4c63bb0..09e8438 100644 (file)
@@ -68,7 +68,7 @@ public:
   //! Perform initialization of default OpenGL context.
   Standard_EXPORT Standard_Boolean InitContext();
 
-#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__)
+#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__)
   //! Initialize default OpenGL context using existing one.
   //! @param theEglDisplay EGL connection to the Display
   //! @param theEglContext EGL rendering context
@@ -168,7 +168,7 @@ public:
   //!                 any context will be returned otherwise
   Standard_EXPORT const Handle(OpenGl_Context)& GetSharedContext (bool theBound = false) const;
 
-#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__)
+#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__)
   Aspect_Display          getRawGlDisplay() const { return myEglDisplay; }
   Aspect_RenderingContext getRawGlContext() const { return myEglContext;  }
   void*                   getRawGlConfig()  const { return myEglConfig; }
@@ -188,7 +188,7 @@ public:
 protected:
 
   Standard_Boolean        myIsOwnContext; //!< indicates that shared context has been created within OpenGl_GraphicDriver
-#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__)
+#if defined(HAVE_EGL) || defined(HAVE_GLES2) || defined(OCCT_UWP) || defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__)
   Aspect_Display          myEglDisplay;   //!< EGL connection to the Display : EGLDisplay
   Aspect_RenderingContext myEglContext;   //!< EGL rendering context         : EGLContext
   void*                   myEglConfig;    //!< EGL configuration             : EGLConfig
index b7f3c40..c7328ce 100644 (file)
@@ -1630,6 +1630,15 @@ int OpenGl_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgr
   }
   (void )toUseDerivates;
 #else
+
+#if defined(__EMSCRIPTEN__)
+  if (myContext->IsGlGreaterEqual (3, 0))
+  {
+    // consider this is browser responsibility to provide working WebGL 2.0 implementation
+    // and black-list broken drivers (there is no OpenGL ES greater than 3.0)
+    theProgram->SetHeader ("#version 300 es");
+  }
+#endif
   // prefer "100 es" on OpenGL ES 3.0- devices (save the features unavailable before "300 es")
   // and    "300 es" on OpenGL ES 3.1+ devices
   if (myContext->IsGlGreaterEqual (3, 1))
index 918688f..b01f7f5 100644 (file)
@@ -224,6 +224,7 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
       //throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to retrieve current surface!");
       if (anEglConfig != NULL)
       {
+      #if !defined(__EMSCRIPTEN__) // eglCreatePbufferSurface() is not implemented by Emscripten EGL
         const int aSurfAttribs[] =
         {
           EGL_WIDTH,  myWidth,
@@ -237,6 +238,7 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
         {
           throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to create off-screen surface!");
         }
+      #endif
       }
       myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
                                 "OpenGl_Window::CreateWindow: WARNING, a Window is created without a EGL Surface!");
index 4a7c664..4ce134c 100644 (file)
@@ -15,7 +15,7 @@
 
 #include <Quantity_ColorRGBA.hxx>
 
-#include <Graphic3d_Vec4.hxx>
+#include <NCollection_Vec4.hxx>
 #include <Standard_Dump.hxx>
 
 #include <algorithm>
@@ -69,7 +69,7 @@ namespace
     Standard_ASSERT_RETURN (theColorComponentBase >= 2,
                             __FUNCTION__ ": 'theColorComponentBase' must be greater than 1.",
                             0.0f);
-    Graphic3d_Vec4 aColor (1.0f);
+    NCollection_Vec4<float> aColor (1.0f);
     if (hasAlphaComponent)
     {
       const Standard_ShortReal anAlphaComponent = takeColorComponentFromInteger (theColorInteger,
index 05eafa8..d0c4f1e 100644 (file)
@@ -102,7 +102,7 @@ uniform mat4 occWorldViewMatrixInverseTranspose;  //!< Transpose of the inverse
 uniform mat4 occProjectionMatrixInverseTranspose; //!< Transpose of the inverse of the projection  matrix
 uniform mat4 occModelWorldMatrixInverseTranspose; //!< Transpose of the inverse of the model-world matrix
 
-// light type enumeration
+// light type enumeration (same as Graphic3d_TypeOfLightSource)
 const int OccLightType_Direct = 1; //!< directional     light source
 const int OccLightType_Point  = 2; //!< isotropic point light source
 const int OccLightType_Spot   = 3; //!< spot            light source
@@ -111,16 +111,36 @@ const int OccLightType_Spot   = 3; //!< spot            light source
 uniform               vec4 occLightAmbient;      //!< Cumulative ambient color
 #if defined(THE_MAX_LIGHTS) && (THE_MAX_LIGHTS > 0)
 uniform THE_PREC_ENUM int  occLightSourcesCount; //!< Total number of light sources
-int   occLight_Type              (in int theId); //!< Type of light source
-int   occLight_IsHeadlight       (in int theId); //!< Is light a headlight?
-vec4  occLight_Diffuse           (in int theId); //!< Diffuse intensity for specified light source
-vec4  occLight_Specular          (in int theId); //!< Specular intensity (currently - equals to diffuse intencity)
-vec4  occLight_Position          (in int theId); //!< Position of specified light source
-vec4  occLight_SpotDirection     (in int theId); //!< Direction of specified spot light source
-float occLight_ConstAttenuation  (in int theId); //!< Const attenuation factor of positional light source
-float occLight_LinearAttenuation (in int theId); //!< Linear attenuation factor of positional light source
-float occLight_SpotCutOff        (in int theId); //!< Maximum spread angle of the spot light (in radians)
-float occLight_SpotExponent      (in int theId); //!< Attenuation of the spot light intensity (from 0 to 1)
+
+//! Type of light source, int (see OccLightType enum).
+#define occLight_Type(theId)              occLightSourcesTypes[theId].x
+
+//! Is light a headlight, int?
+#define occLight_IsHeadlight(theId)       occLightSourcesTypes[theId].y
+
+//! Specular intensity (equals to diffuse), vec4.
+#define occLight_Specular(theId)          occLightSources[theId * 4 + 0]
+
+//! Position of specified light source, vec4.
+#define occLight_Position(theId)          occLightSources[theId * 4 + 1]
+
+//! Direction of specified spot light source, vec4.
+#define occLight_SpotDirection(theId)     occLightSources[theId * 4 + 2]
+
+//! Maximum spread angle of the spot light (in radians), float.
+#define occLight_SpotCutOff(theId)        occLightSources[theId * 4 + 3].z
+
+//! Attenuation of the spot light intensity (from 0 to 1), float.
+#define occLight_SpotExponent(theId)      occLightSources[theId * 4 + 3].w
+
+//! Diffuse intensity (equals to Specular), vec4.
+#define occLight_Diffuse(theId)           occLightSources[theId * 4 + 0]
+
+//! Const attenuation factor of positional light source, float.
+#define occLight_ConstAttenuation(theId)  occLightSources[theId * 4 + 3].x
+
+//! Linear attenuation factor of positional light source, float.
+#define occLight_LinearAttenuation(theId) occLightSources[theId * 4 + 3].y
 #endif
 
 // Front material properties accessors
index 5fd67ed..37ac72b 100644 (file)
@@ -21,18 +21,6 @@ void occSetFragColor (in vec4 theColor)
 // arrays of light sources
 uniform THE_PREC_ENUM ivec2 occLightSourcesTypes[THE_MAX_LIGHTS]; //!< packed light sources types
 uniform               vec4  occLightSources[THE_MAX_LIGHTS * 4];  //!< packed light sources parameters
-
-// light source properties accessors
-int   occLight_Type              (in int theId) { return occLightSourcesTypes[theId].x; }
-int   occLight_IsHeadlight       (in int theId) { return occLightSourcesTypes[theId].y; }
-vec4  occLight_Diffuse           (in int theId) { return occLightSources[theId * 4 + 0]; }
-vec4  occLight_Specular          (in int theId) { return occLightSources[theId * 4 + 0]; }
-vec4  occLight_Position          (in int theId) { return occLightSources[theId * 4 + 1]; }
-vec4  occLight_SpotDirection     (in int theId) { return occLightSources[theId * 4 + 2]; }
-float occLight_ConstAttenuation  (in int theId) { return occLightSources[theId * 4 + 3].x; }
-float occLight_LinearAttenuation (in int theId) { return occLightSources[theId * 4 + 3].y; }
-float occLight_SpotCutOff        (in int theId) { return occLightSources[theId * 4 + 3].z; }
-float occLight_SpotExponent      (in int theId) { return occLightSources[theId * 4 + 3].w; }
 #endif
 
 // material state
index 6b454b0..71a6b03 100644 (file)
@@ -24,18 +24,6 @@ static const char Shaders_DeclarationsImpl_glsl[] =
   "// arrays of light sources\n"
   "uniform THE_PREC_ENUM ivec2 occLightSourcesTypes[THE_MAX_LIGHTS]; //!< packed light sources types\n"
   "uniform               vec4  occLightSources[THE_MAX_LIGHTS * 4];  //!< packed light sources parameters\n"
-  "\n"
-  "// light source properties accessors\n"
-  "int   occLight_Type              (in int theId) { return occLightSourcesTypes[theId].x; }\n"
-  "int   occLight_IsHeadlight       (in int theId) { return occLightSourcesTypes[theId].y; }\n"
-  "vec4  occLight_Diffuse           (in int theId) { return occLightSources[theId * 4 + 0]; }\n"
-  "vec4  occLight_Specular          (in int theId) { return occLightSources[theId * 4 + 0]; }\n"
-  "vec4  occLight_Position          (in int theId) { return occLightSources[theId * 4 + 1]; }\n"
-  "vec4  occLight_SpotDirection     (in int theId) { return occLightSources[theId * 4 + 2]; }\n"
-  "float occLight_ConstAttenuation  (in int theId) { return occLightSources[theId * 4 + 3].x; }\n"
-  "float occLight_LinearAttenuation (in int theId) { return occLightSources[theId * 4 + 3].y; }\n"
-  "float occLight_SpotCutOff        (in int theId) { return occLightSources[theId * 4 + 3].z; }\n"
-  "float occLight_SpotExponent      (in int theId) { return occLightSources[theId * 4 + 3].w; }\n"
   "#endif\n"
   "\n"
   "// material state\n"
index 39929a5..12af3c4 100644 (file)
@@ -105,7 +105,7 @@ static const char Shaders_Declarations_glsl[] =
   "uniform mat4 occProjectionMatrixInverseTranspose; //!< Transpose of the inverse of the projection  matrix\n"
   "uniform mat4 occModelWorldMatrixInverseTranspose; //!< Transpose of the inverse of the model-world matrix\n"
   "\n"
-  "// light type enumeration\n"
+  "// light type enumeration (same as Graphic3d_TypeOfLightSource)\n"
   "const int OccLightType_Direct = 1; //!< directional     light source\n"
   "const int OccLightType_Point  = 2; //!< isotropic point light source\n"
   "const int OccLightType_Spot   = 3; //!< spot            light source\n"
@@ -114,16 +114,36 @@ static const char Shaders_Declarations_glsl[] =
   "uniform               vec4 occLightAmbient;      //!< Cumulative ambient color\n"
   "#if defined(THE_MAX_LIGHTS) && (THE_MAX_LIGHTS > 0)\n"
   "uniform THE_PREC_ENUM int  occLightSourcesCount; //!< Total number of light sources\n"
-  "int   occLight_Type              (in int theId); //!< Type of light source\n"
-  "int   occLight_IsHeadlight       (in int theId); //!< Is light a headlight?\n"
-  "vec4  occLight_Diffuse           (in int theId); //!< Diffuse intensity for specified light source\n"
-  "vec4  occLight_Specular          (in int theId); //!< Specular intensity (currently - equals to diffuse intencity)\n"
-  "vec4  occLight_Position          (in int theId); //!< Position of specified light source\n"
-  "vec4  occLight_SpotDirection     (in int theId); //!< Direction of specified spot light source\n"
-  "float occLight_ConstAttenuation  (in int theId); //!< Const attenuation factor of positional light source\n"
-  "float occLight_LinearAttenuation (in int theId); //!< Linear attenuation factor of positional light source\n"
-  "float occLight_SpotCutOff        (in int theId); //!< Maximum spread angle of the spot light (in radians)\n"
-  "float occLight_SpotExponent      (in int theId); //!< Attenuation of the spot light intensity (from 0 to 1)\n"
+  "\n"
+  "//! Type of light source, int (see OccLightType enum).\n"
+  "#define occLight_Type(theId)              occLightSourcesTypes[theId].x\n"
+  "\n"
+  "//! Is light a headlight, int?\n"
+  "#define occLight_IsHeadlight(theId)       occLightSourcesTypes[theId].y\n"
+  "\n"
+  "//! Specular intensity (equals to diffuse), vec4.\n"
+  "#define occLight_Specular(theId)          occLightSources[theId * 4 + 0]\n"
+  "\n"
+  "//! Position of specified light source, vec4.\n"
+  "#define occLight_Position(theId)          occLightSources[theId * 4 + 1]\n"
+  "\n"
+  "//! Direction of specified spot light source, vec4.\n"
+  "#define occLight_SpotDirection(theId)     occLightSources[theId * 4 + 2]\n"
+  "\n"
+  "//! Maximum spread angle of the spot light (in radians), float.\n"
+  "#define occLight_SpotCutOff(theId)        occLightSources[theId * 4 + 3].z\n"
+  "\n"
+  "//! Attenuation of the spot light intensity (from 0 to 1), float.\n"
+  "#define occLight_SpotExponent(theId)      occLightSources[theId * 4 + 3].w\n"
+  "\n"
+  "//! Diffuse intensity (equals to Specular), vec4.\n"
+  "#define occLight_Diffuse(theId)           occLightSources[theId * 4 + 0]\n"
+  "\n"
+  "//! Const attenuation factor of positional light source, float.\n"
+  "#define occLight_ConstAttenuation(theId)  occLightSources[theId * 4 + 3].x\n"
+  "\n"
+  "//! Linear attenuation factor of positional light source, float.\n"
+  "#define occLight_LinearAttenuation(theId) occLightSources[theId * 4 + 3].y\n"
   "#endif\n"
   "\n"
   "// Front material properties accessors\n"
index 678e211..f220fba 100644 (file)
@@ -44,7 +44,7 @@ inline int Standard_Atomic_Decrement (volatile int* theValue);
 inline bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue);
 
 // Platform-dependent implementation
-#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
+#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__EMSCRIPTEN__)
 // gcc explicitly defines the macros __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
 // starting with version 4.4+, although built-in functions
 // are available since 4.1.x. However unless __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
index 37d7ed6..62a9889 100644 (file)
@@ -15,7 +15,7 @@
 
 #include <Xw_Window.hxx>
 
-#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
+#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
 
 #include <Aspect_Convert.hxx>
 #include <Aspect_WindowDefinitionError.hxx>
index a9d806e..6b21974 100644 (file)
@@ -16,7 +16,7 @@
 #ifndef _Xw_Window_H__
 #define _Xw_Window_H__
 
-#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
+#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
 
 #include <Aspect_Window.hxx>