Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HdJavaScript and JavaScript API wrappers #2

Draft
wants to merge 15 commits into
base: usdjs
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
.DS_Store
.AppleDouble
USD_emscripten/
build
.vscode/

4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.12)

project(usd)

if (NOT CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT PXR_ENABLE_JS_SUPPORT)
if (NOT CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT EMSCRIPTEN)
if (WIN32)
message(FATAL_ERROR "Compiler does not support 64-bit builds. "
"If you are using Visual Studio, make sure you are in the "
Expand Down Expand Up @@ -39,7 +39,7 @@ set(CMAKE_CXX_FLAGS "${_PXR_CXX_FLAGS} ${CMAKE_CXX_FLAGS}")

if(PXR_ENABLE_JS_SUPPORT)
# Add EMSCRIPTEN specific compiler flags (is this the right place)?
set(EMSCRIPTEN_COMPILE_FLAGS "-s ALLOW_MEMORY_GROWTH=1 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 -s MODULARIZE=1 -s EXPORT_NAME='getUsdModule' -s 'EXTRA_EXPORTED_RUNTIME_METHODS=[\"FS\"]' -s FORCE_FILESYSTEM=1")
set(EMSCRIPTEN_COMPILE_FLAGS "-s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s ASSERTIONS=1 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 -s MODULARIZE=1 -s EXPORT_NAME='getUsdModule' -s 'EXTRA_EXPORTED_RUNTIME_METHODS=[\"FS\"]' -s FORCE_FILESYSTEM=1 --pre-js ${CMAKE_SOURCE_DIR}/js/prejs.js")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EMSCRIPTEN_COMPILE_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EMSCRIPTEN_COMPILE_FLAGS}")

Expand Down
38 changes: 30 additions & 8 deletions build_scripts/build_usd.py
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@ def InstallBoost(context, force, buildArgs):
TBB_URL = "https://github.com/oneapi-src/oneTBB/archive/2018_U6.tar.gz"

# Note: this refers to a fork of tbb for wasm. Is this maintained?
TBB_EMSCRIPTEN_URL = "https://github.com/hpcwasm/wasmtbb/archive/master.zip"
TBB_EMSCRIPTEN_URL = "https://github.com/sdunkel/wasmtbb/archive/master.zip"
kaischroeder marked this conversation as resolved.
Show resolved Hide resolved

def InstallTBB(context, force, buildArgs):
if context.emscripten:
Expand Down Expand Up @@ -1399,6 +1399,15 @@ def InstallMaterialX(context, force, buildArgs):

MATERIALX = Dependency("MaterialX", InstallMaterialX, "include/MaterialXCore/Library.h")

############################################################
# Three.js
THREE_URL = "https://unpkg.com/[email protected]/build/three.js"

def InstallThreeJs(context, force, buildArgs):
DownloadURL(THREE_URL, context, force)

THREE = Dependency("ThreeJs", InstallThreeJs, "src/three.js")

############################################################
# Embree
# For MacOS we use version 3.7.0 to include a fix from Intel
Expand Down Expand Up @@ -1610,9 +1619,16 @@ def InstallUSD(context, force, buildArgs):
extraArgs.append('-DOPENSUBDIV_INCLUDE_DIR=' + os.path.join(context.usdInstDir, 'include'))
extraArgs.append('-DOPENSUBDIV_OSDCPU_LIBRARY=' + os.path.join(context.usdInstDir, 'lib/libosdCPU.a'))

extraArgs.append('-DTHREE_JS_FILE=' + os.path.join(context.usdInstDir, 'src/three.js'))

extraArgs.append('-DPXR_ENABLE_GL_SUPPORT=OFF')
extraArgs.append('-DBUILD_SHARED_LIBS=OFF')

if context.emscripten == 'EMSCRIPTEN_NODE':
extraArgs.append('-DPXR_EMSCRIPTEN_NODE=1')
else:
extraArgs.append('-DPXR_EMSCRIPTEN_NODE=0')

RunCMake(context, force, extraArgs)

USD = Dependency("USD", InstallUSD, "include/pxr/pxr.h")
Expand Down Expand Up @@ -1739,7 +1755,8 @@ def InstallUSD(context, force, buildArgs):
subgroup = group.add_mutually_exclusive_group()
subgroup.add_argument("--emscripten", dest="emscripten", action="store_const", const='EMSCRIPTEN',
help="Build for emscripten")

subgroup.add_argument("--emscriptenNode", dest="emscripten", action="store_const", const='EMSCRIPTEN_NODE',
help="Build emscripten for NodeJS (embed data into JS)")
if Linux():
group.add_argument("--use-cxx11-abi", type=int, choices=[0, 1],
help=("Use C++11 ABI for libstdc++. (see docs above)"))
Expand Down Expand Up @@ -2078,13 +2095,13 @@ def ForceBuildDependency(self, dep):
context.buildPython = False
disabled.append('Python')

if context.buildImaging:
context.buildImaging = NO_IMAGING
disabled.append('imaging')
# if context.buildImaging:
# context.buildImaging = NO_IMAGING
# disabled.append('imaging')

if context.buildUsdImaging:
context.buildUsdImaging = NO_IMAGING
disabled.append('usdImaging')
# if context.buildUsdImaging:
# context.buildUsdImaging = NO_IMAGING
# disabled.append('usdImaging')

if context.buildExamples:
context.buildExamples = False
Expand All @@ -2111,6 +2128,9 @@ def ForceBuildDependency(self, dep):
if not context.emscripten:
requiredDependencies += [ZLIB]

if context.emscripten and context.buildTests:
requiredDependencies += [THREE]

if context.buildAlembic:
if context.enableHDF5:
requiredDependencies += [HDF5]
Expand Down Expand Up @@ -2267,6 +2287,7 @@ def _JoinVersion(v):
CMake generator {cmakeGenerator}
CMake toolset {cmakeToolset}
Emscripten {emscripten}
Node {emscriptenNode}
Downloader {downloader}

Building {buildType}
Expand Down Expand Up @@ -2327,6 +2348,7 @@ def FormatBuildArguments(buildArgs):
cmakeToolset=("Default" if not context.cmakeToolset
else context.cmakeToolset),
emscripten=("Enabled" if context.emscripten else "Disabled"),
emscriptenNode=("Enabled" if context.emscripten == 'EMSCRIPTEN_NODE' else "Disabled"),
downloader=(context.downloaderName),
dependencies=("None" if not dependenciesToBuild else
", ".join([d.name for d in dependenciesToBuild])),
Expand Down
2 changes: 1 addition & 1 deletion cmake/macros/Private.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ function(_install_resource_files NAME pluginInstallPrefix pluginToLibraryPath)
if (PXR_ENABLE_JS_SUPPORT)
string(REGEX REPLACE "^lib\\/" "/" LOCAL_PATH "${resourcesPath}")

list(APPEND EMSCRIPTEN_RESOURCE_FILES "--embed-file ${EMSCRIPTEN_RESOURCE_FILE}@${LOCAL_PATH}/${dirPath}/${destFileName}")
list(APPEND EMSCRIPTEN_RESOURCE_FILES "--preload-file ${EMSCRIPTEN_RESOURCE_FILE}@${LOCAL_PATH}/${dirPath}/${destFileName}")
endif()
install(
FILES ${resourceFile}
Expand Down
36 changes: 36 additions & 0 deletions cmake/modules/FindOpenGLEMScripten.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Locate OpenGL
# This module defines:
# OPENGL_FOUND - system has OpenGL
# OPENGL_XMESA_FOUND - system has XMESA
# OPENGL_GLU_FOUND - system has GLU
# OPENGL_INCLUDE_DIR - the GL include directory
# OPENGL_LIBRARIES - Link these to use OpenGL and GLU
# OPENGL_gl_LIBRARY - Path to OpenGL Library
# OPENGL_glu_LIBRARY - Path to GLU Library

# The implementation is based on the standard FindOpenGL.cmake provided with CMake,
# but customized for targeting Emscripten only.

# These libraries are provided with Emscripten
SET(OPENGL_FOUND TRUE)
SET(OPENGL_GLU_FOUND TRUE)

# Doesn't look like this one is part of Emscripten
SET(OPENGL_XMESA_FOUND FALSE)

# This is the path where <GL/gl.h> is found
SET(OPENGL_INCLUDE_DIR "${EMSCRIPTEN_ROOT_PATH}/system/include")

# No library to link against for OpenGL, since Emscripten picks it up automatically from library_gl.js,
# but need to report something, or CMake thinks we failed in the search.
SET(OPENGL_LIBRARIES "")
SET(OPENGL_gl_LIBRARY "")
SET(OPENGL_glu_LIBRARY "")

message('EMSCRIPTEN OpenGl')

mark_as_advanced(
OPENGL_INCLUDE_DIR
OPENGL_glu_LIBRARY
OPENGL_gl_LIBRARY
)
44 changes: 42 additions & 2 deletions extras/usd/js_bindings/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,41 @@ endif()

set(BINDINGS_NAME "jsBindings")
set(BINDING_DEPENDENCIES "")
list(APPEND BINDING_DEPENDENCIES usd usdLux usdGeom usdUtils sdf tf)
list(APPEND BINDING_DEPENDENCIES hd usd usdLux usdGeom usdUtils sdf tf usdShaders)

set(RESOURCE_PARAMETERS "")
function(add_resources target)
# This local var is needed since list append cannot update the PARENT_SCOPE
set(LOCAL_VAR ${RESOURCE_PARAMETERS})
get_property(RESSOURCES TARGET ${target} PROPERTY EMSCRIPTEN_RESOURCES)
message("RESOURCE FILES ${RESSOURCES}")
list(APPEND LOCAL_VAR "${RESSOURCES}")
set(RESOURCE_PARAMETERS "${LOCAL_VAR}" PARENT_SCOPE)
endfunction()

# Gather resources (schemas) to make them available to attach them to the bundle
add_resources(usdShade)
add_resources(sdf)
add_resources(hd)
add_resources(usdHydra)
add_resources(usdShaders)
add_resources(usdImaging)
add_resources(usd)
add_resources(usdLux)
add_resources(ar)
add_resources(usdGeom)
add_resources(ndr)

list(APPEND RESOURCE_PARAMETERS "--embed-file ${PROJECT_BINARY_DIR}/plugins_plugInfo.json@/usd/plugInfo.json")
list(APPEND RESOURCE_PARAMETERS "--preload-file ${PROJECT_BINARY_DIR}/plugins_plugInfo.json@/usd/plugInfo.json")

if(PXR_EMSCRIPTEN_NODE)
list(TRANSFORM RESOURCE_PARAMETERS REPLACE "-preload" "-embed")
endif()
message("RESOURCE LIST ${RESOURCE_PARAMETERS}")

pxr_cpp_bin(${BINDINGS_NAME}
LIBRARIES
#${BINDINGS_NAME}_LIB
${BINDING_DEPENDENCIES}
${RESOURCE_PARAMETERS}
)
Expand All @@ -40,10 +50,40 @@ set(BUILD_FILES
${CMAKE_CURRENT_BINARY_DIR}/${BINDINGS_NAME}.js
${CMAKE_CURRENT_BINARY_DIR}/${BINDINGS_NAME}.wasm
${CMAKE_CURRENT_BINARY_DIR}/${BINDINGS_NAME}.worker.js
${CMAKE_SOURCE_DIR}/js/test.html
)

if(NOT PXR_EMSCRIPTEN_NODE)
list(APPEND BUILD_FILES "${CMAKE_CURRENT_BINARY_DIR}/${BINDINGS_NAME}.data")
endif()

install(
FILES
${BUILD_FILES}
DESTINATION ${CMAKE_BINARY_DIR}/../../bin
)
# Install files for npm package

install(
FILES
${BUILD_FILES}
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../../../js/bindings/${CMAKE_BUILD_TYPE}
)
#[[
# Create ES6 module - TBD
install(
CODE
"execute_process(
COMMAND
${CMAKE_COMMAND}
-DSOURCE_DIR=${CMAKE_SOURCE_DIR}
-P
${CMAKE_CURRENT_LIST_DIR}/create_es6_module.cmake
)"
)

install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/usd.js
DESTINATION ${CMAKE_BINARY_DIR}/../../bin
)
]]
19 changes: 19 additions & 0 deletions extras/usd/js_bindings/create_es6_module.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

set(BINDINGS_NAME "jsBindings")

function(cat IN_FILE OUT_FILE)
file(READ ${IN_FILE} CONTENTS)
file(APPEND ${OUT_FILE} "${CONTENTS}")
endfunction()

message(STATUS "SOURCE_DIR: ${SOURCE_DIR}")

set(ES6_MODULE_FILES
${CMAKE_BINARY_DIR}/extras/usd/js_bindings/${BINDINGS_NAME}.js
${SOURCE_DIR}/js/usd-module-appendix.js
)
file(WRITE ${CMAKE_BINARY_DIR}/extras/usd/js_bindings/usd.js "")

foreach(ES6_MODULE_FILE ${ES6_MODULE_FILES})
cat(${ES6_MODULE_FILE} ${CMAKE_BINARY_DIR}/extras/usd/js_bindings/usd.js)
endforeach()
13 changes: 10 additions & 3 deletions js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ or in watch mode
npm run test -- --watch
```

After installation you have a *bin* subfolder under your *build* folder. This contains
a *test.html* file you can open in a browser. USD-for-Web uses the SharedArrayBuffer
feature - this requires certain security headers (CORS).
If you don't want to worry about this for testing purposes you can run the Chrome browser
with --enable-features=SharedArrayBuffer as a command line argument.

NPM package consumption
------------------------

Expand All @@ -67,16 +73,17 @@ and after adding `<script src="jsBindings.js"></script>` to your HTML page use i
```
<script src="jsBindings.js"></script>
<script type="module">
import {UsdStage} from './usd.js';
const Usd = await usdModule();
const UsdStage = Usd.UsdStage;
let stage = UsdStage.CreateNew('HelloWorld.usda');
</script>
```

In Node.Js you can load it via
```
const usdModule = require("usd");
let Usd = await usdModule();
let UsdStage = Usd.UsdStage;
const Usd = await usdModule();
const UsdStage = Usd.UsdStage;

let stage = UsdStage.CreateNew('HelloWorld.usda');
...
Expand Down
28 changes: 28 additions & 0 deletions js/__tests__/UsdGeomXform.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const Module = require("../bindings/Release/jsBindings");

let stage;
let Usd;

describe('UsdGeomXform', () => {
beforeEach(async () => {
Usd = await Module();
const fileName = "HelloWorld.usda";
stage = Usd.UsdStage.CreateNew(fileName);
}, 500000);

afterEach(() => {
Usd.PThread.runningWorkers.forEach(x => x.onmessage = function() {});
Usd.PThread.terminateAllThreads();
Usd = null;
stage = null;
process.removeAllListeners('unhandledRejection')
process.removeAllListeners('uncaughtException')
});

it("Define constructor should modify the stage", () => {
Usd.UsdGeomXform.Define(stage, "/test")
let data = stage.ExportToString();
expect(data).toContain("Xform");
expect(data).toContain("test")
});
});
46 changes: 46 additions & 0 deletions js/__tests__/UsdGeomXformable.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const Module = require("../bindings/Release/jsBindings");

let stage;
let xform;
let Usd;

describe('UsdGeomXformable', () => {
beforeEach(async () => {
Usd = await Module();
const fileName = "HelloWorld.usda";
stage = Usd.UsdStage.CreateNew(fileName);
xform = Usd.UsdGeomXform.Define(stage, "/test");
}, 500000);

afterEach(() => {
Usd.PThread.runningWorkers.forEach(x => x.onmessage = function() {});
Usd.PThread.terminateAllThreads();
Usd = null;
stage = null;
xform = null;
process.removeAllListeners('unhandledRejection')
process.removeAllListeners('uncaughtException')
});

it("AddScaleOp constructor should modify the stage", () => {
const scaleOp = xform.AddScaleOp();
scaleOp.Set([1, 2, 3]);
let data = stage.ExportToString();
expect(data).toContain("xformOp:scale");
expect(data).toContain("(1, 2, 3)");
});

it("AddTranslateOp constructor should modify the stage", () => {
const scaleOp = xform.AddTranslateOp();
scaleOp.Set([1, 2, 3]);
let data = stage.ExportToString();
expect(data).toContain("xformOp:translate");
expect(data).toContain("(1, 2, 3)");
});

it("SetXformOpOrder should modify the stage", () => {
xform.SetXformOpOrder([]);
let data = stage.ExportToString();
expect(data).toContain("uniform token[] xformOpOrder = []");
});
});
Loading