]> OCCT Git - occt.git/commitdiff
0032065: Samples - use MODULARIZE within WebGL sample
authorkgv <kgv@opencascade.com>
Mon, 18 Jan 2021 17:50:52 +0000 (20:50 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 22 Jan 2021 16:03:14 +0000 (19:03 +0300)
Fixed multitouch input.

Module is now exported with global functions hidden via MODULARIZE
as global object OccViewerModule created by createOccViewerModule().
Global Module setup has been moved to occt-webgl-viewer.js.

Use EMSCRIPTEN_KEEPALIVE attribute istead of listing C functions via EXTRA_EXPORTED_RUNTIME_METHODS.
WasmOcctView now exports static methods as Module functions using EMSCRIPTEN_BINDINGS.

Standard_ASSERT_DBGBREAK_() is now defined using emscripten_debugger().

14 files changed:
adm/scripts/ios_build.sh
adm/scripts/wasm_build.bat
adm/scripts/wasm_custom.bat.template
adm/scripts/wasm_sample_build.bat
samples/webgl/CMakeLists.txt
samples/webgl/WasmOcctPixMap.cpp [new file with mode: 0644]
samples/webgl/WasmOcctPixMap.h [new file with mode: 0644]
samples/webgl/WasmOcctView.cpp
samples/webgl/WasmOcctView.h
samples/webgl/main.cpp
samples/webgl/occt-webgl-sample.html
samples/webgl/occt-webgl-viewer.js [new file with mode: 0644]
src/DrawResources/OCC_logo.png
src/Standard/Standard_Assert.hxx

index 840da17d22a85bf433f5f81a210afdaa372395d5..7de7c13d7972a1d8cd0993eb096253afcffa23b3 100755 (executable)
@@ -110,7 +110,7 @@ if [[ $toCMake == 1 ]]; then
   -D ENABLE_VISIBILITY:BOOL="TRUE" \
   -D CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS:BOOL="OFF" \
   -D CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS:BOOL="OFF" \
-  -D CMAKE_BUILD_TYPE:STRING="Release" \
+  -D CMAKE_BUILD_TYPE:STRING="$aBuildType" \
   -D BUILD_LIBRARY_TYPE:STRING="$aLibType" \
   -D INSTALL_DIR:PATH="$aDestDir" \
   -D INSTALL_DIR_INCLUDE:STRING="inc" \
index c3ee490a66ea7d06e1542972909290a336036e46..6581b7eaef7307aedc6ddad3ec00488a0fb5cd55 100644 (file)
@@ -20,7 +20,9 @@ set "toClean=0"
 set "toMake=1"
 set "toInstall=1"
 set "toPack=0"
+set "toDebug=0"
 set "toBuildSample=0"
+set "sourceMapBase="
 
 rem OCCT Modules to build
 set "BUILD_ModelingData=ON"
@@ -50,6 +52,13 @@ for /f tokens^=2^ delims^=^" %%i in ('findstr /b /c:"#define OCC_VERSION_DEVELOP
 for /f tokens^=2^ delims^=^" %%i in ('findstr /b /c:"#define OCC_VERSION_COMPLETE" "%aCasSrc%\src\Standard\Standard_Version.hxx"') do ( set "anOcctVersion=%%i" )
 for /f %%i in ('git symbolic-ref --short HEAD') do ( set "aGitBranch=%%i" )
 
+set "aBuildType=Release"
+set "aBuildTypePrefix="
+if ["%toDebug%"] == ["1"] (
+  set "aBuildType=Debug"
+  set "aBuildTypePrefix=-debug"
+)
+
 call :cmakeGenerate
 if errorlevel 1 (
   if not ["%1"] == ["-nopause"] (
@@ -72,7 +81,7 @@ set DAY00=%DAY00:~-2%
 set MONTH00=%MONTH00:~-2%
 set "aRevision=-%YEAR%-%MONTH00%-%DAY00%"
 rem set "aRevision=-%aGitBranch%"
-set "anArchName=occt-%anOcctVersion%%anOcctVerSuffix%%aRevision%-wasm32"
+set "anArchName=occt-%anOcctVersion%%anOcctVerSuffix%%aRevision%-wasm32%aBuildTypePrefix%"
 set "aTarget=%aBuildRoot%\%anArchName%"
 if ["%toPack%"] == ["1"] (
   echo Creating archive %anArchName%.7z
@@ -95,10 +104,10 @@ if not ["%1"] == ["-nopause"] (
 goto :eof
 
 :cmakeGenerate
-set "aPlatformAndCompiler=wasm32"
-set "aWorkDir=%aBuildRoot%\%aPlatformAndCompiler%-make"
-set "aDestDir=%aBuildRoot%\%aPlatformAndCompiler%"
-set "aLogFile=%aBuildRoot%\build-%aPlatformAndCompiler%.log"
+set "aPlatformAndCompiler=wasm32%aBuildTypePrefix%"
+set "aWorkDir=%aBuildRoot%\occt-%aPlatformAndCompiler%-make"
+set "aDestDir=%aBuildRoot%\occt-%aPlatformAndCompiler%"
+set "aLogFile=%aBuildRoot%\occt-%aPlatformAndCompiler%-build.log"
 if ["%toCMake%"] == ["1"] (
   if ["%toClean%"] == ["1"] (
     rmdir /S /Q %aWorkDir%"
@@ -109,9 +118,9 @@ if not exist "%aWorkDir%" ( mkdir "%aWorkDir%" )
 if     exist "%aLogFile%" ( del   "%aLogFile%" )
 
 set "aSrcRootSmpl=%aCasSrc%\samples\webgl"
-set "aWorkDirSmpl=%aBuildRoot%\%aPlatformAndCompiler%-sample-make"
-set "aDestDirSmpl=%aBuildRoot%\%aPlatformAndCompiler%-sample"
-set "aLogFileSmpl=%aBuildRoot%\build-%aPlatformAndCompiler%-sample.log"
+set "aWorkDirSmpl=%aBuildRoot%\sample-%aPlatformAndCompiler%-make"
+set "aDestDirSmpl=%aBuildRoot%\sample-%aPlatformAndCompiler%"
+set "aLogFileSmpl=%aBuildRoot%\sample-%aPlatformAndCompiler%-build.log"
 if ["%toBuildSample%"] == ["1"] (
   if ["%toCMake%"] == ["1"] (
     if ["%toClean%"] == ["1"] (
@@ -139,7 +148,7 @@ if ["%toCMake%"] == ["1"] (
   echo Configuring OCCT for WASM...
   cmake -G "MinGW Makefiles" ^
  -D CMAKE_TOOLCHAIN_FILE:FILEPATH="%aToolchain%" ^
- -D CMAKE_BUILD_TYPE:STRING="Release" ^
+ -D CMAKE_BUILD_TYPE:STRING="%aBuildType%" ^
  -D BUILD_LIBRARY_TYPE:STRING="Static" ^
  -D INSTALL_DIR:PATH="%aDestDir%" ^
  -D INSTALL_DIR_INCLUDE:STRING="inc" ^
@@ -226,8 +235,9 @@ pushd "%aWorkDirSmpl%"
 if ["%toCMake%"] == ["1"] (
   cmake -G "MinGW Makefiles" ^
  -D CMAKE_TOOLCHAIN_FILE:FILEPATH="%aToolchain%" ^
- -D CMAKE_BUILD_TYPE:STRING="Release" ^
+ -D CMAKE_BUILD_TYPE:STRING="%aBuildType%" ^
  -D CMAKE_INSTALL_PREFIX:PATH="%aDestDirSmpl%" ^
+ -D SOURCE_MAP_BASE:STRING="%sourceMapBase%" ^
  -D OpenCASCADE_DIR:PATH="%aDestDir%/lib/cmake/opencascade" ^
  -D freetype_DIR:PATH="%aFreeType%/lib/cmake/freetype" ^
  "%aSrcRootSmpl%"
index a9ef56f60d08fd8c8f06954c9b1283177e15ce55..1b07aa71448f1289fcb70aceefe95af9ea3787a8 100644 (file)
@@ -7,11 +7,15 @@ rem set "aCmakeBin=%ProgramW6432%\CMake\bin"
 rem Uncomment to customize building steps
 rem set "aBuildRoot=work"
 rem set "toCMake=1"
-rem set "toClean=0"
+rem set "toClean=1"
 rem set "toMake=1"
 rem set "toInstall=1"
-rem set "toPack=0"
+rem set "toPack=1"
+rem set "toDebug=1"
 rem set "toBuildSample=1"
+rem Source map base (should point to server where C++ sources will be copied)
+rem enables -g4 debug building option for WebGL sample and allows navigating C++ source code within JavaScript debugger.
+rem set "sourceMapBase=http://localhost:9090/"
 
 rem set "BUILD_ModelingData=ON"
 rem set "BUILD_ModelingAlgorithms=ON"
index 84c917e33f240a05bac5d49fd44c1ffde395ff1b..fd9a33b301e58e950dc56d7e4a7eeed970effbbe 100644 (file)
@@ -18,6 +18,8 @@ set "toCMake=1"
 set "toClean=0"
 set "toMake=1"
 set "toInstall=1"
+set "toDebug=0"
+set "sourceMapBase="
 
 rem Configuration file
 if exist "%~dp0wasm_custom.bat" call "%~dp0wasm_custom.bat"
@@ -26,6 +28,13 @@ call "%EMSDK_ROOT%\emsdk_env.bat"
 set "aToolchain=%EMSDK%/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake"
 if not ["%aCmakeBin%"] == [""] ( set "PATH=%aCmakeBin%;%PATH%" )
 
+set "aBuildType=Release"
+set "aBuildTypePrefix="
+if ["%toDebug%"] == ["1"] (
+  set "aBuildType=Debug"
+  set "aBuildTypePrefix=-debug"
+)
+
 call :cmakeGenerate
 if not ["%1"] == ["-nopause"] (
   pause
@@ -34,12 +43,12 @@ if not ["%1"] == ["-nopause"] (
 goto :eof
 
 :cmakeGenerate
-set "aPlatformAndCompiler=wasm32"
-set "aDestDirOcct=%aBuildRoot%\%aPlatformAndCompiler%"
+set "aPlatformAndCompiler=wasm32%aBuildTypePrefix%"
+set "aDestDirOcct=%aBuildRoot%\occt-%aPlatformAndCompiler%"
 set "aSrcRootSmpl=%aCasSrc%\samples\webgl"
-set "aWorkDirSmpl=%aBuildRoot%\%aPlatformAndCompiler%-sample-make"
-set "aDestDirSmpl=%aBuildRoot%\%aPlatformAndCompiler%-sample"
-set "aLogFileSmpl=%aBuildRoot%\build-%aPlatformAndCompiler%-sample.log"
+set "aWorkDirSmpl=%aBuildRoot%\sample-%aPlatformAndCompiler%-make"
+set "aDestDirSmpl=%aBuildRoot%\sample-%aPlatformAndCompiler%"
+set "aLogFileSmpl=%aBuildRoot%\sample-%aPlatformAndCompiler%-build.log"
 if ["%toCMake%"] == ["1"] (
   if ["%toClean%"] == ["1"] (
     rmdir /S /Q %aWorkDirSmpl%"
@@ -54,8 +63,9 @@ pushd "%aWorkDirSmpl%"
 if ["%toCMake%"] == ["1"] (
   cmake -G "MinGW Makefiles" ^
  -D CMAKE_TOOLCHAIN_FILE:FILEPATH="%aToolchain%" ^
- -D CMAKE_BUILD_TYPE:STRING="Release" ^
+ -D CMAKE_BUILD_TYPE:STRING="%aBuildType%" ^
  -D CMAKE_INSTALL_PREFIX:PATH="%aDestDirSmpl%" ^
+ -D SOURCE_MAP_BASE:STRING="%sourceMapBase%" ^
  -D OpenCASCADE_DIR:PATH="%aDestDirOcct%/lib/cmake/opencascade" ^
  -D freetype_DIR:PATH="%aFreeType%/lib/cmake/freetype" ^
  "%aSrcRootSmpl%"
index ee35d9d828e9149ee313584eefef78a717641903..bdcb29aa7bc8f2b5354cc3d7a66fd384eb2b4a0b 100644 (file)
@@ -7,16 +7,29 @@ set(APP_VERSION_MAJOR 1)
 set(APP_VERSION_MINOR 0)
 set(APP_TARGET occt-webgl-sample)
 
+# option to enable or disable use of precompiled headers
+if (NOT DEFINED SOURCE_MAP_BASE)
+  set (SOURCE_MAP_BASE "" CACHE STRING "Path to source map server for debugging C++ code; e.g. http://localhost:9090/")
+endif()
+
 # 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} --bind")
 #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")
+if (NOT "${SOURCE_MAP_BASE}" STREQUAL "")
+  set(CMAKE_CXX_FLAGS_DEBUG "-g4 --source-map-base ${SOURCE_MAP_BASE}")
+endif()
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s MODULARIZE=1")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='createOccViewerModule'")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap']")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --extern-post-js ${CMAKE_CURRENT_SOURCE_DIR}/occt-webgl-viewer.js")
 
 INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})
 file(GLOB SOURCES
@@ -24,9 +37,11 @@ file(GLOB SOURCES
   *.cpp
 )
 source_group ("Headers" FILES
-  WasmOcctView.h)
+  WasmOcctView.h
+  WasmOcctPixMap.h)
 source_group ("Sources" FILES
   WasmOcctView.cpp
+  WasmOcctPixMap.cpp
   main.cpp)
 
 # FreeType
@@ -57,10 +72,14 @@ target_link_libraries(
   ${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})
+if (NOT "${SOURCE_MAP_BASE}" STREQUAL "")
+  if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.wasm.map DESTINATION ${CMAKE_INSTALL_PREFIX})
+  endif()
+endif()
 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/WasmOcctPixMap.cpp b/samples/webgl/WasmOcctPixMap.cpp
new file mode 100644 (file)
index 0000000..7a39a26
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright (c) 2021 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 "WasmOcctPixMap.h"
+
+#include <Message.hxx>
+
+#include <emscripten.h>
+
+// ================================================================
+// Function : WasmOcctPixMap
+// Purpose  :
+// ================================================================
+WasmOcctPixMap::WasmOcctPixMap()
+: myRawDataPtr (nullptr) {}
+
+// ================================================================
+// Function : ~WasmOcctPixMap
+// Purpose  :
+// ================================================================
+WasmOcctPixMap::~WasmOcctPixMap()
+{
+  Clear();
+}
+
+// ================================================================
+// Function : Clear
+// Purpose  :
+// ================================================================
+void WasmOcctPixMap::Clear()
+{
+  if (myRawDataPtr != nullptr) { free (myRawDataPtr); }
+  myRawDataPtr = nullptr;
+  Image_PixMap::Clear();
+}
+
+// ================================================================
+// Function : Init
+// Purpose  :
+// ================================================================
+bool WasmOcctPixMap::Init (const char* theFilePath)
+{
+  Clear();
+  int aSizeX = 0, aSizeY = 0;
+  char* anImgData = emscripten_get_preloaded_image_data (theFilePath, &aSizeX, &aSizeY);
+  if (anImgData == nullptr)
+  {
+    Message::DefaultMessenger()->Send (TCollection_AsciiString("Error: invalid image ") + theFilePath, Message_Fail);
+    return false;
+  }
+
+  Message::DefaultMessenger()->Send (TCollection_AsciiString("Loaded image ") + theFilePath + "@" + aSizeX + "x" + aSizeY, Message_Info);
+  InitWrapper (Image_Format_RGBA, (Standard_Byte* )anImgData, aSizeX, aSizeY);
+  SetTopDown (true);
+  myRawDataPtr = anImgData;
+  return true;
+}
diff --git a/samples/webgl/WasmOcctPixMap.h b/samples/webgl/WasmOcctPixMap.h
new file mode 100644 (file)
index 0000000..6cd0faa
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright (c) 2021 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 _WasmOcctPixMap_HeaderFile
+#define _WasmOcctPixMap_HeaderFile
+
+#include <Image_PixMap.hxx>
+
+//! Image pixmap loading image using Emscripten.
+class WasmOcctPixMap : public Image_PixMap
+{
+public:
+  //! Empty constructor.
+  WasmOcctPixMap();
+
+  //! Destructor.
+  virtual ~WasmOcctPixMap();
+
+  //! Load RGBA pixmap using emscripten_get_preloaded_image_data() from the given path.
+  bool Init (const char* theFilePath);
+
+  //! Release memory.
+  virtual void Clear() override;
+
+private:
+  char* myRawDataPtr;
+};
+
+#endif // _WasmOcctPixMap_HeaderFile
index db4c6ac7734271103e33c2f50be98a3691a407d5..ec333033005dfbe04dd3c4a1eb5e7b0fe8bccb7c 100644 (file)
@@ -22,6 +22,7 @@
 #include "WasmOcctView.h"
 
 #include "WasmVKeys.h"
+#include "WasmOcctPixMap.h"
 
 #include <AIS_Shape.hxx>
 #include <AIS_ViewCube.hxx>
 #include <Aspect_NeutralWindow.hxx>
 #include <Message.hxx>
 #include <Message_Messenger.hxx>
+#include <Graphic3d_CubeMapPacked.hxx>
 #include <OpenGl_GraphicDriver.hxx>
 #include <Prs3d_DatumAspect.hxx>
+#include <Prs3d_ToolCylinder.hxx>
+#include <Prs3d_ToolDisk.hxx>
+
+#include <BRep_Builder.hxx>
+#include <BRepBndLib.hxx>
+#include <BRepTools.hxx>
+#include <Standard_ArrayStreamBuffer.hxx>
+
+#include <emscripten/bind.h>
 
 #include <iostream>
 
 namespace
 {
   EM_JS(int, jsCanvasGetWidth, (), {
-    return canvas.width;
+    return Module.canvas.width;
   });
 
   EM_JS(int, jsCanvasGetHeight, (), {
-    return canvas.height;
+    return Module.canvas.height;
   });
 
   EM_JS(float, jsDevicePixelRatio, (), {
@@ -57,6 +68,65 @@ namespace
   {
     return Graphic3d_Vec2i (jsCanvasGetWidth(), jsCanvasGetHeight());
   }
+
+  //! Auxiliary wrapper for loading model.
+  struct ModelAsyncLoader
+  {
+    std::string Name;
+    std::string Path;
+
+    ModelAsyncLoader (const char* theName, const char* thePath)
+    : Name (theName), Path (thePath) {}
+
+    //! File data read event.
+    static void onDataRead (void* theOpaque, void* theBuffer, int theDataLen)
+    {
+      const ModelAsyncLoader* aTask = (ModelAsyncLoader* )theOpaque;
+      WasmOcctView::openFromMemory (aTask->Name, reinterpret_cast<uintptr_t>(theBuffer), theDataLen, false);
+      delete aTask;
+    }
+
+    //! File read error event.
+    static void onReadFailed (void* theOpaque)
+    {
+      const ModelAsyncLoader* aTask = (ModelAsyncLoader* )theOpaque;
+      Message::DefaultMessenger()->Send (TCollection_AsciiString("Error: unable to load file ") + aTask->Path.c_str(), Message_Fail);
+      delete aTask;
+    }
+  };
+
+  //! Auxiliary wrapper for loading cubemap.
+  struct CubemapAsyncLoader
+  {
+    //! Image file read event.
+    static void onImageRead (const char* theFilePath)
+    {
+      Handle(Graphic3d_CubeMapPacked) aCubemap;
+      Handle(WasmOcctPixMap) anImage = new WasmOcctPixMap();
+      if (anImage->Init (theFilePath))
+      {
+        aCubemap = new Graphic3d_CubeMapPacked (anImage);
+      }
+      WasmOcctView::Instance().View()->SetBackgroundCubeMap (aCubemap, true, false);
+      WasmOcctView::Instance().UpdateView();
+    }
+
+    //! Image file failed read event.
+    static void onImageFailed (const char* theFilePath)
+    {
+      Message::DefaultMessenger()->Send (TCollection_AsciiString("Error: unable to load image ") + theFilePath, Message_Fail);
+    }
+  };
+}
+
+// ================================================================
+// Function : Instance
+// Purpose  :
+// ================================================================
+WasmOcctView& WasmOcctView::Instance()
+{
+  static WasmOcctView aViewer;
+  return aViewer;
 }
 
 // ================================================================
@@ -239,6 +309,14 @@ bool WasmOcctView::initViewer()
   aViewer->SetDefaultShadingModel (Graphic3d_TOSM_FRAGMENT);
   aViewer->SetDefaultLights();
   aViewer->SetLightOn();
+  for (V3d_ListOfLight::Iterator aLightIter (aViewer->ActiveLights()); aLightIter.More(); aLightIter.Next())
+  {
+    const Handle(V3d_Light)& aLight = aLightIter.Value();
+    if (aLight->Type() == Graphic3d_TOLS_DIRECTIONAL)
+    {
+      aLight->SetCastShadows (true);
+    }
+  }
 
   Handle(Aspect_NeutralWindow) aWindow = new Aspect_NeutralWindow();
   Graphic3d_Vec2i aWinSize = jsCanvasSize();
@@ -260,7 +338,9 @@ bool WasmOcctView::initViewer()
   myTextStyle->SetVerticalJustification (Graphic3d_VTA_BOTTOM);
 
   myView = new V3d_View (aViewer);
+  myView->Camera()->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
   myView->SetImmediateUpdate (false);
+  myView->ChangeRenderingParams().IsShadowEnabled = false;
   myView->ChangeRenderingParams().Resolution = (unsigned int )(96.0 * myDevicePixelRatio + 0.5);
   myView->ChangeRenderingParams().ToShowStats = true;
   myView->ChangeRenderingParams().StatsTextAspect = myTextStyle->Aspect();
@@ -301,6 +381,18 @@ void WasmOcctView::initDemoScene()
   // Build with "--preload-file MySampleFile.brep" option to load some shapes here.
 }
 
+// ================================================================
+// Function : UpdateView
+// Purpose  :
+// ================================================================
+void WasmOcctView::UpdateView()
+{
+  if (!myView.IsNull())
+  {
+    myView->Invalidate();
+    updateView();
+  }
+}
 
 // ================================================================
 // Function : updateView
@@ -536,7 +628,7 @@ EM_BOOL WasmOcctView::onTouchEvent (int theEventType, const EmscriptenTouchEvent
     }
 
     const Standard_Size aTouchId = (Standard_Size )aTouch.identifier;
-    const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (aTouch.canvasX, aTouch.canvasY));
+    const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (aTouch.targetX, aTouch.targetY));
     switch (theEventType)
     {
       case EMSCRIPTEN_EVENT_TOUCHSTART:
@@ -677,3 +769,278 @@ EM_BOOL WasmOcctView::onKeyUpEvent (int theEventType, const EmscriptenKeyboardEv
   }
   return EM_FALSE;
 }
+
+// ================================================================
+// Function : setCubemapBackground
+// Purpose  :
+// ================================================================
+void WasmOcctView::setCubemapBackground (const std::string& theImagePath)
+{
+  if (!theImagePath.empty())
+  {
+    emscripten_async_wget (theImagePath.c_str(), "/emulated/cubemap.jpg", CubemapAsyncLoader::onImageRead, CubemapAsyncLoader::onImageFailed);
+  }
+  else
+  {
+    WasmOcctView::Instance().View()->SetBackgroundCubeMap (Handle(Graphic3d_CubeMapPacked)(), true, false);
+    WasmOcctView::Instance().UpdateView();
+  }
+}
+
+// ================================================================
+// Function : fitAllObjects
+// Purpose  :
+// ================================================================
+void WasmOcctView::fitAllObjects (bool theAuto)
+{
+  WasmOcctView& aViewer = Instance();
+  if (theAuto)
+  {
+    aViewer.FitAllAuto (aViewer.Context(), aViewer.View());
+  }
+  else
+  {
+    aViewer.View()->FitAll (0.01, false);
+  }
+  aViewer.UpdateView();
+}
+
+// ================================================================
+// Function : removeAllObjects
+// Purpose  :
+// ================================================================
+void WasmOcctView::removeAllObjects()
+{
+  WasmOcctView& aViewer = Instance();
+  for (NCollection_IndexedDataMap<TCollection_AsciiString, Handle(AIS_InteractiveObject)>::Iterator anObjIter (aViewer.myObjects);
+       anObjIter.More(); anObjIter.Next())
+  {
+    aViewer.Context()->Remove (anObjIter.Value(), false);
+  }
+  aViewer.myObjects.Clear();
+  aViewer.UpdateView();
+}
+
+// ================================================================
+// Function : removeObject
+// Purpose  :
+// ================================================================
+bool WasmOcctView::removeObject (const std::string& theName)
+{
+  WasmOcctView& aViewer = Instance();
+  Handle(AIS_InteractiveObject) anObj;
+  if (!theName.empty()
+   && !aViewer.myObjects.FindFromKey (theName.c_str(), anObj))
+  {
+    return false;
+  }
+
+  aViewer.Context()->Remove (anObj, false);
+  aViewer.myObjects.RemoveKey (theName.c_str());
+  aViewer.UpdateView();
+  return true;
+}
+
+// ================================================================
+// Function : eraseObject
+// Purpose  :
+// ================================================================
+bool WasmOcctView::eraseObject (const std::string& theName)
+{
+  WasmOcctView& aViewer = Instance();
+  Handle(AIS_InteractiveObject) anObj;
+  if (!theName.empty()
+   && !aViewer.myObjects.FindFromKey (theName.c_str(), anObj))
+  {
+    return false;
+  }
+
+  aViewer.Context()->Erase (anObj, false);
+  aViewer.UpdateView();
+  return true;
+}
+
+// ================================================================
+// Function : displayObject
+// Purpose  :
+// ================================================================
+bool WasmOcctView::displayObject (const std::string& theName)
+{
+  WasmOcctView& aViewer = Instance();
+  Handle(AIS_InteractiveObject) anObj;
+  if (!theName.empty()
+   && !aViewer.myObjects.FindFromKey (theName.c_str(), anObj))
+  {
+    return false;
+  }
+
+  aViewer.Context()->Display (anObj, false);
+  aViewer.UpdateView();
+  return true;
+}
+
+// ================================================================
+// Function : openFromUrl
+// Purpose  :
+// ================================================================
+void WasmOcctView::openFromUrl (const std::string& theName,
+                                const std::string& theModelPath)
+{
+  ModelAsyncLoader* aTask = new ModelAsyncLoader (theName.c_str(), theModelPath.c_str());
+  emscripten_async_wget_data (theModelPath.c_str(), (void* )aTask, ModelAsyncLoader::onDataRead, ModelAsyncLoader::onReadFailed);
+}
+
+// ================================================================
+// Function : openFromMemory
+// Purpose  :
+// ================================================================
+bool WasmOcctView::openFromMemory (const std::string& theName,
+                                   uintptr_t theBuffer, int theDataLen,
+                                   bool theToFree)
+{
+  removeObject (theName);
+  char* aBytes = reinterpret_cast<char*>(theBuffer);
+  if (aBytes == nullptr
+   || theDataLen <= 0)
+  {
+    return false;
+  }
+
+  // Function to check if specified data stream starts with specified header.
+  #define dataStartsWithHeader(theData, theHeader) (::strncmp(theData, theHeader, sizeof(theHeader) - 1) == 0)
+
+  if (dataStartsWithHeader(aBytes, "DBRep_DrawableShape"))
+  {
+    return openBRepFromMemory (theName, theBuffer, theDataLen, theToFree);
+  }
+  else if (dataStartsWithHeader(aBytes, "glTF"))
+  {
+    //return openGltfFromMemory (theName, theBuffer, theDataLen, theToFree);
+  }
+  if (theToFree)
+  {
+    free (aBytes);
+  }
+
+  Message::SendFail() << "Error: file '" << theName.c_str() << "' has unsupported format";
+  return false;
+}
+
+// ================================================================
+// Function : openBRepFromMemory
+// Purpose  :
+// ================================================================
+bool WasmOcctView::openBRepFromMemory (const std::string& theName,
+                                       uintptr_t theBuffer, int theDataLen,
+                                       bool theToFree)
+{
+  removeObject (theName);
+
+  WasmOcctView& aViewer = Instance();
+  TopoDS_Shape aShape;
+  BRep_Builder aBuilder;
+  bool isLoaded = false;
+  {
+    char* aRawData = reinterpret_cast<char*>(theBuffer);
+    Standard_ArrayStreamBuffer aStreamBuffer (aRawData, theDataLen);
+    std::istream aStream (&aStreamBuffer);
+    BRepTools::Read (aShape, aStream, aBuilder);
+    if (theToFree)
+    {
+      free (aRawData);
+    }
+    isLoaded = true;
+  }
+  if (!isLoaded)
+  {
+    return false;
+  }
+
+  Handle(AIS_Shape) aShapePrs = new AIS_Shape (aShape);
+  if (!theName.empty())
+  {
+    aViewer.myObjects.Add (theName.c_str(), aShapePrs);
+  }
+  aShapePrs->SetMaterial (Graphic3d_NameOfMaterial_Silver);
+  aViewer.Context()->Display (aShapePrs, AIS_Shaded, 0, false);
+  aViewer.View()->FitAll (0.01, false);
+  aViewer.UpdateView();
+
+  Message::DefaultMessenger()->Send (TCollection_AsciiString("Loaded file ") + theName.c_str(), Message_Info);
+  Message::DefaultMessenger()->Send (OSD_MemInfo::PrintInfo(), Message_Trace);
+  return true;
+}
+
+// ================================================================
+// Function : displayGround
+// Purpose  :
+// ================================================================
+void WasmOcctView::displayGround (bool theToShow)
+{
+  static Handle(AIS_Shape) aGroundPrs = new AIS_Shape (TopoDS_Shape());
+
+  WasmOcctView& aViewer = Instance();
+  Bnd_Box aBox;
+  if (theToShow)
+  {
+    aViewer.Context()->Remove (aGroundPrs, false);
+    aBox = aViewer.View()->View()->MinMaxValues();
+  }
+  if (aBox.IsVoid()
+  ||  aBox.IsZThin (Precision::Confusion()))
+  {
+    if (!aGroundPrs.IsNull()
+      && aGroundPrs->HasInteractiveContext())
+    {
+      aViewer.Context()->Remove (aGroundPrs, false);
+      aViewer.UpdateView();
+    }
+    return;
+  }
+
+  const gp_XYZ aSize   = aBox.CornerMax().XYZ() - aBox.CornerMin().XYZ();
+  const double aRadius = Max (aSize.X(), aSize.Y());
+  const double aZValue = aBox.CornerMin().Z() - Min (10.0, aSize.Z() * 0.01);
+  const double aZSize  = aRadius * 0.01;
+  gp_XYZ aGroundCenter ((aBox.CornerMin().X() + aBox.CornerMax().X()) * 0.5,
+                        (aBox.CornerMin().Y() + aBox.CornerMax().Y()) * 0.5,
+                         aZValue);
+
+  TopoDS_Compound aGround;
+  gp_Trsf aTrsf1, aTrsf2;
+  aTrsf1.SetTranslation (gp_Vec (aGroundCenter - gp_XYZ(0.0, 0.0, aZSize)));
+  aTrsf2.SetTranslation (gp_Vec (aGroundCenter));
+  Prs3d_ToolCylinder aCylTool  (aRadius, aRadius, aZSize, 50, 1);
+  Prs3d_ToolDisk     aDiskTool (0.0, aRadius, 50, 1);
+  TopoDS_Face aCylFace, aDiskFace1, aDiskFace2;
+  BRep_Builder().MakeFace (aCylFace,   aCylTool .CreatePolyTriangulation (aTrsf1));
+  BRep_Builder().MakeFace (aDiskFace1, aDiskTool.CreatePolyTriangulation (aTrsf1));
+  BRep_Builder().MakeFace (aDiskFace2, aDiskTool.CreatePolyTriangulation (aTrsf2));
+
+  BRep_Builder().MakeCompound (aGround);
+  BRep_Builder().Add (aGround, aCylFace);
+  BRep_Builder().Add (aGround, aDiskFace1);
+  BRep_Builder().Add (aGround, aDiskFace2);
+
+  aGroundPrs->SetShape (aGround);
+  aGroundPrs->SetToUpdate();
+  aGroundPrs->SetMaterial (Graphic3d_NameOfMaterial_Stone);
+  aGroundPrs->SetInfiniteState (false);
+  aViewer.Context()->Display (aGroundPrs, AIS_Shaded, -1, false);
+  aGroundPrs->SetInfiniteState (true);
+  aViewer.UpdateView();
+}
+
+// Module exports
+EMSCRIPTEN_BINDINGS(OccViewerModule) {
+  emscripten::function("setCubemapBackground", &WasmOcctView::setCubemapBackground);
+  emscripten::function("fitAllObjects",    &WasmOcctView::fitAllObjects);
+  emscripten::function("removeAllObjects", &WasmOcctView::removeAllObjects);
+  emscripten::function("removeObject",     &WasmOcctView::removeObject);
+  emscripten::function("eraseObject",      &WasmOcctView::eraseObject);
+  emscripten::function("displayObject",    &WasmOcctView::displayObject);
+  emscripten::function("displayGround",    &WasmOcctView::displayGround);
+  emscripten::function("openFromUrl",      &WasmOcctView::openFromUrl);
+  emscripten::function("openFromMemory",   &WasmOcctView::openFromMemory, emscripten::allow_raw_pointers());
+  emscripten::function("openBRepFromMemory", &WasmOcctView::openBRepFromMemory, emscripten::allow_raw_pointers());
+}
index 0715e7cbacf8cef1f0c0f93f504f2402c706a820..c05ce179a34e08b77e8322d032acedf4ae65ce7a 100644 (file)
@@ -35,6 +35,72 @@ class AIS_ViewCube;
 class WasmOcctView : protected AIS_ViewController
 {
 public:
+
+  //! Return global viewer instance.
+  static WasmOcctView& Instance();
+
+public: //! @name methods exported by Module
+
+  //! Set cubemap background.
+  //! File will be loaded asynchronously.
+  //! @param theImagePath [in] image path to load
+  static void setCubemapBackground (const std::string& theImagePath);
+
+  //! Clear all named objects from viewer.
+  static void removeAllObjects();
+
+  //! Fit all/selected objects into view.
+  //! @param theAuto [in] fit selected objects (TRUE) or all objects (FALSE)
+  static void fitAllObjects (bool theAuto);
+
+  //! Remove named object from viewer.
+  //! @param theName [in] object name
+  //! @return FALSE if object was not found
+  static bool removeObject (const std::string& theName);
+
+  //! Temporarily hide named object.
+  //! @param theName [in] object name
+  //! @return FALSE if object was not found
+  static bool eraseObject (const std::string& theName);
+
+  //! Display temporarily hidden object.
+  //! @param theName [in] object name
+  //! @return FALSE if object was not found
+  static bool displayObject (const std::string& theName);
+
+  //! Show/hide ground.
+  //! @param theToShow [in] show or hide flag
+  static void displayGround (bool theToShow);
+
+  //! Open object from the given URL.
+  //! File will be loaded asynchronously.
+  //! @param theName      [in] object name
+  //! @param theModelPath [in] model path
+  static void openFromUrl (const std::string& theName,
+                           const std::string& theModelPath);
+
+  //! Open object from memory.
+  //! @param theName    [in] object name
+  //! @param theBuffer  [in] pointer to data
+  //! @param theDataLen [in] data length
+  //! @param theToFree  [in] free theBuffer if set to TRUE
+  //! @return FALSE on reading error
+  static bool openFromMemory (const std::string& theName,
+                              uintptr_t theBuffer, int theDataLen,
+                              bool theToFree);
+
+  //! Open BRep object from memory.
+  //! @param theName    [in] object name
+  //! @param theBuffer  [in] pointer to data
+  //! @param theDataLen [in] data length
+  //! @param theToFree  [in] free theBuffer if set to TRUE
+  //! @return FALSE on reading error
+  static bool openBRepFromMemory (const std::string& theName,
+                                  uintptr_t theBuffer, int theDataLen,
+                                  bool theToFree);
+
+public:
+
   //! Default constructor.
   WasmOcctView();
 
@@ -53,6 +119,9 @@ public:
   //! Return device pixel ratio for handling high DPI displays.
   float DevicePixelRatio() const { return myDevicePixelRatio; }
 
+  //! Request view redrawing.
+  void UpdateView();
+
 private:
 
   //! Create window.
@@ -142,6 +211,8 @@ private:
 
 private:
 
+  NCollection_IndexedDataMap<TCollection_AsciiString, Handle(AIS_InteractiveObject)> myObjects; //!< map of named objects
+
   Handle(AIS_InteractiveContext) myContext;          //!< interactive context
   Handle(V3d_View)               myView;             //!< 3D view
   Handle(Prs3d_TextAspect)       myTextStyle;        //!< text style for OSD elements
index 306a42f517ea5d93f3365be8c9ff630dc625442b..d39f55e2616e080435e7d8670c3645517abf4e44 100644 (file)
@@ -8,17 +8,9 @@
 #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;
-
 //! Dummy main loop callback for a single shot.
 extern "C" void onMainLoop()
 {
@@ -26,42 +18,7 @@ extern "C" void onMainLoop()
   emscripten_cancel_main_loop();
 }
 
-//! 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_NameOfMaterial_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()
+EMSCRIPTEN_KEEPALIVE int main()
 {
   Message::DefaultMessenger()->Printers().First()->SetTraceLevel (Message_Trace);
   Handle(Message_PrinterSystemLog) aJSConsolePrinter = new Message_PrinterSystemLog ("webgl-sample", Message_Trace);
@@ -71,10 +28,8 @@ int main()
   // setup a dummy single-shot main loop callback just to shut up a useless Emscripten error message on calling eglSwapInterval()
   emscripten_set_main_loop (onMainLoop, -1, 0);
 
+  WasmOcctView& aViewer = WasmOcctView::Instance();
   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;
 }
index efec7dba0e19e2c2e637e14347421c98463fb424..c04add8b47a38b855f5b7dd2d06ace29364eac5a 100644 (file)
@@ -9,11 +9,15 @@
 \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
+  <canvas id=occViewerCanvas 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
+<div>\r
+  <label for="fileInput">Choose BREP file to upload: </label><input type="file" id="fileInput" accept=".brep">\r
+  <input type="button" value="Clear All" onclick="OccViewerModule.removeAllObjects()">\r
+  <input type="button" value="Fit All"   onclick="OccViewerModule.fitAllObjects(true)">\r
+</div>\r
 <h4>Console output:</h4>\r
 <p id="output"></p>\r
 <script>\r
@@ -25,13 +29,13 @@ function updateCanvasSize()
   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
+  occViewerCanvas.style.width  = aSizeX + "px";\r
+  occViewerCanvas.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
+  occViewerCanvas.width  = aSizeX * aDevicePixelRatio;\r
+  occViewerCanvas.height = aSizeY * aDevicePixelRatio;\r
 \r
   occlogo.style.top = (aSizeY - 30) + "px";\r
 }\r
@@ -59,24 +63,6 @@ if (!isWasmSupported())
   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
-    console.warn(theText);\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
@@ -86,17 +72,12 @@ fileInput.onchange = function()
   var aReader = new FileReader();\r
   aReader.onload = function()\r
   {\r
-    var aNameLenBytes = lengthBytesUTF8(aFile.name) + 1;\r
-    const aNameBuffer = Module._malloc(aNameLenBytes);\r
-    stringToUTF8(aFile.name, aNameBuffer, aNameLenBytes);\r
-\r
     var aDataArray = new Uint8Array (aReader.result);\r
-    const aDataBuffer = Module._malloc(aDataArray.length);\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
+    const aDataBuffer = OccViewerModule._malloc (aDataArray.length);\r
+    OccViewerModule.HEAPU8.set (aDataArray, aDataBuffer);\r
+    OccViewerModule.openFromMemory (aFile.name, aDataBuffer, aDataArray.length, true);\r
+    //OccViewerModule._free (aDataBuffer); will be freed by called method\r
+    OccViewerModule.displayGround (true);\r
   };\r
   aReader.readAsArrayBuffer(aFile);\r
 };\r
diff --git a/samples/webgl/occt-webgl-viewer.js b/samples/webgl/occt-webgl-viewer.js
new file mode 100644 (file)
index 0000000..484b519
--- /dev/null
@@ -0,0 +1,28 @@
+var OccViewerModule =\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
+    console.warn(theText);\r
+  },\r
+  canvas: (function() {\r
+    var aCanvas = document.getElementById('occViewerCanvas');\r
+    var aGlCtx =                   aCanvas.getContext ('webgl2', { alpha: false, depth: true, antialias: false, preserveDrawingBuffer: true } );\r
+    if (aGlCtx == null) { aGlCtx = aCanvas.getContext ('webgl',  { alpha: false, depth: true, antialias: false, preserveDrawingBuffer: true } ); }\r
+    return aCanvas;\r
+  })(),\r
+\r
+  onRuntimeInitialized: function() {\r
+    //console.log(" @@ onRuntimeInitialized()" + Object.getOwnPropertyNames(OccViewerModule));\r
+  }\r
+};\r
+\r
+const OccViewerModuleInitialized = createOccViewerModule(OccViewerModule);\r
+OccViewerModuleInitialized.then(function(Module) {\r
+  //OccViewerModule.setCubemapBackground ("cubemap.jpg");\r
+  OccViewerModule.openFromUrl ("ball", "samples/Ball.brep");\r
+});\r
index 0ca8a9662a80a98d695be3803116ccbf070beec1..8648df8f8704623166c09b5320959702683387c4 100644 (file)
Binary files a/src/DrawResources/OCC_logo.png and b/src/DrawResources/OCC_logo.png differ
index 283570e68c733f02371544976ac34ea0b9c8e48a..628b50db46db6380f99a205ba9ec43e7814745f2 100644 (file)
@@ -80,6 +80,9 @@ inline void Standard_ASSERT_DO_NOTHING() {}
       #include <windows.h>
       #define Standard_ASSERT_DBGBREAK_() DebugBreak()
     #endif
+  #elif defined(__EMSCRIPTEN__)
+    #include <emscripten.h>
+    #define Standard_ASSERT_DBGBREAK_() emscripten_debugger()
   #else
     // POSIX systems
     #include <signal.h>