diff --git a/dox/FILES_HTML.txt b/dox/FILES_HTML.txt index 2c1be0ed01..2accb6670a 100644 --- a/dox/FILES_HTML.txt +++ b/dox/FILES_HTML.txt @@ -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 index 0000000000..7d3781faad Binary files /dev/null and b/dox/overview/images/sample_webgl.png differ diff --git a/dox/overview/overview.md b/dox/overview/overview.md index 289c0e6d0d..6096a2d5b3 100644 --- a/dox/overview/overview.md +++ b/dox/overview/overview.md @@ -214,6 +214,7 @@ for which OCCT is certified to work. | Linux | GNU gcc 4.3+
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 index 0000000000..ecdfdf7c9c --- /dev/null +++ b/samples/webgl/.gitignore @@ -0,0 +1,2 @@ +/build +/work diff --git a/samples/webgl/CMakeLists.txt b/samples/webgl/CMakeLists.txt new file mode 100644 index 0000000000..ee35d9d828 --- /dev/null +++ b/samples/webgl/CMakeLists.txt @@ -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 index 0000000000..7e748eb026 --- /dev/null +++ b/samples/webgl/ReadMe.md @@ -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 index 0000000000..68a8b86bba --- /dev/null +++ b/samples/webgl/WasmOcctView.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 index 0000000000..0715e7cbac --- /dev/null +++ b/samples/webgl/WasmOcctView.h @@ -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 +#include +#include + +#include +#include + +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 index 0000000000..3c8bb326a0 --- /dev/null +++ b/samples/webgl/WasmVKeys.h @@ -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 + +#include + +//! 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 index 0000000000..44206bb0cc --- /dev/null +++ b/samples/webgl/main.cpp @@ -0,0 +1,66 @@ +#include + +#include "WasmOcctView.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +//! 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 index 0000000000..80f7e6f4d8 --- /dev/null +++ b/samples/webgl/occt-webgl-sample.html @@ -0,0 +1,133 @@ + + + + + +OCCT WebGL Viewer Sample + + + +

OCCT WebGL Viewer Sample

+
+ + +
+ +
+

Console output:

+

+ + + + diff --git a/src/Aspect/Aspect_DisplayConnection.cxx b/src/Aspect/Aspect_DisplayConnection.cxx index 1d5a53bc55..d6643b32e6 100755 --- a/src/Aspect/Aspect_DisplayConnection.cxx +++ b/src/Aspect/Aspect_DisplayConnection.cxx @@ -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 : diff --git a/src/Aspect/Aspect_DisplayConnection.hxx b/src/Aspect/Aspect_DisplayConnection.hxx index 137749536b..e31f0f2cf4 100755 --- a/src/Aspect/Aspect_DisplayConnection.hxx +++ b/src/Aspect/Aspect_DisplayConnection.hxx @@ -20,7 +20,7 @@ #include #include -#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 #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. diff --git a/src/Aspect/Aspect_FBConfig.hxx b/src/Aspect/Aspect_FBConfig.hxx index ffdb65bc48..bbed1e4e74 100644 --- a/src/Aspect/Aspect_FBConfig.hxx +++ b/src/Aspect/Aspect_FBConfig.hxx @@ -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 diff --git a/src/Aspect/Aspect_XWD.hxx b/src/Aspect/Aspect_XWD.hxx index 46fed65bb9..7d248402d2 100644 --- a/src/Aspect/Aspect_XWD.hxx +++ b/src/Aspect/Aspect_XWD.hxx @@ -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 # else diff --git a/src/Font/Font_FontMgr.cxx b/src/Font/Font_FontMgr.cxx index 530237ac71..0032a4332e 100644 --- a/src/Font/Font_FontMgr.cxx +++ b/src/Font/Font_FontMgr.cxx @@ -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 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::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; } diff --git a/src/InterfaceGraphic/InterfaceGraphic.hxx b/src/InterfaceGraphic/InterfaceGraphic.hxx index 43ab88a23a..c533f68cd5 100644 --- a/src/InterfaceGraphic/InterfaceGraphic.hxx +++ b/src/InterfaceGraphic/InterfaceGraphic.hxx @@ -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 diff --git a/src/OSD/OSD_Chronometer.cxx b/src/OSD/OSD_Chronometer.cxx index b2de7b0252..24b1cad3ed 100644 --- a/src/OSD/OSD_Chronometer.cxx +++ b/src/OSD/OSD_Chronometer.cxx @@ -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; diff --git a/src/OSD/OSD_MemInfo.cxx b/src/OSD/OSD_MemInfo.cxx index 277804e203..8a1f6f8a84 100644 --- a/src/OSD/OSD_MemInfo.cxx +++ b/src/OSD/OSD_MemInfo.cxx @@ -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; diff --git a/src/OSD/OSD_Path.cxx b/src/OSD/OSD_Path.cxx index cca6172504..6e5c5836eb 100644 --- a/src/OSD/OSD_Path.cxx +++ b/src/OSD/OSD_Path.cxx @@ -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 diff --git a/src/OSD/OSD_signal.cxx b/src/OSD/OSD_signal.cxx index 654523afd9..af86c675bb 100644 --- a/src/OSD/OSD_signal.cxx +++ b/src/OSD/OSD_signal.cxx @@ -703,7 +703,7 @@ typedef void (* SIG_PFV) (int); #include -#if !defined(__ANDROID__) && !defined(__QNX__) +#if !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__) #include #endif diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx index 89a5ca6ab0..40ec4b535a 100644 --- a/src/OpenGl/OpenGl_Context.cxx +++ b/src/OpenGl/OpenGl_Context.cxx @@ -63,6 +63,29 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Context,Standard_Transient) #include // glXGetProcAddress() #endif +#ifdef __EMSCRIPTEN__ + #include + + //! 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]) diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx index e9471d8e8e..747c8721a8 100644 --- a/src/OpenGl/OpenGl_Context.hxx +++ b/src/OpenGl/OpenGl_Context.hxx @@ -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); } diff --git a/src/OpenGl/OpenGl_FrameBuffer.cxx b/src/OpenGl/OpenGl_FrameBuffer.cxx index f65a9abc5f..e9344f9f0d 100644 --- a/src/OpenGl/OpenGl_FrameBuffer.cxx +++ b/src/OpenGl/OpenGl_FrameBuffer.cxx @@ -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) { diff --git a/src/OpenGl/OpenGl_GlFunctions.hxx b/src/OpenGl/OpenGl_GlFunctions.hxx index 20e6eaab1a..ec2f93d096 100644 --- a/src/OpenGl/OpenGl_GlFunctions.hxx +++ b/src/OpenGl/OpenGl_GlFunctions.hxx @@ -54,7 +54,7 @@ #include #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 @@ -160,6 +160,7 @@ #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 @@ -225,7 +226,7 @@ #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 diff --git a/src/OpenGl/OpenGl_GraphicDriver.cxx b/src/OpenGl/OpenGl_GraphicDriver.cxx index 1dddb00d59..1694e17664 100644 --- a/src/OpenGl/OpenGl_GraphicDriver.cxx +++ b/src/OpenGl/OpenGl_GraphicDriver.cxx @@ -44,11 +44,11 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_GraphicDriver,Graphic3d_GraphicDriver) #include #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 // 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 #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); diff --git a/src/OpenGl/OpenGl_GraphicDriver.hxx b/src/OpenGl/OpenGl_GraphicDriver.hxx index 4c63bb02e8..09e8438e16 100644 --- a/src/OpenGl/OpenGl_GraphicDriver.hxx +++ b/src/OpenGl/OpenGl_GraphicDriver.hxx @@ -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 diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index b7f3c4069f..c7328cedd3 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -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)) diff --git a/src/OpenGl/OpenGl_Window.cxx b/src/OpenGl/OpenGl_Window.cxx index 918688f74f..b01f7f58c2 100644 --- a/src/OpenGl/OpenGl_Window.cxx +++ b/src/OpenGl/OpenGl_Window.cxx @@ -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!"); diff --git a/src/Quantity/Quantity_ColorRGBA.cxx b/src/Quantity/Quantity_ColorRGBA.cxx index 4a7c664dd1..4ce134c4b6 100644 --- a/src/Quantity/Quantity_ColorRGBA.cxx +++ b/src/Quantity/Quantity_ColorRGBA.cxx @@ -15,7 +15,7 @@ #include -#include +#include #include #include @@ -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 aColor (1.0f); if (hasAlphaComponent) { const Standard_ShortReal anAlphaComponent = takeColorComponentFromInteger (theColorInteger, diff --git a/src/Shaders/Declarations.glsl b/src/Shaders/Declarations.glsl index 05eafa88b0..d0c4f1ec97 100644 --- a/src/Shaders/Declarations.glsl +++ b/src/Shaders/Declarations.glsl @@ -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 diff --git a/src/Shaders/DeclarationsImpl.glsl b/src/Shaders/DeclarationsImpl.glsl index 5fd67ed020..37ac72b1d8 100644 --- a/src/Shaders/DeclarationsImpl.glsl +++ b/src/Shaders/DeclarationsImpl.glsl @@ -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 diff --git a/src/Shaders/Shaders_DeclarationsImpl_glsl.pxx b/src/Shaders/Shaders_DeclarationsImpl_glsl.pxx index 6b454b066e..71a6b03674 100644 --- a/src/Shaders/Shaders_DeclarationsImpl_glsl.pxx +++ b/src/Shaders/Shaders_DeclarationsImpl_glsl.pxx @@ -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" diff --git a/src/Shaders/Shaders_Declarations_glsl.pxx b/src/Shaders/Shaders_Declarations_glsl.pxx index 39929a58fc..12af3c4dba 100644 --- a/src/Shaders/Shaders_Declarations_glsl.pxx +++ b/src/Shaders/Shaders_Declarations_glsl.pxx @@ -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" diff --git a/src/Standard/Standard_Atomic.hxx b/src/Standard/Standard_Atomic.hxx index 678e211dc2..f220fbadb1 100644 --- a/src/Standard/Standard_Atomic.hxx +++ b/src/Standard/Standard_Atomic.hxx @@ -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_* diff --git a/src/Xw/Xw_Window.cxx b/src/Xw/Xw_Window.cxx index 37d7ed690e..62a9889ae3 100644 --- a/src/Xw/Xw_Window.cxx +++ b/src/Xw/Xw_Window.cxx @@ -15,7 +15,7 @@ #include -#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 #include diff --git a/src/Xw/Xw_Window.hxx b/src/Xw/Xw_Window.hxx index a9d806e972..6b21974f6c 100644 --- a/src/Xw/Xw_Window.hxx +++ b/src/Xw/Xw_Window.hxx @@ -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