diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d96309b0c2..3f67667550 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,17 +18,17 @@ jobs: fail-fast: false matrix: include: - - name: Linux_GCC_9_Python37 - os: ubuntu-20.04 + - name: Linux_GCC_10_Python37 + os: ubuntu-22.04 compiler: gcc - compiler_version: "9" + compiler_version: "10" python: 3.7 - cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON + cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON -DMATERIALX_BUILD_MONOLITHIC=ON - - name: Linux_GCC_12_Python311 - os: ubuntu-22.04 + - name: Linux_GCC_13_Python311 + os: ubuntu-24.04 compiler: gcc - compiler_version: "12" + compiler_version: "13" python: 3.11 build_javascript: ON @@ -37,21 +37,19 @@ jobs: compiler: gcc compiler_version: "14" python: 3.12 - static_analysis: ON - cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - name: Linux_GCC_CoverageAnalysis - os: ubuntu-22.04 + os: ubuntu-24.04 compiler: gcc compiler_version: "None" python: None coverage_analysis: ON cmake_config: -DMATERIALX_COVERAGE_ANALYSIS=ON -DMATERIALX_BUILD_RENDER=OFF -DMATERIALX_BUILD_PYTHON=OFF - - name: Linux_Clang_10_Python37 - os: ubuntu-20.04 + - name: Linux_Clang_13_Python37 + os: ubuntu-22.04 compiler: clang - compiler_version: "10" + compiler_version: "13" python: 3.7 cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON @@ -63,30 +61,32 @@ jobs: test_render: ON clang_format: ON - - name: MacOS_Xcode_13_Python37 - os: macos-12 + - name: MacOS_Xcode_14_Python39 + os: macos-13 compiler: xcode - compiler_version: "13.1" + compiler_version: "14.1" cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON - python: 3.7 + python: 3.9 - - name: MacOS_Xcode_14_Python311 + - name: MacOS_Xcode_15_Python311 os: macos-14 compiler: xcode - compiler_version: "14.3" + compiler_version: "15.1" python: 3.11 + static_analysis: ON + cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - name: MacOS_Xcode_15_Python312 os: macos-14 compiler: xcode - compiler_version: "15.0" + compiler_version: "15.4" python: 3.12 test_shaders: ON - name: MacOS_Xcode_DynamicAnalysis os: macos-14 compiler: xcode - compiler_version: "15.0" + compiler_version: "15.4" python: None dynamic_analysis: ON cmake_config: -DMATERIALX_DYNAMIC_ANALYSIS=ON @@ -94,9 +94,9 @@ jobs: - name: iOS_Xcode_15 os: macos-14 compiler: xcode - compiler_version: "15.0" + compiler_version: "15.4" python: None - cmake_config: -DMATERIALX_BUILD_IOS=ON -DCMAKE_OSX_SYSROOT=`xcrun --sdk iphoneos --show-sdk-path` -DCMAKE_OSX_ARCHITECTURES=arm64 + cmake_config: -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=`xcrun --sdk iphoneos --show-sdk-path` -DCMAKE_OSX_ARCHITECTURES=arm64 - name: Windows_VS2019_Win32_Python37 os: windows-2019 @@ -127,6 +127,7 @@ jobs: - name: Install Dependencies (Linux) if: runner.os == 'Linux' run: | + sudo apt-get update sudo apt-get install xorg-dev if [ "${{ matrix.compiler_version }}" != 'None' ]; then if [ "${{ matrix.compiler }}" = "gcc" ]; then @@ -228,13 +229,14 @@ jobs: run: | vcpkg/vcpkg install glslang --triplet=x64-windows glslangValidator.exe -v - python python/Scripts/generateshader.py resources/Materials/Examples/StandardSurface --target glsl --validator glslangValidator.exe --vulkanGlsl True --validatorArgs="-V --aml" - python python/Scripts/generateshader.py resources/Materials/Examples/StandardSurface --target essl --validator glslangValidator.exe + python python/Scripts/generateshader.py resources/Materials/Examples --target glsl --validator glslangValidator.exe + python python/Scripts/generateshader.py resources/Materials/Examples --target essl --validator glslangValidator.exe - name: Shader Validation Tests (MacOS) if: matrix.test_shaders == 'ON' && runner.os == 'macOS' run: | - python python/Scripts/generateshader.py resources/Materials/Examples/StandardSurface --target msl --validator "xcrun metal --language=metal" --validatorArgs="-w" + python python/Scripts/generateshader.py resources/Materials/Examples --target msl --validator "xcrun metal --language=metal" --validatorArgs="-w" + python python/Scripts/generateshader.py resources/Materials/TestSuite/stdlib --target msl --validator "xcrun metal --language=metal" --validatorArgs="-w" - name: Coverage Analysis Tests if: matrix.coverage_analysis == 'ON' @@ -245,10 +247,14 @@ jobs: working-directory: build - name: Static Analysis Tests - if: matrix.static_analysis == 'ON' && runner.os == 'Linux' + if: matrix.static_analysis == 'ON' run: | - sudo apt-get install cppcheck - cppcheck --project=build/compile_commands.json --error-exitcode=1 --suppress=*:*/External/* --suppress=*:*/NanoGUI/* + if [ "${{ runner.os }}" = "Linux" ]; then + sudo apt-get install cppcheck + else + brew install cppcheck + fi + cppcheck --project=build/compile_commands.json --error-exitcode=1 --suppress=normalCheckLevelMaxBranches --suppress=*:*/External/* --suppress=*:*/NanoGUI/* - name: Initialize Virtual Framebuffer if: matrix.test_render == 'ON' && runner.os == 'Linux' @@ -332,7 +338,7 @@ jobs: - name: Deploy Web Viewer if: matrix.build_javascript == 'ON' && github.event_name != 'pull_request' - uses: JamesIves/github-pages-deploy-action@v4 + uses: JamesIves/github-pages-deploy-action@v4.6.4 with: branch: gh-pages folder: javascript/MaterialXView/dist @@ -347,7 +353,7 @@ jobs: sdist: name: Python SDist - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: github.repository == 'AcademySoftwareFoundation/MaterialX' outputs: sdist_filename: ${{ steps.generate.outputs.filename }} @@ -383,7 +389,7 @@ jobs: fail-fast: false matrix: python-minor: ['7', '8', '9', '10', '11', '12'] - os: ['ubuntu-latest', 'windows-2022', 'macos-13'] + os: ['ubuntu-22.04', 'windows-2022', 'macos-14-large'] steps: - name: Sync Repository @@ -401,7 +407,7 @@ jobs: path: sdist - name: Build Wheel - uses: pypa/cibuildwheel@v2.17.0 + uses: pypa/cibuildwheel@v2.19.2 with: package-dir: ${{ github.workspace }}/sdist/${{ needs.sdist.outputs.sdist_filename }} env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..6ddb62f2b4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,43 @@ +name: release + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + + release: + name: Release Signing + runs-on: ubuntu-latest + env: + RELEASE_TAG: ${{ github.ref_name }} + permissions: + contents: write + id-token: write + repository-projects: write + + steps: + - name: Sync Repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Create Archive Name + run: echo "MATERIALX_ARCHIVE=MaterialX-${RELEASE_TAG//v}" >> $GITHUB_ENV + + - name: Generate Archives + run: | + git archive --prefix ${MATERIALX_ARCHIVE}/ --output ${MATERIALX_ARCHIVE}.zip ${RELEASE_TAG} + git archive --prefix ${MATERIALX_ARCHIVE}/ --output ${MATERIALX_ARCHIVE}.tar.gz ${RELEASE_TAG} + + - name: Sign and Upload Archives + uses: sigstore/gh-action-sigstore-python@v3.0.0 + with: + inputs: | + ${{ env.MATERIALX_ARCHIVE }}.zip + ${{ env.MATERIALX_ARCHIVE }}.tar.gz + upload-signing-artifacts: true + release-signing-artifacts: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 495feae6dc..8ab737cbe6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,37 +1,98 @@ # Change Log -## [1.39.0] - Development +## [1.39.2] - Development ### Added -- Added a [MaterialX implementation](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1816) of the [OpenPBR Surface](https://academysoftwarefoundation.github.io/OpenPBR/) shading model. -- Added support for [Hoffman-Schlick Fresnel](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1727), [Zeltner-Burley sheen](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1825), and [energy-compensated Oren-Nayar diffuse](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1822) in physically based shading. +- Added support for the [Chiang Hair BSDF](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1968), with initial implementations in hardware shading languages and MDL. +- Added support for the [Disney Principled](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2004) shading model, implemented as a language-independent graph. +- Added support for [data library referencing](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2054), enabling improved performance in shader generation. +- Added support for [custom structure types](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1831) in MaterialX. +- Added support for [functional equivalence](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2003) tests between MaterialX elements. +- Added support for [transmission effects](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2027) in the translation graph from Standard Surface to glTF PBR. +- Added support for [coated emission](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2087) in the translation graph from Standard Surface to UsdPreviewSurface. +- Added support for [Apple framework builds](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2020). +- Added support for [MDL 1.9](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2102) in shader generation. +- Added support for [viewdirection space](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2036) in hardware shading languages. +- Added a [combined version define](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2031) to MaterialX C++. +- Added a [release signing workflow](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2009) to GitHub Actions. +- Added documentation for [keyboard shortcuts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2026) in the MaterialX Viewer. + +### Changed +- Improved the performance of [graph traversal](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2023) by skipping edges that have already been visited. +- Reduced duplication between the [MSL and GLSL implementations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2068) of nodes. + +### Fixed +- Fixed [unintentional camera orbiting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2032) in the render view of the MaterialX Graph Editor. +- Fixed [banding artifacts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1977) in the MaterialX Viewer on MacOS. +- Fixed the handling of [missing scenes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2124) in the MaterialX Web Viewer. +- Fixed a call to the [anisotropic_vdf closure](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2016) in OSL shader generation. + +### Removed +- Removed support for the [legacy OSL closures](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2121), focusing exclusively on the MaterialX-synchronized closures in OSL 1.12 and beyond. + +## [1.39.1] - 2024-09-03 + +### Added +- Added initial shader translation graphs between [Standard Surface](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1934) and [OpenPBR Surface](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1949). +- Added initial support for [code generation hints](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1954). + +### Changed +- Raised the minimum CMake version to [CMake 3.24](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1929). +- Moved feature proposals from the main specification to a new [MaterialX Proposals](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1953) document. +- Updated the open definitions of the [MaterialX Lama nodes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1955) to improve alignment with RenderMan. + +### Fixed +- Fixed errors in the [installation steps](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1923) for CMake builds. +- Fixed the computation of [Fresnel transmission](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1962) in GLSL. +- Fixed an implementation of the [combine2 node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1975) in MDL. +- Fixed transposed matrices in color transforms for the [displayp3 space](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1960). +- Fixed edge cases in the version upgrade process for [swizzle](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1945) [nodes](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1957). +- Fixed a crash in the Graph Editor when [renaming a node graph](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1930). +- Fixed the exporting of [PugiXML symbols](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1944) in MaterialXFormat. + +### Removed +- Removed an extra installation of the [resources folder](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1927) in MaterialXGenShader. + +## [1.39.0] - 2024-07-05 + +### Added +- Added support for the [OpenPBR Surface](https://academysoftwarefoundation.github.io/OpenPBR/) shading model, including the [MaterialX definition](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/open_pbr_surface.mtlx) and [example materials](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples/OpenPbr) for OpenPBR Surface v1.1. +- Added support for [Hoffman-Schlick Fresnel](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1727), [Zeltner sheen](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1880), and [energy-compensated Oren-Nayar diffuse](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1822), with initial implementations in hardware shading languages. +- Added support for the [LamaGeneralizedSchlick and LamaIridescence](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1897) nodes, with definitions provided as MaterialX graphs. - Added support for integer-type [add, subtract](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1777), and [conditional](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1786) nodes. - Added support for matrix-type [switch](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1779) and [conditional](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1780) nodes. +- Added support for additional [convert node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1905) input and output types. - Added support for [monolithic builds](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1725) of MaterialX. -- Added support for [Python 3.12](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1802) in Python wheel generation. - Added support for the [full set of shader generators](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1771) in JavaScript. -- Added an example script to [generate a MaterialX document](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1746) from a folder of textures. - Added support for [frame timing](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1739) in the MaterialX Viewer. +- Added a [uiScale option](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1586) for adjusting DPI in the Graph Editor. +- Added an example script to [generate a MaterialX document](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1746) from a folder of textures. - Added unit tests for [core utilities](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1768) and [ESSL shader generation](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1781). +- Added support for [Python 3.12](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1802) in Python wheel generation. +- Added [GCC 14](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1913) and [Clang 18](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1820) builds to GitHub Actions CI. ### Changed - Raised the minimum C++ version for MaterialX builds to [C++17](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1712). - Updated the [PyBind11 library](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1839) to version 2.12.0, enabling support for recent compilers and CMake versions. - Improved the expression of [thin-film layering](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1413) in MaterialX 1.39, with automatic upgrade logic for legacy documents. +- Improved the generality of the [normalmap node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1911) in MaterialX 1.39, with automatic upgrade logic for legacy documents. - Extended the [switch node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1660) to ten inputs in MaterialX 1.39, with automatic upgrade logic for legacy documents. - Renamed the inputs of the [atan2 node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1659) in MaterialX 1.39, with automatic upgrade logic for legacy documents. +- Changed the type of [subsurface_bsdf radius](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1834) from vector3 to color3 in MaterialX 1.39, with automatic upgrade logic for legacy documents. - Renamed the [normalmap nodedef](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1677) in MaterialX 1.39, with automatic upgrade logic for legacy documents. +- Improved the support for [double-sided materials](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1866) in MaterialX 1.39. - Optimized [Fresnel](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1732) [computations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1733) in [GLSL](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1736), improving the performance of physically based shading in real-time renders. - Applied [lossless optimization](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1738) to PNG and JPG textures in the MaterialX repository. +### Fixed +- Fixed default values for the [creatematrix node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1788). +- Fixed an issue with [keyboard input focus](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1596) in the Graph Editor. + ### Removed - Removed the [swizzle node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1793) in MaterialX 1.39, with automatic upgrade logic for legacy documents. - Removed the [channels attribute](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1804) in MaterialX 1.39, with automatic upgrade logic for legacy documents. - Removed the unimplemented [arrayappend node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1707) in MaterialX 1.39. -### Fixed -- Fixed default values for the [creatematrix node](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1788). - ## [1.38.10] - 2024-04-12 ### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index 4505ab106b..569cceeebd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,11 @@ # MaterialX Version set(MATERIALX_MAJOR_VERSION 1) set(MATERIALX_MINOR_VERSION 39) -set(MATERIALX_BUILD_VERSION 0) +set(MATERIALX_BUILD_VERSION 2) set(MATERIALX_LIBRARY_VERSION ${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION}) # Cmake setup -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.24) set(CMAKE_CXX_STANDARD 17) set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) set(CMAKE_MACOSX_RPATH ON) @@ -57,12 +57,24 @@ option(MATERIALX_TEST_RENDER "Run rendering tests for MaterialX Render module. G option(MATERIALX_WARNINGS_AS_ERRORS "Interpret all compiler warnings as errors." OFF) option(MATERIALX_COVERAGE_ANALYSIS "Build MaterialX libraries with coverage analysis on supporting platforms." OFF) option(MATERIALX_DYNAMIC_ANALYSIS "Build MaterialX libraries with dynamic analysis on supporting platforms." OFF) -option(MATERIALX_OSL_LEGACY_CLOSURES "Build OSL shader generation supporting the legacy OSL closures." OFF) -option(MATERIALX_BUILD_IOS "Build MaterialX for iOS." OFF) +option(MATERIALX_BUILD_IOS "Build MaterialX for iOS. (Deprecated. Set CMAKE_SYSTEM_NAME instead)" OFF) +option(MATERIALX_BUILD_APPLE_FRAMEWORK "Build MaterialX as an Apple Framework" ${__build_apple_framework}) if (MATERIALX_BUILD_IOS) + MESSAGE(WARNING "The MATERIALX_BUILD_IOS is deprecated. Set the CMAKE_SYSTEM_NAME to the platform instead") set(CMAKE_SYSTEM_NAME iOS) - add_definitions(-DTARGET_OS_IOS=1) +endif() + +# Apple ecosystem cross-compilation +# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos +set(MATERIALX_BUILD_APPLE_EMBEDDED OFF) +set(__build_apple_framework OFF) +if (CMAKE_SYSTEM_NAME MATCHES "iOS" OR CMAKE_SYSTEM_NAME MATCHES "tvOS" OR CMAKE_SYSTEM_NAME MATCHES "visionOS" OR CMAKE_SYSTEM_NAME MATCHES "watchOS") + set(MATERIALX_BUILD_APPLE_EMBEDDED ON) + set(__build_apple_framework ${MATERIALX_BUILD_SHARED_LIBS}) + # TARGET_OS_IPHONE refers to all IPHONE derived platforms + # https://chaosinmotion.com/2021/08/02/things-to-remember-compiler-conditionals-for-macos-ios-etc/ + add_definitions(-DTARGET_OS_IPHONE=1) set(MATERIALX_BUILD_MONOLITHIC ON) set(MATERIALX_BUILD_PYTHON OFF) set(MATERIALX_BUILD_VIEWER OFF) @@ -73,6 +85,20 @@ if (MATERIALX_BUILD_IOS) set(MATERIALX_BUILD_TESTS OFF) endif() +# Apple framework handling +if(APPLE) + set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" CACHE STRING "The Codesigning identity needed to sign compiled objects") +endif() +if (MATERIALX_BUILD_APPLE_FRAMEWORK) + add_definitions(-DBUILD_APPLE_FRAMEWORK) + set(MATERIALX_BUILD_MONOLITHIC ON) + set(MATERIALX_BUILD_PYTHON OFF) + set(MATERIALX_BUILD_VIEWER OFF) + set(MATERIALX_BUILD_GRAPH_EDITOR OFF) + set(MATERIALX_BUILD_TESTS OFF) + set(MATERIALX_BUILD_SHARED_LIBS ON) +endif() + if (MATERIALX_BUILD_JS) set(MATERIALX_BUILD_RENDER OFF) set(MATERIALX_BUILD_TESTS OFF) @@ -153,7 +179,6 @@ mark_as_advanced(MATERIALX_PYTHON_EXECUTABLE) mark_as_advanced(MATERIALX_PYTHON_OCIO_DIR) mark_as_advanced(MATERIALX_PYTHON_PYBIND11_DIR) mark_as_advanced(MATERIALX_OIIO_DIR) -mark_as_advanced(MATERIALX_OSL_LEGACY_CLOSURES) mark_as_advanced(MATERIALX_OSL_BINARY_OSLC) mark_as_advanced(MATERIALX_OSL_BINARY_TESTRENDER) mark_as_advanced(MATERIALX_OSL_INCLUDE_PATH) @@ -163,6 +188,7 @@ mark_as_advanced(MATERIALX_INSTALL_STDLIB_PATH) mark_as_advanced(MATERIALX_BUILD_JS) mark_as_advanced(MATERIALX_EMSDK_PATH) mark_as_advanced(MATERIALX_BUILD_IOS) +mark_as_advanced(MATERIALX_BUILD_APPLE_FRAMEWORK) if (MATERIALX_BUILD_GEN_MDL) mark_as_advanced(MATERIALX_MDLC_EXECUTABLE) mark_as_advanced(MATERIALX_MDL_RENDER_EXECUTABLE) @@ -180,13 +206,25 @@ if (MATERIALX_BUILD_USE_CCACHE) endif() endif() -# Add global definitions -add_definitions(-DMATERIALX_OSL_BINARY_OSLC=\"${MATERIALX_OSL_BINARY_OSLC}\") -add_definitions(-DMATERIALX_OSL_BINARY_TESTRENDER=\"${MATERIALX_OSL_BINARY_TESTRENDER}\") -add_definitions(-DMATERIALX_OSL_INCLUDE_PATH=\"${MATERIALX_OSL_INCLUDE_PATH}\") -if (MATERIALX_OSL_LEGACY_CLOSURES) - add_definitions(-DMATERIALX_OSL_LEGACY_CLOSURES) +# Attempt to configure OSL testing if it can be found by cmake. +# This will not override any explicitly provided oslc and testrender +if(MATERIALX_BUILD_RENDER AND MATERIALX_BUILD_GEN_OSL AND MATERIALX_BUILD_TESTS) + # We currently only need the actual OSL binaries if we're running tests with Render and GenOSL enabled. + find_package(OSL QUIET) + if(OSL_FOUND) + if(NOT MATERIALX_OSL_BINARY_OSLC) + set(MATERIALX_OSL_BINARY_OSLC $) + endif() + if(NOT MATERIALX_OSL_BINARY_TESTRENDER) + # currently OSL does not export a cmake target for testrender, but once that's added this can be simplified. + set(MATERIALX_OSL_BINARY_TESTRENDER $/testrender) + endif() + # NOTE : we do not derive a value for MATERIALX_OSL_INCLUDE_PATH here, as a a cmake installed OSL package + # should have the shader includes in the expected location. + endif() endif() + +# Add global definitions if(MATERIALX_BUILD_OIIO) add_definitions(-DMATERIALX_BUILD_OIIO) endif() @@ -286,7 +324,8 @@ function(mx_add_library MATERIALX_MODULE_NAME) set(multiValueArgs SOURCE_FILES HEADER_FILES - LIBRARIES) + INLINED_FILES + MTLX_MODULES) cmake_parse_arguments(args "${options}" "${oneValueArgs}" @@ -301,11 +340,12 @@ function(mx_add_library MATERIALX_MODULE_NAME) endif() assign_source_group("Source Files" ${args_SOURCE_FILES}) + assign_source_group("Source Files" ${args_INLINED_FILES}) assign_source_group("Header Files" ${args_HEADER_FILES}) if (NOT MATERIALX_BUILD_MONOLITHIC) set(TARGET_NAME ${MATERIALX_MODULE_NAME}) - add_library(${TARGET_NAME} ${args_SOURCE_FILES} ${args_HEADER_FILES}) + add_library(${TARGET_NAME}) # Create version resource if(MATERIALX_BUILD_SHARED_LIBS AND MSVC) @@ -313,9 +353,9 @@ function(mx_add_library MATERIALX_MODULE_NAME) target_sources(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) endif() - target_link_libraries( - ${TARGET_NAME} - ${args_LIBRARIES} + target_link_libraries(${TARGET_NAME} + PUBLIC + ${args_MTLX_MODULES} ${CMAKE_DL_LIBS}) target_include_directories(${TARGET_NAME} @@ -336,15 +376,33 @@ function(mx_add_library MATERIALX_MODULE_NAME) else() set(TARGET_NAME ${MATERIALX_MONOLITHIC_TARGET}) - target_sources(${TARGET_NAME} PRIVATE ${args_SOURCE_FILES}) - target_sources(${TARGET_NAME} PRIVATE ${args_HEADER_FILES}) - add_library(${MATERIALX_MODULE_NAME} ALIAS ${MATERIALX_MONOLITHIC_TARGET}) # Store the aliased MaterialX modules name to create cmake export aliases later. set_property(GLOBAL APPEND PROPERTY MATERIALX_MODULES ${MATERIALX_MODULE_NAME}) endif() + set_target_properties(${TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) + set_target_properties(${TARGET_NAME} PROPERTIES CMAKE_VISIBILITY_INLINES_HIDDEN 1) + + target_sources(${TARGET_NAME} + PRIVATE + ${args_SOURCE_FILES} + PUBLIC + FILE_SET + mxHeaders + TYPE + HEADERS + BASE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_BINARY_DIR}/.. + FILES + ${args_HEADER_FILES} + ${args_INLINED_FILES}) + + target_include_directories(${TARGET_NAME} PUBLIC + $) + target_compile_definitions(${TARGET_NAME} PRIVATE "-D${args_EXPORT_DEFINE}") if(NOT SKBUILD) @@ -353,15 +411,10 @@ function(mx_add_library MATERIALX_MODULE_NAME) EXPORT MaterialX ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) + RUNTIME DESTINATION bin + FILE_SET mxHeaders) endif() - install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH}/${MATERIALX_MODULE_NAME}/ MESSAGE_NEVER - FILES_MATCHING - PATTERN "*.h*" - PATTERN "*.inl") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${MATERIALX_MODULE_NAME}.pdb" DESTINATION "${MATERIALX_INSTALL_LIB_PATH}/" OPTIONAL) endif() @@ -452,6 +505,41 @@ if(MATERIALX_BUILD_JS) add_subdirectory(source/JsMaterialX) endif() +if (MATERIALX_BUILD_MONOLITHIC) + # MaterialX monolithic build target needs to be installed after any other included + # modules to ensure the correct files are in mxHeaders + if(NOT SKBUILD) + install(TARGETS ${MATERIALX_MONOLITHIC_TARGET} + EXPORT MaterialX + ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} + LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} + RUNTIME DESTINATION bin + FILE_SET mxHeaders) + + # Note : we don't install the headers etc. here, and rely on each separate modules CMakeLists.txt + # to do that installation, thus we respect the build options configuration, and only install + # the headers for the modules we've built in to the monolithic build. + + # Finally do the framework build if requested + # This uses a zsh script since zsh is guaranteed to exist on systems + if(MATERIALX_BUILD_APPLE_FRAMEWORK) + # Conform cmake formats to zsh expected formats + set(__embedded_build "false") + if (MATERIALX_BUILD_APPLE_EMBEDDED) + set(__embedded_build "true") + endif() + + # Install the Info.plist and shell script + math(EXPR CFBUNDLEVERSION "${MATERIALX_MAJOR_VERSION} * 10000 + ${MATERIALX_MINOR_VERSION} * 100 + ${MATERIALX_BUILD_VERSION}") + configure_file(cmake/modules/Info.plist.in "${PROJECT_BINARY_DIR}/Info.plist" @ONLY) + configure_file(cmake/modules/AppleFrameworkBuild.zsh.in "${PROJECT_BINARY_DIR}/AppleFrameworkBuild.zsh" @ONLY) + + # Run the shell script for the primary configuration + install(CODE "execute_process(COMMAND zsh ${PROJECT_BINARY_DIR}/AppleFrameworkBuild.zsh )") + endif() + endif() +endif() + if(MATERIALX_BUILD_VIEWER) set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT MaterialXView) elseif(MATERIALX_BUILD_GRAPH_EDITOR) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5cebfc0499..7c3ea19e54 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,33 +1,214 @@ # Contributing to MaterialX -Thank you for your interest in contributing to MaterialX! This document explains our contribution process and procedures. +Thank you for your interest in contributing to MaterialX! This document +explains our contribution process and procedures. ## Community and Discussion There are two primary ways to connect with the MaterialX community: -* The MaterialX channel of the [Academy Software Foundation Slack](http://academysoftwarefdn.slack.com/). This platform is appropriate for general questions, feature requests, and discussion of the MaterialX project as a whole. You can request an invitation to join the Academy Software Foundation Slack at https://slack.aswf.io/. -* The [Issues](https://github.com/AcademySoftwareFoundation/MaterialX/issues) panel of the MaterialX GitHub, which is used to report and discuss bugs and build issues. +- The MaterialX channel of the +[Academy Software Foundation Slack](http://academysoftwarefdn.slack.com/). +This platform is appropriate for general questions, feature requests, and +discussion of the MaterialX project as a whole. +You can request an invitation to join the Academy Software Foundation Slack +at https://www.aswf.io/get-involved/. +- The [Issues](https://github.com/AcademySoftwareFoundation/MaterialX/issues) +panel of the MaterialX GitHub, which is used both to track bugs and to discuss +feature requests. -## Contributor License Agreements +### How to Ask for Help -To contribute to MaterialX, you must sign a Contributor License Agreement through the *EasyCLA* system, which is integrated with GitHub as a pull request check. +If you have trouble installing, building, or using the library, but there's +not yet reason to suspect you've encountered a genuine bug, start by posting +a question to the MaterialX channel of the +[Academy Software Foundation Slack](http://academysoftwarefdn.slack.com/). +This is the place for questions such has "How do I...". -Prior to submitting a pull request, you can sign the form through [this link](https://contributor.easycla.lfx.linuxfoundation.org/#/cla/project/68fa91fe-51fe-41ac-a21d-e0a0bf688a53/user/564e571e-12d7-4857-abd4-898939accdd7). If you submit a pull request before the form is signed, the EasyCLA check will fail with a red *NOT COVERED* message, and you'll have another opportunity to sign the form through the provided link. +### How to Report a Bug -* If you are an individual writing the code on your own time and you're sure you are the sole owner of any intellectual property you contribute, you can sign the CLA as an Individual Contributor. -* If you are writing the code as part of your job, or if your employer retains ownership to intellectual property you create, then your company's legal affairs representatives should sign a Corporate Contributor License Agreement. If your company already has a signed CCLA on file, ask your local CLA manager to add you to your company's approved list. +MaterialX uses +[GitHub Issues](https://github.com/AcademySoftwareFoundation/MaterialX/issues) +for reporting and tracking bugs, enhancements, and feature requests. -The MaterialX CLAs are the standard forms used by Linux Foundation projects and [recommended by the ASWF TAC](https://github.com/AcademySoftwareFoundation/tac/blob/main/process/contributing.md#contributor-license-agreement-cla). +If you are submitting a bug report, please be sure to note which version of +MaterialX you are using, on what platform (OS/version, which compiler you used, +and any special build flags or other unusual environmental issues). Please +give a specific account of the following, with enough detail that others can +reproduce the problem: -## Coding Conventions +- What you tried. +- What happened. +- What you expected to happen instead. -The coding style of the MaterialX project is defined by a [clang-format](.clang-format) file in the repository, which is supported by Clang versions 13 and newer. +### How to Report a Security Vulnerability -When adding new source files to the repository, use the provided clang-format file to automatically align the code to MaterialX conventions. When modifying existing code, follow the surrounding formatting conventions so that new or modified code blends in with the current code. +If you think you've found a potential vulnerability in MaterialX, please refer +to [SECURITY.md](SECURITY.md) to responsibly disclose it. -## Unit Tests +### How to Contribute a Bug Fix or Change -Each MaterialX module has a companion folder within the [MaterialXTest](source/MaterialXTest) module, containing a set of unit tests that validate its functionality. +To contribute code to the project, you'll need: -When contributing new code to MaterialX, make sure to include appropriate unit tests in MaterialXTest to validate the expected behavior of the new code. +- Basic knowledge of Git. +- A fork of the MaterialX repository on GitHub. +- An understanding of the project's development workflow. +- Legal authorization, that is, you need to have signed a contributor + License Agreement. See below for details. + +## Legal Requirements + +MaterialX is a project of the Academy Software Foundation and follows the +open source software best practice policies of the Linux Foundation. + +### License + +MaterialX is licensed under the [Apache 2.0](LICENSE.md) license. +Contributions to the project should abide by that standard license. + +### Contributor License Agreements + +To contribute to MaterialX, you must sign a Contributor License Agreement +through the *EasyCLA* system, which is integrated with GitHub as a pull +request check. + +Prior to submitting a pull request, you can sign the form through +[this link](https://contributor.easycla.lfx.linuxfoundation.org/#/cla/project/68fa91fe-51fe-41ac-a21d-e0a0bf688a53/user/564e571e-12d7-4857-abd4-898939accdd7). +If you submit a pull request before the form is signed, the EasyCLA check +will fail with a red *NOT COVERED* message, and you'll have another +opportunity to sign the form through the provided link. + +- If you are an individual writing the code on your own time and you're sure +you are the sole owner of any intellectual property you contribute, you can +sign the CLA as an Individual Contributor. +- If you are writing the code as part of your job, or if your employer +retains ownership to intellectual property you create, then your company's +legal affairs representatives should sign a Corporate Contributor License +Agreement. If your company already has a signed CCLA on file, ask your +local CLA manager to add you to your company's approved list. + +The MaterialX CLAs are the standard forms used by Linux Foundation projects +and [recommended by the ASWF TAC](https://github.com/AcademySoftwareFoundation/tac/blob/main/process/contributing.md#contributor-license-agreement-cla). + +## Development Workflow + +### Git Basics + +Working with MaterialX requires a basic understanding of Git and GitHub +terminology. If you’re unfamiliar with these concepts, please look at the +[GitHub Glossary](https://help.github.com/articles/github-glossary/) or +browse [GitHub Help](https://help.github.com/). + +To contribute, you need a GitHub account. This is needed in order to push +changes to the upstream repository, via a pull request. + +You will also need [Git](https://git-scm.com/doc) or a Git client such +as [Git Fork](https://git-fork.com/) or +[GitHub Desktop](https://desktop.github.com/download/) installed +on your local development machine. + +### Repository Structure and Commit Policy + +Development work in the MaterialX project is usually done directly +on the `main` branch. This branch represents the cutting edge of the +project and the majority of new work is proposed, tested, reviewed, +and merged there. + +After sufficient work is done on the `main` branch and the MaterialX +leadership determines that a release is due, they will mark a release with +the current version tag and increment the development version for future +work. This basic repository structure keeps maintenance low, while remaining +simple to understand. + +The `main` branch may include untested features and is not generally stable +enough for release. To retrieve a stable version of the source code, use any +of the +[official releases](https://github.com/AcademySoftwareFoundation/MaterialX/releases) +of the project. + +### Use the Fork, Luke. + +In a typical workflow, you should *fork* the MaterialX repository to +your account. This creates a copy of the repository under your user +namespace and serves as the “home base” for your development branches, +from which you will submit *pull requests* to the upstream +repository to be merged. + +Once your Git environment is operational, the next step is to locally +*clone* your forked MaterialX repository, and add a *remote* +pointing to the upstream MaterialX repository. These topics are +covered in the GitHub documentation +[Cloning a repository](https://help.github.com/articles/cloning-a-repository/) +and +[Configuring a remote for a fork](https://help.github.com/articles/configuring-a-remote-for-a-fork/). + +### Pull Requests + +Contributions should be submitted as GitHub pull requests. See +[Creating a pull request](https://help.github.com/articles/creating-a-pull-request/) +if you're unfamiliar with this concept. + +The development cycle for a code change should follow this protocol: + +1. Create a topic branch in your local repository, assigning the branch a +brief name that describes the feature or fix that you're working on. +2. Make changes, compile, and test thoroughly. Code style should match existing +style and conventions, and changes should be focused on the topic the pull +request will be addressing. Make unrelated changes in a separate topic branch +with a separate pull request. +3. Push commits to your fork. +4. Create a GitHub pull request from your topic branch. +5. Pull requests will be reviewed by project maintainers and contributors, +who may discuss, offer constructive feedback, request changes, or approve +the work. +6. Upon receiving the required number of approvals (as outlined in +[Required Approvals](#code-review-and-required-approvals)), a maintainer +may merge changes into the `main` branch. + +### Code Review and Required Approvals + +Modifications of the contents of the MaterialX repository are made on a +collaborative basis. Anyone with a GitHub account may propose a modification +via pull request and it will be considered by the project maintainers. + +Pull requests must meet a minimum number of maintainer approvals prior to +being merged. Rather than having a hard rule for all PRs, the requirement +is based on the complexity and risk of the proposed changes, factoring in +the length of time the PR has been open to discussion. The following +guidelines outline the project's established approval rules for merging: + +- Minor changes that don't modify current behaviors or are straightforward +fixes to existing features can be approved and merged by a single maintainer +of the repository. +- Moderate changes that modify current behaviors or introduce new features +should be approved by *two* maintainers before merging. Unless the change is +an emergency fix, the author should give the community at least 48 hours to +review the proposed change. +- Major new features and core design decisions should be discussed at length +in the ASWF Slack or in TSC meetings before any PR is submitted, in order to +solicit feedback, build consensus, and alert all stakeholders to be on the +lookout for the eventual PR when it appears. + +### Coding Conventions + +The coding style of the MaterialX project is defined by a +[clang-format](.clang-format) file in the repository, which is supported by +Clang versions 13 and newer. + +When adding new source files to the repository, use the provided clang-format +file to automatically align the code to MaterialX conventions. When modifying +existing code, follow the surrounding formatting conventions so that new or +modified code blends in with the current code. + +### Unit Tests + +Each MaterialX module has a companion folder within the +[MaterialXTest](source/MaterialXTest) module, containing a set of unit tests +that validate its functionality. When contributing new code to MaterialX, make +sure to include appropriate unit tests in MaterialXTest to validate the +expected behavior of the new code. + +The MaterialX test suite can be run locally via MaterialXTest before submitting +a pull request. Upon receiving a pull request, the GitHub CI process will +automatically run MaterialXTest across all platforms, and a successful result +is required before merging a change. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 3cfcab6cd8..cbf17d62e5 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -64,9 +64,9 @@ The current Stakeholders of the MaterialX TSC are: - Henrik Edstrom - Autodesk - Fran González García - Pixar RenderMan -- Dhruv Govil - Apple -- Rafal Jaroszkiewicz - SideFX - Ole Gulbrandsen - Sony Pictures Imageworks +- Rafal Jaroszkiewicz - SideFX +- Lee Kerley - Apple - Lutz Kettner - NVIDIA - Chris Kulla - Epic Games - Bernard Kwok - Khronos Group diff --git a/README.md b/README.md index d495b7735c..fdd06680a4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/LICENSE) @@ -7,18 +7,18 @@ [![Build Status](https://github.com/AcademySoftwareFoundation/MaterialX/workflows/main/badge.svg?branch=main)](https://github.com/AcademySoftwareFoundation/MaterialX/actions?query=branch%3Amain) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/6025/badge)](https://bestpractices.coreinfrastructure.org/projects/6025) -### Introduction +## Introduction MaterialX is an open standard for representing rich material and look-development content in computer graphics, enabling its platform-independent description and exchange across applications and renderers. Launched at [Industrial Light & Magic](https://www.ilm.com/) in 2012, MaterialX has been a key technology in their feature films and real-time experiences since _Star Wars: The Force Awakens_ and _Millennium Falcon: Smugglers Run_. The project was released as open source in 2017, with companies including Sony Pictures Imageworks, Pixar, Autodesk, Adobe, and SideFX contributing to its ongoing development. In 2021, MaterialX became the seventh hosted project of the [Academy Software Foundation](https://www.aswf.io/). -### Quick Start for Developers +## Quick Start for Developers - Download the latest version of the [CMake](https://cmake.org/) build system. - Point CMake to the root of the MaterialX library and generate C++ projects for your platform and compiler. - Select the `MATERIALX_BUILD_PYTHON` option to build Python bindings. - Select the `MATERIALX_BUILD_VIEWER` option to build the MaterialX viewer. -### Supported Platforms +## Supported Platforms The MaterialX codebase requires a compiler with support for C++17, and can be built with any of the following: @@ -28,45 +28,57 @@ The MaterialX codebase requires a compiler with support for C++17, and can be bu The Python bindings for MaterialX are based on [PyBind11](https://github.com/pybind/pybind11), and support Python versions 3.6 and greater. -### MaterialX Viewer +## MaterialX Viewer The [MaterialX Viewer](documents/DeveloperGuide/Viewer.md) leverages shader generation to build GLSL shaders from MaterialX graphs, rendering the results using the NanoGUI framework. **Figure 1:** Procedural and uniform materials in the MaterialX viewer

- - - - + + + +

**Figure 2:** Textured, color-space-managed materials in the MaterialX viewer

- - + +

-### Open Chess Set +## Open Chess Set The Open Chess Set is an open reference asset, consisting of a [MaterialX file](resources/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx) in the Standard Surface shading model and a [geometry file](resources/Geometry) in the glTF format. It was authored by Moeen Sayed and Mujtaba Sayed, and was contributed to the MaterialX project by Side Effects. **Figure 3:** The Open Chess Set, rendered in Arnold for Maya - +![The Open Chess Set rendered in Arnold for Maya](https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/documents/Images/OpenChessSet_Arnold_01.png) **Figure 4:** The Open Chess Set, rendered in Karma XPU for Houdini - +![The Open Chess Set rendered in Karma XPU for Houdini](https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/documents/Images/OpenChessSet_Karma_01.png) -### Pre-Built Binaries +## Pre-Built Binaries The following packages contain pre-built binaries for the latest release, including the MaterialX viewer, Python libraries, and example assets: -- [Microsoft Windows (Visual Studio 2022, Python 3.11)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Windows_VS2022_x64_Python311.zip) -- [MacOS (Xcode 14, Python 3.11)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_MacOS_Xcode_14_Python311.zip) -- [Linux (GCC 12, Python 3.11)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Linux_GCC_12_Python311.zip) +- [Microsoft Windows (Visual Studio 2022, Python 3.12)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Windows_VS2022_x64_Python312.zip) +- [MacOS (Xcode 15, Python 3.12)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_MacOS_Xcode_15_Python312.zip) +- [Linux (GCC 14, Python 3.12)](https://github.com/AcademySoftwareFoundation/MaterialX/releases/latest/download/MaterialX_Linux_GCC_14_Python312.zip) -### Additional Resources +## Additional Resources - The [Developer Guide](http://www.materialx.org/docs/api/index.html) contains a developer-oriented overview of MaterialX with API documentation. - The [Python Scripts](python/Scripts) folder contains standalone examples of MaterialX Python code. - The [JavaScript](javascript) folder contains details on building JavaScript bindings for MaterialX. -- Presentations at [ASWF Open Source Days](https://materialx.org/assets/ASWF_OSD2023_MaterialX_Final.pdf) and the [SIGGRAPH Physically Based Shading Course](https://blog.selfshadow.com/publications/s2020-shading-course/#materialx) provide details on the roadmap for MaterialX development. +- Presentations at [ASWF Open Source Days](https://materialx.org/assets/ASWF_OSD2024_MaterialX_Final.pdf) and the [SIGGRAPH Physically Based Shading Course](https://blog.selfshadow.com/publications/s2020-shading-course/#materialx) provide details on the roadmap for MaterialX development. diff --git a/cmake/modules/AppleFrameworkBuild.zsh.in b/cmake/modules/AppleFrameworkBuild.zsh.in new file mode 100644 index 0000000000..e6e630cc19 --- /dev/null +++ b/cmake/modules/AppleFrameworkBuild.zsh.in @@ -0,0 +1,92 @@ +#!/bin/zsh + +# Creates an Apple framework for the given platform type +# documentation: https://developer.apple.com/documentation/bundleresources/placing_content_in_a_bundle +# https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html +echo "⌛️ Creating MaterialX.framework ..." + +# Variables are substituted by CMake +CMAKE_INSTALL_PREFIX="@CMAKE_INSTALL_PREFIX@" +PROJECT_BINARY_DIR="@PROJECT_BINARY_DIR@" + +FRAMEWORK_NAME="MaterialX" +FRAMEWORK_DIR="${CMAKE_INSTALL_PREFIX}/frameworks/${FRAMEWORK_NAME}.framework" +FRAMEWORK_LIBRARIES_DIR="${FRAMEWORK_DIR}/Libraries" +FRAMEWORK_ROOT_LIBRARY_NAME="libMaterialX.@MATERIALX_LIBRARY_VERSION@.dylib" +EMBEDDED_BUILD=@__embedded_build@ +FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}" +MATERIALX_SOURCE_LIBRARIES="${CMAKE_INSTALL_PREFIX}/libraries/" +BUNDLE_IDENTIFIER="org.aswf.materialx" +CODESIGN_ID="@CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY@" +OLD_RC_PATH="${CMAKE_INSTALL_PREFIX}/lib" + +# Remove the existing directory if it exists +if [ -d ${FRAMEWORK_DIR} ]; then + echo "Removing existing framework"; + rm -Rf ${FRAMEWORK_DIR}; +fi + +# Create the parent directory +echo "Creating Framework Directory: ${FRAMEWORK_DIR}" +mkdir -p ${FRAMEWORK_DIR} + +if [ "$EMBEDDED_BUILD" = true ];then + FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}/Assets" + FRAMEWORK_PLIST_LOCATION="${FRAMEWORK_DIR}/Info.plist" + FRAMEWORK_HEADERS_DIR="${FRAMEWORK_DIR}/Headers" + FRAMEWORK_LIB_PATH=""${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"" + FRAMEWORK_LINKER_PATH="@rpath/Frameworks/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" +else + FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}/Versions/A/Resources/" + FRAMEWORK_PLIST_LOCATION="${FRAMEWORK_DIR}/Versions/A/Resources/Info.plist" + FRAMEWORK_HEADERS_DIR="${FRAMEWORK_DIR}/Versions/A/Headers" + FRAMEWORK_LIB_PATH="${FRAMEWORK_DIR}/Versions/A/${FRAMEWORK_NAME}" + FRAMEWORK_LINKER_PATH="@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" +fi + +echo "Creating Resources Root: ${FRAMEWORK_RESOURCES_DIR}" +mkdir -p ${FRAMEWORK_RESOURCES_DIR} + +echo "Creating Headers Root: ${FRAMEWORK_HEADERS_DIR}" +mkdir -p ${FRAMEWORK_HEADERS_DIR} + +# Copy the plist over +echo "Copying files into ${FRAMEWORK_DIR}" +ditto "${PROJECT_BINARY_DIR}/Info.plist" "${FRAMEWORK_PLIST_LOCATION}" + +# Copy the primary directories over +ditto "${CMAKE_INSTALL_PREFIX}/include/" ${FRAMEWORK_HEADERS_DIR} +ditto "${CMAKE_INSTALL_PREFIX}/libraries/" "${FRAMEWORK_RESOURCES_DIR}/libraries" +ditto "${CMAKE_INSTALL_PREFIX}/resources" "${FRAMEWORK_RESOURCES_DIR}/render" + +cp "${CMAKE_INSTALL_PREFIX}/lib/${FRAMEWORK_ROOT_LIBRARY_NAME}" "${FRAMEWORK_LIB_PATH}" + +# Setup symlinks +if [ "$EMBEDDED_BUILD" = false ];then + (cd "${FRAMEWORK_DIR}/Versions" && ln -s "A" "Current") + (cd ${FRAMEWORK_DIR} && ln -s "Versions/Current/Resources" "Resources") + (cd ${FRAMEWORK_DIR} && ln -s "Versions/Current/Headers" "Headers") + (cd ${FRAMEWORK_DIR} && ln -s "Versions/Current/${FRAMEWORK_NAME}" ${FRAMEWORK_NAME}) +fi + +# Fix the linkage on the primary dylib +install_name_tool -id "${FRAMEWORK_LINKER_PATH}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}" +install_name_tool -change "@rpath/libMaterialX.@MATERIALX_MAJOR_VERSION@.dylib" "${FRAMEWORK_LINKER_PATH}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}" + +# Frameworks require all includes to use the framework name as the prefix for automatic discovery +echo "Modifying headers..." +HEADER_SET="" +for i in $(cd $FRAMEWORK_HEADERS_DIR && ls -d */ | cut -f1 -d'/');do + HEADER_SET+="${i}|" +done; +# Sed on macOS is POSIX compliant and so uses different args than GNU +# Things to be aware of are [[:<:]] and [[:>:]] are for word boundaries and spaces are explicit literals +INCLUDE_PATTERN="^# *include [\"|<]([[:<:]](${HEADER_SET::-1})[[:>:]].*)[\"|>].*$" +find ${FRAMEWORK_HEADERS_DIR} -type f -name "*.h*" -print0 | xargs -0 sed -i "" -E "s,${INCLUDE_PATTERN},#include <${FRAMEWORK_NAME}/\1>,g" + +# Sign the final framework +echo "Codesigning the framework..." +set -e +codesign --force --sign ${CODESIGN_ID} --generate-entitlement-der --identifier ${BUNDLE_IDENTIFIER} --verbose ${FRAMEWORK_DIR} + +echo "✅ Finished creating framework at ${FRAMEWORK_DIR}" diff --git a/cmake/modules/Info.plist.in b/cmake/modules/Info.plist.in new file mode 100644 index 0000000000..1293cdcbbf --- /dev/null +++ b/cmake/modules/Info.plist.in @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + MaterialX + CFBundleIdentifier + org.aswf.materialx + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + MaterialX + CFBundlePackageType + FMWK + CFBundleShortVersionString + @MATERIALX_LIBRARY_VERSION@ + CFBundleVersion + @CFBUNDLEVERSION@ + CSResourcesFileMapped + + + diff --git a/documents/DeveloperGuide/GraphEditor.md b/documents/DeveloperGuide/GraphEditor.md index aaac7b75a2..394754c309 100644 --- a/documents/DeveloperGuide/GraphEditor.md +++ b/documents/DeveloperGuide/GraphEditor.md @@ -2,29 +2,30 @@ The MaterialX Graph Editor is an example application for visualizing, creating, and editing MaterialX graphs. It utilizes the ImGui framework as well as additional ImGui extensions such as the Node Editor. -### Example Images +## Example Images **Figure 1:** MaterialX Graph Editor with procedural marble example - -## Building The MaterialX Graph Editor +![MaterialX Graph Editor with procedural marble example](https://github.com/AcademySoftwareFoundation/MaterialX/raw/main/documents/Images/MaterialXGraphEditor_Marble.png) + +## Building the MaterialX Graph Editor Select the `MATERIALX_BUILD_GRAPH_EDITOR` option in CMake to build the MaterialX Graph Editor. Installation will copy the **MaterialXGraphEditor** executable to a `/bin` directory within the selected install folder. -### Summary of Graph Editor Features +## Summary of Graph Editor Features -1. **Load Material**: Load a material document in the MTLX format. -2. **Save Material**: Save out a graph as a mterial document in MTLX format. -3. **New Material**: Clear all information to set up for the creation of a new material -4. **Node Property Editor**: View or edit properties of the selected node. -5. **Render View**: View the rendered material. +1. **`Load Material`**: Load a material document in the MTLX format. +2. **`Save Material`**: Save out a graph as a mterial document in MTLX format. +3. **`New Material`**: Clear all information to set up for the creation of a new material +4. **`Node Property Editor`**: View or edit properties of the selected node. +5. **`Render View`**: View the rendered material. -### Buttons +## Buttons -To display a new material and graph, click the `Load Material` button and and navigate to the [Example Materials](../../resources/Materials/Examples) folder, which contains a selection of materials in the MTLX format, and select a document to load. The Graph Editor will display the graph hierarchy of the selected document for visualization and editing. +To display a new material and graph, click the `Load Material` button and and navigate to the [Materials/Examples](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples) folder, which contains a selection of materials in the MTLX format, and select a document to load. The Graph Editor will display the graph hierarchy of the selected document for visualization and editing. To save out changes to the graphs as MTLX files click the `Save Material` button. This will save the position of the nodes in the graph for future use as well. -### Editor Window +## Editor Window The MaterialX document is displayed as nodes in the Editor window. When a file is intially loaded the material node, surface shader node, and any enclosing nodegraphs will be displayed. Double-clicking on a nodegraph, or any node defined as a subgraph, will display the contents of that graph. @@ -40,19 +41,19 @@ Another type of node present in the `Add Node` pop-up is the group, or backgroun To search the editor window for a specific node use `CTRL` + `F` to bring up the search bar. -### Node Property Editor +## Node Property Editor When a node is selected in the graph, its information is displayed on the left-hand column in the `Node Property Editor`. This editor displays the name of the node, its category, its inputs, the input name, types and values. Inputs that are connected to other nodes will not display a value. This is where a node's properties such as its name and input values can be adjusted. When an input value is changed the material is automatically updated to reflect that change. The node info button displays the `doc` string for the selected node and its inputs if they exist. This `doc` string is currently read only. The show All Inputs checkbox displays all possible inputs for a node. With the box unchecked only inputs that have a connection or have had a value set will be shown. Only these inputs will be saved out when the graph is saved. -### Render View +## Render View Above the `Node Property Editor`, the `Render View` displays the current material on the Arnold Shader Ball. If inside a subgraph it will display the material associated with that subgraph; otherwise it will display the output of the selected node. It automatically updates when any changes are made to the graph. To adjust the relative sizes of the Node Property Editor and Render View windows, drag the separator between these windows in the application. The render view window camera can be changed using the left or right mouse buttons to manipulate the shader ball. -### Keyboard Shortcuts +## Keyboard Shortcuts - `TAB`: Add Node Popup - `Right Click`: pan along the editor @@ -66,7 +67,7 @@ To adjust the relative sizes of the Node Property Editor and Render View windows - `+` : Zoom in with the camera when mouse is over the Render View Window. - `-` : Zoom out with the camera when mouse is over the Render View Window. -### Command-Line Options +## Command-Line Options The following are common command-line options for MaterialXGraphEditor, and a complete list can be displayed with the `--help` option. - `--material [FILENAME]` : Specify the filename of the MTLX document to be displayed in the graph editor @@ -75,7 +76,7 @@ The following are common command-line options for MaterialXGraphEditor, and a co - `--library [FILEPATH]` : Specify an additional data library folder (e.g. 'vendorlib', 'studiolib'). This relative path will be appended to each location in the data search path when loading data libraries. - `--captureFilename [FILENAME]` : Specify the filename to which the first rendered frame should be written -### Known Limitations +## Known Limitations - Creating new connections using the `channels` attribute of an input is not yet supported, though existing `channels` connections will be displayed in graphs. - Assigning a new `colorspace` attribute to an input is not yet supported, though existing `colorspace` attributes on inputs will be respected by the render view. diff --git a/documents/DeveloperGuide/MainPage.md b/documents/DeveloperGuide/MainPage.md index 9cf0a0d8e0..155c58eb4d 100644 --- a/documents/DeveloperGuide/MainPage.md +++ b/documents/DeveloperGuide/MainPage.md @@ -2,14 +2,14 @@ MaterialX is an open standard for representing rich material and look-development content in computer graphics, enabling its platform-independent description and exchange across applications and renderers. Launched at [Industrial Light & Magic](https://www.ilm.com/) in 2012, MaterialX has been a key technology in their feature films and real-time experiences since _Star Wars: The Force Awakens_ and _Millennium Falcon: Smugglers Run_. The project was released as open source in 2017, with companies including Sony Pictures Imageworks, Pixar, Autodesk, Adobe, and SideFX contributing to its ongoing development. In 2021, MaterialX became the seventh hosted project of the [Academy Software Foundation](https://www.aswf.io/). -### Quick Start for Developers +## Quick Start for Developers - Download the latest version of the [CMake](https://cmake.org/) build system. - Point CMake to the root of the MaterialX library and generate C++ projects for your platform and compiler. - Select the `MATERIALX_BUILD_PYTHON` option to build Python bindings. - Select the `MATERIALX_BUILD_VIEWER` option to build the MaterialX viewer. -### Supported Platforms +## Supported Platforms The MaterialX codebase requires a compiler with support for C++17, and can be built with any of the following: @@ -19,9 +19,9 @@ The MaterialX codebase requires a compiler with support for C++17, and can be bu The Python bindings for MaterialX are based on [PyBind11](https://github.com/pybind/pybind11), and support Python versions 3.6 and greater. -### Building MaterialX +## Building MaterialX -#### Building MaterialX C++ +### Building MaterialX C++ The MaterialX C++ libraries are automatically included when building MaterialX through CMake. @@ -32,7 +32,7 @@ To enable OpenImageIO support in MaterialX builds, the following additional opti See the [MaterialX Unit Tests](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/source/MaterialXTest) page for documentation on shader generation and render testing in GLSL, OSL, and MDL. -#### Building MaterialX Python +### Building MaterialX Python By default, the `MATERIALX_BUILD_PYTHON` option will use the active version of Python in the developer's path. To select a specific version of Python, use one or more of the following advanced options: @@ -44,32 +44,32 @@ Additional options for the generation of MaterialX Python include the following: - `MATERIALX_PYTHON_OCIO_DIR`: Path to a folder containing the default OCIO configuration to be packaged with MaterialX Python. The recommended OpenColorIO configuration for MaterialX is [ACES 1.2](https://github.com/colour-science/OpenColorIO-Configs/tree/feature/aces-1.2-config/aces_1.2). - `MATERIALX_PYTHON_PYBIND11_DIR`: Path to a folder containing the PyBind11 source to be used in building MaterialX Python. Defaults to the included PyBind11 source. -#### Building The MaterialX Viewer +### Building The MaterialX Viewer -Select the `MATERIALX_BUILD_VIEWER` option to build the MaterialX Viewer. Installation will copy the **MaterialXView** executable to a `bin/` directory within the selected install folder. +Select the `MATERIALX_BUILD_VIEWER` option to build the MaterialX Viewer. Installation will copy the `MaterialXView` executable to a `bin/` directory within the selected install folder. -#### Building API Documentation +### Building API Documentation To generate HTML documentation for the MaterialX C++ API, make sure a version of [Doxygen](https://www.doxygen.org/) is on your path, and select the advanced option `MATERIALX_BUILD_DOCS` in CMake. This option will add a target named `MaterialXDocs` to your project, which can be built as an independent step from your development environment. -### Installing MaterialX +## Installing MaterialX Building the `install` target of your project will install the MaterialX C++ and Python libraries to the folder specified by the `CMAKE_INSTALL_PREFIX` setting, and will install MaterialX Python as a third-party library in your Python environment. Installation of MaterialX Python as a third-party library can be disabled by setting `MATERIALX_INSTALL_PYTHON` to `OFF`. -### MaterialX Versioning +## MaterialX Versioning -The MaterialX codebase uses a modified semantic versioning system where the *major* and *minor* versions match that of the corresponding MaterialX [specification](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/documents/Specification/MaterialX.Specification.md), and the *build* version represents engineering advances within that specification version. MaterialX documents are similarly marked with the specification version they were authored in, and they are valid to load into any MaterialX codebase with an equal or higher specification version. +The MaterialX codebase uses a modified semantic versioning system where the *major* and *minor* versions match that of the corresponding [MaterialX Specification](https://materialx.org/Specification.html), and the *build* version represents engineering advances within that specification version. MaterialX documents are similarly marked with the specification version they were authored in, and they are valid to load into any MaterialX codebase with an equal or higher specification version. -Upgrading of MaterialX documents from earlier versions is handled at import time by the `Document::upgradeVersion` method, which applies the syntax and node interface upgrades that have occurred in previous specification revisions. This allows the syntax conventions of MaterialX and the names and interfaces of nodes to evolve over time, without invalidating documents from earlier versions. +Upgrading of MaterialX documents from earlier versions is handled at import time by the `Document::upgradeVersion()` method, which applies the syntax and node interface upgrades that have occurred in previous specification revisions. This allows the syntax conventions of MaterialX and the names and interfaces of nodes to evolve over time, without invalidating documents from earlier versions. -#### MaterialX API Changes +### MaterialX API Changes The following rules describe the categories of changes to the [MaterialX API](https://materialx.org/docs/api/classes.html) that are allowed in version upgrades: - In *build* version upgrades, only non-breaking changes to the MaterialX API are allowed. For any API call that is modified in a build version upgrade, backwards compatibility should be maintained using deprecated C++ and Python wrappers for the original API call. - In *minor* and *major* version upgrades, breaking changes to the MaterialX API are allowed, though their benefit should be carefully weighed against their cost. Any breaking changes to API calls should be highlighted in the release notes for the new version. -#### MaterialX Data Library Changes +### MaterialX Data Library Changes The following rules describe the categories of changes to the [MaterialX Data Libraries](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/libraries) that are allowed in version upgrades: @@ -77,7 +77,7 @@ The following rules describe the categories of changes to the [MaterialX Data Li - In *minor* version upgrades, changes to the names and interfaces of MaterialX nodes are allowed, with the requirement that version upgrade logic be used to maintain the validity and visual interpretation of documents from earlier versions. - In *major* version upgrades, changes to the syntax rules of MaterialX documents are allowed, with the requirement that version upgrade logic be used to maintain the validity and visual interpretation of documents from earlier versions. These changes usually require synchronized updates to both the MaterialX API and data libraries. -### Additional Links +## Additional Links - The main [MaterialX website](http://www.materialx.org) provides background on the project's history, industry collaborations, and recent presentations. - The [Python Scripts](https://github.com/materialx/MaterialX/tree/main/python/Scripts) folder contains standalone examples of MaterialX Python code. diff --git a/documents/DeveloperGuide/ShaderGeneration.md b/documents/DeveloperGuide/ShaderGeneration.md index 01bd823ec4..594715fb39 100644 --- a/documents/DeveloperGuide/ShaderGeneration.md +++ b/documents/DeveloperGuide/ShaderGeneration.md @@ -1,13 +1,13 @@ # Shader Generation ## 1.1 Scope -A shader generation framework is implemented as part of MaterialX. This can help applications to transform the agnostic MaterialX data description into executable shader code for a specific renderer. A library module named MaterialXGenShader contains the core shader generation features, and support for specific languages resides in separate libraries, e.g. [MaterialXGenGlsl](/source/MaterialXGenGlsl), [MaterialXGenOsl](/source/MaterialXGenOsl). +A shader generation framework is implemented as part of MaterialX. This can help applications to transform the agnostic MaterialX data description into executable shader code for a specific renderer. A library module named MaterialXGenShader contains the core shader generation features, and support for specific languages resides in separate libraries, e.g. [MaterialXGenGlsl](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/source/MaterialXGenGlsl), [MaterialXGenOsl](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/source/MaterialXGenOsl). Note that this system has no runtime and the output produced is source code, not binary executable code. The source code produced needs to be compiled by a shading language compiler before being executed by the renderer. See Figure 1 for a high level overview of the system. -![Shader generation with multiple shader generators](/documents/Images/shadergen.png) +![Shader generation with multiple shader generators](https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/documents/Images/shadergen.png) -**Figure 1**: Shader generation with multiple shader generators. +**Figure 1:** Shader generation with multiple shader generators. ## 1.2 Languages and Shader Generators The MaterialX description is free from device specific details and all implementation details needs to be taken care of by shader generators. There is one shader generator for each supported shading language. However for each language there can also be variations needed for different renderers. For example; OpenGL renderers supporting GLSL can use forward rendering or deferred rendering, each with very different requirements for how the shaders are constructed. Another example is different renderers supporting OSL but with different sets of closures or closure parameters. Hence a separate shader generator can be defined for each language/target combination. @@ -28,11 +28,11 @@ In the following sub-sections each of these methods are explained. For all metho ### 1.3.1 Inline Expression Provided code generators support a very simple expression language for inlining code. This is useful for simple nodes where the operation can be expressed as a single line of code. Inlining will reduce the number of function calls and produce more compact code. The syntax to use is the same as the target shading language, with the addition of using the node’s input ports as variables wrapped in double curly brackets: `{{input}}`. The code generator will replace these variables with values assigned or connected to the respective inputs. Figure 2 gives an example. -Connecting the expression to the nodedef is done using an `` element as seen in +Connecting the expression to the `nodedef` is done using an `` element as seen in Figure 2. The first option is to keep inline code in a file. The file extension is used to differentiate inline expressions from source code functions, using `filename.inline`. The second option is to directly embed the inlined code using `sourcecode`. This is the recommended approach for inlining if there the logic can fit on one line of code. ```xml -// Nodedef elements for node + @@ -43,14 +43,14 @@ Figure 2. The first option is to keep inline code in a file. The file extension -<... more types ...> + -// Implementation elements for node + -<... more types ...> + -// Nodedef elements for node + @@ -63,26 +63,26 @@ Figure 2. The first option is to keep inline code in a file. The file extension -<... more types ...> + -// Implementation elements for node + -<... more types ...> + ``` ```c++ // File 'mx_add.inline' contains: {{in1}} + {{in2}} ``` -**Figure 2**: Inline expressions for implementing nodes `` and ``. The code for `` is stored in an additional file, while the code for `` is specified as part of the +**Figure 2:** Inline expressions for implementing nodes `` and ``. The code for `` is stored in an additional file, while the code for `` is specified as part of the `` declaration. ### 1.3.2 Shading Language Function -For nodes that can’t be implemented by inline expressions a function definition can be used instead. The function signature should match the nodedefs interface with inputs and outputs. See Figure 3 for an example. Connecting the source code to the nodedef is done using an `` element, see the [MaterialX specification](../Specification/MaterialX.v1.36.Spec.pdf) for more information. +For nodes that can’t be implemented by inline expressions a function definition can be used instead. The function signature should match the nodedefs interface with inputs and outputs. See Figure 3 for an example. Connecting the source code to the nodedef is done using an `` element, see the [MaterialX Specification](https://materialx.org/Specification.html) for more information. ```xml -// Nodedef element + @@ -97,7 +97,7 @@ For nodes that can’t be implemented by inline expressions a function definitio -// Implementation element + ``` ```c++ @@ -115,7 +115,7 @@ void mx_image_color3(string file, string layer, color defaultvalue, "wrap", uaddressmode); } ``` -**Figure 3**: Shading language function's implementation for node `` in OSL. +**Figure 3:** Shading language function's implementation for node `` in OSL. ### 1.3.3 Node Graph Implementation As an alternative to defining source code, there is also an option to reference a nodegraph as the implementation of a nodedef. The only requirement is that the nodegraph and nodedef have matching inputs and outputs. @@ -147,7 +147,7 @@ This is useful for creating a compound for a set of nodes performing some common ``` -**Figure 4**: Checker node implementation using a nodegraph. +**Figure 4:** Checker node implementation using a nodegraph. ### 1.3.4 Dynamic Code Generation In some situations static source code is not enough to implement a node. The code might need to be customized depending on parameters set on the node. Or for a hardware render target vertex streams or uniform inputs might need to be created in order to supply the data needed for the node implementation. @@ -192,7 +192,7 @@ OslShaderGenerator::OslShaderGenerator() : ... } ``` -**Figure 5**: C++ class for dynamic code generation. +**Figure 5:** C++ class for dynamic code generation. ## 1.4 Shader Generation Steps This section outlines the steps taken in general to produce a shader from the MaterialX description. The `ShaderGenerator` base class and its supporting classes will handle this for you, but it’s good to know the steps involved if custom changes are needed to support a new target. @@ -305,7 +305,7 @@ class TexCoordGlsl : public ShaderNodeImpl } }; ``` -**Figure 6**: Implementation of node `texcoord` in GLSL. Using a `ShaderNodeImpl` sub-class in order to control shader variable creation and code generation into separate shader stages. +**Figure 6:** Implementation of node `texcoord` in GLSL. Using a `ShaderNodeImpl` sub-class in order to control shader variable creation and code generation into separate shader stages. ### 1.6.2 Variable Naming Convention @@ -353,4 +353,4 @@ Uniform variables | u_lightData[] | struct | Array of struct LightData holding parameters for active light sources. The `LightData` struct is built dynamically depending on requirements for bound light shaders. | | u_\UnitTarget[] | integer | An attribute indicating the target unit for a given unit type definition (\). | -**Figure 7** : Listing of predefined variables with their binding rules. +**Figure 7:** Listing of predefined variables with their binding rules. diff --git a/documents/DeveloperGuide/Viewer.md b/documents/DeveloperGuide/Viewer.md index 1d3a1d7dcf..388132ff47 100644 --- a/documents/DeveloperGuide/Viewer.md +++ b/documents/DeveloperGuide/Viewer.md @@ -2,60 +2,72 @@ The MaterialX Viewer leverages shader generation to build GLSL shaders from MaterialX graphs, rendering the results using the NanoGUI framework. The standard set of pattern and physically based shading nodes is supported, and libraries of custom nodes can be included as additional library paths. -### Example Images +## Example Images **Figure 1:** Procedural and uniform materials in the MaterialX viewer

- - - - + + + +

**Figure 2:** Textured, color-space-managed materials in the MaterialX viewer

- - + +

## Building The MaterialX Viewer Select the `MATERIALX_BUILD_VIEWER` option in CMake to build the MaterialX Viewer. Installation will copy the **MaterialXView** executable to a `/bin` directory within the selected install folder. -### Summary of Viewer Options +## Summary of Viewer Options -1. **Load Mesh**: Load a new geometry in the OBJ or glTF format. -2. **Load Material**: Load a material document in the MTLX format. -3. **Load Environment**: Load a lat-long environment light in the HDR format. -4. **Property Editor**: View or edit properties of the current material. -5. **Advanced Settings** : Asset and rendering options. +1. **`Load Mesh`**: Load a new geometry in the OBJ or glTF format. +2. **`Load Material`**: Load a material document in the MTLX format. +3. **`Load Environment`**: Load a lat-long environment light in the HDR format. +4. **`Property Editor`**: View or edit properties of the current material. +5. **`Advanced Settings`** : Asset and rendering options. -### Geometry +## Geometry -The default display geometry for the MaterialX viewer is the Arnold Shader Ball, which was contributed to the MaterialX project by the Solid Angle team at Autodesk. To change the display geometry, click `Load Mesh` and navigate to the [Geometry](../../resources/Geometry) folder for additional models in the OBJ format. +The default display geometry for the MaterialX viewer is the Arnold Shader Ball, which was contributed to the MaterialX project by the Solid Angle team at Autodesk. To change the display geometry, click `Load Mesh` and navigate to the [Geometry](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Geometry) folder for additional models in the OBJ format. If a loaded geometry contains more than one geometric group, then a `Select Geometry` drop-down box will appear, allowing the user to select which group is active. The active geometric group will be used for subsequent actions such as material assignment and rendering property changes. -### Materials +## Materials -To change the displayed material, click `Load Material` and navigate to the [Materials/Examples/StandardSurface](../../resources/Materials/Examples/StandardSurface) or [Materials/Examples/UsdPreviewSurface](../../resources/Materials/Examples/UsdPreviewSurface) folders, which contain a selection of example materials in the MTLX format. +To change the displayed material, click `Load Material` and navigate to the [Materials/Examples/StandardSurface](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples/StandardSurface) or [Materials/Examples/UsdPreviewSurface](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples/UsdPreviewSurface) folders, which contain a selection of example materials in the MTLX format. Once a material is loaded into the viewer, its parameters may be inspected and adjusted by clicking the `Property Editor` and scrolling through the list of parameters. An edited material may be saved to the file system by clicking `Save Material`. Multiple material documents can be combined in a single session by navigating to `Advanced Settings` and enabling `Merge Materials`. Loading new materials with this setting enabled will add them to the current material list, where they can be assigned to geometry via the `Assigned Material` drop-down box. Alternatively the `LEFT` and `RIGHT` arrows can be used to cycle through the list of available materials. -If a material document containing `look` elements is loaded into the viewer, then any material assignments within the look will be applied to geometric groups that match the specified geometry strings. See [standard_surface_look_brass_tiled.mtlx](../../resources/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx) for an example of a material document containing look elements. +If a material document containing `look` elements is loaded into the viewer, then any material assignments within the look will be applied to geometric groups that match the specified geometry strings. See [standard_surface_look_brass_tiled.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx) for an example of a material document containing look elements. -### Lighting +## Lighting -The default lighting environment for the viewer is the San Giuseppe Bridge environment from HDRI Haven. To load another environment into the viewer, click `Load Environment` and navigate to the [Lights](../../resources/Lights) folder, or load any HDR environment in the latitude-longitude format. If the HDR file on disk has a companion MaterialX document with a matching name, then this document will be loaded as the direct lighting rig for the environment; otherwise only indirect lighting will be rendered. If the HDR file on disk has a companion image in an `irradiance` subfolder, then this image will be loaded as the diffuse convolution of the environment; otherwise, a diffuse convolution will be generated at load-time using spherical harmonics. +The default lighting environment for the viewer is the San Giuseppe Bridge environment from HDRI Haven. To load another environment into the viewer, click `Load Environment` and navigate to the [Lights](https://github.com/AcademySoftwareFoundation/MaterialX/tree/main/resources/Lights) folder, or load any HDR environment in the latitude-longitude format. If the HDR file on disk has a companion MaterialX document with a matching name, then this document will be loaded as the direct lighting rig for the environment; otherwise only indirect lighting will be rendered. If the HDR file on disk has a companion image in an `irradiance` subfolder, then this image will be loaded as the diffuse convolution of the environment; otherwise, a diffuse convolution will be generated at load-time using spherical harmonics. Shadow maps from the primary directional light may be enabled with the `Shadow Map` option under `Advanced Settings`. Ambient occlusion, if available for the given geometry, may be enabled with the `Ambient Occlusion` option. The fidelity of environment lighting may be improved by increasing the value of `Environment Samples`, though this requires additional GPU resources and can affect the interactivity of the viewer. -### Images +## Images By default, the MaterialX viewer loads and saves image files using `stb_image`, which supports commmon 8-bit formats such as JPEG, PNG, TGA, and BMP, as well as the HDR format for high-dynamic-range images. If you need access to additional image formats such as EXR and TIFF, then the MaterialX viewer can be built with support for `OpenImageIO`. To build MaterialX with OpenImageIO, check the `MATERIALX_BUILD_OIIO` option in CMake, and specify the location of your OpenImageIO installation with the `MATERIALX_OIIO_DIR` option. -### Keyboard Shortcuts +## Keyboard Shortcuts - `R`: Reload the current material from file. Hold `SHIFT` to reload all standard libraries as well. - `G`: Save the current GLSL shader source to file. @@ -74,7 +86,7 @@ By default, the MaterialX viewer loads and saves image files using `stb_image`, - `+` : Zoom in with the camera. - `-` : Zoom out with the camera. -### Command-Line Options +## Command-Line Options The following are common command-line options for MaterialXView, and a complete list can be displayed with the `--help` option. - `--material [FILENAME]` : Specify the filename of the MTLX document to be displayed in the viewer diff --git a/documents/Specification/MaterialX.PBRSpec.md b/documents/Specification/MaterialX.PBRSpec.md index 32cef574c6..67fecd80b3 100644 --- a/documents/Specification/MaterialX.PBRSpec.md +++ b/documents/Specification/MaterialX.PBRSpec.md @@ -43,6 +43,8 @@ This document describes a number of shader-semantic nodes implementing widely-us **[Shading Model Examples](#shading-model-examples)**  [Autodesk Standard Surface](#autodesk-standard-surface)  [UsdPreviewSurface](#usdpreviewsurface) + [Khronos glTF PBR](#khronos-gltf-pbr) + [OpenPBR Surface](#openpbr-surface) **[References](#references)** @@ -241,6 +243,21 @@ The PBS nodes also make use of the following standard MaterialX types: * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. * `mode` (uniform string): Selects between `conty_kulla` and `zeltner` sheen models. Defaults to `conty_kulla`. + + +* **`chiang_hair_bsdf`**: Constructs a hair BSDF based on the Chiang hair shading model[^Chiang2016]. This node does not support vertical layering. + * `tint_R` (color3): Color multiplier for the first R-lobe. Defaults to (1.0, 1.0, 1.0). + * `tint_TT` (color3): Color multiplier for the first TT-lobe. Defaults to (1.0, 1.0, 1.0). + * `tint_TRT` (color3): Color multiplier for the first TRT-lobe. Defaults to (1.0, 1.0, 1.0). + * `ior` (float): Index of refraction. Defaults to 1.55 being the value for keratin. + * `roughness_R` (vector2): Longitudinal and azimuthal roughness (ν, s) for the first R-lobe, range [0.0, ∞). With (0, 0) specifying pure specular scattering. Defaults to (0.1, 0.1). + * `roughness_TT` (vector2): Longitudinal and azimuthal roughness (ν, s) for the first TT-lobe, range [0.0, ∞). With (0, 0) specifying pure specular scattering. Defaults to (0.05, 0.05). + * `roughness_TRT` (vector2): Longitudinal and azimuthal roughness (ν, s) for the first TRT-lobe, range [0.0, ∞). With (0, 0) specifying pure specular scattering. Defaults to (0.2, 0.2). + * `cuticle_angle` (float): Cuticle angle in radians, Values above 0.5 tilt the scales towards the root of the fiber, range [0.0, 1.0]. With 0.5 specifying no tilt. Defaults to 0.5. + * `absorption_coefficient` (vector3): Absorption coefficient normalized to the hair fiber diameter. Defaults to (0.0, 0.0, 0.0). + * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. + * `curve_direction` (vector3): Direction of the hair geometry. Defaults to world space tangent. + ## EDF Nodes @@ -372,6 +389,27 @@ Note that the standard library includes definitions for [**`displacement`**](./M * `ior` (**output**, vector3): Computed index of refraction. * `extinction` (**output**, vector3): Computed extinction coefficient. + + +* **`chiang_hair_roughness`**: Converts the artistic parameterization hair roughness to roughness for R, TT and TRT lobes, as described in [^Chiang2016]. Output type `multioutput`, `roughness_R`, `roughness_TT` and `roughness_TRT`, `vector2` type. + * `longitudinal` (float): Longitudinal roughness, range [0.0, 1.0]. Defaults to 0.1. + * `azimuthal` (float): Azimuthal roughness, range [0.0, 1.0]. Defaults to 0.2. + * `scale_TT` (float): Roughness scale for TT lobe. Defaults to 0.5[^Marschner2003]. + * `scale_TRT` (float): Roughness scale for TRT lobe. Defaults to 2.0[^Marschner2003]. + + + +* **`deon_hair_absorption_from_melanin`** : Converts the hair melanin parameterization to absorption coefficient based on pigments eumelanin and pheomelanin using the mapping method described in [^d'Eon2011]. The default of `eumelanin_color` and `pheomelanin_color` are `lin_rec709` color converted from the constants[^d'Eon2011] via `exp(-c)`. They may be transformed to scene-linear rendering color space. `Output type `vector3`. + * `melanin_concentration` (float): Amount of melanin affected to the output, range [0.0, 1.0]. Defaults to 0.25. + * `melanin_redness` (float): Amount of redness affected to the output, range [0.0, 1.0]. Defaults to 0.5. + * `eumelanin_color` (color3): Eumelanin color. Defaults to (0.657704, 0.498077, 0.254107) + * `pheomelanin_color` (color3): Pheomelanin color. Defaults to (0.829444, 0.67032, 0.349938) + + + +* **`chiang_hair_absorption_from_color`** : Coverts the hair scattering color to absorption coefficient using the mapping method described in [^Chiang2016]. Output type `vector3`. + * `color` (color3): Scattering color. Defaults to (1.0, 1.0, 1.0). + * `azimuthal_roughness` (float): Azimuthal roughness, range [0.0, 1.0]. Defaults to 0.2. # Shading Model Examples @@ -379,6 +417,14 @@ Note that the standard library includes definitions for [**`displacement`**](./M This section contains examples of shading model implementations using the MaterialX PBS library. For all examples, the shading model is defined via a <nodedef> interface plus a nodegraph implementation. The resulting nodes can be used as shaders by a MaterialX material definition. +## Disney Principled BSDF + +This shading model was presented by Brent Burley from Walt Disney Animation Studios in 2012[^Burley2012], with additional refinements presented in 2015[^Burley2015]. + +A MaterialX definition and nodegraph implementation of the Disney Principled BSDF can be found here: +[https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/disney_principled.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/disney_principled.mtlx) + + ## Autodesk Standard Surface This is a surface shading model used in Autodesk products created by the Solid Angle team for the Arnold renderer. It is an über shader built from ten different BSDF layers[^Georgiev2019]. @@ -428,16 +474,25 @@ The MaterialX PBS Library includes a number of nodegraphs that can be used to ap [^Burley2012]: Brent Burley, **Physically-Based Shading at Disney**, , 2012 +[^Burley2015]: Brent Burley, **Extending the Disney BRDF to a BSDF with Integrated Subsurface Scattering**, , 2015 + +[^Chiang2016]: Matt Jen-Yuan Chiang et al., **A Practical and Controllable Hair and Fur Model for Production +Path Tracing**, , 2016 + [^Christensen2015]: Per H. Christensen, Brent Burley, **Approximate Reflectance Profiles for Efficient Subsurface Scattering**, 2015 [^Conty2017]: Alejandro Conty, Christopher Kulla, **Production Friendly Microfacet Sheen BRDF**, , 2017 +[^d'Eon2011]: Eugene d'Eon et al., **An Energy-Conserving Hair Reflectance Model**, , 2011 + [^Georgiev2019]: Iliyan Georgiev et al., **Autodesk Standard Surface**, , 2019. [^Gulbrandsen2014]: Ole Gulbrandsen, **Artist Friendly Metallic Fresnel**, , 2014 [^Hoffman2023]: Naty Hoffman, **Generalization of Adobe's Fresnel Model**, 2023 +[^Marschner2003]: Stephen R. Marschner et al., **Light Scattering from Human Hair Fibers**, , 2003 + [^Oren1994]: Michael Oren, Shree K. Nayar, **Generalization of Lambert’s Reflectance Model**, , 1994 [^Pharr2023]: Matt Pharr et al., **Physically Based Rendering: From Theory To Implementation**, , 2023 diff --git a/documents/Specification/MaterialX.Proposals.md b/documents/Specification/MaterialX.Proposals.md new file mode 100644 index 0000000000..d387d28718 --- /dev/null +++ b/documents/Specification/MaterialX.Proposals.md @@ -0,0 +1,350 @@ + + + +# MaterialX: Proposed Additions and Changes + +**Proposals for Version 1.39** +September 15, 2024 + + +# Introduction + +The [MaterialX Specification](./MaterialX.Specification.md) has historically included descriptions of not just current functionality, but also forward-looking proposed functionality intended for eventual implementation. We believe it will be beneficial to provide clarity on which functionality is currently supported in the library, and which sections document proposed additions. + +As such, those forward-looking proposals have been moved from the formal Specification documents into this Proposed Additions and Changes document to be discussed and debated. These descriptions can then be migrated into the appropriate formal Specification document once actually implemented in the code base. New proposals for changes and additions to MaterialX may be added to this document once a generally favorable consensus from the community is reached. + + + +## Table of Contents + +**[Introduction](#introduction)** + +**[Proposals: General](#propose-general)** + +**[Proposals: Elements](#propose-elements)** + +**[Proposals: Stdlib Nodes](#propose-stdlib-nodes)** + +**[Proposals: PBR Nodes](#propose-pbr-nodes)** + +**[Proposals: NPR Nodes](#propose-npr-nodes)** + + +

 


+ +# Proposals: General + + +## Color Spaces + +When the OCIO NanoColor library (provide link) becomes available, MaterialX should support the official colorspace names in that spec, with the current MaterialX colorspace names supported as aliases. + +MaterialX should also support the following color spaces: +* `lin_rec2020` +* `g22_rec2020` + + + +

 


+ +# Proposals: Elements + + +### AOV Output Elements + +A functional nodegraph with either a "shader" or "material"-semantic output type may contain a number of <aovoutput> elements to declare arbitrary output variables ("AOVs") which the renderer can see and output as additional streams of information. AOVoutputs must be of type float, color3 or vector3 for pre-shading "pattern" values, or BSDF or EDF for shader-node output values; the renderer is expected to extract the appropriate color-like information from BSDF and EDF types. AOVs defined within a shader-semantic node instantiated within this functional nodegraph may be "passed along" and potentially renamed (but may not be modified or operated on in any way) by providing a sourceaov attribute in the <aovoutput>. + +```xml + +``` + +The attributes for <aovoutput> elements are: + +* name (string, required): a user-chosen name for this aov output definition element. +* type (string, required): the type of the AOV, which must be one of the supported types listed above. +* aovname (string, required): the name that the renderer should use for the AOV. +* nodename (string, required): the name of the node whose output defines the AOV value. +* sourceaov (string, optional): If nodename is a surfaceshader type, the name of the output AOV defined within nodename to pass along as the output AOV. The type of the sourceaov defined within nodename must match the <aovoutput> type. + +Examples: + +```xml + + + nodename="diffuse_bsdf"/> +``` + +#### AovOutput Example + +Example of using <aovoutput> with sourceaov to forward AOVs from within an instantiation of a shader-semantic node; this assumes that <standard_surface> has itself defined <aovoutput>s for "diffuse" and "specular" AOVs: + +```xml + + + + + + + + + + + + + + + + + + + + + +``` + +Layered shaders or materials must internally handle blending of AOV-like values from source layers before outputting them as AOVs: there is currently no facility for blending AOVs defined within post-shading blended surfaceshaders. + +Note: while it is syntactically possible to create <aovoutput>s for geometric primitive values such as shading surface point and normal accessed within a nodegraph, it is preferred that renderers derive such information directly from their internal shading state or geometric primvars. + + + +#### Implementation AOV Elements + +An <implementation> element with a file attribute defining an external compiled implementation of a surface shader may contain one or more <aov> elements to declare the names and types of arbitrary output variables ("AOVs") which the shader can output to the renderer. AOVs must be of type float, color3, vector3, BSDF or EDF. Note that in MaterialX, AOVs for pre-shading "pattern" colors are normally of type color3, while post-shaded color-like values are normally of type BSDF and emissive color-like values are normally of type EDF. An <implementation> with a `nodegraph` attribute may not contain <aov> elements; instead, <aovoutput> elements within the nodegraph should be used. + +```xml + + ...... + + + +``` + + + +### Material Inheritance + +Materials can inherit from other materials, to add or change shaders connected to different inputs; in this example, a displacement shader is added to the above "Mgold" material to create a new "Mgolddsp" material: + +```xml + + + + + + + + + + + +``` + +Inheritance of material-type custom nodes is also allowed, so that new or changed input values can be applied on top of those specified in the inherited material. + + +

 


+ +# Proposals: Stdlib Nodes + + +### Procedural Nodes + + + +* **`tokenvalue`**: a constant "interface token" value, may only be connected to <token>s in nodes, not to <input>s. + * `value` (any uniform non-shader-semantic type): the token value to output; "enum" and "enumvalues" attributes may be provided to define a specific set of allowed token values. + + + +### Noise Nodes + + + +We have a standard 3d fractal noise, but a 2d variant would be useful as well. + +* **`fractal2d`**: Zero-centered 2D Fractal noise in 1, 2, 3 or 4 channels, created by summing several octaves of 2D Perlin noise, increasing the frequency and decreasing the amplitude at each octave. + * `amplitude` (float or vectorN): the center-to-peak amplitude of the noise (peak-to-peak amplitude is 2x this value). Default is 1.0. + * `octaves` (integer): the number of octaves of noise to be summed. Default is 3. + * `lacunarity` (float or vectorN): the exponential scale between successive octaves of noise; must be an integer value if period is non-zero so the result is properly tileable. VectorN-output types can provide either a float (isotropic) or vectorN (anisotropic) values for lacunarity and diminish. Default is 2.0. + * `diminish` (float or vectorN): the rate at which noise amplitude is diminished for each octave. Should be between 0.0 and 1.0; default is 0.5. VectorN-output types can provide either a float (isotropic) or vectorN (anisotropic) values for lacunarity and diminish. + * `period` (float or vectorN): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. + * `texcoord` (vector2): the 2D texture coordinate at which the noise is evaluated. Default is to use the first set of texture coordinates. + + + +1D Cell noise was proposed an an alternative approach to random value generation. + +* **`cellnoise1d`**: 1D cellular noise, 1 or 3 channels (type float or vector3). + * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for input coordinate repeated at that step. Default is 0, meaning the noise is not periodic. + * `in` (float): the 1D coordinate at which the noise is evaluated. + + + +Expanded 2D Worley noise to support different distance metrics and periodicity. + +* **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). + * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". + * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. + + + +Expanded 3D Worley noise to support different distance metrics and periodicity. + +* **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). + * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". + * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. + +#### Periodic Noises + +In #1201 it was decided that separate periodic versions of all of the noises is preferred to adding it to the existing noises. + +### Shape Nodes + + + + +### Geometric Nodes + + + +* **`bump`**: Existing node, proposal to add a vector3 `bitangent` input + + + +* **`geompropvalueuniform`**: the value of the specified uniform geometric property (defined using <geompropdef>) of the currently-bound geometry. This node's type must match that of the referenced geomprop. + * `geomprop` (uniform string): the geometric property to be referenced. + * `default` (same type as the geomprop's value): a value to return if the specified `geomprop` is not defined on the current geometry. + +Note: when <geompropvalueuniform> is added, the text in the first paragraph of the Specification about Node Inputs should be revised to include "<geompropvalueuniform>" as an example of "or any other node whose output is explicitly declared to be uniform". + + +### Global Nodes + + + +* **`ambientocclusion`**: Compute the ambient occlusion at the current surface point, returning a scalar value between 0 and 1. Ambient occlusion represents the accessibility of each surface point to ambient lighting, with larger values representing greater accessibility to light. This node must be of type float. + * `coneangle` (float): the half-angle of a cone about the surface normal, within which geometric surface features are considered as potential occluders. The unit for this input is degrees, and its default value is 90.0 (full hemisphere). + * `maxdistance` (float): the maximum distance from the surface point at which geometric surface features are considered as potential occluders. Defaults to 1e38, e.g. "unlimited". + + + +### Application Nodes + + + +* **`updirection`**: the current scene "up vector" direction, as defined by the shading environment. This node must be of type vector3. + * `space` (uniform string): the space in which to return the up vector direction, defaults to "world". + + + +### Math Nodes + + + +* **`transformcolor`**: transform the incoming color from one specified colorspace to another, ignoring any colorspace declarations that may have been provided upstream. For color4 types, the alpha channel value is unaffected. + * `in` (color3 or color4): the input color. + * `fromspace` (uniform string): the name of a standard colorspace or a colorspace understood by the application to transform the `in` color from; may be empty (the default) to specify the document's working colorspace. + * `tospace` (uniform string): the name of a standard colorspace or a colorspace understood by the application to transform the `in` color to; may be empty (the default) to specify the document's working colorspace. + + + +* **`triplanarblend`** (NG): samples data from three inputs, and projects a tiled representation of the images along each of the three respective coordinate axes, computing a weighted blend of the three samples using the geometric normal. + * `inx` (float or colorN): the image to be projected in the direction from the +X axis back toward the origin. Default is 0 in all channels. + * `iny` (float or colorN): the image to be projected in the direction from the +Y axis back toward the origin with the +X axis to the right. Default is 0 in all channels. + * `inz` (float or colorN): the image to be projected in the direction from the +Z axis back toward the origin. Default is 0 in all channels. + * `position` (vector3): a spatially-varying input specifying the 3D position at which the projection is evaluated. Default is to use the current 3D object-space coordinate. + * `normal` (vector3): a spatially-varying input specifying the 3D normal vector used for blending. Default is to use the current object-space surface normal. + * `blend` (float): a 0-1 weighting factor for blending the three axis samples using the geometric normal, with higher values giving softer blending. Default is 1.0. + * `filtertype` (uniform string): the type of texture filtering to use; standard values include "closest" (nearest-neighbor single-sample), "linear", and "cubic". If not specified, an application may use its own default texture filtering method. + + + +### Adjustment Nodes + + + +* **`curveinversecubic`**: remap a 0-1 input float value using an inverse Catmull-Rom spline lookup on the input `knots` values. Outputs a 0-1 float interpolant value. + * `in` (float): the input value or nodename + * `knots` (uniform floatarray): the list of non-uniformly distributed input values defining the curve for the remapping. At least 2 values must be provided, and the first and last knot have multiplicity 2. + + + +* **`curveuniformlinear`**: output a float, colorN or vectorN value linearly interpolated between a number of `knotvalues` values, using the value of `in` as the interpolant. + * `in` (float): the input interpolant value or nodename + * `knotvalues` (uniform floatarray or colorNarray or vectorNarray): the array of at least 2 values to interpolate between. + + + +* **`curveuniformcubic`**: output a float, colorN or vectorN value smoothly interpolated between a number of `knotvalues` values using a Catmull-Rom spline with the value of `in` as the interpolant. + * `in` (float): the input interpolant value or nodename + * `knotvalues` (uniform floatarray or colorNarray or vectorNarray): the array of at least 2 values to interpolate between. + + + +* **`curveadjust`** (NG): output a smooth remapping of input values using the centripetal Catmull-Rom cubic spline curve defined by specified knot values, using an inverse spline lookup on input knot values and a forward spline through output knot values. All channels of the input will be remapped using the same curve. + * `in` (float or colorN or vectorN): the input value or nodename + * `numknots` (uniform integer): the number of values in the knots and knotvalues arrays + * `knots` (uniform floatarray): the list of input values defining the curve for the remapping. At least 2 and at most 16 values must be provided. + * `knotvalues` (uniform floatarray): the list of output values defining the curve for the remapping. Must be the same length as knots. + + + +* **`curvelookup`** (NG): output a float, colorN or vectorN value smoothly interpolated between a number of knotvalue values, using the position of in within knots as the knotvalues interpolant. + * `in` (float): the input interpolant value or nodename + * `numknots` (uniform integer): the number of values in the knots and knotvalues arrays + * `knots` (uniform floatarray): the list of knot values to interpolate in within. At least 2 and at most 16 values must be provided. + * `knotvalues` (uniform floatarray or colorNarray or vectorNarray): the values at each knot position to interpolate between. Must be the same length as knots. + + + +### Compositing Nodes + + + +### Conditional Nodes + + + +* **`ifelse`**: output the value of one of two input streams, according to whether the value of a boolean selector input is true or false + * `infalse`, `intrue` (float or colorN or vectorN): the values or nodenames to select from based on the value of the `which` input. The types of the various `inN` inputs must match the type of the `switch` node itself. The default value of all `inN` inputs is 0.0 in all channels. + * `which` (boolean): a selector to choose which input to take values from; default is "false". + + + +### Channel Nodes + + + +* **`extractrowvector`**: extract the specified row vector number from a matrixN stream. + * `in` (matrixN): the input value or nodename + * `index` (integer): the row number to extract, should be 0-2 for matrix33 streams, or 0-3 for matrix44 streams. + + + +* **`separatecolor4`** (NG): output the RGB and alpha channels of a color4 as separate outputs. + * `in` (color4): the input value or nodename + * `outcolor` (output, color3): the RGB channel values. + * `outa` (output, float): the value of the alpha channel. + + + +

 


+ +# Proposals: PBR Nodes + + + +

 


+ +# Proposals: NPR Nodes + diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index e6f4bae531..65027694d8 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -8,7 +8,7 @@ MaterialX Specification v1.39 **Version 1.39** Doug Smythe - Industrial Light & Magic Jonathan Stone - Lucasfilm Advanced Development Group -May 9, 2024 +September 15, 2024 # Introduction @@ -24,7 +24,7 @@ At least four distinct interrelated data relationships are required to specify t **MaterialX** addresses the need for an open, platform-independent, well-defined standard for specifying the "look" of computer graphics objects built using node networks by defining a material content schema along with a corresponding XML-based file format to read and write MaterialX content. The MaterialX schema defines a number of primary element types plus several supplemental and sub-element types, as well as a set of **standard nodes** with specific functionality for defining data-processing graphs, shaders and materials. -This document describes the core MaterialX specification. Companion documents [**MaterialX Physically Based Shading Nodes**](./MaterialX.PBRSpec.md), [**MaterialX Geometry Extensions**](./MaterialX.GeomExts.md) and [**MaterialX Supplemental Notes**](./MaterialX.Supplement.md) describe additional node and element types and other information about the library. +This document describes the core MaterialX specification. Companion documents [**MaterialX Physically Based Shading Nodes**](./MaterialX.PBRSpec.md), [**MaterialX Geometry Extensions**](./MaterialX.GeomExts.md) and [**MaterialX Supplemental Notes**](./MaterialX.Supplement.md) describe additional node and element types and other information about the library, while [**MaterialX: Proposed Additions and Changes**](./MaterialX.Proposals.md) describes forward-looking proposed funnctionality for MaterialX. @@ -56,7 +56,6 @@ This document describes the core MaterialX specification. Companion documents [   [Noise Nodes](#noise-nodes)   [Shape Nodes](#shape-nodes)   [Geometric Nodes](#geometric-nodes) -  [Global Nodes](#global-nodes)   [Application Nodes](#application-nodes)  [Standard Operator Nodes](#standard-operator-nodes) @@ -84,7 +83,6 @@ This document describes the core MaterialX specification. Companion documents [    [NodeDef Token Elements](#nodedef-token-elements)    [NodeDef Output Elements](#nodedef-output-elements)   [Custom Node Definition Using Implementation Elements](#custom-node-definition-using-implementation-elements) -   [Implementation AOV Elements](#implementation-aov-elements)    [Example Custom Nodes Defined by External File Implementations](#example-custom-nodes-defined-by-external-file-implementations)   [Custom Node Definition Using Node Graphs](#custom-node-definition-using-node-graphs)    [Functional Nodegraphs](#functional-nodegraphs) @@ -93,10 +91,7 @@ This document describes the core MaterialX specification. Companion documents [   [Custom Node Use](#custom-node-use)  [Shader Nodes](#shader-nodes)   [Standard Library Shader Nodes](#standard-library-shader-nodes) -  [AOV Output Elements](#aov-output-elements) -   [AOVOutput Example](#aovoutput-example)  [Material Nodes](#material-nodes) -  [Material Inheritance](#material-inheritance)   [Example Pre-Shader Compositing Material](#example-pre-shader-compositing-material)  [Material Variants](#material-variants) @@ -258,7 +253,7 @@ While colorN and vectorN types both describe vectors of floati ## Custom Data Types -In addition to the standard data types, MaterialX supports the specification of custom data types for the inputs and outputs of shaders and custom nodes. This allows documents to describe data streams of any complex type an application may require; examples might include spectral color samples or compound geometric data. +In addition to the standard data types, MaterialX supports the specification of custom data types for the inputs and outputs of shaders and custom nodes. This allows documents to describe data streams of any complex type an application may require; examples might include spectral color samples or compound geometric data. The structure of a custom type's contents may be described using a number of elements, though it is also permissible to only declare the custom type's name and treat the type as "blind data". Types can be declared to have a specific semantic, which can be used to determine how values of that type should be interpreted, and how nodes outputting that type can be connected. Currently, MaterialX defines three semantics: @@ -272,12 +267,15 @@ Custom types are defined using the <typedef> element: ```xml - + + + + ``` Attributes for <typedef> elements: -* `name` (string, required): the name of this type. Cannot be the same as a built-in MaterialX type. +* `name` (string, required): the name of this type. Cannot be the same as a built-in MaterialX type. To reduce the possible symbol conflict between custom type names and possible variable names created by code generation, we suggest the convention of using `_struct` as a suffix to the type name. * `semantic` (string, optional): the semantic for this type (see above); the default semantic is "default". * `context` (string, optional): a semantic-specific context in which this type should be applied. For "shader" semantic types, `context` defines the rendering context in which the shader output is interpreted; please see the [Shader Nodes](#shader-nodes) section for details. * `inherit` (string, optional): the name of another type that this type inherits from, which can be either a built-in type or a custom type. Applications that do not have a definition for this type can use the inherited type as a "fallback" type. @@ -285,6 +283,32 @@ Attributes for <typedef> elements: * "halfprecision": the values within this type are half-precision * "doubleprecision: the values within this type are double-precision +Attributes for <member> elements: + +* `name` (string, required): the name of the member variable. Must be unique within the list of other member names for this custom type. +* `type` (string, required): the type of the member variable; can be any built-in MaterialX type, or any previously defined custom type; recursive inclusion for <member> types is not supported. +* `value` (string, required): the default value of the member variable. + +If a number of elements are provided, then a MaterialX file can specify a value for that type any place it is used, as a brace surrounded, semicolon-separated list of numbers and strings, with the expectation that the numbers and strings between semicolons exactly line up with the expected types in order. The use of the braces allows for custom struct types initializers to be nested. For example, if the following was declared: + +```xml + + + + + + + +``` + +Then a permissible input declaration in a custom node using that type could be: + +```xml + +``` + +If child elements are not provided, e.g. if the contents of the custom type cannot be represented as a list of MaterialX types, then a value cannot be provided, and this type can only be used to pass blind data from one custom node's output to another custom node or shader input. + Once a custom type is defined by a <typedef>, it can then be used in any MaterialX element that allows "any MaterialX type"; the list of MaterialX types is effectively expanded to include the new custom type. It should be noted however that the <typedef> is only declaring the existence of the type and perhaps some hints about its intended definition, but it is up to each application and code generator to provide its own precise definition for any type. The standard MaterialX distribution includes definitions for four "shader"-semantic data types: **surfaceshader**, **displacementshader**, **volumeshader**, and **lightshader**. These types are discussed in more detail in the [Shader Nodes](#shader-nodes) section below. @@ -344,9 +368,9 @@ By default, MaterialX supports the following color spaces as defined in ACES 1.2 * `srgb_displayp3` * `lin_displayp3` -The working color space of a MaterialX document is defined by the `colorspace` attribute of its root <materialx> element, and it is strongly recommended that all <materialx> elements define a specific `colorspace` if they wish to use a color-managed workflow rather than relying on a default colorspace setting from an external configuration file. +The working color space of a MaterialX document is defined by the `colorspace` attribute of its root <materialx> element, and it is strongly recommended that all <materialx> elements define a specific `colorspace` if they wish to use a color-managed workflow rather than relying on a default color space setting from an external configuration file. If a MaterialX document is xi:included into another MaterialX document, it will inherit the working color space setting of the parent document, unless it itself declares a specific working color space. -The color space of individual color image files and values may be defined via a `colorspace` attribute in an input which defines a filename or value. Color images and values in spaces other than the working color space are expected to be transformed by the application into the working space before computations are performed. In the example below, an image file has been defined in the “srgb_texture” color space, while its default value has been defined in “lin_rec709”; both should be transformed to the application’s working color space before being applied to any computations. +The color space of individual color image files and values may be defined via a `colorspace` attribute in an input which defines a filename or value. Other elements, such as <nodegraph> or a node instance, are allowed to define a `colorspace` attribute that will apply to elements within their scope; color values in inputs and files that do not explicitly provide a `colorspace` attribute will be treated as if they are in the color space of the nearest enclosing scope which does define a `colorspace` attribute. Color images and values in spaces other than the working color space are expected to be transformed by the application into the working space before computations are performed. In the example below, an image file has been defined in the “srgb_texture” color space, while its default value has been defined in “lin_rec709”; both should be transformed to the application’s working color space before being applied to any computations. ```xml @@ -357,7 +381,7 @@ The color space of individual color image files and values may be defined via a ``` -MaterialX reserves the color space name "none" to mean no color space conversion should be applied to the images and color values within their scope. +MaterialX reserves the color space name "none" to mean no color space conversion should be applied to the images and color values within their scope, regardless of any differences between stated color spaces at the local scope and document or application working color space settings. @@ -579,7 +603,7 @@ MaterialX defines a number of Standard Nodes which all implementations should su ## Inputs -Node elements contain zero or more <input> elements defining the name, type, and value or connection for each node input. Input elements can assign an explicit uniform value by providing a `value` attribute, make a connection to the output of another node by providing a `nodename` attribute, or make a connection to the output of a nodegraph by providing a `nodegraph` attribute. An optional `output` attribute may also be provided for <input> elements, allowing the input to connect to a specific, named output of the referenced upstream node or nodegraph. If the referenced node/nodegraph has multiple outputs, `output` is required; if it has only one output, the `output` attribute of the <input> is ignored. Input elements may be defined to only accept uniform values, in which case the input may provide a `value` or a `nodename` connection to the output of a [<constant> node](#node-constant) (possibly through one or more no-op [<dot> nodes](#node-dot)) or any other node whose output is explicitly declared to be "uniform" (such as [<geompropvalueuniform>](#node-geompropvalueuniform)), but may not provide a `nodename` or `nodegraph` connection to any arbitrary node output or to any nodegraph output. String- and filename-type inputs are required to be "uniform", as are any array-typed inputs. Input elements may be connected to an external parameter interface in the node definition, allowing them to be assigned values from materials or node instantiations; this includes "uniform" and string/filename-type inputs, however, the same connectability restrictions listed above apply to the inputs of the material or node instance. Inputs may only be connected to node/nodegraph outputs or nodedef interface inputs of the same type, though it is permissible for a `string`-type output to be connected to a `filename`-type input (but not the other way around). +Node elements contain zero or more <input> elements defining the name, type, and value or connection for each node input. Input elements can assign an explicit uniform value by providing a `value` attribute, make a connection to the output of another node by providing a `nodename` attribute, or make a connection to the output of a nodegraph by providing a `nodegraph` attribute. An optional `output` attribute may also be provided for <input> elements, allowing the input to connect to a specific, named output of the referenced upstream node or nodegraph. If the referenced node/nodegraph has multiple outputs, `output` is required; if it has only one output, the `output` attribute of the <input> is ignored. Input elements may be defined to only accept uniform values, in which case the input may provide a `value` or a `nodename` connection to the output of a [<constant> node](#node-constant) (possibly through one or more no-op [<dot> nodes](#node-dot)) or any other node whose output is explicitly declared to be "uniform", but may not provide a `nodename` or `nodegraph` connection to any arbitrary node output or to any nodegraph output. String- and filename-type inputs are required to be "uniform", as are any array-typed inputs. Input elements may be connected to an external parameter interface in the node definition, allowing them to be assigned values from materials or node instantiations; this includes "uniform" and string/filename-type inputs, however, the same connectability restrictions listed above apply to the inputs of the material or node instance. Inputs may only be connected to node/nodegraph outputs or nodedef interface inputs of the same type, though it is permissible for a `string`-type output to be connected to a `filename`-type input (but not the other way around). A float/vectorN input of a node, or a "filename"-type input referring to an image file containing float or vectorN values, may specify a unit for its value by providing a `unit` attribute, and that unit must be one associated with the `unittype` for that input in the nodedef, if specified; please see the [Units](#units) section above for details on declaring units and unittypes. If the nodedef for a node (see the [Custom Nodes](#custom-nodes) section below) does not declare a `unittype` for an input, the node may do so; it is not permissible to provide a `unit` for a node input without a compatible `unittype` being defined on either the node or applicable nodedef. @@ -639,7 +663,7 @@ MaterialX also supports the following additional attributes for Output elements Source nodes use external data and/or procedural functions to form an output; they do not have any required inputs. Each source node must define its output type. -This section defines the Source Nodes that all MaterialX implementations are expected to support. Standard Source Nodes are grouped into the following classifications: [Texture Nodes](#texture-nodes), [Procedural Nodes](#procedural-nodes), [Noise Nodes](#noise-nodes), [Shape Nodes](#shape-nodes), [Geometric Nodes](#geometric-nodes), [Global Nodes](#global-nodes) and [Application Nodes](#application-nodes). +This section defines the Source Nodes that all MaterialX implementations are expected to support. Standard Source Nodes are grouped into the following classifications: [Texture Nodes](#texture-nodes), [Procedural Nodes](#procedural-nodes), [Noise Nodes](#noise-nodes), [Shape Nodes](#shape-nodes), [Geometric Nodes](#geometric-nodes) and [Application Nodes](#application-nodes). ### Texture Nodes @@ -745,11 +769,6 @@ Standard Procedural nodes: * **`constant`**: a constant value. * `value` (any non-shader-semantic type): the value to output - - -* **`tokenvalue`**: a constant "interface token" value, may only be connected to <token>s in nodes, not to <input>s. - * `value` (any uniform non-shader-semantic type): the token value to output; "enum" and "enumvalues" attributes may be provided to define a specific set of allowed token values. - * **`ramplr`**: a left-to-right linear value ramp. @@ -843,16 +862,6 @@ Standard Noise nodes: * `period` (float or vectorN): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `position` (vector3): the 3D position at which the noise is evaluated. Default is to use the current 3D object-space coordinate. - - -* **`fractal2d`**: Zero-centered 2D Fractal noise in 1, 2, 3 or 4 channels, created by summing several octaves of 2D Perlin noise, increasing the frequency and decreasing the amplitude at each octave. - * `amplitude` (float or vectorN): the center-to-peak amplitude of the noise (peak-to-peak amplitude is 2x this value). Default is 1.0. - * `octaves` (integer): the number of octaves of noise to be summed. Default is 3. - * `lacunarity` (float or vectorN): the exponential scale between successive octaves of noise; must be an integer value if period is non-zero so the result is properly tileable. VectorN-output types can provide either a float (isotropic) or vectorN (anisotropic) values for lacunarity and diminish. Default is 2.0. - * `diminish` (float or vectorN): the rate at which noise amplitude is diminished for each octave. Should be between 0.0 and 1.0; default is 0.5. VectorN-output types can provide either a float (isotropic) or vectorN (anisotropic) values for lacunarity and diminish. - * `period` (float or vectorN): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. - * `texcoord` (vector2): the 2D texture coordinate at which the noise is evaluated. Default is to use the first set of texture coordinates. - * **`fractal3d`**: Zero-centered 3D Fractal noise in 1, 2, 3 or 4 channels, created by summing several octaves of 3D Perlin noise, increasing the frequency and decreasing the amplitude at each octave. @@ -863,12 +872,6 @@ Standard Noise nodes: * `period` (float or vectorN): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `position` (vector3): the 3D position at which the noise is evaluated. Default is to use the current 3D object-space coordinate. - - -* **`cellnoise1d`**: 1D cellular noise, 1 or 3 channels (type float or vector3). - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for input coordinate repeated at that step. Default is 0, meaning the noise is not periodic. - * `in` (float): the 1D coordinate at which the noise is evaluated. - * **`cellnoise2d`**: 2D cellular noise, 1 or 3 channels (type float or vector3). @@ -884,16 +887,12 @@ Standard Noise nodes: * **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). - * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. * `texcoord` (vector2): the 2D position at which the noise is evaluated. Default is to use the first set of texture coordinates. * **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). - * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. * `position` (vector3): the 3D position at which the noise is evaluated. Default is to use the current 3D object-space coordinate. @@ -1092,13 +1091,7 @@ Standard Geometric nodes: * `geomprop` (uniform string): the geometric property to be referenced. * `default` (same type as the geomprop's value): a value to return if the specified `geomprop` is not defined on the current geometry. - - -* **`geompropvalueuniform`**: the value of the specified uniform geometric property (defined using <geompropdef>) of the currently-bound geometry. This node's type must match that of the referenced geomprop. - * `geomprop` (uniform string): the geometric property to be referenced. - * `default` (same type as the geomprop's value): a value to return if the specified `geomprop` is not defined on the current geometry. - -Additionally, the `geomcolor`, `geompropvalue` and `geompropvalueuniform` nodes for color3/color4-type properties can take a `colorspace` attribute to declare what colorspace the color property value is in; the default is "none" for no colorspace declaration (and hence no colorspace conversion). +Additionally, the `geomcolor` and `geompropvalue` nodes for color3/color4-type properties can take a `colorspace` attribute to declare what colorspace the color property value is in; the default is "none" for no colorspace declaration (and hence no colorspace conversion). @@ -1115,33 +1108,13 @@ Applications may also reference other renderer-specific named spaces, at the exp -### Global Nodes - -Global nodes generate color data using non-local geometric context, requiring access to geometric features beyond the surface point being processed. This non-local context can be provided by tracing rays into the scene, rasterizing scene geometry, or any other appropriate method. - -```xml - - - -``` - -Standard Global nodes: - - - -* **`ambientocclusion`**: Compute the ambient occlusion at the current surface point, returning a scalar value between 0 and 1. Ambient occlusion represents the accessibility of each surface point to ambient lighting, with larger values representing greater accessibility to light. This node must be of type float. - * `coneangle` (float): the half-angle of a cone about the surface normal, within which geometric surface features are considered as potential occluders. The unit for this input is degrees, and its default value is 90.0 (full hemisphere). - * `maxdistance` (float): the maximum distance from the surface point at which geometric surface features are considered as potential occluders. Defaults to 1e38, e.g. "unlimited". - - - ### Application Nodes Application nodes are used to reference application-defined properties within a node graph, and have no inputs: ```xml - +

@@ -96,7 +98,6 @@ The following new standard physically based shading nodes have been added: **Other Changes** -* The <member> element for <typedef>s and the "member" attribute for inputs have been removed from the Specification, as they had never been implemented and it was not clear how they could be implemented generally. * The "valuerange" and "valuecurve" attributes describing expressions and function curves have been removed, in favor of using the new <curveinversecubic> / <curveuniformcubic> / etc. nodes. * The <geomcolor>, <geompropvalue> and <geompropvalueuniform> nodes for color3/4-type values can now take a "colorspace" attribute to declare the colorspace of the property value. * The <cellnoise2d> and <cellnoise3d> nodes now support vectorN output types in addition to float output. diff --git a/javascript/MaterialXTest/element.spec.js b/javascript/MaterialXTest/element.spec.js index cbb672c5c2..bafee4d6af 100644 --- a/javascript/MaterialXTest/element.spec.js +++ b/javascript/MaterialXTest/element.spec.js @@ -164,3 +164,28 @@ describe('Element', () => }); }); }); + +describe('Equivalence', () => +{ + let mx, doc, doc2 + + before(async () => { + mx = await Module(); + doc = mx.createDocument(); + doc.addNodeGraph("graph"); + doc2 = mx.createDocument(); + doc2.addNodeGraph("graph1"); + }); + + it('Compare document equivalency', () => + { + let options = new mx.ElementEquivalenceOptions(); + let differences = {}; + options.performValueComparisons = false; + let result = doc.isEquivalent(doc2, options, differences); + expect(result).to.be.false; + expect(differences.message).to.not.be.empty; + result = doc.isEquivalent(doc2, options, undefined); + expect(result).to.be.false; + }); +}); diff --git a/javascript/MaterialXTest/package-lock.json b/javascript/MaterialXTest/package-lock.json index 4bd40a8468..d40a804991 100644 --- a/javascript/MaterialXTest/package-lock.json +++ b/javascript/MaterialXTest/package-lock.json @@ -9,17 +9,17 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { - "@babel/core": "^7.24.7", - "@babel/preset-env": "^7.24.7", - "@babel/register": "^7.24.6", - "chai": "^4.4.1", + "@babel/core": "^7.25.7", + "@babel/preset-env": "^7.25.7", + "@babel/register": "^7.25.7", + "chai": "^4.5.0", "copyfiles": "^2.4.1", - "karma": "^6.4.3", + "karma": "^6.4.4", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^3.2.0", "karma-mocha": "^2.0.1", "karma-mocha-reporter": "^2.2.5", - "mocha": "^10.4.0", + "mocha": "^10.7.3", "rimraf": "^3.0.2" } }, @@ -38,13 +38,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/highlight": "^7.25.7", "picocolors": "^1.0.0" }, "engines": { @@ -52,9 +52,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", - "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.7.tgz", + "integrity": "sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw==", "dev": true, "license": "MIT", "engines": { @@ -62,22 +62,22 @@ } }, "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.7.tgz", + "integrity": "sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helpers": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -93,58 +93,58 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", + "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7", + "@babel/types": "^7.25.7", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", + "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", - "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.7.tgz", + "integrity": "sha512-12xfNeKNH7jubQNm7PAkzlLwEmCs1tfuX3UjIw6vP6QXi+leKh6+LyC/+Ed4EIQermwd58wsyh070yjDHFlNGg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", - "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", + "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -153,20 +153,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz", - "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.7.tgz", + "integrity": "sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-member-expression-to-functions": "^7.25.7", + "@babel/helper-optimise-call-expression": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/traverse": "^7.25.7", "semver": "^6.3.1" }, "engines": { @@ -177,14 +175,14 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", - "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.7.tgz", + "integrity": "sha512-byHhumTj/X47wJ6C6eLpK7wW/WBEcnUeb7D0FNc/jFQnQVw7DOso3Zz5u9x/zLrFVkHa89ZGDbkAa1D54NdrCQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "regexpu-core": "^5.3.1", + "@babel/helper-annotate-as-pure": "^7.25.7", + "regexpu-core": "^6.1.1", "semver": "^6.3.1" }, "engines": { @@ -211,86 +209,45 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz", - "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.7.tgz", + "integrity": "sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", + "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", - "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", + "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -300,22 +257,22 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.7.tgz", + "integrity": "sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", - "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", + "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", "dev": true, "license": "MIT", "engines": { @@ -323,15 +280,15 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", - "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.7.tgz", + "integrity": "sha512-kRGE89hLnPfcz6fTrlNU+uhgcwv0mBE4Gv3P9Ke9kLVJYpi4AMVVEElXvB5CabrPZW4nCM8P8UyyjrzCM0O2sw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-wrap-function": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -341,15 +298,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", - "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.7.tgz", + "integrity": "sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7" + "@babel/helper-member-expression-to-functions": "^7.25.7", + "@babel/helper-optimise-call-expression": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -359,50 +316,37 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", + "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.7.tgz", + "integrity": "sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", "dev": true, "license": "MIT", "engines": { @@ -410,9 +354,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", "dev": true, "license": "MIT", "engines": { @@ -420,9 +364,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", - "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", + "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", "dev": true, "license": "MIT", "engines": { @@ -430,43 +374,42 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", - "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.7.tgz", + "integrity": "sha512-MA0roW3JF2bD1ptAaJnvcabsVlNQShUaThyJbCDD4bCp8NEgiFvpoqRI2YS22hHlc2thjO/fTg2ShLMC3jygAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", - "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", + "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -476,11 +419,14 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz", + "integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.7" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -489,14 +435,30 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", - "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.7.tgz", + "integrity": "sha512-UV9Lg53zyebzD1DwQoT9mzkEKa922LNUp5YkTJ6Uta0RbyXaQNUgcvSt7qIu1PpPzVb6rd10OVNTzkyBGeVmxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.7.tgz", + "integrity": "sha512-GDDWeVLNxRIkQTnJn2pDOM1pkCgYdSqPeT1a9vh9yIqu2uzzgw1zcqEb+IJOhy+dTBMlNdThrDIksr2o09qrrQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -506,13 +468,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", - "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.7.tgz", + "integrity": "sha512-wxyWg2RYaSUYgmd9MR0FyRGyeOMQE/Uzr1wzd/g5cf5bwi9A4v6HFdDm7y1MgDtod/fLOSTZY6jDgV0xU9d5bA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -522,15 +484,15 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", - "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.7.tgz", + "integrity": "sha512-Xwg6tZpLxc4iQjorYsyGMyfJE7nP5MV8t/Ka58BgiA7Jw0fRqQNcANlLfdJ/yvBt9z9LD2We+BEkT7vLqZRWng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", + "@babel/plugin-transform-optional-chaining": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -540,14 +502,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", - "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.7.tgz", + "integrity": "sha512-UVATLMidXrnH+GMUIuxq55nejlj02HP7F5ETyBONzP6G87fPBogG4CH6kxrSrdIuAjdwNO9VzyaYsrZPscWUrw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -638,13 +600,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.7.tgz", + "integrity": "sha512-ZvZQRmME0zfJnDQnVBKYzHxXT7lYBB3Revz1GuS7oLXWMgqUPX4G+DDbT30ICClht9WKV34QVrZhSw6WdklwZQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -654,13 +616,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz", + "integrity": "sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -823,13 +785,13 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", - "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.7.tgz", + "integrity": "sha512-EJN2mKxDwfOUCPxMO6MUI58RN3ganiRAG/MS/S3HfB6QFNjroAMelQo/gybyYq97WerCBAZoyrAoW8Tzdq2jWg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -839,16 +801,16 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", - "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.7.tgz", + "integrity": "sha512-4B6OhTrwYKHYYgcwErvZjbmH9X5TxQBsaBHdzEIB4l71gR5jh/tuHGlb9in47udL2+wVUcOz5XXhhfhVJwEpEg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-remap-async-to-generator": "^7.25.7", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -858,15 +820,15 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", - "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.7.tgz", + "integrity": "sha512-ZUCjAavsh5CESCmi/xCpX1qcCaAglzs/7tmuvoFnJgA1dM7gQplsguljoTg+Ru8WENpX89cQyAtWoaE0I3X3Pg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7" + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-remap-async-to-generator": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -876,13 +838,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", - "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.7.tgz", + "integrity": "sha512-xHttvIM9fvqW+0a3tZlYcZYSBpSWzGBFIt/sYG3tcdSzBB8ZeVgz2gBP7Df+sM0N1850jrviYSSeUuc+135dmQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -892,13 +854,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", - "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.7.tgz", + "integrity": "sha512-ZEPJSkVZaeTFG/m2PARwLZQ+OG0vFIhPlKHK/JdIMy8DbRJ/htz6LRrTFtdzxi9EHmcwbNPAKDnadpNSIW+Aow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -908,14 +870,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", - "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.7.tgz", + "integrity": "sha512-mhyfEW4gufjIqYFo9krXHJ3ElbFLIze5IDp+wQTxoPd+mwFb1NxatNAwmv8Q8Iuxv7Zc+q8EkiMQwc9IhyGf4g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -925,14 +887,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", - "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.7.tgz", + "integrity": "sha512-rvUUtoVlkDWtDWxGAiiQj0aNktTPn3eFynBcMC2IhsXweehwgdI9ODe+XjWw515kEmv22sSOTp/rxIRuTiB7zg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -943,19 +905,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.7.tgz", - "integrity": "sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.7.tgz", + "integrity": "sha512-9j9rnl+YCQY0IGoeipXvnk3niWicIB6kCsWRGLwX241qSXpbA4MKxtp/EdvFxsc4zI5vqfLxzOd0twIJ7I99zg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7", + "@babel/traverse": "^7.25.7", "globals": "^11.1.0" }, "engines": { @@ -966,14 +926,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", - "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.7.tgz", + "integrity": "sha512-QIv+imtM+EtNxg/XBKL3hiWjgdLjMOmZ+XzQwSgmBfKbfxUjBzGgVPklUuE55eq5/uVoh8gg3dqlrwR/jw3ZeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/template": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -983,13 +943,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.7.tgz", - "integrity": "sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.7.tgz", + "integrity": "sha512-xKcfLTlJYUczdaM1+epcdh1UGewJqr9zATgrNHcLBcV2QmfvPPEixo/sK/syql9cEmbr7ulu5HMFG5vbbt/sEA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -999,14 +959,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", - "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.7.tgz", + "integrity": "sha512-kXzXMMRzAtJdDEgQBLF4oaiT6ZCU3oWHgpARnTKDAqPkDJ+bs3NrZb310YYevR5QlRo3Kn7dzzIdHbZm1VzJdQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1016,13 +976,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", - "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.7.tgz", + "integrity": "sha512-by+v2CjoL3aMnWDOyCIg+yxU9KXSRa9tN6MbqggH5xvymmr9p4AMjYkNlQy4brMceBnUyHZ9G8RnpvT8wP7Cfg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1031,14 +991,31 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.7.tgz", + "integrity": "sha512-HvS6JF66xSS5rNKXLqkk7L9c/jZ/cdIVIcoPVrnl8IsVpLggTjXs8OWekbLHs/VtYDDh5WXnQyeE3PPUGm22MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", - "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.7.tgz", + "integrity": "sha512-UvcLuual4h7/GfylKm2IAA3aph9rwvAM2XBA0uPKU3lca+Maai4jBjjEVUS568ld6kJcgbouuumCBhMd/Yz17w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -1049,14 +1026,14 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", - "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.7.tgz", + "integrity": "sha512-yjqtpstPfZ0h/y40fAXRv2snciYr0OAoMXY/0ClC7tm4C/nG5NJKmIItlaYlLbIVAWNfrYuy9dq1bE0SbX0PEg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1066,13 +1043,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", - "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.7.tgz", + "integrity": "sha512-h3MDAP5l34NQkkNulsTNyjdaR+OiB0Im67VU//sFupouP8Q6m9Spy7l66DcaAQxtmCqGdanPByLsnwFttxKISQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -1083,14 +1060,14 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", - "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.7.tgz", + "integrity": "sha512-n/TaiBGJxYFWvpJDfsxSj9lEEE44BFM1EPGz4KEiTipTgkoFVVcCmzAL3qA7fdQU96dpo4gGf5HBx/KnDvqiHw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1100,15 +1077,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", - "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.7.tgz", + "integrity": "sha512-5MCTNcjCMxQ63Tdu9rxyN6cAWurqfrDZ76qvVPrGYdBxIj+EawuuxTu/+dgJlhK5eRz3v1gLwp6XwS8XaX2NiQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1118,13 +1095,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", - "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.7.tgz", + "integrity": "sha512-Ot43PrL9TEAiCe8C/2erAjXMeVSnE/BLEx6eyrKLNFCCw5jvhTHKyHxdI1pA0kz5njZRYAnMO2KObGqOCRDYSA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -1135,13 +1112,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", - "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.7.tgz", + "integrity": "sha512-fwzkLrSu2fESR/cm4t6vqd7ebNIopz2QHGtjoU+dswQo/P6lwAG04Q98lliE3jkz/XqnbGFLnUcE0q0CVUf92w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1151,13 +1128,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", - "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.7.tgz", + "integrity": "sha512-iImzbA55BjiovLyG2bggWS+V+OLkaBorNvc/yJoeeDQGztknRnDdYfp2d/UPmunZYEnZi6Lg8QcTmNMHOB0lGA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -1168,13 +1145,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", - "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.7.tgz", + "integrity": "sha512-Std3kXwpXfRV0QtQy5JJcRpkqP8/wG4XL7hSKZmGlxPlDqmpXtEPRmhF7ztnlTCtUN3eXRUJp+sBEZjaIBVYaw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1184,14 +1161,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", - "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.7.tgz", + "integrity": "sha512-CgselSGCGzjQvKzghCvDTxKHP3iooenLpJDO842ehn5D2G5fJB222ptnDwQho0WjEvg7zyoxb9P+wiYxiJX5yA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1201,15 +1178,15 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz", - "integrity": "sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.7.tgz", + "integrity": "sha512-L9Gcahi0kKFYXvweO6n0wc3ZG1ChpSFdgG+eV1WYZ3/dGbJK7vvk91FgGgak8YwRgrCuihF8tE/Xg07EkL5COg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-simple-access": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1219,16 +1196,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", - "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.7.tgz", + "integrity": "sha512-t9jZIvBmOXJsiuyOwhrIGs8dVcD6jDyg2icw1VL4A/g+FnWyJKwUfSSU2nwJuMV2Zqui856El9u+ElB+j9fV1g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "@babel/traverse": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1238,14 +1215,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", - "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.7.tgz", + "integrity": "sha512-p88Jg6QqsaPh+EB7I9GJrIqi1Zt4ZBHUQtjw3z1bzEXcLh6GfPqzZJ6G+G1HBGKUNukT58MnKG7EN7zXQBCODw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1255,14 +1232,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", - "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.7.tgz", + "integrity": "sha512-BtAT9LzCISKG3Dsdw5uso4oV1+v2NlVXIIomKJgQybotJY3OwCwJmkongjHgwGKoZXd0qG5UZ12JUlDQ07W6Ow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1272,13 +1249,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", - "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.7.tgz", + "integrity": "sha512-CfCS2jDsbcZaVYxRFo2qtavW8SpdzmBXC2LOI4oO0rP+JSRDxxF3inF4GcPsLgfb5FjkhXG5/yR/lxuRs2pySA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1288,13 +1265,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", - "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.7.tgz", + "integrity": "sha512-FbuJ63/4LEL32mIxrxwYaqjJxpbzxPVQj5a+Ebrc8JICV6YX8nE53jY+K0RZT3um56GoNWgkS2BQ/uLGTjtwfw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -1305,13 +1282,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", - "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.7.tgz", + "integrity": "sha512-8CbutzSSh4hmD+jJHIA8vdTNk15kAzOnFLVVgBSMGr28rt85ouT01/rezMecks9pkU939wDInImwCKv4ahU4IA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -1322,16 +1299,16 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", - "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.7.tgz", + "integrity": "sha512-1JdVKPhD7Y5PvgfFy0Mv2brdrolzpzSoUq2pr6xsR+m+3viGGeHEokFKsCgOkbeFOQxfB1Vt2F0cPJLRpFI4Zg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.7" + "@babel/plugin-transform-parameters": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1341,14 +1318,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", - "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.7.tgz", + "integrity": "sha512-pWT6UXCEW3u1t2tcAGtE15ornCBvopHj9Bps9D2DsH15APgNVOTwwczGckX+WkAvBmuoYKRCFa4DK+jM8vh5AA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-replace-supers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1358,13 +1335,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", - "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.7.tgz", + "integrity": "sha512-m9obYBA39mDPN7lJzD5WkGGb0GO54PPLXsbcnj1Hyeu8mSRz7Gb4b1A6zxNX32ZuUySDK4G6it8SDFWD1nCnqg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -1375,14 +1352,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.7.tgz", - "integrity": "sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.7.tgz", + "integrity": "sha512-h39agClImgPWg4H8mYVAbD1qP9vClFbEjqoJmt87Zen8pjqK8FTPUwrOXAvqu5soytwxrLMd2fx2KSCp2CHcNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { @@ -1393,13 +1370,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", - "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.7.tgz", + "integrity": "sha512-FYiTvku63me9+1Nz7TOx4YMtW3tWXzfANZtrzHhUZrz4d47EEtMQhzFoZWESfXuAMMT5mwzD4+y1N8ONAX6lMQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1409,14 +1386,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", - "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.7.tgz", + "integrity": "sha512-KY0hh2FluNxMLwOCHbxVOKfdB5sjWG4M183885FmaqWWiGMhRZq4DQRKH6mHdEucbJnyDyYiZNwNG424RymJjA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1426,15 +1403,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", - "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.7.tgz", + "integrity": "sha512-LzA5ESzBy7tqj00Yjey9yWfs3FKy4EmJyKOSWld144OxkTji81WWnUT8nkLUn+imN/zHL8ZQlOu/MTUAhHaX3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-create-class-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -1445,13 +1422,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", - "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.7.tgz", + "integrity": "sha512-lQEeetGKfFi0wHbt8ClQrUSUMfEeI3MMm74Z73T9/kuz990yYVtfofjf3NuA42Jy3auFOpbjDyCSiIkTs1VIYw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1461,13 +1438,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", - "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.7.tgz", + "integrity": "sha512-mgDoQCRjrY3XK95UuV60tZlFCQGXEtMg8H+IsW72ldw1ih1jZhzYXbJvghmAEpg5UVhhnCeia1CkGttUvCkiMQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.7", "regenerator-transform": "^0.15.2" }, "engines": { @@ -1478,13 +1455,13 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", - "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.7.tgz", + "integrity": "sha512-3OfyfRRqiGeOvIWSagcwUTVk2hXBsr/ww7bLn6TRTuXnexA+Udov2icFOxFX9abaj4l96ooYkcNN1qi2Zvqwng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1494,13 +1471,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", - "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.7.tgz", + "integrity": "sha512-uBbxNwimHi5Bv3hUccmOFlUy3ATO6WagTApenHz9KzoIdn0XeACdB12ZJ4cjhuB2WSi80Ez2FWzJnarccriJeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1510,14 +1487,14 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", - "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.7.tgz", + "integrity": "sha512-Mm6aeymI0PBh44xNIv/qvo8nmbkpZze1KvR8MkEqbIREDxoiWTi18Zr2jryfRMwDfVZF9foKh060fWgni44luw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1527,13 +1504,13 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", - "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.7.tgz", + "integrity": "sha512-ZFAeNkpGuLnAQ/NCsXJ6xik7Id+tHuS+NT+ue/2+rn/31zcdnupCdmunOizEaP0JsUmTFSTOPoQY7PkK2pttXw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1543,13 +1520,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", - "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.7.tgz", + "integrity": "sha512-SI274k0nUsFFmyQupiO7+wKATAmMFf8iFgq2O+vVFXZ0SV9lNfT1NGzBEhjquFmD8I9sqHLguH+gZVN3vww2AA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1559,13 +1536,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.7.tgz", - "integrity": "sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.7.tgz", + "integrity": "sha512-OmWmQtTHnO8RSUbL0NTdtpbZHeNTnm68Gj5pA4Y2blFNh+V4iZR68V1qL9cI37J21ZN7AaCnkfdHtLExQPf2uA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1575,13 +1552,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", - "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.7.tgz", + "integrity": "sha512-BN87D7KpbdiABA+t3HbVqHzKWUDN3dymLaTnPFAMyc8lV+KN3+YzNhVRNdinaCPA4AUqx7ubXbQ9shRjYBl3SQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1591,14 +1568,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", - "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.7.tgz", + "integrity": "sha512-IWfR89zcEPQGB/iB408uGtSPlQd3Jpq11Im86vUgcmSTcoWAiQMCTOa2K2yNNqFJEBVICKhayctee65Ka8OB0w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1608,14 +1585,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", - "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.7.tgz", + "integrity": "sha512-8JKfg/hiuA3qXnlLx8qtv5HWRbgyFx2hMMtpDDuU2rTckpKkGu4ycK5yYHwuEa16/quXfoxHBIApEsNyMWnt0g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1625,14 +1602,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", - "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.7.tgz", + "integrity": "sha512-YRW8o9vzImwmh4Q3Rffd09bH5/hvY0pxg+1H1i0f7APoUeg12G7+HhLj9ZFNIrYkgBXhIijPJ+IXypN0hLTIbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7" }, "engines": { "node": ">=6.9.0" @@ -1642,28 +1619,29 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.7.tgz", - "integrity": "sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.7.tgz", + "integrity": "sha512-Gibz4OUdyNqqLj+7OAvBZxOD7CklCtMA5/j0JgUEwOnaRULsPDXmic2iKxL2DX2vQduPR5wH2hjZas/Vr/Oc0g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/compat-data": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.7", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.7", - "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-assertions": "^7.25.7", + "@babel/plugin-syntax-import-attributes": "^7.25.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", @@ -1675,59 +1653,60 @@ "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", - "@babel/plugin-transform-class-properties": "^7.24.7", - "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.7", - "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.7", - "@babel/plugin-transform-dotall-regex": "^7.24.7", - "@babel/plugin-transform-duplicate-keys": "^7.24.7", - "@babel/plugin-transform-dynamic-import": "^7.24.7", - "@babel/plugin-transform-exponentiation-operator": "^7.24.7", - "@babel/plugin-transform-export-namespace-from": "^7.24.7", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", - "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-member-expression-literals": "^7.24.7", - "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", - "@babel/plugin-transform-modules-umd": "^7.24.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-new-target": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-object-super": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-property-literals": "^7.24.7", - "@babel/plugin-transform-regenerator": "^7.24.7", - "@babel/plugin-transform-reserved-words": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", - "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.7", - "@babel/plugin-transform-unicode-escapes": "^7.24.7", - "@babel/plugin-transform-unicode-property-regex": "^7.24.7", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/plugin-transform-arrow-functions": "^7.25.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.7", + "@babel/plugin-transform-async-to-generator": "^7.25.7", + "@babel/plugin-transform-block-scoped-functions": "^7.25.7", + "@babel/plugin-transform-block-scoping": "^7.25.7", + "@babel/plugin-transform-class-properties": "^7.25.7", + "@babel/plugin-transform-class-static-block": "^7.25.7", + "@babel/plugin-transform-classes": "^7.25.7", + "@babel/plugin-transform-computed-properties": "^7.25.7", + "@babel/plugin-transform-destructuring": "^7.25.7", + "@babel/plugin-transform-dotall-regex": "^7.25.7", + "@babel/plugin-transform-duplicate-keys": "^7.25.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.7", + "@babel/plugin-transform-dynamic-import": "^7.25.7", + "@babel/plugin-transform-exponentiation-operator": "^7.25.7", + "@babel/plugin-transform-export-namespace-from": "^7.25.7", + "@babel/plugin-transform-for-of": "^7.25.7", + "@babel/plugin-transform-function-name": "^7.25.7", + "@babel/plugin-transform-json-strings": "^7.25.7", + "@babel/plugin-transform-literals": "^7.25.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.7", + "@babel/plugin-transform-member-expression-literals": "^7.25.7", + "@babel/plugin-transform-modules-amd": "^7.25.7", + "@babel/plugin-transform-modules-commonjs": "^7.25.7", + "@babel/plugin-transform-modules-systemjs": "^7.25.7", + "@babel/plugin-transform-modules-umd": "^7.25.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.7", + "@babel/plugin-transform-new-target": "^7.25.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.7", + "@babel/plugin-transform-numeric-separator": "^7.25.7", + "@babel/plugin-transform-object-rest-spread": "^7.25.7", + "@babel/plugin-transform-object-super": "^7.25.7", + "@babel/plugin-transform-optional-catch-binding": "^7.25.7", + "@babel/plugin-transform-optional-chaining": "^7.25.7", + "@babel/plugin-transform-parameters": "^7.25.7", + "@babel/plugin-transform-private-methods": "^7.25.7", + "@babel/plugin-transform-private-property-in-object": "^7.25.7", + "@babel/plugin-transform-property-literals": "^7.25.7", + "@babel/plugin-transform-regenerator": "^7.25.7", + "@babel/plugin-transform-reserved-words": "^7.25.7", + "@babel/plugin-transform-shorthand-properties": "^7.25.7", + "@babel/plugin-transform-spread": "^7.25.7", + "@babel/plugin-transform-sticky-regex": "^7.25.7", + "@babel/plugin-transform-template-literals": "^7.25.7", + "@babel/plugin-transform-typeof-symbol": "^7.25.7", + "@babel/plugin-transform-unicode-escapes": "^7.25.7", + "@babel/plugin-transform-unicode-property-regex": "^7.25.7", + "@babel/plugin-transform-unicode-regex": "^7.25.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.7", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.31.0", + "core-js-compat": "^3.38.1", "semver": "^6.3.1" }, "engines": { @@ -1753,9 +1732,9 @@ } }, "node_modules/@babel/register": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.24.6.tgz", - "integrity": "sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.25.7.tgz", + "integrity": "sha512-qHTd2Rhn/rKhSUwdY6+n98FmwXN+N+zxSVx3zWqRe9INyvTpv+aQ5gDV2+43ACd3VtMBzPPljbb0gZb8u5ma6Q==", "dev": true, "license": "MIT", "dependencies": { @@ -1772,17 +1751,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true, - "license": "MIT" - }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", "dev": true, "license": "MIT", "dependencies": { @@ -1793,35 +1765,32 @@ } }, "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", + "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/code-frame": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/types": "^7.25.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", + "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/types": "^7.25.7", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1830,14 +1799,14 @@ } }, "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz", + "integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1890,9 +1859,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true, "license": "MIT" }, @@ -1932,13 +1901,13 @@ } }, "node_modules/@types/node": { - "version": "20.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.6.tgz", - "integrity": "sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==", + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/accepts": { @@ -1956,9 +1925,9 @@ } }, "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "license": "MIT", "engines": { @@ -2035,14 +2004,14 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", - "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -2092,9 +2061,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "license": "MIT", "dependencies": { @@ -2106,7 +2075,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -2165,9 +2134,9 @@ "license": "ISC" }, "node_modules/browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "funding": [ { @@ -2185,10 +2154,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -2248,9 +2217,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001636", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", - "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", + "version": "1.0.30001667", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", + "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", "dev": true, "funding": [ { @@ -2269,9 +2238,9 @@ "license": "CC-BY-4.0" }, "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", "dev": true, "license": "MIT", "dependencies": { @@ -2281,7 +2250,7 @@ "get-func-name": "^2.0.2", "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.8" + "type-detect": "^4.1.0" }, "engines": { "node": ">=4" @@ -2502,13 +2471,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", - "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", + "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.0" + "browserslist": "^4.23.3" }, "funding": { "type": "opencollective", @@ -2554,13 +2523,13 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2644,9 +2613,9 @@ "license": "MIT" }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -2674,9 +2643,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.806", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.806.tgz", - "integrity": "sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg==", + "version": "1.5.32", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.32.tgz", + "integrity": "sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw==", "dev": true, "license": "ISC" }, @@ -2698,9 +2667,9 @@ } }, "node_modules/engine.io": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", - "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.1.tgz", + "integrity": "sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og==", "dev": true, "license": "MIT", "dependencies": { @@ -2720,9 +2689,9 @@ } }, "node_modules/engine.io-parser": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", - "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "dev": true, "license": "MIT", "engines": { @@ -2730,11 +2699,17 @@ } }, "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.1.tgz", + "integrity": "sha512-QHuXVeZx9d+tIQAz/XztU0ZwZf2Agg9CcXcgE1rurqvdBeDBrpSwjl8/6XUqMg7tw2Y7uAdKb2sRv+bSEFqQ5A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/es-define-property": { "version": "1.0.0", @@ -2760,9 +2735,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { @@ -2922,9 +2897,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "dev": true, "funding": [ { @@ -3264,13 +3239,16 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3413,16 +3391,16 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json5": { @@ -3449,9 +3427,9 @@ } }, "node_modules/karma": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz", - "integrity": "sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==", + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", + "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", "dependencies": { @@ -3743,32 +3721,32 @@ } }, "node_modules/mocha": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", - "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", @@ -3834,34 +3812,6 @@ "node": ">=8" } }, - "node_modules/mocha/node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/mocha/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3882,31 +3832,6 @@ "dev": true, "license": "MIT" }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "license": "MIT" - }, "node_modules/mocha/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3969,9 +3894,9 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "license": "ISC", "dependencies": { @@ -3981,13 +3906,6 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -4005,9 +3923,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -4022,9 +3940,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true, "license": "MIT" }, @@ -4060,11 +3978,14 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4182,9 +4103,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "dev": true, "license": "ISC" }, @@ -4307,6 +4228,13 @@ "dev": true, "license": "MIT" }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, "node_modules/qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", @@ -4318,13 +4246,13 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -4403,9 +4331,9 @@ "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, "license": "MIT", "dependencies": { @@ -4433,16 +4361,16 @@ } }, "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", + "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.11.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" }, @@ -4450,28 +4378,26 @@ "node": ">=4" } }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.1.tgz", + "integrity": "sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -4570,9 +4496,9 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -4637,9 +4563,9 @@ } }, "node_modules/socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz", + "integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==", "dev": true, "license": "MIT", "dependencies": { @@ -4647,7 +4573,7 @@ "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", - "engine.io": "~6.5.2", + "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, @@ -4918,9 +4844,9 @@ } }, "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, "license": "MIT", "engines": { @@ -4942,9 +4868,9 @@ } }, "node_modules/ua-parser-js": { - "version": "0.7.38", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.38.tgz", - "integrity": "sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==", + "version": "0.7.39", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.39.tgz", + "integrity": "sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w==", "dev": true, "funding": [ { @@ -4961,21 +4887,24 @@ } ], "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, "engines": { "node": "*" } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, "license": "MIT", "engines": { @@ -4997,9 +4926,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, "license": "MIT", "engines": { @@ -5047,9 +4976,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", - "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -5067,8 +4996,8 @@ ], "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -5128,9 +5057,9 @@ } }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true, "license": "Apache-2.0" }, @@ -5287,9 +5216,9 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "license": "ISC", "engines": { diff --git a/javascript/MaterialXTest/package.json b/javascript/MaterialXTest/package.json index 02f42e430f..08578ceb32 100644 --- a/javascript/MaterialXTest/package.json +++ b/javascript/MaterialXTest/package.json @@ -16,17 +16,17 @@ "author": "", "license": "ISC", "devDependencies": { - "@babel/core": "^7.24.7", - "@babel/preset-env": "^7.24.7", - "@babel/register": "^7.24.6", - "chai": "^4.4.1", + "@babel/core": "^7.25.7", + "@babel/preset-env": "^7.25.7", + "@babel/register": "^7.25.7", + "chai": "^4.5.0", "copyfiles": "^2.4.1", - "karma": "^6.4.3", + "karma": "^6.4.4", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^3.2.0", "karma-mocha": "^2.0.1", "karma-mocha-reporter": "^2.2.5", - "mocha": "^10.4.0", + "mocha": "^10.7.3", "rimraf": "^3.0.2" } } diff --git a/javascript/MaterialXView/package-lock.json b/javascript/MaterialXView/package-lock.json index cf4b120c32..298f6d7f72 100644 --- a/javascript/MaterialXView/package-lock.json +++ b/javascript/MaterialXView/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "lil-gui": "^0.19.2", "three": "^0.152.2", - "webpack": "^5.92.1" + "webpack": "^5.95.0" }, "devDependencies": { "copy-webpack-plugin": "^8.1.1", @@ -73,9 +73,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -175,30 +175,10 @@ "@types/node": "*" } }, - "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "license": "MIT", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "license": "MIT" }, "node_modules/@types/express": { @@ -215,9 +195,22 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz", + "integrity": "sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", "dev": true, "license": "MIT", "dependencies": { @@ -242,9 +235,9 @@ "license": "MIT" }, "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -265,12 +258,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.6.tgz", - "integrity": "sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==", + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" } }, "node_modules/@types/node-forge": { @@ -284,9 +277,9 @@ } }, "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", "dev": true, "license": "MIT" }, @@ -348,9 +341,9 @@ } }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, "license": "MIT", "dependencies": { @@ -569,9 +562,9 @@ } }, "node_modules/acorn": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", - "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -624,16 +617,16 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -738,9 +731,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "license": "MIT", "dependencies": { @@ -752,7 +745,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -815,9 +808,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "funding": [ { "type": "opencollective", @@ -834,10 +827,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -894,9 +887,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001636", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", - "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", + "version": "1.0.30001667", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz", + "integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==", "funding": [ { "type": "opencollective", @@ -1359,15 +1352,15 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.806", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.806.tgz", - "integrity": "sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg==", + "version": "1.5.32", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.32.tgz", + "integrity": "sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw==", "license": "ISC" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", "engines": { @@ -1375,9 +1368,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -1398,9 +1391,9 @@ } }, "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", "dev": true, "license": "MIT", "bin": { @@ -1434,15 +1427,15 @@ } }, "node_modules/es-module-lexer": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.3.tgz", - "integrity": "sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", "license": "MIT" }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", "engines": { "node": ">=6" @@ -1549,38 +1542,38 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1620,6 +1613,13 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.2.tgz", + "integrity": "sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row==", + "dev": true, + "license": "MIT" + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -1667,14 +1667,14 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1710,9 +1710,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "dev": true, "funding": [ { @@ -2166,9 +2166,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dev": true, "license": "MIT", "dependencies": { @@ -2214,9 +2214,9 @@ } }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -2224,9 +2224,9 @@ } }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "license": "MIT", "dependencies": { @@ -2296,13 +2296,16 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2470,9 +2473,9 @@ } }, "node_modules/launch-editor": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", - "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", "dev": true, "license": "MIT", "dependencies": { @@ -2549,11 +2552,14 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -2582,9 +2588,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { @@ -2718,9 +2724,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "license": "MIT" }, "node_modules/normalize-path": { @@ -2760,11 +2766,14 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2982,9 +2991,9 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", "dev": true, "license": "MIT" }, @@ -2999,9 +3008,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "license": "ISC" }, "node_modules/picomatch": { @@ -3082,13 +3091,13 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -3415,9 +3424,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "license": "MIT", "dependencies": { @@ -3439,6 +3448,16 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3526,16 +3545,16 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -3712,13 +3731,13 @@ } }, "node_modules/spdy-transport/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3730,20 +3749,20 @@ } }, "node_modules/spdy-transport/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, "node_modules/spdy/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3755,9 +3774,9 @@ } }, "node_modules/spdy/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -3842,9 +3861,9 @@ } }, "node_modules/terser": { - "version": "5.31.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz", - "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==", + "version": "5.34.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.34.1.tgz", + "integrity": "sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -3945,9 +3964,9 @@ } }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", "dev": true, "license": "0BSD" }, @@ -3966,9 +3985,9 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "license": "MIT" }, "node_modules/unpipe": { @@ -3982,9 +4001,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", - "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "funding": [ { "type": "opencollective", @@ -4001,8 +4020,8 @@ ], "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -4065,9 +4084,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", @@ -4088,12 +4107,11 @@ } }, "node_modules/webpack": { - "version": "5.92.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", - "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "version": "5.95.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", + "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.12.1", @@ -4102,7 +4120,7 @@ "acorn-import-attributes": "^1.9.5", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -4217,16 +4235,16 @@ } }, "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -4334,16 +4352,16 @@ } }, "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -4470,9 +4488,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, "license": "MIT", "engines": { diff --git a/javascript/MaterialXView/package.json b/javascript/MaterialXView/package.json index df27cebb57..74dd12bd85 100644 --- a/javascript/MaterialXView/package.json +++ b/javascript/MaterialXView/package.json @@ -12,7 +12,7 @@ "dependencies": { "lil-gui": "^0.19.2", "three": "^0.152.2", - "webpack": "^5.92.1" + "webpack": "^5.95.0" }, "devDependencies": { "copy-webpack-plugin": "^8.1.1", diff --git a/javascript/MaterialXView/source/helper.js b/javascript/MaterialXView/source/helper.js index cd3f144f06..3f3be46c79 100644 --- a/javascript/MaterialXView/source/helper.js +++ b/javascript/MaterialXView/source/helper.js @@ -89,7 +89,7 @@ function fromMatrix(matrix, dimension) */ function toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, flipY) { - let outValue; + let outValue = null; switch (type) { case 'float': @@ -117,18 +117,63 @@ function toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, case 'filename': if (value) { - let fullPath = searchPath + IMAGE_PATH_SEPARATOR + value; - const texture = textureLoader.load(fullPath); - // Set address & filtering mode - if (texture) - setTextureParameters(texture, name, uniforms, flipY); - outValue = texture; + // Cache / reuse texture to avoid reload overhead. + // Note: that data blobs and embedded data textures are not cached as they are transient data. + let checkCache = true; + let texturePath = searchPath + IMAGE_PATH_SEPARATOR + value; + if (value.startsWith('blob:')) + { + texturePath = value; + console.log('Load blob URL:', texturePath); + checkCache = false; + } + else if (value.startsWith('http')) + { + texturePath = value; + console.log('Load HTTP URL:', texturePath); + } + else if (value.startsWith('data:')) + { + texturePath = value; + checkCache = false; + console.log('Load data URL:', texturePath); + } + const cachedTexture = checkCache && THREE.Cache.get(texturePath); + if (cachedTexture) + { + // Get texture from cache + outValue = cachedTexture; + console.log('Use cached texture: ', texturePath, outValue); + } + else + { + outValue = textureLoader.load( + texturePath, + function (texture) { + console.log('Load new texture: ' + texturePath, texture); + outValue = texture; + + // Add texture to ThreeJS cache + if (checkCache) + THREE.Cache.add(texturePath, texture); + }, + undefined, + function (error) { + console.error('Error loading texture: ', error); + }); + + // Set address & filtering mode + if (outValue) + setTextureParameters(outValue, name, uniforms, flipY); + } } break; case 'samplerCube': case 'string': - default: break; + default: + console.log('Value type not supported: ' + type); + outValue = null; } return outValue; diff --git a/javascript/MaterialXView/source/viewer.js b/javascript/MaterialXView/source/viewer.js index 57e155c87b..77437b8c56 100644 --- a/javascript/MaterialXView/source/viewer.js +++ b/javascript/MaterialXView/source/viewer.js @@ -90,14 +90,14 @@ export class Scene } this.#_rootNode = null; - const model = gltfData.scene; + let model = gltfData.scene; if (!model) { const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshBasicMaterial({ color: 0xdddddd }); const cube = new THREE.Mesh(geometry, material); - obj = new Group(); - obj.add(geometry); + model = new Group(); + model.add(cube); } else { @@ -221,9 +221,14 @@ export class Scene orbitControls.update(); } - setUpdateTransforms() + setUpdateTransforms(val=true) { - this.#_updateTransforms = true; + this.#_updateTransforms = val; + } + + getUpdateTransforms() + { + return this.#_updateTransforms; } updateTransforms() @@ -235,7 +240,7 @@ export class Scene { return; } - this.#_updateTransforms = false; + this.setUpdateTransforms(false); const scene = this.getScene(); const camera = this.getCamera(); @@ -601,7 +606,7 @@ export class Material // Re-initialize document var startDocTime = performance.now(); var doc = mx.createDocument(); - doc.importLibrary(viewer.getLibrary()); + doc.setDataLibrary(viewer.getLibrary()); viewer.setDocument(doc); const fileloader = viewer.getFileLoader(); @@ -622,7 +627,12 @@ export class Material // Load material if (mtlxMaterial) - await mx.readFromXmlString(doc, mtlxMaterial, searchPath); + try { + await mx.readFromXmlString(doc, mtlxMaterial, searchPath); + } + catch (error) { + console.log('Error loading material file: ', error); + } else Material.createFallbackMaterial(doc); @@ -1481,7 +1491,7 @@ export class Viewer this.document = this.mx.createDocument(); this.stdlib = this.mx.loadStandardLibraries(this.genContext); - this.document.importLibrary(this.stdlib); + this.document.setDataLibrary(this.stdlib); this.initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml); diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index d60a54cf3b..6852090932 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,15 +1,9 @@ -if (MATERIALX_OSL_LEGACY_CLOSURES) - set(PBRLIB_SUFFIX "legacy") -else() - set(PBRLIB_SUFFIX "mtlx") -endif() - if(NOT SKBUILD) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}" PATTERN "CMakeLists.txt" EXCLUDE PATTERN "pbrlib_genosl_impl.*" EXCLUDE) - install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.${PBRLIB_SUFFIX}" + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.mtlx" DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) endif() @@ -23,6 +17,6 @@ if(MATERIALX_BUILD_PYTHON) DESTINATION "${MATERIALX_PYTHON_LIBRARIES_PATH}" PATTERN "CMakeLists.txt" EXCLUDE PATTERN "pbrlib_genosl_impl.*" EXCLUDE) - install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.${PBRLIB_SUFFIX}" + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.mtlx" DESTINATION "${MATERIALX_PYTHON_LIBRARIES_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) endif() diff --git a/libraries/README.md b/libraries/README.md index 15916f76e2..0ace221bcc 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -74,7 +74,4 @@ This folder contains the standard data libraries for MaterialX, providing declar - Basic GLSL and MSL `lightshader` node definitions and implementations are provided for the following light types: - point, directional, spot - Shader generation does not currently support: - - `ambientocclusion` node. - - `arrayappend` node. - - `curveadjust` node. - `displacementshader` and `volumeshader` nodes for hardware shading targets (GLSL, MSL). diff --git a/libraries/bxdf/disney_brdf_2015.mtlx b/libraries/bxdf/disney_brdf_2015.mtlx deleted file mode 100644 index 916c7d55af..0000000000 --- a/libraries/bxdf/disney_brdf_2015.mtlx +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libraries/bxdf/disney_principled.mtlx b/libraries/bxdf/disney_principled.mtlx new file mode 100644 index 0000000000..72394cb84f --- /dev/null +++ b/libraries/bxdf/disney_principled.mtlx @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libraries/bxdf/lama/lama_conductor.mtlx b/libraries/bxdf/lama/lama_conductor.mtlx index 07a7b7fcd6..4b6b80f64a 100644 --- a/libraries/bxdf/lama/lama_conductor.mtlx +++ b/libraries/bxdf/lama/lama_conductor.mtlx @@ -3,15 +3,15 @@ - + - @@ -21,7 +21,7 @@ doc="Defines the amount of anisotropy, changing the co-tangent axis roughness from the original value to 1 (or to 0 with a negative value)." /> - @@ -40,13 +40,13 @@ - - + + - - + + @@ -110,8 +110,6 @@ - - diff --git a/libraries/bxdf/lama/lama_dielectric.mtlx b/libraries/bxdf/lama/lama_dielectric.mtlx index 5e98670dd7..eb5509033c 100644 --- a/libraries/bxdf/lama/lama_dielectric.mtlx +++ b/libraries/bxdf/lama/lama_dielectric.mtlx @@ -5,12 +5,12 @@ doc="Color multiplier for external reflection. It should be used with parcimony, as a non-white value breaks physicality." /> - + - + - - + doc="Interior volume absorption color. It is defined as the negative logarithm of the extinction coefficient, with values between 0 and 1, such that the object itself and its shadows are tinted proportionnally. If set to 1, there is no absorption, and if set to 0, the object will be completely opaque. Note that for single scattering to kick in, the value must be inferior to 1. This value will also act as coating color, when this node is used as the top material in a layer node." /> + + doc="Color (aka scattering albedo) of the medium, defines what proportion of the light hitting volumetric particles is scattered around by the phase function (as opposed to just absorbed), for each color channel. Only takes effect if the corresponding channel has a non-null density, in other words if the Absorption Color value for that channel is inferior to 1." /> + doc="Anisotropy of the medium's phase function, ranging from full backward scattering at -1 to forward scattering at 1. Only takes effect if the Scatter Color is non-null." /> @@ -47,8 +47,8 @@ - - + + diff --git a/libraries/bxdf/lama/lama_emission.mtlx b/libraries/bxdf/lama/lama_emission.mtlx index 87da14bd91..3f731442c1 100644 --- a/libraries/bxdf/lama/lama_emission.mtlx +++ b/libraries/bxdf/lama/lama_emission.mtlx @@ -1,7 +1,7 @@ - diff --git a/libraries/bxdf/lama/lama_generalized_schlick.mtlx b/libraries/bxdf/lama/lama_generalized_schlick.mtlx index c8c5f40f5b..887273de45 100644 --- a/libraries/bxdf/lama/lama_generalized_schlick.mtlx +++ b/libraries/bxdf/lama/lama_generalized_schlick.mtlx @@ -4,47 +4,41 @@ - + doc="Color multiplier for rays going inside the medium (covers external transmission and internal reflection). It should be used sparingly, as a non-white value breaks physicality. The prefered way to define the color of a dielectric is through the Interior attributes right below." /> + + doc="Index of refraction (often denoted by eta), defining the amount reflected by the surface in the normal direction, and how the rays are bent by refraction. A separate value can be specified for each color channel, if desired." /> - - - + - - + doc="Interior volume absorption color. It is defined as the negative logarithm of the extinction coefficient, with values between 0 and 1, such that the object itself and its shadows are tinted proportionally. If set to 1, there is no absorption, and if set to 0, the object will be completely opaque. Note that for single scattering to kick in, the value must be inferior to 1. This value will also act as coating color, when this node is used as top layer in a stack." /> + + doc="Color (aka scattering albedo) of the medium, defines what proportion of the light hitting volumetric particles is scattered around by the phase function (as opposed to just absorbed), for each color channel. Only takes effect if the corresponding channel has a non-null density, in other words if the Absorption Color value for that channel is inferior to 1." /> + doc="Anisotropy of the medium's phase function, ranging from full backward scattering at -1 to forward scattering at 1. Only takes effect if the Scatter Color is non-null." /> - - - - - - - + @@ -64,26 +58,12 @@ - - - - - + - - - - - + - - - - - - @@ -91,30 +71,15 @@ - - - - - - - + - - - + - - - - - - - - - + + - + @@ -156,27 +121,32 @@ - - + + - - + + + - - + + + + + + - + - - + + @@ -184,10 +154,14 @@ + + + + - + diff --git a/libraries/bxdf/lama/lama_iridescence.mtlx b/libraries/bxdf/lama/lama_iridescence.mtlx index 914f70ae1b..aaf3617965 100644 --- a/libraries/bxdf/lama/lama_iridescence.mtlx +++ b/libraries/bxdf/lama/lama_iridescence.mtlx @@ -5,13 +5,17 @@ doc="Micro-facet distribution roughness." /> - + + - - - @@ -53,6 +57,27 @@ + + + + + + + + + + + + + + + + /> + + + + + @@ -66,6 +91,7 @@ + diff --git a/libraries/bxdf/lama/lama_sheen.mtlx b/libraries/bxdf/lama/lama_sheen.mtlx index 76c7b9597d..8accb41837 100644 --- a/libraries/bxdf/lama/lama_sheen.mtlx +++ b/libraries/bxdf/lama/lama_sheen.mtlx @@ -4,7 +4,7 @@ + doc="Roughness of the sheen effect. Very rough sheen can be used to create a rough diffuse look (when combined with a diffuse node by a layer or mix)." /> diff --git a/libraries/bxdf/lama/lama_sss.mtlx b/libraries/bxdf/lama/lama_sss.mtlx index ded26871ff..f09d2da51d 100644 --- a/libraries/bxdf/lama/lama_sss.mtlx +++ b/libraries/bxdf/lama/lama_sss.mtlx @@ -6,39 +6,29 @@ - + doc="Diffuse Mean Free Path, expressed for each color channel in mm. Indicates on average how much the light travels under the surface before being scattered. The higher the value, the softer the result will be. If zero (black), which is the default value, the computation simplifies to a Lambertian reflection lobe with no subsurface scattering." /> + - + - + doc="Controls how strongly normals are considered in the subsurface computation. For path-traced sss (sssMode 0 and 1), the followTopology parameter reduces sss paths being blocked by backsides behind a surface, but also reduces sss from one side to another in convex regions such as ridges and ears. For diffusion sss (sssMode 2 and 3), the followTopology parameter reduces sss from one side to another in concave regions such as crevasses and wrinkles." /> + doc="This is the multiplier that converts between millimeters and scene units. Both mean free path and diffuse mean free path are specified in millimeters and this parameter is used for the unit conversion. The default value of 0.00328 converts millimeters to feet. For centimeter scene units, this would be 0.1, for meters it would be 0.001 etc." /> - - - - - diff --git a/libraries/bxdf/lama/lama_surface.mtlx b/libraries/bxdf/lama/lama_surface.mtlx index 4ffa9a63df..b7e84a510c 100644 --- a/libraries/bxdf/lama/lama_surface.mtlx +++ b/libraries/bxdf/lama/lama_surface.mtlx @@ -2,11 +2,11 @@ + doc="Material used on the front side (as defined by the geometric normal)." /> + doc="Material used on the back side (as defined by the geometric normal)." /> + doc="Connect a mask here to apply a cutout pattern to your object. This is useful for cutouts like creating leaves and other thin, complex shapes. It can also be used as opacity for gray values for semi-opaque results when seen directly by the camera." /> diff --git a/libraries/bxdf/lama/lama_translucent.mtlx b/libraries/bxdf/lama/lama_translucent.mtlx index 9577e9c14f..ec3e968e09 100644 --- a/libraries/bxdf/lama/lama_translucent.mtlx +++ b/libraries/bxdf/lama/lama_translucent.mtlx @@ -9,10 +9,6 @@ doc="Shading normal, typically defined by bump or normal mapping. Defaults to the smooth surface normal if not set." /> - - diff --git a/libraries/bxdf/open_pbr_surface.mtlx b/libraries/bxdf/open_pbr_surface.mtlx index 8186482cf8..87084bf7fe 100644 --- a/libraries/bxdf/open_pbr_surface.mtlx +++ b/libraries/bxdf/open_pbr_surface.mtlx @@ -23,7 +23,7 @@ doc="Index of refraction of the dielectric base." /> - @@ -75,7 +75,7 @@ doc="The amount of emitted light, as a luminance in nits." /> - diff --git a/libraries/bxdf/standard_surface.mtlx b/libraries/bxdf/standard_surface.mtlx index 20ef806699..495958448d 100644 --- a/libraries/bxdf/standard_surface.mtlx +++ b/libraries/bxdf/standard_surface.mtlx @@ -82,7 +82,7 @@ + doc="The thickness of the thin film layer on a surface. Use for materials such as multitone car paint or soap bubbles (in nanometers)." /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx b/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx index 461e918400..51dfc6c634 100644 --- a/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx +++ b/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx @@ -76,12 +76,24 @@ - + + + + + + + + + + + + + @@ -96,9 +108,18 @@ - - - + + + + + + + + + + + + diff --git a/libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx b/libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx new file mode 100644 index 0000000000..535f65b700 --- /dev/null +++ b/libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libraries/bxdf/translation/standard_surface_to_usd.mtlx b/libraries/bxdf/translation/standard_surface_to_usd.mtlx index 099465e369..f1009e3a4c 100644 --- a/libraries/bxdf/translation/standard_surface_to_usd.mtlx +++ b/libraries/bxdf/translation/standard_surface_to_usd.mtlx @@ -12,6 +12,8 @@ + + @@ -47,13 +49,18 @@ + + + + + - + @@ -80,10 +87,14 @@ - + + + + + diff --git a/libraries/bxdf/usd_preview_surface.mtlx b/libraries/bxdf/usd_preview_surface.mtlx index 7106da779b..4abdb91d9f 100644 --- a/libraries/bxdf/usd_preview_surface.mtlx +++ b/libraries/bxdf/usd_preview_surface.mtlx @@ -6,21 +6,21 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/libraries/cmlib/cmlib_ng.mtlx b/libraries/cmlib/cmlib_ng.mtlx index f6f844f48e..4ac94c2f7a 100644 --- a/libraries/cmlib/cmlib_ng.mtlx +++ b/libraries/cmlib/cmlib_ng.mtlx @@ -315,7 +315,8 @@ - + @@ -354,7 +355,8 @@ - + diff --git a/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl b/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl index 0b28f3645f..1d61576650 100644 --- a/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl @@ -43,8 +43,8 @@ vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distributio // Compute the geometric term. float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); - // Compute the combined FG term, which is inverted for refraction. - vec3 FG = fd.refraction ? vec3(1.0) - (F * G) : F * G; + // Compute the combined FG term, which simplifies to inverted Fresnel for refraction. + vec3 FG = fd.refraction ? vec3(1.0) - F : F * G; // Add the radiance contribution of this sample. // From https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf diff --git a/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl b/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl index 7a80d0d3ec..7bc202bfeb 100644 --- a/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl @@ -13,9 +13,9 @@ vec3 mx_latlong_map_projection_inverse(vec2 uv) float latitude = (uv.y - 0.5) * M_PI; float longitude = (uv.x - 0.5) * M_PI * 2.0; - float x = -cos(latitude) * sin(longitude); - float y = -sin(latitude); - float z = cos(latitude) * cos(longitude); + float x = -mx_cos(latitude) * mx_sin(longitude); + float y = -mx_sin(latitude); + float z = mx_cos(latitude) * mx_cos(longitude); return vec3(x, y, z); } diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl index f0e6f55c13..05c12e907c 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl @@ -77,8 +77,8 @@ vec3 mx_uniform_sample_hemisphere(vec2 Xi) float phi = 2.0 * M_PI * Xi.x; float cosTheta = 1.0 - Xi.y; float sinTheta = sqrt(1.0 - mx_square(cosTheta)); - return vec3(cos(phi) * sinTheta, - sin(phi) * sinTheta, + return vec3(mx_cos(phi) * sinTheta, + mx_sin(phi) * sinTheta, cosTheta); } @@ -88,8 +88,8 @@ vec3 mx_cosine_sample_hemisphere(vec2 Xi) float phi = 2.0 * M_PI * Xi.x; float cosTheta = sqrt(Xi.y); float sinTheta = sqrt(1.0 - Xi.y); - return vec3(cos(phi) * sinTheta, - sin(phi) * sinTheta, + return vec3(mx_cos(phi) * sinTheta, + mx_sin(phi) * sinTheta, cosTheta); } diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl index 622db85012..f26c15df37 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl @@ -89,7 +89,7 @@ float mx_oren_nayar_fujii_diffuse_dir_albedo(float cosTheta, float roughness) float A = 1.0 / (1.0 + FUJII_CONSTANT_1 * roughness); float B = roughness * A; float Si = sqrt(max(0.0, 1.0 - mx_square(cosTheta))); - float G = Si * (acos(clamp(cosTheta, -1.0, 1.0)) - Si * cosTheta) + + float G = Si * (mx_acos(clamp(cosTheta, -1.0, 1.0)) - Si * cosTheta) + 2.0 * ((Si / cosTheta) * (1.0 - Si * Si * Si) - Si) / 3.0; return A + (B * G * M_PI_INV); } @@ -169,7 +169,7 @@ vec3 mx_burley_diffusion_profile(float dist, vec3 shape) // Inspired by Eric Penner's presentation in http://advances.realtimerendering.com/s2011/ vec3 mx_integrate_burley_diffusion(vec3 N, vec3 L, float radius, vec3 mfp) { - float theta = acos(dot(N, L)); + float theta = mx_acos(dot(N, L)); // Estimate the Burley diffusion shape from mean free path. vec3 shape = vec3(1.0) / max(mfp, 0.1); @@ -182,9 +182,9 @@ vec3 mx_integrate_burley_diffusion(vec3 N, vec3 L, float radius, vec3 mfp) for (int i = 0; i < SAMPLE_COUNT; i++) { float x = -M_PI + (float(i) + 0.5) * SAMPLE_WIDTH; - float dist = radius * abs(2.0 * sin(x * 0.5)); + float dist = radius * abs(2.0 * mx_sin(x * 0.5)); vec3 R = mx_burley_diffusion_profile(dist, shape); - sumD += R * max(cos(theta + x), 0.0); + sumD += R * max(mx_cos(theta + x), 0.0); sumR += R; } diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl index fe4eee34e9..6301105dd1 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl @@ -1,6 +1,6 @@ #include "mx_microfacet.glsl" -// http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf +// https://fpsunflower.github.io/ckulla/data/s2017_pbs_imageworks_sheen.pdf // Equation 2 float mx_imageworks_sheen_NDF(float NdotH, float roughness) { @@ -123,7 +123,7 @@ mat3 mx_orthonormal_basis_ltc(vec3 V, vec3 N, float NdotV) float lenSqr = dot(X, X); if (lenSqr > 0.0) { - X *= inversesqrt(lenSqr); + X *= mx_inversesqrt(lenSqr); vec3 Y = cross(N, X); return mat3(X, Y, N); } @@ -173,7 +173,7 @@ vec3 mx_zeltner_sheen_importance_sample(vec2 Xi, vec3 V, vec3 N, float roughness vec3 w = vec3(wo.x/aInv - wo.z*bInv/aInv, wo.y / aInv, wo.z); float lenSqr = dot(w, w); - w *= inversesqrt(lenSqr); + w *= mx_inversesqrt(lenSqr); // D(w) = Do(wo) . ||M.wo||^3 / |M| // = Do(wo / ||M.wo||) . ||M.wo||^4 / |M| diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index 0e77e545e9..fd52bd7435 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -48,8 +48,8 @@ vec3 mx_ggx_importance_sample_VNDF(vec2 Xi, vec3 V, vec2 alpha) float phi = 2.0 * M_PI * Xi.x; float z = (1.0 - Xi.y) * (1.0 + V.z) - V.z; float sinTheta = sqrt(clamp(1.0 - z * z, 0.0, 1.0)); - float x = sinTheta * cos(phi); - float y = sinTheta * sin(phi); + float x = sinTheta * mx_cos(phi); + float y = sinTheta * mx_sin(phi); vec3 c = vec3(x, y, z); // Compute the microfacet normal. @@ -286,9 +286,9 @@ void mx_fresnel_conductor_phase_polarized(float cosTheta, float eta1, vec3 eta2, vec3 U = sqrt((A+B)/2.0); vec3 V = max(vec3(0.0), sqrt((B-A)/2.0)); - phiS = atan(2.0*eta1*V*cosTheta, U*U + V*V - mx_square(eta1*cosTheta)); - phiP = atan(2.0*eta1*eta2*eta2*cosTheta * (2.0*k2*U - (vec3(1.0)-k2*k2) * V), - mx_square(eta2*eta2*(vec3(1.0)+k2*k2)*cosTheta) - eta1*eta1*(U*U+V*V)); + phiS = mx_atan(2.0*eta1*V*cosTheta, U*U + V*V - mx_square(eta1*cosTheta)); + phiP = mx_atan(2.0*eta1*eta2*eta2*cosTheta * (2.0*k2*U - (vec3(1.0)-k2*k2) * V), + mx_square(eta2*eta2*(vec3(1.0)+k2*k2)*cosTheta) - eta1*eta1*(U*U+V*V)); } // https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html @@ -299,8 +299,8 @@ vec3 mx_eval_sensitivity(float opd, vec3 shift) vec3 val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13); vec3 pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06); vec3 var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09); - vec3 xyz = val * sqrt(2.0*M_PI * var) * cos(pos * phase + shift) * exp(- var * phase*phase); - xyz.x += 9.7470e-14 * sqrt(2.0*M_PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift[0]) * exp(- 4.5282e+09 * phase*phase); + vec3 xyz = val * sqrt(2.0*M_PI * var) * mx_cos(pos * phase + shift) * exp(- var * phase*phase); + xyz.x += 9.7470e-14 * sqrt(2.0*M_PI * 4.5282e+09) * mx_cos(2.2399e+06 * phase + shift[0]) * exp(- 4.5282e+09 * phase*phase); return xyz / 1.0685e-7; } @@ -341,7 +341,7 @@ vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) } // Phase shift - float cosB = cos(atan(eta2 / eta1)); + float cosB = mx_cos(mx_atan(eta2 / eta1)); vec2 phi21 = vec2(cosTheta < cosB ? 0.0 : M_PI, M_PI); vec3 phi23p, phi23s; if (fd.model == FRESNEL_MODEL_SCHLICK) @@ -486,8 +486,8 @@ vec3 mx_refraction_solid_sphere(vec3 R, vec3 N, float ior) vec2 mx_latlong_projection(vec3 dir) { - float latitude = -asin(dir.y) * M_PI_INV + 0.5; - float longitude = atan(dir.x, -dir.z) * M_PI_INV * 0.5 + 0.5; + float latitude = -mx_asin(dir.y) * M_PI_INV + 0.5; + float longitude = mx_atan(dir.x, -dir.z) * M_PI_INV * 0.5 + 0.5; return vec2(longitude, latitude); } diff --git a/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl b/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl new file mode 100644 index 0000000000..22b2226ab3 --- /dev/null +++ b/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl @@ -0,0 +1,351 @@ +#include "lib/mx_microfacet_specular.glsl" + +// https://eugenedeon.com/pdfs/egsrhair.pdf +void mx_deon_hair_absorption_from_melanin( + float melanin_concentration, + float melanin_redness, + // constants converted to color via exp(-c). the defaults are lin_rec709 colors, they may be + // transformed to scene-linear rendering color space. + vec3 eumelanin_color, // default: (0.657704, 0.498077, 0.254106) == exp(-(0.419, 0.697, 1.37)) + vec3 pheomelanin_color, // default: (0.829443, 0.670320, 0.349937) == exp(-(0.187, 0.4, 1.05)) + out vec3 absorption) +{ + float melanin = -log(max(1.0 - melanin_concentration, 0.0001)); + float eumelanin = melanin * (1.0 - melanin_redness); + float pheomelanin = melanin * melanin_redness; + absorption = max( + eumelanin * -log(eumelanin_color) + pheomelanin * -log(pheomelanin_color), + vec3(0.0) + ); +} + +// https://media.disneyanimation.com/uploads/production/publication_asset/152/asset/eurographics2016Fur_Smaller.pdf +void mx_chiang_hair_absorption_from_color(vec3 color, float betaN, out vec3 absorption) +{ + float b2 = betaN* betaN; + float b4 = b2 * b2; + float b_fac = + 5.969 - + (0.215 * betaN) + + (2.532 * b2) - + (10.73 * b2 * betaN) + + (5.574 * b4) + + (0.245 * b4 * betaN); + vec3 sigma = log(min(max(color, 0.001), vec3(1.0))) / b_fac; + absorption = sigma * sigma; +} + +void mx_chiang_hair_roughness( + float longitudinal, + float azimuthal, + float scale_TT, // empirical roughenss scale from Marschner et al. (2003). + float scale_TRT, // default: scale_TT = 0.5, scale_TRT = 2.0 + out vec2 roughness_R, + out vec2 roughness_TT, + out vec2 roughness_TRT +) +{ + float lr = clamp(longitudinal, 0.001, 1.0); + float ar = clamp(azimuthal, 0.001, 1.0); + + // longitudinal variance + float v = 0.726 * lr + 0.812 * lr * lr + 3.7 * pow(lr, 20.0); + v = v * v; + + float s = 0.265 * ar + 1.194 * ar * ar + 5.372 * pow(ar, 22.0); + + roughness_R = vec2(v, s); + roughness_TT = vec2(v * scale_TT * scale_TT, s); + roughness_TRT = vec2(v * scale_TRT * scale_TRT, s); +} + +float mx_hair_transform_sin_cos(float x) +{ + return sqrt(max(1.0 - x * x, 0.0)); +} + +float mx_hair_I0(float x) +{ + float v = 1.0; + float n = 1.0; + float d = 1.0; + float f = 1.0; + float x2 = x * x; + for (int i = 0; i < 9 ; ++i) + { + d *= 4.0 * (f * f); + n *= x2; + v += n / d; + f += 1.0; + } + return v; +} + +float mx_hair_log_I0(float x) +{ + if (x > 12.0) + return x + 0.5 * (-log(2.0 * M_PI) + log(1.0 / x) + 1.0 / (8.0 * x)); + else + return log(mx_hair_I0(x)); +} + +float mx_hair_logistic(float x, float s) +{ + if (x > 0.0) + x = -x; + float f = exp(x / s); + return f / (s * (1.0 + f) * (1.0 + f)); +} + +float mx_hair_logistic_cdf(float x, float s) +{ + return 1.0 / (1.0 + exp(-x / s)); +} + +float mx_hair_trimmed_logistic(float x, float s, float a, float b) +{ + // the constant can be found in Chiang et al. (2016) Appendix A, eq. (12) + s *= 0.626657; // sqrt(M_PI/8) + return mx_hair_logistic(x, s) / (mx_hair_logistic_cdf(b, s) - mx_hair_logistic_cdf(a, s)); +} + +float mx_hair_phi(int p, float gammaO, float gammaT) +{ + float fP = float(p); + return 2.0 * fP * gammaT - 2.0 * gammaO + fP * M_PI; +} + +float mx_hair_longitudinal_scattering( // Mp + float sinThetaI, + float cosThetaI, + float sinThetaO, + float cosThetaO, + float v +) +{ + float inv_v = 1.0 / v; + float a = cosThetaO * cosThetaI * inv_v; + float b = sinThetaO * sinThetaI * inv_v; + if (v < 0.1) + return exp(mx_hair_log_I0(a) - b - inv_v + 0.6931 + log(0.5 * inv_v)); + else + return ((exp(-b) * mx_hair_I0(a)) / (2.0 * v * sinh(inv_v))); +} + +float mx_hair_azimuthal_scattering( // Np + float phi, + int p, + float s, + float gammaO, + float gammaT +) +{ + if (p >= 3) + return float(0.5 / M_PI); + + float dphi = phi - mx_hair_phi(p, gammaO, gammaT); + if (isinf(dphi)) + return float(0.5 / M_PI); + + while (dphi > M_PI) dphi -= (2.0 * M_PI); + while (dphi < (-M_PI)) dphi += (2.0 * M_PI); + + return mx_hair_trimmed_logistic(dphi, s, -M_PI, M_PI); +} + +void mx_hair_alpha_angles( + float alpha, + float sinThetaI, + float cosThetaI, + out vec2 angles[4] +) +{ + // 0:R, 1:TT, 2:TRT, 3:TRRT+ + for (int i = 0; i <= 3; ++i) + { + if (alpha == 0.0 || i == 3) + angles[i] = vec2(sinThetaI, cosThetaI); + else + { + float m = 2.0 - float(i) * 3.0; + float sa = sin(m * alpha); + float ca = cos(m * alpha); + angles[i].x = sinThetaI * ca + cosThetaI * sa; + angles[i].y = cosThetaI * ca - sinThetaI * sa; + } + } +} + +void mx_hair_attenuation(float f, vec3 T, out vec3 Ap[4]) // Ap +{ + // 0:R, 1:TT, 2:TRT, 3:TRRT+ + Ap[0] = vec3(f); + Ap[1] = (1.0 - f) * (1.0 - f) * T; + Ap[2] = Ap[1] * T * f; + Ap[3] = Ap[2] * T * f / (vec3(1.0) - T * f); +} + +vec3 mx_chiang_hair_bsdf( + vec3 L, + vec3 V, + vec3 tint_R, + vec3 tint_TT, + vec3 tint_TRT, + float ior, + vec2 roughness_R, + vec2 roughness_TT, + vec2 roughness_TRT, + float cuticle_angle, + vec3 absorption_coefficient, + vec3 N, + vec3 X +) +{ + N = mx_forward_facing_normal(N, V); + X = normalize(X - dot(X, N) * N); + vec3 Y = cross(N, X); + + float sinThetaO = dot(V, X); + float sinThetaI = dot(L, X); + float cosThetaO = mx_hair_transform_sin_cos(sinThetaO); + float cosThetaI = mx_hair_transform_sin_cos(sinThetaI); + + float y1 = dot(L, N); + float x1 = dot(L, Y); + float y2 = dot(V, N); + float x2 = dot(V, Y); + float phi = mx_atan(y1 * x2 - y2 * x1, x1 * x2 + y1 * y2); + + vec3 k1_p = normalize(V - X * dot(V, X)); + float cosGammaO = dot(N, k1_p); + float sinGammaO = mx_hair_transform_sin_cos(cosGammaO); + if (dot(k1_p, Y) > 0.0) + sinGammaO = -sinGammaO; + float gammaO = asin(sinGammaO); + + float sinThetaT = sinThetaO / ior; + float cosThetaT = mx_hair_transform_sin_cos(sinThetaT); + float etaP = sqrt(max(ior * ior - sinThetaO * sinThetaO, 0.0)) / max(cosThetaO, 1e-8); + float sinGammaT = max(min(sinGammaO / etaP, 1.0), -1.0); + float cosGammaT = sqrt(1.0 - sinGammaT * sinGammaT); + float gammaT = asin(sinGammaT); + + // attenuation + vec3 Ap[4]; + float fresnel = mx_fresnel_dielectric(cosThetaO * cosGammaO, ior); + vec3 T = exp(-absorption_coefficient * (2.0 * cosGammaT / cosThetaT)); + mx_hair_attenuation(fresnel, T, Ap); + + // parameters for each lobe + vec2 angles[4]; + float alpha = cuticle_angle * M_PI - (M_PI / 2.0); // remap [0, 1] to [-PI/2, PI/2] + mx_hair_alpha_angles(alpha, sinThetaI, cosThetaI, angles); + + vec3 tint[4]; + tint[0] = tint_R; + tint[1] = tint_TT; + tint[2] = tint_TRT; + tint[3] = tint_TRT; + + roughness_R = clamp(roughness_R, 0.001, 1.0); + roughness_TT = clamp(roughness_TT, 0.001, 1.0); + roughness_TRT = clamp(roughness_TRT, 0.001, 1.0); + + vec2 vs[4]; + vs[0] = roughness_R; + vs[1] = roughness_TT; + vs[2] = roughness_TRT; + vs[3] = roughness_TRT; + + // R, TT, TRT, TRRT+ + vec3 F = vec3(0.0); + for (int i = 0; i <= 3; ++i) + { + tint[i] = max(tint[i], vec3(0.0)); + float Mp = mx_hair_longitudinal_scattering(angles[i].x, angles[i].y, sinThetaO, cosThetaO, vs[i].x); + float Np = (i == 3) ? (1.0 / 2.0 * M_PI) : mx_hair_azimuthal_scattering(phi, i, vs[i].y, gammaO, gammaT); + F += Mp * Np * tint[i] * Ap[i]; + } + + return F; +} + +void mx_chiang_hair_bsdf_reflection( + vec3 L, + vec3 V, + vec3 P, + float occlusion, + vec3 tint_R, + vec3 tint_TT, + vec3 tint_TRT, + float ior, + vec2 roughness_R, + vec2 roughness_TT, + vec2 roughness_TRT, + float cuticle_angle, + vec3 absorption_coefficient, + vec3 N, + vec3 X, + inout BSDF bsdf +) +{ + vec3 F = mx_chiang_hair_bsdf( + L, + V, + tint_R, + tint_TT, + tint_TRT, + ior, + roughness_R, + roughness_TT, + roughness_TRT, + cuticle_angle, + absorption_coefficient, + N, + X + ); + + bsdf.throughput = vec3(0.0); + bsdf.response = F * occlusion * M_PI_INV; +} + +void mx_chiang_hair_bsdf_indirect( + vec3 V, + vec3 tint_R, + vec3 tint_TT, + vec3 tint_TRT, + float ior, + vec2 roughness_R, + vec2 roughness_TT, + vec2 roughness_TRT, + float cuticle_angle, + vec3 absorption_coefficient, + vec3 N, + vec3 X, + inout BSDF bsdf +) +{ + // this indirect lighing is *very* rough approximation + + N = mx_forward_facing_normal(N, V); + + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + + FresnelData fd = mx_init_fresnel_dielectric(ior, 0.0, 1.0); + vec3 F = mx_compute_fresnel(NdotV, fd); + + vec2 roughness = (roughness_R + roughness_TT + roughness_TRT) / vec2(3.0); // ? + vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); + float avgAlpha = mx_average_alpha(safeAlpha); + + // use ggx because the environment map for FIS is preintegrated with ggx + float F0 = mx_ior_to_f0(ior); + vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); + vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, F0, 1.0) * comp; + + vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, 0, fd); + vec3 tint = (tint_R + tint_TT + tint_TRT) / vec3(3.0); // ? + + bsdf.throughput = vec3(0.0); + bsdf.response = Li * comp * tint; +} diff --git a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl index 764412b90d..f4598dd0d0 100644 --- a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl @@ -66,7 +66,7 @@ void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, { float avgF0 = dot(safeColor0, vec3(1.0 / 3.0)); fd.ior = vec3(mx_f0_to_ior(avgF0)); - bsdf.response = mx_surface_transmission(N, V, X, safeAlpha, distribution, fd, safeColor0) * weight; + bsdf.response = mx_surface_transmission(N, V, X, safeAlpha, distribution, fd, vec3(1.0)) * weight; } } diff --git a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx index 2a23886640..4b3be10faf 100644 --- a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx +++ b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx @@ -25,6 +25,9 @@ + + + @@ -74,4 +77,13 @@ + + + + + + + + + diff --git a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx index 86b19eaa71..45f83f164a 100644 --- a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx +++ b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx @@ -2,7 +2,7 @@ - + @@ -11,13 +11,13 @@ - + - + @@ -25,6 +25,9 @@ + + + @@ -90,4 +93,13 @@ + + + + + + + + + diff --git a/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx b/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx index e88a47a1dc..30dd6e937d 100644 --- a/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx +++ b/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx @@ -1,33 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -46,29 +19,10 @@ - - - - - - - - - - - - - - - - - - - diff --git a/libraries/pbrlib/genosl/legacy/mx_anisotropic_vdf.osl b/libraries/pbrlib/genosl/legacy/mx_anisotropic_vdf.osl deleted file mode 100644 index 6d52e08509..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_anisotropic_vdf.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_anisotropic_vdf(vector absorption, vector scattering, float anisotropy, output VDF vdf) -{ - // Not implemented in vanilla OSL - vdf = 0; // volume_henyey_greenstein(color(absorption), color(scattering), color(0.0), anisotropy); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_burley_diffuse_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_burley_diffuse_bsdf.osl deleted file mode 100644 index 5f7d397dce..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_burley_diffuse_bsdf.osl +++ /dev/null @@ -1,6 +0,0 @@ -void mx_burley_diffuse_bsdf(float weight, color reflectance, float roughness, normal N, output BSDF bsdf) -{ - // TODO: Implement properly. - bsdf.response = reflectance * weight * oren_nayar(N, roughness); - bsdf.throughput = color(0.0); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl deleted file mode 100644 index 82cb6f32be..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl +++ /dev/null @@ -1,32 +0,0 @@ -#include "../lib/mx_microfacet_specular.osl" - -void mx_conductor_bsdf(float weight, color ior_n, color ior_k, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, output BSDF bsdf) -{ - bsdf.throughput = color(0.0); - - if (weight < M_FLOAT_EPS) - { - bsdf.response = 0; - return; - } - - // Calculate conductor fresnel - // - // Fresnel should be based on microfacet normal - // but we have no access to that from here, so just use - // view direction and surface normal instead - // - float NdotV = fabs(dot(N,-I)); - color F = mx_fresnel_conductor(NdotV, ior_n, ior_k); - - // Calculate compensation for multiple scattering. - // This should normally be done inside the closure - // but since vanilla OSL doesen't support this we - // add it here in shader code instead. - vector2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); - float avgAlpha = mx_average_alpha(safeAlpha); - color comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - - // Set ior to 0.0 to disable the internal dielectric fresnel - bsdf.response = F * comp * weight * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, 0.0, false); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl deleted file mode 100644 index 5e50834746..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl +++ /dev/null @@ -1,36 +0,0 @@ -#include "../lib/mx_microfacet_specular.osl" - -void mx_dielectric_bsdf(float weight, color tint, float ior, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) -{ - if (scatter_mode == "T") - { - bsdf.response = tint * weight * microfacet(distribution, N, U, roughness.x, roughness.y, ior, 1); - bsdf.throughput = tint * weight; - return; - } - - float NdotV = clamp(dot(N,-I), M_FLOAT_EPS, 1.0); - float F0 = mx_ior_to_f0(ior); - float F = mx_fresnel_schlick(NdotV, F0); - - // Calculate compensation for multiple scattering. - // This should normally be done inside the closure - // but since vanilla OSL doesen't support this we - // add it here in shader code instead. - vector2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); - float avgAlpha = mx_average_alpha(safeAlpha); - float comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - - // Calculate throughput from directional albedo. - float dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, ior) * comp; - bsdf.throughput = 1.0 - dirAlbedo * weight; - - if (scatter_mode == "R") - { - bsdf.response = tint * weight * comp * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, ior, 0); - } - else - { - bsdf.response = tint * weight * comp * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, ior, 2); - } -} diff --git a/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl deleted file mode 100644 index cd022f8295..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl +++ /dev/null @@ -1,38 +0,0 @@ -#include "../lib/mx_microfacet_specular.osl" - -void mx_generalized_schlick_bsdf(float weight, color color0, color color82, color color90, float exponent, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) -{ - float avgF0 = dot(color0, color(1.0 / 3.0)); - float ior = mx_f0_to_ior(avgF0); - - if (scatter_mode == "T") - { - bsdf.response = weight * microfacet(distribution, N, U, roughness.x, roughness.y, ior, 1); - bsdf.throughput = weight; - return; - } - - float NdotV = fabs(dot(N,-I)); - color F = mx_fresnel_schlick(NdotV, color0, color90, exponent); - - // Calculate compensation for multiple scattering. - // This should normally be done inside the closure - // but since vanilla OSL doesen't support this we - // add it here in shader code instead. - vector2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); - float avgAlpha = mx_average_alpha(safeAlpha); - color comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - - // Calculate throughput from directional albedo. - color dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, color0, color90) * comp; - float avgDirAlbedo = dot(dirAlbedo, color(1.0 / 3.0)); - bsdf.throughput = 1.0 - avgDirAlbedo * weight; - - // Calculate the reflection response, setting IOR to zero to disable internal Fresnel. - bsdf.response = F * comp * weight * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, 0.0, 0); - - if (scatter_mode == "RT") - { - bsdf.response += bsdf.throughput * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, ior, 1); - } -} diff --git a/libraries/pbrlib/genosl/legacy/mx_oren_nayar_diffuse_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_oren_nayar_diffuse_bsdf.osl deleted file mode 100644 index b9c5fba797..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_oren_nayar_diffuse_bsdf.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_oren_nayar_diffuse_bsdf(float weight, color _color, float roughness, normal N, int energy_compensation, output BSDF bsdf) -{ - bsdf.response = _color * weight * oren_nayar(N, roughness); - bsdf.throughput = color(0.0); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_sheen_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_sheen_bsdf.osl deleted file mode 100644 index e94325fe99..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_sheen_bsdf.osl +++ /dev/null @@ -1,24 +0,0 @@ -#include "../lib/mx_microfacet_sheen.osl" - -// TODO: Vanilla OSL doesn't have a proper sheen closure, -// so use 'diffuse' scaled by sheen directional albedo for now. -void mx_sheen_bsdf(float weight, color Ks, float roughness, vector N, output BSDF bsdf) -{ - if (weight < M_FLOAT_EPS) - { - bsdf.response = 0; - bsdf.throughput = color(1.0); - return; - } - - // TODO: Normalization should not be needed. My suspicion is that - // BSDF sampling of new outgoing direction in 'testrender' needs - // to be fixed. - vector V = normalize(-I); - - float NdotV = fabs(dot(N,V)); - float alpha = clamp(roughness, M_FLOAT_EPS, 1.0); - float albedo = weight * mx_imageworks_sheen_dir_albedo(NdotV, alpha); - bsdf.response = albedo * Ks * diffuse(N); - bsdf.throughput = 1.0 - albedo; -} diff --git a/libraries/pbrlib/genosl/legacy/mx_subsurface_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_subsurface_bsdf.osl deleted file mode 100644 index da0e3cc12a..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_subsurface_bsdf.osl +++ /dev/null @@ -1,6 +0,0 @@ -void mx_subsurface_bsdf(float weight, color _color, color radius, float anisotropy, normal N, output BSDF bsdf) -{ - // TODO: Subsurface closure is not supported by vanilla OSL. - bsdf.response = _color * weight * diffuse(N); - bsdf.throughput = color(0.0); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_surface.osl b/libraries/pbrlib/genosl/legacy/mx_surface.osl deleted file mode 100644 index d48320411e..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_surface.osl +++ /dev/null @@ -1,6 +0,0 @@ -void mx_surface(BSDF bsdf, EDF edf, float opacity, int thin_walled, output surfaceshader result) -{ - result.bsdf = bsdf.response; - result.edf = edf; - result.opacity = clamp(opacity, 0.0, 1.0); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_translucent_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_translucent_bsdf.osl deleted file mode 100644 index fd56a37db8..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_translucent_bsdf.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_translucent_bsdf(float weight, color _color, normal N, output BSDF bsdf) -{ - bsdf.response = _color * weight * translucent(N); - bsdf.throughput = color(0.0); -} diff --git a/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl b/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl index 6b2a7d5298..eb48e72e65 100644 --- a/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl +++ b/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl @@ -1,6 +1,8 @@ -void mx_anisotropic_vdf(vector absorption, vector scattering, float anisotropy, output VDF vdf) +void mx_anisotropic_vdf(color absorption, color scattering, float anisotropy, output VDF vdf) { - // TODO: Need to remap parameters to match the new closure, - // or change the MaterialX spec to OSL parameterization. - vdf = 0; + // Convert from absorption and scattering coefficients to + // extinction coefficient and single-scattering albedo. + color extinction = absorption + scattering; + color albedo = scattering / extinction; + vdf = anisotropic_vdf(albedo, extinction, anisotropy); } diff --git a/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl b/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl new file mode 100644 index 0000000000..002bdc3044 --- /dev/null +++ b/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl @@ -0,0 +1,7 @@ +void mx_chiang_hair_roughness(float longitudinal, float azimuthal, float scale_TT, float scale_TRT, output vector2 roughness_R, output vector2 roughness_TT, output vector2 roughness_TRT) +{ + // TODO: Write OSL implementation of this node. + roughness_R = vector2(0.0, 0.0); + roughness_TT = vector2(0.0, 0.0); + roughness_TRT = vector2(0.0, 0.0); +} diff --git a/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy b/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy deleted file mode 100644 index e4a424e1ac..0000000000 --- a/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx index d3849a5ddb..beac984518 100644 --- a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx +++ b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx @@ -22,6 +22,9 @@ + + + @@ -71,4 +74,13 @@ + + + + + + + + + diff --git a/libraries/pbrlib/pbrlib_defs.mtlx b/libraries/pbrlib/pbrlib_defs.mtlx index 2e71f80611..0bb75716e6 100644 --- a/libraries/pbrlib/pbrlib_defs.mtlx +++ b/libraries/pbrlib/pbrlib_defs.mtlx @@ -136,6 +136,25 @@ + + + + + + + + + + + + + + + + @@ -404,4 +423,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libraries/stdlib/genglsl/lib/mx_math.glsl b/libraries/stdlib/genglsl/lib/mx_math.glsl index 781a24a6e7..d196615e70 100644 --- a/libraries/stdlib/genglsl/lib/mx_math.glsl +++ b/libraries/stdlib/genglsl/lib/mx_math.glsl @@ -1,5 +1,16 @@ #define M_FLOAT_EPS 1e-8 +#define mx_mod mod +#define mx_inverse inverse +#define mx_inversesqrt inversesqrt +#define mx_sin sin +#define mx_cos cos +#define mx_tan tan +#define mx_asin asin +#define mx_acos acos +#define mx_atan atan +#define mx_radians radians + float mx_square(float x) { return x*x; diff --git a/libraries/stdlib/genglsl/mx_burn_color3.glsl b/libraries/stdlib/genglsl/mx_burn_color3.glsl index 10f4008f1a..8e60f857d6 100644 --- a/libraries/stdlib/genglsl/mx_burn_color3.glsl +++ b/libraries/stdlib/genglsl/mx_burn_color3.glsl @@ -2,7 +2,8 @@ void mx_burn_color3(vec3 fg, vec3 bg, float mixval, out vec3 result) { - mx_burn_float(fg.x, bg.x, mixval, result.x); - mx_burn_float(fg.y, bg.y, mixval, result.y); - mx_burn_float(fg.z, bg.z, mixval, result.z); + float f; + mx_burn_float(fg.x, bg.x, mixval, f); result.x = f; + mx_burn_float(fg.y, bg.y, mixval, f); result.y = f; + mx_burn_float(fg.z, bg.z, mixval, f); result.z = f; } diff --git a/libraries/stdlib/genglsl/mx_burn_color4.glsl b/libraries/stdlib/genglsl/mx_burn_color4.glsl index df6802a646..a1add5a372 100644 --- a/libraries/stdlib/genglsl/mx_burn_color4.glsl +++ b/libraries/stdlib/genglsl/mx_burn_color4.glsl @@ -2,8 +2,9 @@ void mx_burn_color4(vec4 fg, vec4 bg, float mixval, out vec4 result) { - mx_burn_float(fg.x, bg.x, mixval, result.x); - mx_burn_float(fg.y, bg.y, mixval, result.y); - mx_burn_float(fg.z, bg.z, mixval, result.z); - mx_burn_float(fg.w, bg.w, mixval, result.w); + float f; + mx_burn_float(fg.x, bg.x, mixval, f); result.x = f; + mx_burn_float(fg.y, bg.y, mixval, f); result.y = f; + mx_burn_float(fg.z, bg.z, mixval, f); result.z = f; + mx_burn_float(fg.w, bg.w, mixval, f); result.w = f; } diff --git a/libraries/stdlib/genglsl/mx_dodge_color3.glsl b/libraries/stdlib/genglsl/mx_dodge_color3.glsl index a8cfd1dff7..aa9cf023a6 100644 --- a/libraries/stdlib/genglsl/mx_dodge_color3.glsl +++ b/libraries/stdlib/genglsl/mx_dodge_color3.glsl @@ -2,7 +2,8 @@ void mx_dodge_color3(vec3 fg, vec3 bg, float mixval, out vec3 result) { - mx_dodge_float(fg.x, bg.x, mixval, result.x); - mx_dodge_float(fg.y, bg.y, mixval, result.y); - mx_dodge_float(fg.z, bg.z, mixval, result.z); + float f; + mx_dodge_float(fg.x, bg.x, mixval, f); result.x = f; + mx_dodge_float(fg.y, bg.y, mixval, f); result.y = f; + mx_dodge_float(fg.z, bg.z, mixval, f); result.z = f; } diff --git a/libraries/stdlib/genglsl/mx_dodge_color4.glsl b/libraries/stdlib/genglsl/mx_dodge_color4.glsl index c492043ceb..25888219b6 100644 --- a/libraries/stdlib/genglsl/mx_dodge_color4.glsl +++ b/libraries/stdlib/genglsl/mx_dodge_color4.glsl @@ -2,8 +2,9 @@ void mx_dodge_color4(vec4 fg , vec4 bg , float mixval, out vec4 result) { - mx_dodge_float(fg.x, bg.x, mixval, result.x); - mx_dodge_float(fg.y, bg.y, mixval, result.y); - mx_dodge_float(fg.z, bg.z, mixval, result.z); - mx_dodge_float(fg.w, bg.w, mixval, result.w); + float f; + mx_dodge_float(fg.x, bg.x, mixval, f); result.x = f; + mx_dodge_float(fg.y, bg.y, mixval, f); result.y = f; + mx_dodge_float(fg.z, bg.z, mixval, f); result.z = f; + mx_dodge_float(fg.w, bg.w, mixval, f); result.w = f; } diff --git a/libraries/stdlib/genglsl/mx_normalmap.glsl b/libraries/stdlib/genglsl/mx_normalmap.glsl index 19e0797c4f..66c50f31f5 100644 --- a/libraries/stdlib/genglsl/mx_normalmap.glsl +++ b/libraries/stdlib/genglsl/mx_normalmap.glsl @@ -1,21 +1,13 @@ -void mx_normalmap_vector2(vec3 value, int map_space, vec2 normal_scale, vec3 N, vec3 T, out vec3 result) +void mx_normalmap_vector2(vec3 value, vec2 normal_scale, vec3 N, vec3 T, vec3 B, out vec3 result) { - // Decode the normal map. - value = (value == vec3(0.0f)) ? vec3(0.0, 0.0, 1.0) : value * 2.0 - 1.0; - - // Transform from tangent space if needed. - if (map_space == 0) - { - vec3 B = normalize(cross(N, T)); - value.xy *= normal_scale; - value = T * value.x + B * value.y + N * value.z; - } - - // Normalize the result. + value = (dot(value, value) == 0.0) ? vec3(0.0, 0.0, 1.0) : value * 2.0 - 1.0; + value = T * value.x * normal_scale.x + + B * value.y * normal_scale.y + + N * value.z; result = normalize(value); } -void mx_normalmap_float(vec3 value, int map_space, float normal_scale, vec3 N, vec3 T, out vec3 result) +void mx_normalmap_float(vec3 value, float normal_scale, vec3 N, vec3 T, vec3 B, out vec3 result) { - mx_normalmap_vector2(value, map_space, vec2(normal_scale), N, T, result); + mx_normalmap_vector2(value, vec2(normal_scale), N, T, B, result); } diff --git a/libraries/stdlib/genglsl/mx_rotate_vector2.glsl b/libraries/stdlib/genglsl/mx_rotate_vector2.glsl index a66c17d0ab..d01270d8ce 100644 --- a/libraries/stdlib/genglsl/mx_rotate_vector2.glsl +++ b/libraries/stdlib/genglsl/mx_rotate_vector2.glsl @@ -1,7 +1,7 @@ void mx_rotate_vector2(vec2 _in, float amount, out vec2 result) { - float rotationRadians = radians(amount); - float sa = sin(rotationRadians); - float ca = cos(rotationRadians); + float rotationRadians = mx_radians(amount); + float sa = mx_sin(rotationRadians); + float ca = mx_cos(rotationRadians); result = vec2(ca*_in.x + sa*_in.y, -sa*_in.x + ca*_in.y); } diff --git a/libraries/stdlib/genglsl/mx_rotate_vector3.glsl b/libraries/stdlib/genglsl/mx_rotate_vector3.glsl index fb06e120ec..fda1188379 100644 --- a/libraries/stdlib/genglsl/mx_rotate_vector3.glsl +++ b/libraries/stdlib/genglsl/mx_rotate_vector3.glsl @@ -1,8 +1,8 @@ mat4 mx_rotationMatrix(vec3 axis, float angle) { axis = normalize(axis); - float s = sin(angle); - float c = cos(angle); + float s = mx_sin(angle); + float c = mx_cos(angle); float oc = 1.0 - c; return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, @@ -13,7 +13,7 @@ mat4 mx_rotationMatrix(vec3 axis, float angle) void mx_rotate_vector3(vec3 _in, float amount, vec3 axis, out vec3 result) { - float rotationRadians = radians(amount); + float rotationRadians = mx_radians(amount); mat4 m = mx_rotationMatrix(axis, rotationRadians); result = (m * vec4(_in, 1.0)).xyz; } diff --git a/libraries/stdlib/genglsl/mx_smoothstep_float.glsl b/libraries/stdlib/genglsl/mx_smoothstep_float.glsl index 1bca2e4d9b..0b317bdf33 100644 --- a/libraries/stdlib/genglsl/mx_smoothstep_float.glsl +++ b/libraries/stdlib/genglsl/mx_smoothstep_float.glsl @@ -1,9 +1,9 @@ void mx_smoothstep_float(float val, float low, float high, out float result) { - if (val <= low) - result = 0.0; - else if (val >= high) + if (val >= high) result = 1.0; + else if (val <= low) + result = 0.0; else result = smoothstep(low, high, val); } diff --git a/libraries/stdlib/genglsl/mx_smoothstep_vector2.glsl b/libraries/stdlib/genglsl/mx_smoothstep_vector2.glsl deleted file mode 100644 index f0e630af20..0000000000 --- a/libraries/stdlib/genglsl/mx_smoothstep_vector2.glsl +++ /dev/null @@ -1,7 +0,0 @@ -#include "mx_smoothstep_float.glsl" - -void mx_smoothstep_vector2(vec2 val, vec2 low, vec2 high, out vec2 result) -{ - mx_smoothstep_float(val.x, low.x, high.x, result.x); - mx_smoothstep_float(val.y, low.y, high.y, result.y); -} diff --git a/libraries/stdlib/genglsl/mx_smoothstep_vector3.glsl b/libraries/stdlib/genglsl/mx_smoothstep_vector3.glsl deleted file mode 100644 index b6094785a8..0000000000 --- a/libraries/stdlib/genglsl/mx_smoothstep_vector3.glsl +++ /dev/null @@ -1,8 +0,0 @@ -#include "mx_smoothstep_float.glsl" - -void mx_smoothstep_vector3(vec3 val, vec3 low, vec3 high, out vec3 result) -{ - mx_smoothstep_float(val.x, low.x, high.x, result.x); - mx_smoothstep_float(val.y, low.y, high.y, result.y); - mx_smoothstep_float(val.z, low.z, high.z, result.z); -} diff --git a/libraries/stdlib/genglsl/mx_smoothstep_vector4.glsl b/libraries/stdlib/genglsl/mx_smoothstep_vector4.glsl deleted file mode 100644 index 1a2d4a986b..0000000000 --- a/libraries/stdlib/genglsl/mx_smoothstep_vector4.glsl +++ /dev/null @@ -1,9 +0,0 @@ -#include "mx_smoothstep_float.glsl" - -void mx_smoothstep_vector4(vec4 val, vec4 low, vec4 high, out vec4 result) -{ - mx_smoothstep_float(val.x, low.x, high.x, result.x); - mx_smoothstep_float(val.y, low.y, high.y, result.y); - mx_smoothstep_float(val.z, low.z, high.z, result.z); - mx_smoothstep_float(val.w, low.w, high.w, result.w); -} diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index 2c8d697c89..ad3a21e9cf 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -129,12 +129,6 @@ - - - - - - @@ -252,17 +246,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -326,30 +320,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -458,8 +452,8 @@ - - + + @@ -488,9 +482,6 @@ - - - diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index 32bf05aeac..6ac2b862dd 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -44,8 +44,8 @@ - - + + @@ -131,13 +131,6 @@ - - - - - - - @@ -686,7 +679,7 @@ - + @@ -695,7 +688,7 @@ - + diff --git a/libraries/stdlib/genmsl/lib/mx_math.metal b/libraries/stdlib/genmsl/lib/mx_math.metal index 7c4851ea31..afd8fb4a7e 100644 --- a/libraries/stdlib/genmsl/lib/mx_math.metal +++ b/libraries/stdlib/genmsl/lib/mx_math.metal @@ -1,5 +1,11 @@ #define M_FLOAT_EPS 1e-8 +#define mx_sin sin +#define mx_cos cos +#define mx_tan tan +#define mx_asin asin +#define mx_acos acos + float mx_square(float x) { return x*x; @@ -15,17 +21,18 @@ vec3 mx_square(vec3 x) return x*x; } +float mx_inversesqrt(float x) +{ + return ::rsqrt(x); +} + template T1 mx_mod(T1 x, T2 y) { return x - y * floor(x/y); } -#ifdef __DECL_GL_MATH_FUNCTIONS__ - -float radians(float degree) { return (degree * M_PI_F / 180.0f); } - -float3x3 inverse(float3x3 m) +float3x3 mx_inverse(float3x3 m) { float n11 = m[0][0], n12 = m[1][0], n13 = m[2][0]; float n21 = m[0][1], n22 = m[1][1], n23 = m[2][1]; @@ -51,7 +58,7 @@ float3x3 inverse(float3x3 m) return ret; } -float4x4 inverse(float4x4 m) +float4x4 mx_inverse(float4x4 m) { float n11 = m[0][0], n12 = m[1][0], n13 = m[2][0], n14 = m[3][0]; float n21 = m[0][1], n22 = m[1][1], n23 = m[2][1], n24 = m[3][1]; @@ -91,20 +98,32 @@ float4x4 inverse(float4x4 m) return ret; } -template -T atan(T y_over_x) { return ::atan(y_over_x); } +float mx_atan(float y_over_x) +{ + return ::atan(y_over_x); +} -template -T atan(T y, T x) { return ::atan2(y, x); } +float mx_atan(float y, float x) +{ + return ::atan2(y, x); +} -template -T inversesqrt(T x) { return ::rsqrt(x); } +vec2 mx_atan(vec2 y, vec2 x) +{ + return ::atan2(y, x); +} -#define lessThan(a, b) ((a) < (b)) -#define lessThanEqual(a, b) ((a) <= (b)) -#define greaterThan(a, b) ((a) > (b)) -#define greaterThanEqual(a, b) ((a) >= (b)) -#define equal(a, b) ((a) == (b)) -#define notEqual(a, b) ((a) != (b)) +vec3 mx_atan(vec3 y, vec3 x) +{ + return ::atan2(y, x); +} -#endif +vec4 mx_atan(vec4 y, vec4 x) +{ + return ::atan2(y, x); +} + +float mx_radians(float degree) +{ + return (degree * M_PI_F / 180.0f); +} diff --git a/libraries/stdlib/genmsl/lib/mx_texture.metal b/libraries/stdlib/genmsl/lib/mx_texture.metal index 479a8836bf..7e90b60686 100644 --- a/libraries/stdlib/genmsl/lib/mx_texture.metal +++ b/libraries/stdlib/genmsl/lib/mx_texture.metal @@ -2,13 +2,8 @@ struct MetalTexture { texture2d tex; sampler s; - int get_width() { return tex.get_width(); } - int get_height() { return tex.get_height(); } - int get_num_mip_levels() { return tex.get_num_mip_levels(); } }; -int get_width(MetalTexture mtlTex) { return mtlTex.get_width(); } - float4 texture(MetalTexture mtlTex, float2 uv) { return mtlTex.tex.sample(mtlTex.s, uv); @@ -21,10 +16,5 @@ float4 textureLod(MetalTexture mtlTex, float2 uv, float lod) int2 textureSize(MetalTexture mtlTex, int mipLevel) { - return int2(mtlTex.get_width(), mtlTex.get_height()); -} - -int texture_mips(MetalTexture mtlTex) -{ - return mtlTex.tex.get_num_mip_levels(); + return int2(mtlTex.tex.get_width(), mtlTex.tex.get_height()); } diff --git a/libraries/stdlib/genmsl/mx_burn_color3.metal b/libraries/stdlib/genmsl/mx_burn_color3.metal deleted file mode 100644 index 856d79c929..0000000000 --- a/libraries/stdlib/genmsl/mx_burn_color3.metal +++ /dev/null @@ -1,9 +0,0 @@ -#include "mx_burn_float.metal" - -void mx_burn_color3(vec3 fg, vec3 bg, float mixval, out vec3 result) -{ - float f; - mx_burn_float(fg.x, bg.x, mixval, f); result.x = f; - mx_burn_float(fg.y, bg.y, mixval, f); result.y = f; - mx_burn_float(fg.z, bg.z, mixval, f); result.z = f; -} diff --git a/libraries/stdlib/genmsl/mx_burn_color4.metal b/libraries/stdlib/genmsl/mx_burn_color4.metal deleted file mode 100644 index 48dc6bfa47..0000000000 --- a/libraries/stdlib/genmsl/mx_burn_color4.metal +++ /dev/null @@ -1,10 +0,0 @@ -#include "mx_burn_float.metal" - -void mx_burn_color4(vec4 fg, vec4 bg, float mixval, out vec4 result) -{ - float f; - mx_burn_float(fg.x, bg.x, mixval, f); result.x = f; - mx_burn_float(fg.y, bg.y, mixval, f); result.y = f; - mx_burn_float(fg.z, bg.z, mixval, f); result.z = f; - mx_burn_float(fg.w, bg.w, mixval, f); result.w = f; -} diff --git a/libraries/stdlib/genmsl/mx_burn_float.metal b/libraries/stdlib/genmsl/mx_burn_float.metal deleted file mode 100644 index 31d981ddb9..0000000000 --- a/libraries/stdlib/genmsl/mx_burn_float.metal +++ /dev/null @@ -1,9 +0,0 @@ -void mx_burn_float(float fg, float bg, float mixval, out float result) -{ - if (abs(fg) < M_FLOAT_EPS) - { - result = 0.0; - return; - } - result = mixval*(1.0 - ((1.0 - bg) / fg)) + ((1.0-mixval)*bg); -} diff --git a/libraries/stdlib/genmsl/mx_dodge_color3.metal b/libraries/stdlib/genmsl/mx_dodge_color3.metal deleted file mode 100644 index 864a6a2529..0000000000 --- a/libraries/stdlib/genmsl/mx_dodge_color3.metal +++ /dev/null @@ -1,9 +0,0 @@ -#include "mx_dodge_float.metal" - -void mx_dodge_color3(vec3 fg, vec3 bg, float mixval, out vec3 result) -{ - float f; - mx_dodge_float(fg.x, bg.x, mixval, f); result.x = f; - mx_dodge_float(fg.y, bg.y, mixval, f); result.y = f; - mx_dodge_float(fg.z, bg.z, mixval, f); result.z = f; -} diff --git a/libraries/stdlib/genmsl/mx_dodge_color4.metal b/libraries/stdlib/genmsl/mx_dodge_color4.metal deleted file mode 100644 index dc226b4271..0000000000 --- a/libraries/stdlib/genmsl/mx_dodge_color4.metal +++ /dev/null @@ -1,10 +0,0 @@ -#include "mx_dodge_float.metal" - -void mx_dodge_color4(vec4 fg , vec4 bg , float mixval, out vec4 result) -{ - float f; - mx_dodge_float(fg.x, bg.x, mixval, f); result.x = f; - mx_dodge_float(fg.y, bg.y, mixval, f); result.y = f; - mx_dodge_float(fg.z, bg.z, mixval, f); result.z = f; - mx_dodge_float(fg.w, bg.w, mixval, f); result.w = f; -} diff --git a/libraries/stdlib/genmsl/mx_dodge_float.metal b/libraries/stdlib/genmsl/mx_dodge_float.metal deleted file mode 100644 index f138354138..0000000000 --- a/libraries/stdlib/genmsl/mx_dodge_float.metal +++ /dev/null @@ -1,9 +0,0 @@ -void mx_dodge_float(float fg, float bg, float mixval, out float result) -{ - if (abs(1.0 - fg) < M_FLOAT_EPS) - { - result = 0.0; - return; - } - result = mixval*(bg / (1.0 - fg)) + ((1.0-mixval)*bg); -} diff --git a/libraries/stdlib/genmsl/mx_normalmap.metal b/libraries/stdlib/genmsl/mx_normalmap.metal deleted file mode 100644 index a3ffedaad5..0000000000 --- a/libraries/stdlib/genmsl/mx_normalmap.metal +++ /dev/null @@ -1,21 +0,0 @@ -void mx_normalmap_vector2(vec3 value, int map_space, vec2 normal_scale, vec3 N, vec3 T, out vec3 result) -{ - // Decode the normal map. - value = all(value == vec3(0.0f)) ? vec3(0.0, 0.0, 1.0) : value * 2.0 - 1.0; - - // Transform from tangent space if needed. - if (map_space == 0) - { - vec3 B = normalize(cross(N, T)); - value.xy *= normal_scale; - value = T * value.x + B * value.y + N * value.z; - } - - // Normalize the result. - result = normalize(value); -} - -void mx_normalmap_float(vec3 value, int map_space, float normal_scale, vec3 N, vec3 T, out vec3 result) -{ - mx_normalmap_vector2(value, map_space, vec2(normal_scale), N, T, result); -} diff --git a/libraries/stdlib/genmsl/mx_smoothstep_float.metal b/libraries/stdlib/genmsl/mx_smoothstep_float.metal deleted file mode 100644 index 1bca2e4d9b..0000000000 --- a/libraries/stdlib/genmsl/mx_smoothstep_float.metal +++ /dev/null @@ -1,9 +0,0 @@ -void mx_smoothstep_float(float val, float low, float high, out float result) -{ - if (val <= low) - result = 0.0; - else if (val >= high) - result = 1.0; - else - result = smoothstep(low, high, val); -} diff --git a/libraries/stdlib/genmsl/mx_smoothstep_vector2.metal b/libraries/stdlib/genmsl/mx_smoothstep_vector2.metal deleted file mode 100644 index 34fec594ee..0000000000 --- a/libraries/stdlib/genmsl/mx_smoothstep_vector2.metal +++ /dev/null @@ -1,8 +0,0 @@ -#include "mx_smoothstep_float.metal" - -void mx_smoothstep_vector2(vec2 val, vec2 low, vec2 high, out vec2 result) -{ - float f; - mx_smoothstep_float(val.x, low.x, high.x, f); result.x = f; - mx_smoothstep_float(val.y, low.y, high.y, f); result.y = f; -} diff --git a/libraries/stdlib/genmsl/mx_smoothstep_vector3.metal b/libraries/stdlib/genmsl/mx_smoothstep_vector3.metal deleted file mode 100644 index 5b0a9b62cf..0000000000 --- a/libraries/stdlib/genmsl/mx_smoothstep_vector3.metal +++ /dev/null @@ -1,9 +0,0 @@ -#include "mx_smoothstep_float.metal" - -void mx_smoothstep_vector3(vec3 val, vec3 low, vec3 high, thread vec3& result) - { - float f; - mx_smoothstep_float(val.x, low.x, high.x, f); result.x = f; - mx_smoothstep_float(val.y, low.y, high.y, f); result.y = f; - mx_smoothstep_float(val.z, low.z, high.z, f); result.z = f; - } \ No newline at end of file diff --git a/libraries/stdlib/genmsl/mx_smoothstep_vector4.metal b/libraries/stdlib/genmsl/mx_smoothstep_vector4.metal deleted file mode 100644 index 04dc755149..0000000000 --- a/libraries/stdlib/genmsl/mx_smoothstep_vector4.metal +++ /dev/null @@ -1,10 +0,0 @@ -#include "mx_smoothstep_float.metal" - -void mx_smoothstep_vector4(vec4 val, vec4 low, vec4 high, out vec4 result) -{ - float f; - mx_smoothstep_float(val.x, low.x, high.x, f); result.x = f; - mx_smoothstep_float(val.y, low.y, high.y, f); result.y = f; - mx_smoothstep_float(val.z, low.z, high.z, f); result.z = f; - mx_smoothstep_float(val.w, low.w, high.w, f); result.w = f; -} diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index f6454c13ac..3cb99052cf 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -41,100 +41,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -186,255 +96,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -444,236 +105,22 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -688,18 +135,6 @@ - - - - - - - - - - - - @@ -719,29 +154,8 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/libraries/stdlib/genosl/mx_ambientocclusion_float.osl b/libraries/stdlib/genosl/mx_ambientocclusion_float.osl deleted file mode 100644 index 10baf0b736..0000000000 --- a/libraries/stdlib/genosl/mx_ambientocclusion_float.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_ambientocclusion_float(float coneangle, float maxdistance, output float result) -{ - // This node is a stub and does not currently operate to specification - result = 0; -} diff --git a/libraries/stdlib/genosl/mx_normalmap.osl b/libraries/stdlib/genosl/mx_normalmap.osl index 79b31df69d..88c12cc389 100644 --- a/libraries/stdlib/genosl/mx_normalmap.osl +++ b/libraries/stdlib/genosl/mx_normalmap.osl @@ -1,22 +1,19 @@ -void mx_normalmap_vector2(vector value, string map_space, vector2 normal_scale, vector N, vector U, output vector result) +void mx_normalmap_vector2(vector value, vector2 normal_scale, vector N, vector T, vector B, output vector result) { - // Tangent space - if (map_space == "tangent") + vector decodedValue; + if (value == vector(0.0)) { - vector v = value * 2.0 - 1.0; - vector T = normalize(U - dot(U, N) * N); - vector B = normalize(cross(N, T)); - result = normalize(T * v[0] * normal_scale.x + B * v[1] * normal_scale.y + N * v[2]); + decodedValue = vector(0.0, 0.0, 1.0); } - // Object space else { - vector n = value * 2.0 - 1.0; - result = normalize(n); + decodedValue = value * 2.0 - 1.0; } + + result = normalize(T * decodedValue[0] * normal_scale.x + B * decodedValue[1] * normal_scale.y + N * decodedValue[2]); } -void mx_normalmap_float(vector value, string map_space, float normal_scale, vector N, vector U, output vector result) +void mx_normalmap_float(vector value, float normal_scale, vector N, vector T, vector B, output vector result) { - mx_normalmap_vector2(value, map_space, vector2(normal_scale, normal_scale), N, U, result); + mx_normalmap_vector2(value, vector2(normal_scale, normal_scale), N, T, B, result); } diff --git a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx index 716e1072d7..db318976c5 100644 --- a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx +++ b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx @@ -131,13 +131,6 @@ - - - - - - - diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index c9c3fc8431..8f86a03b44 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -465,6 +465,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - @@ -2604,18 +2638,18 @@ --> - + - + @@ -2899,44 +2933,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2899,114 +3120,306 @@ to output 0-1. --> - + - - + + - - + + - - - - - + + + + + - - - - + + + + + + + + + + + + + + + + - + - - + + - - + + - - - - - + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + - - + + + + + - + + + + + + + + + + + + + + + + - - - - - - - + - - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + - - + + + + + + + + + + - + + + + + - - - - - - - + - - + + + + + + + + + + + + + + + - + + + + + + - - - - - - - + - - + + + + + + + + + + + + + + + + + + + + - + + + + + + + diff --git a/python/MaterialXTest/tests_to_html.bat b/python/MaterialXTest/tests_to_html.bat index 78ddcf1a01..92f44ec240 100644 --- a/python/MaterialXTest/tests_to_html.bat +++ b/python/MaterialXTest/tests_to_html.bat @@ -1 +1,2 @@ -python tests_to_html.py -i1 ../../build +@echo off +python tests_to_html.py -i1 ../../build %* diff --git a/python/MaterialXTest/tests_to_html.py b/python/MaterialXTest/tests_to_html.py index 110830fc1a..05269b5dbe 100644 --- a/python/MaterialXTest/tests_to_html.py +++ b/python/MaterialXTest/tests_to_html.py @@ -16,11 +16,11 @@ def createDiff(image1Path, image2Path, imageDiffPath): try: if os.path.exists(imageDiffPath): os.remove(imageDiffPath) - + if not os.path.exists(image1Path): print ("Image diff input missing: " + image1Path) return - + if not os.path.exists(image2Path): print ("Image diff input missing: " + image2Path) return @@ -38,8 +38,8 @@ def main(args=None): parser = argparse.ArgumentParser() parser.add_argument('-i1', '--inputdir1', dest='inputdir1', action='store', help='Input directory', default=".") - parser.add_argument('-i2', '--inputdir2', dest='inputdir2', action='store', help='Second input directory', default=".") - parser.add_argument('-i3', '--inputdir3', dest='inputdir3', action='store', help='Third input directory', default=".") + parser.add_argument('-i2', '--inputdir2', dest='inputdir2', action='store', help='Second input directory', default="") + parser.add_argument('-i3', '--inputdir3', dest='inputdir3', action='store', help='Third input directory', default="") parser.add_argument('-o', '--outputfile', dest='outputfile', action='store', help='Output file name', default="tests.html") parser.add_argument('-d', '--diff', dest='CREATE_DIFF', action='store_true', help='Perform image diff', default=False) parser.add_argument('-t', '--timestamp', dest='ENABLE_TIMESTAMPS', action='store_true', help='Write image timestamps', default=False) @@ -67,24 +67,37 @@ def main(args=None): fh.write("}") fh.write("") fh.write("\n") - dir1 = os.getcwd() if args.inputdir1 == "." else args.inputdir1 - dir2 = os.getcwd() if args.inputdir2 == "." else args.inputdir2 - dir3 = os.getcwd() if args.inputdir3 == "." else args.inputdir3 - - useThirdLang = True if args.lang3 and (args.inputdir1 != args.inputdir3 or args.lang1 != args.lang3) else False + + if args.inputdir1 == ".": + args.inputdir1 = os.getcwd() + + if args.inputdir2 == ".": + args.inputdir2 = os.getcwd() + elif args.inputdir2 == "": + args.inputdir2 = args.inputdir1 + + if args.inputdir3 == ".": + args.inputdir3 = os.getcwd() + elif args.inputdir3 == "": + args.inputdir3 = args.inputdir1 + + useThirdLang = args.lang3 if useThirdLang: - fh.write("

" + args.lang1 + " (in: " + dir1 + ") vs "+ args.lang2 + " (in: " + dir2 + ") vs "+ args.lang3 + " (in: " + dir3 + ")

\n") + fh.write("

" + args.lang1 + " (in: " + args.inputdir1 + ") vs "+ args.lang2 + " (in: " + args.inputdir2 + ") vs "+ args.lang3 + " (in: " + args.inputdir3 + ")

\n") else: - fh.write("

" + args.lang1 + " (in: " + dir1 + ") vs "+ args.lang2 + " (in: " + dir2 + ")

\n") + fh.write("

" + args.lang1 + " (in: " + args.inputdir1 + ") vs "+ args.lang2 + " (in: " + args.inputdir2 + ")

\n") if not DIFF_ENABLED and args.CREATE_DIFF: print("--diff argument ignored. Diff utility not installed.") - if not args.inputdir2: - args.inputdir2 = args.inputdir1 - if useThirdLang and not args.inputdir3: - args.inputdir3 = args.inputdir1 + # Remove potential trailing path separators + if args.inputdir1[-1:] == '/' or args.inputdir1[-1:] == '\\': + args.inputdir1 = args.inputdir1[:-1] + if args.inputdir2[-1:] == '/' or args.inputdir2[-1:] == '\\': + args.inputdir2 = args.inputdir2[:-1] + if args.inputdir3[-1:] == '/' or args.inputdir3[-1:] == '\\': + args.inputdir3 = args.inputdir3[:-1] # Get all source files langFiles1 = [] @@ -93,21 +106,22 @@ def main(args=None): for curFile in files: if curFile.endswith(args.lang1 + ".png"): langFiles1.append(curFile) - langPaths1.append(subdir) + langPaths1.append(subdir) # Get all destination files, matching source files langFiles2 = [] langPaths2 = [] langFiles3 = [] langPaths3 = [] - postFix = args.lang1 + ".png" + preFixLen: int = len(args.inputdir1) + 1 # including the path separator + postFix: str = args.lang1 + ".png" for file1, path1 in zip(langFiles1, langPaths1): # Allow for just one language to be shown if source and dest are the same. # Otherwise add in equivalent name with dest language replacement if # pointing to the same directory if args.inputdir1 != args.inputdir2 or args.lang1 != args.lang2: file2 = file1[:-len(postFix)] + args.lang2 + ".png" - path2 = os.path.join(args.inputdir2, path1) + path2 = os.path.join(args.inputdir2, path1[len(args.inputdir1)+1:]) else: file2 = "" path2 = None @@ -116,7 +130,7 @@ def main(args=None): if useThirdLang: file3 = file1[:-len(postFix)] + args.lang3 + ".png" - path3 = os.path.join(args.inputdir2, path1) + path3 = os.path.join(args.inputdir2, path1[len(args.inputdir1)+1:]) else: file3 = "" path3 = None @@ -142,33 +156,34 @@ def main(args=None): curPath = path1 if file1 and file2 and DIFF_ENABLED and args.CREATE_DIFF: - diffPath1 = fullPath1[0:-8] + "_" + args.lang1 + "_vs_" + args.lang2 + "_diff.png" + diffPath1 = fullPath1[0:-8] + "_" + args.lang1 + "-1_vs_" + args.lang2 + "-2_diff.png" createDiff(fullPath1, fullPath2, diffPath1) if useThirdLang and file1 and file3 and DIFF_ENABLED and args.CREATE_DIFF: - diffPath2 = fullPath1[0:-8] + "_" + args.lang1 + "_vs_" + args.lang3 + "_diff.png" + diffPath2 = fullPath1[0:-8] + "_" + args.lang1 + "-1_vs_" + args.lang3 + "-3_diff.png" createDiff(fullPath1, fullPath3, diffPath2) - diffPath3 = fullPath1[0:-8] + "_" + args.lang2 + "_vs_" + args.lang3 + "_diff.png" + diffPath3 = fullPath1[0:-8] + "_" + args.lang2 + "-2_vs_" + args.lang3 + "-3_diff.png" createDiff(fullPath2, fullPath3, diffPath3) - if os.path.isabs(args.outputfile): - fileUri = 'file:///' - else: - fileUri ='' + def prependFileUri(filepath: str) -> str: + if os.path.isabs(filepath): + return 'file:///' + filepath + else: + return filepath fh.write("\n") if fullPath1: - fh.write("\n") + fh.write("\n") if fullPath2: - fh.write("\n") + fh.write("\n") if fullPath3: - fh.write("\n") + fh.write("\n") if diffPath1: - fh.write("\n") + fh.write("\n") if diffPath2: - fh.write("\n") + fh.write("\n") if diffPath3: - fh.write("\n") + fh.write("\n") fh.write("\n") fh.write("\n") diff --git a/python/Scripts/baketextures.py b/python/Scripts/baketextures.py index ce132036a6..7856dca749 100644 --- a/python/Scripts/baketextures.py +++ b/python/Scripts/baketextures.py @@ -27,13 +27,7 @@ def main(): parser.add_argument(dest="outputFilename", help="Filename of the output document.") opts = parser.parse_args() - doc = mx.createDocument() - try: - mx.readFromXmlFile(doc, opts.inputFilename) - except mx.ExceptionFileMissing as err: - print(err) - sys.exit(0) - + # Load standard and custom data libraries. stdlib = mx.createDocument() searchPath = mx.getDefaultDataSearchPath() searchPath.append(os.path.dirname(opts.inputFilename)) @@ -48,21 +42,28 @@ def main(): libraryFolders.append(library) libraryFolders.extend(mx.getDefaultDataLibraryFolders()) mx.loadLibraries(libraryFolders, searchPath, stdlib) - doc.importLibrary(stdlib) + # Read and validate the source document. + doc = mx.createDocument() + try: + mx.readFromXmlFile(doc, opts.inputFilename) + doc.setDataLibrary(stdlib) + except mx.ExceptionFileMissing as err: + print(err) + sys.exit(0) valid, msg = doc.validate() if not valid: print("Validation warnings for input document:") print(msg) + # Construct the texture baker. baseType = mx_render.BaseType.FLOAT if opts.hdr else mx_render.BaseType.UINT8 - - if platform == "darwin" and not opts.useGlslBackend: baker = mx_render_msl.TextureBaker.create(opts.width, opts.height, baseType) else: baker = mx_render_glsl.TextureBaker.create(opts.width, opts.height, baseType) + # Bake materials to textures. if opts.average: baker.setAverageImages(True) baker.writeDocumentPerMaterial(opts.writeDocumentPerMaterial) diff --git a/python/Scripts/generateshader.py b/python/Scripts/generateshader.py index f6158d270a..b00311eb2e 100644 --- a/python/Scripts/generateshader.py +++ b/python/Scripts/generateshader.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ''' -Utility to generate the shader for materials found in a MaterialX document. One file will be generated -for each material / shader found. The currently supported target languages are GLSL, OSL, MDL and ESSL. +Generate shader code for each renderable element in a MaterialX document or folder. +The currently supported target languages are GLSL, ESSL, MSL, OSL, and MDL. ''' import sys, os, argparse, subprocess @@ -43,7 +43,7 @@ def getMaterialXFiles(rootPath): return filelist def main(): - parser = argparse.ArgumentParser(description='Generate shader code for each material / shader in a document.') + parser = argparse.ArgumentParser(description='Generate shader code for each renderable element in a MaterialX document or folder.') parser.add_argument('--path', dest='paths', action='append', nargs='+', help='An additional absolute search path location (e.g. "/projects/MaterialX")') parser.add_argument('--library', dest='libraries', action='append', nargs='+', help='An additional relative path to a custom data library folder (e.g. "libraries/custom")') parser.add_argument('--target', dest='target', default='glsl', help='Target shader generator to use (e.g. "glsl, osl, mdl, essl, vulkan"). Default is glsl.') @@ -55,38 +55,33 @@ def main(): parser.add_argument(dest='inputFilename', help='Path to input document or folder containing input documents.') opts = parser.parse_args() - filelist = getMaterialXFiles(opts.inputFilename) - - for inputFilename in filelist: + # Load standard and custom data libraries. + stdlib = mx.createDocument() + searchPath = mx.getDefaultDataSearchPath() + libraryFolders = [] + if opts.paths: + for pathList in opts.paths: + for path in pathList: + searchPath.append(path) + if opts.libraries: + for libraryList in opts.libraries: + for library in libraryList: + libraryFolders.append(library) + libraryFolders.extend(mx.getDefaultDataLibraryFolders()) + mx.loadLibraries(libraryFolders, searchPath, stdlib) + + # Generate shaders for each input document. + for inputFilename in getMaterialXFiles(opts.inputFilename): doc = mx.createDocument() try: mx.readFromXmlFile(doc, inputFilename) + doc.setDataLibrary(stdlib) except mx.ExceptionFileMissing as err: print('Generation failed: "', err, '"') sys.exit(-1) print('---------- Generate code for file: ', inputFilename, '--------------------') - stdlib = mx.createDocument() - searchPath = mx.getDefaultDataSearchPath() - searchPath.append(os.path.dirname(inputFilename)) - libraryFolders = [] - if opts.paths: - for pathList in opts.paths: - for path in pathList: - searchPath.append(path) - if opts.libraries: - for libraryList in opts.libraries: - for library in libraryList: - libraryFolders.append(library) - libraryFolders.extend(mx.getDefaultDataLibraryFolders()) - try: - mx.loadLibraries(libraryFolders, searchPath, stdlib) - doc.importLibrary(stdlib) - except Exception as err: - print('Generation failed: "', err, '"') - sys.exit(-1) - valid, msg = doc.validate() if not valid: print('Validation warnings for input document:') @@ -108,8 +103,10 @@ def main(): else: shadergen = mx_gen_glsl.GlslShaderGenerator.create() + codeSearchPath = searchPath + codeSearchPath.append(os.path.dirname(inputFilename)) context = mx_gen_shader.GenContext(shadergen) - context.registerSourceCodeSearchPath(searchPath) + context.registerSourceCodeSearchPath(codeSearchPath) # If we're generating Vulkan-compliant GLSL then set the binding context if opts.vulkanCompliantGlsl: @@ -139,13 +136,6 @@ def main(): shadergen.setUnitSystem(unitsystem) genoptions.targetDistanceUnit = 'meter' - # Look for renderable nodes - nodes = mx_gen_shader.findRenderableElements(doc) - if not nodes: - nodes = doc.getMaterialNodes() - if not nodes: - nodes = doc.getNodesOfType(mx.SURFACE_SHADER_TYPE_STRING) - pathPrefix = '' if opts.outputPath and os.path.exists(opts.outputPath): pathPrefix = opts.outputPath + os.path.sep @@ -154,11 +144,11 @@ def main(): print('- Shader output path: ' + pathPrefix) failedShaders = "" - for node in nodes: - nodeName = node.getName() - print('-- Generate code for node: ' + nodeName) - nodeName = mx.createValidName(nodeName) - shader = shadergen.generate(nodeName, node, context) + for elem in mx_gen_shader.findRenderableElements(doc): + elemName = elem.getName() + print('-- Generate code for element: ' + elemName) + elemName = mx.createValidName(elemName) + shader = shadergen.generate(elemName, elem, context) if shader: # Use extension of .vert and .frag as it's type is # recognized by glslangValidator @@ -189,17 +179,17 @@ def main(): errors = validateCode(filename, opts.validator, opts.validatorArgs) if errors != "": - print("--- Validation failed for node: ", nodeName) + print("--- Validation failed for element: ", elemName) print("----------------------------") print('--- Error log: ', errors) print("----------------------------") - failedShaders += (nodeName + ' ') + failedShaders += (elemName + ' ') else: - print("--- Validation passed for node:", nodeName) + print("--- Validation passed for element:", elemName) else: - print("--- Validation failed for node:", nodeName) - failedShaders += (nodeName + ' ') + print("--- Validation failed for element:", elemName) + failedShaders += (elemName + ' ') if failedShaders != "": sys.exit(-1) diff --git a/python/Scripts/genmdl.py b/python/Scripts/genmdl.py index 2ac5afffcd..e7c2c0481f 100644 --- a/python/Scripts/genmdl.py +++ b/python/Scripts/genmdl.py @@ -439,13 +439,7 @@ def main(): # TODO: Skip array definitions for now nodeCategory = nodedef.getAttribute('node') - if nodeCategory == 'arrayappend': - print('Skip ' + nodeDefName + ' implementation. Not supported yet') - continue - if nodeCategory == 'curveadjust': - print('Skip ' + nodeDefName + ' implementation. Not supported yet') - #continue - elif nodeCategory == 'geomcolor': + if nodeCategory == 'geomcolor': print('Skip ' + nodeDefName + ' implementation. Not supported in MDL') #continue elif nodeCategory == 'geomattrvalue': diff --git a/python/Scripts/mxvalidate.py b/python/Scripts/mxvalidate.py index 8b5271e9ed..e0ccf34a4e 100755 --- a/python/Scripts/mxvalidate.py +++ b/python/Scripts/mxvalidate.py @@ -16,13 +16,8 @@ def main(): parser.add_argument(dest="inputFilename", help="Filename of the input document.") opts = parser.parse_args() - doc = mx.createDocument() - try: - mx.readFromXmlFile(doc, opts.inputFilename) - except mx.ExceptionFileMissing as err: - print(err) - sys.exit(0) - + # Load standard libraries if requested. + stdlib = None if opts.stdlib: stdlib = mx.createDocument() try: @@ -30,15 +25,24 @@ def main(): except Exception as err: print(err) sys.exit(0) - doc.importLibrary(stdlib) - (valid, message) = doc.validate() + # Read and validate the source document. + doc = mx.createDocument() + try: + mx.readFromXmlFile(doc, opts.inputFilename) + if stdlib: + doc.setDataLibrary(stdlib) + except mx.ExceptionFileMissing as err: + print(err) + sys.exit(0) + valid, message = doc.validate() if (valid): print("%s is a valid MaterialX document in v%s" % (opts.inputFilename, mx.getVersionString())) else: print("%s is not a valid MaterialX document in v%s" % (opts.inputFilename, mx.getVersionString())) print(message) + # Generate verbose output if requested. if opts.verbose: nodegraphs = doc.getNodeGraphs() materials = doc.getMaterialNodes() diff --git a/python/Scripts/translateshader.py b/python/Scripts/translateshader.py index f7c5686211..fca1e2ab07 100644 --- a/python/Scripts/translateshader.py +++ b/python/Scripts/translateshader.py @@ -24,19 +24,12 @@ def main(): parser.add_argument('--writeDocumentPerMaterial', dest='writeDocumentPerMaterial', type=mx.stringToBoolean, default=True, help='Specify whether to write baked materials to seprate MaterialX documents. Default is True') if platform == "darwin": parser.add_argument("--glsl", dest="useGlslBackend", default=False, type=bool, help="Set to True to use GLSL backend (default = Metal).") - parser.add_argument(dest="inputFilename", help="Filename of the input document.") parser.add_argument(dest="outputFilename", help="Filename of the output document.") parser.add_argument(dest="destShader", help="Destination shader for translation") opts = parser.parse_args() - doc = mx.createDocument() - try: - mx.readFromXmlFile(doc, opts.inputFilename) - except mx.ExceptionFileMissing as err: - print(err) - sys.exit(0) - + # Load standard and custom data libraries. stdlib = mx.createDocument() searchPath = mx.getDefaultDataSearchPath() searchPath.append(os.path.dirname(opts.inputFilename)) @@ -51,8 +44,15 @@ def main(): libraryFolders.append(library) libraryFolders.extend(mx.getDefaultDataLibraryFolders()) mx.loadLibraries(libraryFolders, searchPath, stdlib) - doc.importLibrary(stdlib) + # Read and validate the source document. + doc = mx.createDocument() + try: + mx.readFromXmlFile(doc, opts.inputFilename) + doc.setDataLibrary(stdlib) + except mx.ExceptionFileMissing as err: + print(err) + sys.exit(0) valid, msg = doc.validate() if not valid: print("Validation warnings for input document:") diff --git a/resources/Materials/Examples/DisneyPrincipled/disney_principled_carpaint.mtlx b/resources/Materials/Examples/DisneyPrincipled/disney_principled_carpaint.mtlx new file mode 100644 index 0000000000..7c5a0ae94f --- /dev/null +++ b/resources/Materials/Examples/DisneyPrincipled/disney_principled_carpaint.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/libraries/bxdf/disney_brdf_2012.mtlx b/resources/Materials/Examples/DisneyPrincipled/disney_principled_default.mtlx similarity index 60% rename from libraries/bxdf/disney_brdf_2012.mtlx rename to resources/Materials/Examples/DisneyPrincipled/disney_principled_default.mtlx index d65e7dbc55..717d769870 100644 --- a/libraries/bxdf/disney_brdf_2012.mtlx +++ b/resources/Materials/Examples/DisneyPrincipled/disney_principled_default.mtlx @@ -1,18 +1,21 @@ - + - - - + - - - + + + + + + + + diff --git a/resources/Materials/Examples/DisneyPrincipled/disney_principled_glass.mtlx b/resources/Materials/Examples/DisneyPrincipled/disney_principled_glass.mtlx new file mode 100644 index 0000000000..dfb1fab67d --- /dev/null +++ b/resources/Materials/Examples/DisneyPrincipled/disney_principled_glass.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/Materials/Examples/DisneyPrincipled/disney_principled_gold.mtlx b/resources/Materials/Examples/DisneyPrincipled/disney_principled_gold.mtlx new file mode 100644 index 0000000000..f0dde69049 --- /dev/null +++ b/resources/Materials/Examples/DisneyPrincipled/disney_principled_gold.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/Materials/Examples/DisneyPrincipled/disney_principled_plastic.mtlx b/resources/Materials/Examples/DisneyPrincipled/disney_principled_plastic.mtlx new file mode 100644 index 0000000000..7b2561b5ec --- /dev/null +++ b/resources/Materials/Examples/DisneyPrincipled/disney_principled_plastic.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx b/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx new file mode 100644 index 0000000000..b3dbd80f9a --- /dev/null +++ b/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx new file mode 100644 index 0000000000..8d95ffe63f --- /dev/null +++ b/resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx index 05eb071558..bc31308a47 100644 --- a/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx +++ b/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx @@ -2,11 +2,8 @@ - - - - - + + @@ -15,11 +12,8 @@ - - - - - + + @@ -28,11 +22,8 @@ - - - - - + + @@ -50,11 +41,9 @@ - - - - - + + + @@ -63,11 +52,9 @@ - - - - - + + + @@ -76,11 +63,9 @@ - - - - - + + + @@ -98,11 +83,10 @@ - - - - - + + + + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx new file mode 100644 index 0000000000..056c79b554 --- /dev/null +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx index ee0852899f..87cc8211e7 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx @@ -8,7 +8,7 @@ - + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_diffuse.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_diffuse.mtlx index 05676c948a..92e286bd17 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_diffuse.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_diffuse.mtlx @@ -3,7 +3,7 @@ - + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx index cae5722d1f..f21d752d20 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx @@ -3,7 +3,7 @@ - + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_generalized_schlick.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_generalized_schlick.mtlx index 0a6cff3c53..75eedac8a7 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_generalized_schlick.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_generalized_schlick.mtlx @@ -11,7 +11,7 @@ - + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx index a6bc228773..73737a6e8d 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx @@ -3,8 +3,9 @@ - + + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sss.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sss.mtlx index f7065de192..61ba552725 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sss.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sss.mtlx @@ -3,15 +3,15 @@ - - - - + + + + - - - - + + + + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx index a5d9b80bc3..122741aead 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx @@ -3,11 +3,9 @@ - + - - diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx index e3c1eee089..defa4c4bbd 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx @@ -15,7 +15,6 @@ - @@ -40,7 +39,6 @@ - diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/transparency_hints.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/transparency_hints.mtlx new file mode 100644 index 0000000000..0773e7e654 --- /dev/null +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/transparency_hints.mtlx @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx index 621fba621d..dbdc8f3ac3 100644 --- a/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx +++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx @@ -14,7 +14,6 @@ - diff --git a/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx b/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx deleted file mode 100644 index 83c4b95e9b..0000000000 --- a/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx b/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx new file mode 100644 index 0000000000..6260df8c57 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx b/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx new file mode 100644 index 0000000000..9175411a5d --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/adjustment/smoothstep.mtlx b/resources/Materials/TestSuite/stdlib/adjustment/smoothstep.mtlx index afc64f1116..20962e7b0e 100644 --- a/resources/Materials/TestSuite/stdlib/adjustment/smoothstep.mtlx +++ b/resources/Materials/TestSuite/stdlib/adjustment/smoothstep.mtlx @@ -4,21 +4,56 @@ Basic adjustment function tests each test is in a separate graph for each variation in input type. - smoothstep --> - - - - - + + + + + + + + + + - + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + @@ -28,14 +63,6 @@ - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/channel/channel.mtlx b/resources/Materials/TestSuite/stdlib/channel/channel.mtlx deleted file mode 100644 index 59dbd160eb..0000000000 --- a/resources/Materials/TestSuite/stdlib/channel/channel.mtlx +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/channel/combine.mtlx b/resources/Materials/TestSuite/stdlib/channel/combine.mtlx new file mode 100644 index 0000000000..403b344226 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/channel/combine.mtlx @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/channel/extract.mtlx b/resources/Materials/TestSuite/stdlib/channel/extract.mtlx new file mode 100644 index 0000000000..467707a47f --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/channel/extract.mtlx @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx b/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx index d1c1fd5626..62c6033222 100644 --- a/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx +++ b/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx @@ -26,7 +26,6 @@ - diff --git a/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx b/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx index 4a2d032be6..b60b9803a9 100644 --- a/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx +++ b/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx @@ -8,7 +8,6 @@ - burn - dodge - screen - - overlay - disjointover - mask - matte @@ -181,30 +180,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx b/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx deleted file mode 100644 index 38f36a7290..0000000000 --- a/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/convert/convert.mtlx b/resources/Materials/TestSuite/stdlib/convert/convert.mtlx deleted file mode 100644 index 377cb015df..0000000000 --- a/resources/Materials/TestSuite/stdlib/convert/convert.mtlx +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx b/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx new file mode 100644 index 0000000000..86bddc9650 --- /dev/null +++ b/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx b/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx index e3503d68f6..55a8cfa707 100644 --- a/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx +++ b/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx @@ -274,7 +274,6 @@ - diff --git a/resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx b/resources/Materials/TestSuite/stdlib/texture/token_graph.mtlx similarity index 100% rename from resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx rename to resources/Materials/TestSuite/stdlib/texture/token_graph.mtlx diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 10279959bb..01ac2c9cbe 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -5,14 +5,16 @@ if (MATERIALX_BUILD_MONOLITHIC) # such that the individual module would have been built if not in monolithic build mode add_library(${MATERIALX_MODULE_NAME} "" "" ) + set_target_properties(${MATERIALX_MODULE_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) + set_target_properties(${MATERIALX_MODULE_NAME} PROPERTIES CMAKE_VISIBILITY_INLINES_HIDDEN 1) + # Create version resource if(MATERIALX_BUILD_SHARED_LIBS AND MSVC) configure_file(${CMAKE_SOURCE_DIR}/cmake/modules/MaterialXVersion.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc) target_sources(${MATERIALX_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) endif() - set_target_properties( - ${MATERIALX_MODULE_NAME} PROPERTIES + set_target_properties(${MATERIALX_MODULE_NAME} PROPERTIES OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX} COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}" LINK_FLAGS "${EXTERNAL_LINK_FLAGS}" @@ -20,8 +22,8 @@ if (MATERIALX_BUILD_MONOLITHIC) VERSION "${MATERIALX_LIBRARY_VERSION}" SOVERSION "${MATERIALX_MAJOR_VERSION}") - target_link_libraries( - ${MATERIALX_MODULE_NAME} + target_link_libraries(${MATERIALX_MODULE_NAME} + PUBLIC ${CMAKE_DL_LIBS}) target_include_directories(${MATERIALX_MODULE_NAME} @@ -32,15 +34,6 @@ if (MATERIALX_BUILD_MONOLITHIC) PRIVATE ${EXTERNAL_INCLUDE_DIRS}) - if(NOT SKBUILD) - install(TARGETS ${MATERIALX_MODULE_NAME} - EXPORT MaterialX - ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH} - RUNTIME DESTINATION bin) - - # Note : we don't install the headers etc. here, and rely on each separate modules CMakeLists.txt - # to do that installation, thus we respect the build options configuration, and only install - # the headers for the modules we've built in to the monolithic build. - endif() + # Monolithic target is installed in the root CMakeLists.txt to allow for collection + # of all necessary headers. endif() diff --git a/source/JsMaterialX/JsMaterialXCore/JsDocument.cpp b/source/JsMaterialX/JsMaterialXCore/JsDocument.cpp index ec4881732d..18750666b7 100644 --- a/source/JsMaterialX/JsMaterialXCore/JsDocument.cpp +++ b/source/JsMaterialX/JsMaterialXCore/JsDocument.cpp @@ -23,6 +23,9 @@ EMSCRIPTEN_BINDINGS(document) .class_function("createDocument", &mx::Document::createDocument) .function("initialize", &mx::Document::initialize) .function("copy", &mx::Document::copy) + .function("setDataLibrary", &mx::Document::setDataLibrary) + .function("getDataLibrary", &mx::Document::getDataLibrary) + .function("hasDataLibrary", &mx::Document::hasDataLibrary) .function("importLibrary", &mx::Document::importLibrary) .function("getReferencedSourceUris", ems::optional_override([](mx::Document &self) { mx::StringSet set = self.getReferencedSourceUris(); diff --git a/source/JsMaterialX/JsMaterialXCore/JsElement.cpp b/source/JsMaterialX/JsMaterialXCore/JsElement.cpp index c912d036c1..31670ad090 100644 --- a/source/JsMaterialX/JsMaterialXCore/JsElement.cpp +++ b/source/JsMaterialX/JsMaterialXCore/JsElement.cpp @@ -35,11 +35,35 @@ namespace mx = MaterialX; EMSCRIPTEN_BINDINGS(element) { + ems::class_("ElementEquivalenceOptions") + .constructor<>() + .property("performValueComparisons", &mx::ElementEquivalenceOptions::performValueComparisons) + .property("floatFormat", &mx::ElementEquivalenceOptions::floatFormat) + .property("floatPrecision", &mx::ElementEquivalenceOptions::floatPrecision) + .function("setAttributeExclusionList", ems::optional_override([](mx::ElementEquivalenceOptions& self, const std::vector& exclusionList) + { + self.attributeExclusionList = std::set(exclusionList.begin(), exclusionList.end()); + })); + ems::class_("Element") .smart_ptr>("Element") .smart_ptr>("Element") // mx::ConstElementPtr .function("equals", ems::optional_override([](mx::Element& self, const mx::Element& rhs) { return self == rhs; })) .function("notEquals", ems::optional_override([](mx::Element& self, const mx::Element& rhs) { return self != rhs; })) + .function("isEquivalent", ems::optional_override([](mx::Element &self, const mx::Element& rhs, + const mx::ElementEquivalenceOptions& options, + ems::val message = ems::val::undefined()) + { + mx::ConstElementPtr rhsPtr = rhs.getSelf(); + std::string nativeMessage; + bool handleMessage = !message.isUndefined() && message.typeOf().as() == "object"; + bool res = self.isEquivalent(rhsPtr, options, handleMessage ? &nativeMessage : nullptr); + if (!res && handleMessage) + { + message.set("message", nativeMessage); + } + return res; + })) .function("setCategory", &mx::Element::setCategory) .function("getCategory", &mx::Element::getCategory) .function("setName", &mx::Element::setName) diff --git a/source/JsMaterialX/JsMaterialXCore/JsValue.cpp b/source/JsMaterialX/JsMaterialXCore/JsValue.cpp index d0ddba7e17..5e45ef16cd 100644 --- a/source/JsMaterialX/JsMaterialXCore/JsValue.cpp +++ b/source/JsMaterialX/JsMaterialXCore/JsValue.cpp @@ -47,7 +47,7 @@ EMSCRIPTEN_BINDINGS(value) .function("copy", &mx::Value::copy, ems::pure_virtual()) .function("getTypeString", &mx::Value::getTypeString) .function("getValueString", &mx::Value::getValueString) - .class_function("createValueFromStrings", &mx::Value::createValueFromStrings) + BIND_CLASS_FUNC("createValueFromStrings", mx::Value, createValueFromStrings, 2, 3, stRef, stRef, mx::ConstTypeDefPtr) .class_function("setFloatFormat", &mx::Value::setFloatFormat) .class_function("setFloatPrecision", &mx::Value::setFloatPrecision) .class_function("getFloatFormat", &mx::Value::getFloatFormat) diff --git a/source/MaterialXCore/Definition.cpp b/source/MaterialXCore/Definition.cpp index 842330c95c..da6c3ca3af 100644 --- a/source/MaterialXCore/Definition.cpp +++ b/source/MaterialXCore/Definition.cpp @@ -100,6 +100,19 @@ InterfaceElementPtr NodeDef::getImplementation(const string& target) const return InterfaceElementPtr(); } +StringMap NodeDef::getInputHints() const +{ + StringMap hints; + for (InputPtr input : getActiveInputs()) + { + if (input->hasHint()) + { + hints[input->getName()] = input->getHint(); + } + } + return hints; +} + bool NodeDef::validate(string* message) const { bool res = true; @@ -183,4 +196,12 @@ vector UnitTypeDef::getUnitDefs() const return unitDefs; } +ValuePtr AttributeDef::getValue() const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getValueString(), getType(), getDocument()->getTypeDef(getType())); +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXCore/Definition.h b/source/MaterialXCore/Definition.h index 9ec7251221..0ce7761b6d 100644 --- a/source/MaterialXCore/Definition.h +++ b/source/MaterialXCore/Definition.h @@ -146,6 +146,13 @@ class MX_CORE_API NodeDef : public InterfaceElement /// an Implementation element or a NodeGraph element. InterfaceElementPtr getImplementation(const string& target = EMPTY_STRING) const; + /// @} + /// @name Hints + /// @{ + + /// Return list of input hint pairs of the form { input_name, hint_string } + StringMap getInputHints() const; + /// @} /// @name Validation /// @{ @@ -416,11 +423,11 @@ class MX_CORE_API TargetDef : public TypedElement /// @class Member /// A member element within a TypeDef. -class MX_CORE_API Member : public TypedElement +class MX_CORE_API Member : public ValueElement { public: Member(ElementPtr parent, const string& name) : - TypedElement(parent, CATEGORY, name) + ValueElement(parent, CATEGORY, name) { } virtual ~Member() { } @@ -618,12 +625,7 @@ class MX_CORE_API AttributeDef : public TypedElement /// /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getValue() const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getValueString(), getType()); - } + ValuePtr getValue() const; /// @} /// @name Elements diff --git a/source/MaterialXCore/Document.cpp b/source/MaterialXCore/Document.cpp index dd3d9b2602..1cd031d87c 100644 --- a/source/MaterialXCore/Document.cpp +++ b/source/MaterialXCore/Document.cpp @@ -12,7 +12,6 @@ MATERIALX_NAMESPACE_BEGIN const string Document::CMS_ATTRIBUTE = "cms"; const string Document::CMS_CONFIG_ATTRIBUTE = "cmsconfig"; - // // Document factory function // @@ -164,7 +163,7 @@ NodeDefPtr Document::addNodeDefFromGraph(NodeGraphPtr nodeGraph, const string& n { throw Exception("Cannot create duplicate nodegraph: " + newGraphName); } - + // Create a new functional nodegraph, and copy over the // contents from the compound nodegraph NodeGraphPtr graph = addNodeGraph(newGraphName); @@ -174,7 +173,7 @@ NodeDefPtr Document::addNodeDefFromGraph(NodeGraphPtr nodeGraph, const string& n { graphChild->removeAttribute(Element::XPOS_ATTRIBUTE); graphChild->removeAttribute(Element::YPOS_ATTRIBUTE); - } + } graph->setNodeDefString(nodeDefName); // Create a new nodedef and set its category @@ -182,11 +181,11 @@ NodeDefPtr Document::addNodeDefFromGraph(NodeGraphPtr nodeGraph, const string& n nodeDef->setNodeString(category); // Expose any existing interfaces from the graph. - // Any connection attributes ("nodegraph", "nodename", "interfacename") on the + // Any connection attributes ("nodegraph", "nodename", "interfacename") on the // existing interface should be removed from the definition as well as any source URI. // Attributes which should not be copied over - StringSet filterAttributes = { PortElement::NODE_GRAPH_ATTRIBUTE, PortElement::NODE_NAME_ATTRIBUTE, + StringSet filterAttributes = { PortElement::NODE_GRAPH_ATTRIBUTE, PortElement::NODE_NAME_ATTRIBUTE, PortElement::INTERFACE_NAME_ATTRIBUTE, Element::XPOS_ATTRIBUTE, Element::YPOS_ATTRIBUTE }; // Transfer input interface from the graph to the nodedef @@ -196,13 +195,13 @@ NodeDefPtr Document::addNodeDefFromGraph(NodeGraphPtr nodeGraph, const string& n if (nodeDefInput) { nodeDefInput->copyContentFrom(input); - for (const string& filterAttribute : filterAttributes ) + for (const string& filterAttribute : filterAttributes) { nodeDefInput->removeAttribute(filterAttribute); } nodeDefInput->setSourceUri(EMPTY_STRING); input->setInterfaceName(nodeDefInput->getName()); - } + } } // Remove interfaces from the nodegraph for (InputPtr input : graph->getInputs()) @@ -358,34 +357,40 @@ vector Document::getMaterialOutputs() const vector Document::getMatchingNodeDefs(const string& nodeName) const { + // Recurse to data library if present. + vector matchingNodeDefs = hasDataLibrary() ? + getDataLibrary()->getMatchingNodeDefs(nodeName) : + vector(); + // Refresh the cache. _cache->refresh(); // Return all nodedefs matching the given node name. if (_cache->nodeDefMap.count(nodeName)) { - return _cache->nodeDefMap.at(nodeName); - } - else - { - return vector(); + matchingNodeDefs.insert(matchingNodeDefs.end(), _cache->nodeDefMap.at(nodeName).begin(), _cache->nodeDefMap.at(nodeName).end()); } + + return matchingNodeDefs; } vector Document::getMatchingImplementations(const string& nodeDef) const { + // Recurse to data library if present. + vector matchingImplementations = hasDataLibrary() ? + getDataLibrary()->getMatchingImplementations(nodeDef) : + vector(); + // Refresh the cache. _cache->refresh(); // Return all implementations matching the given nodedef string. if (_cache->implementationMap.count(nodeDef)) { - return _cache->implementationMap.at(nodeDef); - } - else - { - return vector(); + matchingImplementations.insert(matchingImplementations.end(), _cache->implementationMap.at(nodeDef).begin(), _cache->implementationMap.at(nodeDef).end()); } + + return matchingImplementations; } bool Document::validate(string* message) const @@ -412,5 +417,4 @@ NodeDefPtr Document::addNodeDefFromGraph(NodeGraphPtr nodeGraph, const string& n return addNodeDefFromGraph(nodeGraph, nodeDefName, node, newGraphName); } - MATERIALX_NAMESPACE_END diff --git a/source/MaterialXCore/Document.h b/source/MaterialXCore/Document.h index 08b3e1d22e..ab01bbbc11 100644 --- a/source/MaterialXCore/Document.h +++ b/source/MaterialXCore/Document.h @@ -50,18 +50,41 @@ class MX_CORE_API Document : public GraphElement { DocumentPtr doc = createDocument(); doc->copyContentFrom(getSelf()); + doc->setDataLibrary(getDataLibrary()); return doc; } - /// Import the given document as a library within this document. - /// The contents of the library document are copied into this one, and + /// Get a list of source URIs referenced by the document + StringSet getReferencedSourceUris() const; + + /// @name Data Libraries + /// @{ + + /// Store a reference to a data library in this document. + void setDataLibrary(ConstDocumentPtr dataLibrary) + { + _dataLibrary = dataLibrary; + } + + /// Return true if this document has a data library. + bool hasDataLibrary() const + { + return (_dataLibrary != nullptr); + } + + /// Return the data library, if any, referenced by this document. + ConstDocumentPtr getDataLibrary() const + { + return _dataLibrary; + } + + /// Import the given data library into this document. + /// The contents of the data library are copied into this one, and /// are assigned the source URI of the library. - /// @param library The library document to be imported. + /// @param library The data library to be imported. void importLibrary(const ConstDocumentPtr& library); - /// Get a list of source URI's referenced by the document - StringSet getReferencedSourceUris() const; - + /// @} /// @name NodeGraph Elements /// @{ @@ -335,7 +358,7 @@ class MX_CORE_API Document : public GraphElement /// Create a NodeDef and Functional Graph based on a Compound NodeGraph /// @param nodeGraph Compound NodeGraph. - /// @param newGraphName Name of new functional NodeGraph. + /// @param newGraphName Name of new functional NodeGraph. /// @param nodeDefName Name of new NodeDef /// @param category Category of the new NodeDef /// @return New declaration if successful. @@ -679,6 +702,9 @@ class MX_CORE_API Document : public GraphElement private: class Cache; + + private: + ConstDocumentPtr _dataLibrary; std::unique_ptr _cache; }; diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp index 94836245a7..5d0cf693d0 100644 --- a/source/MaterialXCore/Element.cpp +++ b/source/MaterialXCore/Element.cpp @@ -278,6 +278,41 @@ ElementPtr Element::changeChildCategory(ElementPtr child, const string& category return newChild; } +template shared_ptr Element::getChildOfType(const string& name) const +{ + ElementPtr child; + ConstDocumentPtr doc = asA(); + if (doc && doc->hasDataLibrary()) + { + child = doc->getDataLibrary()->getChild(name); + } + if (!child) + { + child = getChild(name); + } + return child ? child->asA() : shared_ptr(); +} + +template vector> Element::getChildrenOfType(const string& category) const +{ + vector> children; + ConstDocumentPtr doc = asA(); + if (doc && doc->hasDataLibrary()) + { + children = doc->getDataLibrary()->getChildrenOfType(category); + } + for (ElementPtr child : _childOrder) + { + shared_ptr instance = child->asA(); + if (!instance) + continue; + if (!category.empty() && child->getCategory() != category) + continue; + children.push_back(instance); + } + return children; +} + ElementPtr Element::getRoot() { ElementPtr root = _root.lock(); @@ -334,6 +369,134 @@ bool Element::hasInheritanceCycle() const return false; } +bool Element::isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, string* message) const +{ + if (getName() != rhs->getName()) + { + if (message) + { + *message += "Name of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } + return false; + } + if (getCategory() != rhs->getCategory()) + { + if (message) + { + *message += "Category of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } + return false; + } + + // Compare attribute names. + StringVec attributeNames = getAttributeNames(); + StringVec rhsAttributeNames = rhs->getAttributeNames(); + + // Filter out any attributes specified in the options. + const StringSet& attributeExclusionList = options.attributeExclusionList; + if (!attributeExclusionList.empty()) + { + attributeNames.erase(std::remove_if(attributeNames.begin(), attributeNames.end(), + [&attributeExclusionList](const string& attr) { return attributeExclusionList.find(attr) != attributeExclusionList.end(); }), + attributeNames.end()); + rhsAttributeNames.erase(std::remove_if(rhsAttributeNames.begin(), rhsAttributeNames.end(), + [&attributeExclusionList](const string& attr) { return attributeExclusionList.find(attr) != attributeExclusionList.end(); }), + rhsAttributeNames.end()); + } + + // Ignore attribute ordering by sorting names + std::sort(attributeNames.begin(), attributeNames.end()); + std::sort(rhsAttributeNames.begin(), rhsAttributeNames.end()); + + if (attributeNames != rhsAttributeNames) + { + if (message) + { + *message += "Attribute names of '" + getNamePath() + "' differ from '" + rhs->getNamePath() + "\n"; + } + return false; + } + + for (const string& attr : rhsAttributeNames) + { + if (!isAttributeEquivalent(rhs, attr, options, message)) + { + return false; + } + } + + // Compare all child elements that affect functional equivalence. + vector children; + for (ElementPtr child : getChildren()) + { + if (child->getCategory() == CommentElement::CATEGORY) + { + continue; + } + children.push_back(child); + } + vector rhsChildren; + for (ElementPtr child : rhs->getChildren()) + { + if (child->getCategory() == CommentElement::CATEGORY) + { + continue; + } + rhsChildren.push_back(child); + } + if (children.size() != rhsChildren.size()) + { + if (message) + { + *message += "Child count of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } + return false; + } + for (size_t i = 0; i < children.size(); i++) + { + ElementPtr rhsElement = rhsChildren[i]; + // Handle unordered children if parent is a compound graph (NodeGraph, Document). + // (Functional graphs have a "nodedef" reference and define node interfaces + // so require strict interface ordering.) + ConstGraphElementPtr graph = this->getSelf()->asA(); + if (graph) + { + ConstNodeGraphPtr nodeGraph = graph->asA(); + ConstDocumentPtr document = graph->asA(); + if (document || (nodeGraph && !nodeGraph->getNodeDef())) + { + const string& childName = children[i]->getName(); + rhsElement = rhs->getChild(childName); + if (!rhsElement) + { + if (message) + { + *message += "Child name `" + childName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } + return false; + } + } + } + if (!children[i]->isEquivalent(rhsElement, options, message)) + return false; + } + return true; +} + +bool Element::isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, + const ElementEquivalenceOptions& /*options*/, string* message) const +{ + if (getAttribute(attributeName) != rhs->getAttribute(attributeName)) + { + if (message) + { + *message += "Attribute name `" + attributeName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } + return false; + } + return true; +} + TreeIterator Element::traverseTree() const { return TreeIterator(getSelfNonConst()); @@ -495,6 +658,22 @@ string ValueElement::getResolvedValueString(StringResolverPtr resolver) const return resolver->resolve(getValueString(), getType()); } +ValuePtr ValueElement::getValue() const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getValueString(), getType(), getDocument()->getTypeDef(getType())); +} + +ValuePtr ValueElement::getResolvedValue(StringResolverPtr resolver) const +{ + if (!hasValue()) + return ValuePtr(); + + return Value::createValueFromStrings(getResolvedValueString(resolver), getType(), getDocument()->getTypeDef(getType())); +} + ValuePtr ValueElement::getDefaultValue() const { ConstElementPtr parent = getParent(); @@ -534,6 +713,76 @@ const string& ValueElement::getActiveUnit() const return EMPTY_STRING; } +bool ValueElement::isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, + const ElementEquivalenceOptions& options, string* message) const +{ + // Perform value comparisons + bool performedValueComparison = false; + if (options.performValueComparisons) + { + const StringSet uiAttributes = + { + ValueElement::UI_MIN_ATTRIBUTE, ValueElement::UI_MAX_ATTRIBUTE, + ValueElement::UI_SOFT_MIN_ATTRIBUTE, ValueElement::UI_SOFT_MAX_ATTRIBUTE, + ValueElement::UI_STEP_ATTRIBUTE + }; + + // Get precision and format options + ScopedFloatFormatting fmt(options.floatFormat, options.floatPrecision); + + ConstValueElementPtr rhsValueElement = rhs->asA(); + + // Check value equality + if (attributeName == ValueElement::VALUE_ATTRIBUTE) + { + ValuePtr thisValue = getValue(); + ValuePtr rhsValue = rhsValueElement->getValue(); + if (thisValue && rhsValue) + { + if (thisValue->getValueString() != rhsValue->getValueString()) + { + if (message) + { + *message += "Attribute `" + attributeName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } + return false; + } + } + performedValueComparison = true; + } + + // Check ui attribute value equality + else if (uiAttributes.find(attributeName) != uiAttributes.end()) + { + const string& uiAttribute = getAttribute(attributeName); + const string& rhsUiAttribute = rhs->getAttribute(attributeName); + ValuePtr uiValue = !rhsUiAttribute.empty() ? Value::createValueFromStrings(uiAttribute, getType()) : nullptr; + ValuePtr rhsUiValue = !rhsUiAttribute.empty() ? Value::createValueFromStrings(rhsUiAttribute, getType()) : nullptr; + if (uiValue && rhsUiValue) + { + if (uiValue->getValueString() != rhsUiValue->getValueString()) + { + if (message) + { + *message += "Attribute `" + attributeName + "` of " + getNamePath() + " differs from " + rhs->getNamePath() + "\n"; + } + return false; + } + } + + performedValueComparison = true; + } + } + + // If did not peform a value comparison, perform the default comparison + if (!performedValueComparison) + { + return Element::isAttributeEquivalent(rhs, attributeName, options, message); + } + + return true; +} + bool ValueElement::validate(string* message) const { bool res = true; @@ -692,9 +941,11 @@ template class ElementRegistry // Template instantiations // -#define INSTANTIATE_SUBCLASS(T) \ - template MX_CORE_API shared_ptr Element::asA(); \ - template MX_CORE_API shared_ptr Element::asA() const; +#define INSTANTIATE_SUBCLASS(T) \ + template MX_CORE_API shared_ptr Element::asA(); \ + template MX_CORE_API shared_ptr Element::asA() const; \ + template MX_CORE_API shared_ptr Element::getChildOfType(const string& name) const; \ + template MX_CORE_API vector> Element::getChildrenOfType(const string& category) const; INSTANTIATE_SUBCLASS(Element) INSTANTIATE_SUBCLASS(GeomElement) diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h index d1abcdfdca..6b145a57b1 100644 --- a/source/MaterialXCore/Element.h +++ b/source/MaterialXCore/Element.h @@ -71,6 +71,8 @@ using ElementMap = std::unordered_map; /// A standard function taking an ElementPtr and returning a boolean. using ElementPredicate = std::function; +class ElementEquivalenceOptions; + /// @class Element /// The base class for MaterialX elements. /// @@ -435,11 +437,7 @@ class MX_CORE_API Element : public std::enable_shared_from_this /// Return the child element, if any, with the given name and subclass. /// If a child with the given name exists, but belongs to a different /// subclass, then an empty shared pointer is returned. - template shared_ptr getChildOfType(const string& name) const - { - ElementPtr child = getChild(name); - return child ? child->asA() : shared_ptr(); - } + template shared_ptr getChildOfType(const string& name) const; /// Return a constant vector of all child elements. /// The returned vector maintains the order in which children were added. @@ -451,20 +449,7 @@ class MX_CORE_API Element : public std::enable_shared_from_this /// Return a vector of all child elements that are instances of the given /// subclass, optionally filtered by the given category string. The returned /// vector maintains the order in which children were added. - template vector> getChildrenOfType(const string& category = EMPTY_STRING) const - { - vector> children; - for (ElementPtr child : _childOrder) - { - shared_ptr instance = child->asA(); - if (!instance) - continue; - if (!category.empty() && child->getCategory() != category) - continue; - children.push_back(instance); - } - return children; - } + template vector> getChildrenOfType(const string& category = EMPTY_STRING) const; /// Set the index of the child, if any, with the given name. /// If the given index is out of bounds, then an exception is thrown. @@ -612,6 +597,31 @@ class MX_CORE_API Element : public std::enable_shared_from_this return nullptr; } + /// @} + /// @name Functional Equivalence + /// @{ + + /// Return true if the given element tree, including all descendents, + /// is considered to be equivalent to this one based on the equivalence + /// criteria provided. + /// @param rhs Element to compare against + /// @param options Equivalence criteria + /// @param message Optional text description of differences + /// @return True if the elements are equivalent. False otherwise. + bool isEquivalent(ConstElementPtr rhs, const ElementEquivalenceOptions& options, + string* message = nullptr) const; + + /// Return true if the attribute on a given element is equivalent + /// based on the equivalence criteria provided. + /// @param rhs Element to compare against + /// @param attributeName Name of attribute to compare + /// @param options Equivalence criteria + /// @param message Optional text description of differences + /// @return True if the attribute on the elements are equivalent. False otherwise. + virtual bool isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, + const ElementEquivalenceOptions& options, + string* message = nullptr) const; + /// @} /// @name Traversal /// @{ @@ -1025,12 +1035,7 @@ class MX_CORE_API ValueElement : public TypedElement /// /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getValue() const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getValueString(), getType()); - } + ValuePtr getValue() const; /// Return the resolved value of an element as a generic value object, which /// may be queried to access its data. @@ -1040,12 +1045,7 @@ class MX_CORE_API ValueElement : public TypedElement /// will be created at this scope and applied to the return value. /// @return A shared pointer to the typed value of this element, or an /// empty shared pointer if no value is present. - ValuePtr getResolvedValue(StringResolverPtr resolver = nullptr) const - { - if (!hasValue()) - return ValuePtr(); - return Value::createValueFromStrings(getResolvedValueString(resolver), getType()); - } + ValuePtr getResolvedValue(StringResolverPtr resolver = nullptr) const; /// Return the default value for this element as a generic value object, which /// may be queried to access its data. @@ -1114,6 +1114,21 @@ class MX_CORE_API ValueElement : public TypedElement return getTypedAttribute(UNIFORM_ATTRIBUTE); } + /// @} + /// @name Functional Equivalence + /// @{ + + /// Return true if the attribute on a given element is equivalent + /// based on the equivalence criteria provided. + /// @param rhs Element to compare against + /// @param attributeName Name of attribute to compare + /// @param options Equivalence criteria + /// @param message Optional text description of differences + /// @return True if the attribute on the elements are equivalent. False otherwise. + bool isAttributeEquivalent(ConstElementPtr rhs, const string& attributeName, + const ElementEquivalenceOptions& options, + string* message = nullptr) const override; + /// @} /// @name Validation /// @{ @@ -1336,6 +1351,42 @@ class MX_CORE_API StringResolver StringMap _geomNameMap; }; +/// @class ElementEquivalenceOptions +/// A set of options for comparing the functional equivalence of elements. +class MX_CORE_API ElementEquivalenceOptions +{ + public: + ElementEquivalenceOptions() + { + performValueComparisons = true; + floatFormat = Value::getFloatFormat(); + floatPrecision = Value::getFloatPrecision(); + attributeExclusionList = {}; + }; + ~ElementEquivalenceOptions() { } + + /// Perform value comparisons as opposed to literal string comparisons. + /// Default is true. + bool performValueComparisons; + + /// Floating point format to use for floating point value comparisons + Value::FloatFormat floatFormat; + + /// Floating point precision to use for floating point value comparisons + int floatPrecision; + + /// Specifies the set of attributes that should be excluded when performing a comparison. + /// By default all attributes are considered. Name and category attributes cannot be excluded. + /// + /// For example, to exclude UI and documentation attributes from consideration the follow may be set: + /// attributeExclusionList = { + /// ValueElement::UI_MIN_ATTRIBUTE, ValueElement::UI_MAX_ATTRIBUTE, + /// ValueElement::UI_SOFT_MIN_ATTRIBUTE, ValueElement::UI_SOFT_MAX_ATTRIBUTE, + /// ValueElement::UI_STEP_ATTRIBUTE, Element::XPOS_ATTRIBUTE, + /// Element::YPOS_ATTRIBUTE, Element::DOC_ATTRIBUTE }; + StringSet attributeExclusionList; +}; + /// @class ExceptionOrphanedElement /// An exception that is thrown when an ElementPtr is used after its owning /// Document has gone out of scope. diff --git a/source/MaterialXCore/Exception.h b/source/MaterialXCore/Exception.h index 4fc0c728ec..4cf51f1cd5 100644 --- a/source/MaterialXCore/Exception.h +++ b/source/MaterialXCore/Exception.h @@ -50,6 +50,14 @@ class MX_CORE_API Exception : public std::exception string _msg; }; +/// @class ExceptionTypeError +/// An exception that is thrown when a type mismatch is encountered. +class MX_CORE_API ExceptionTypeError : public Exception +{ + public: + using Exception::Exception; +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXCore/Interface.cpp b/source/MaterialXCore/Interface.cpp index 6b200a8dcf..1c12e38ded 100644 --- a/source/MaterialXCore/Interface.cpp +++ b/source/MaterialXCore/Interface.cpp @@ -20,6 +20,10 @@ const string InterfaceElement::TARGET_ATTRIBUTE = "target"; const string InterfaceElement::VERSION_ATTRIBUTE = "version"; const string InterfaceElement::DEFAULT_VERSION_ATTRIBUTE = "isdefaultversion"; const string Input::DEFAULT_GEOM_PROP_ATTRIBUTE = "defaultgeomprop"; +const string Input::HINT_ATTRIBUTE = "hint"; +const string Input::TRANSPARENCY_HINT = "transparency"; +const string Input::OPACITY_HINT = "opacity"; +const string Input::ANISOTROPY_HINT = "anisotropy"; const string Output::DEFAULT_INPUT_ATTRIBUTE = "defaultinput"; // @@ -291,7 +295,7 @@ bool Input::validate(string* message) const if (hasDefaultGeomPropString()) { - validateRequire(parent->isA(), res, message, "Invalid defaultgeomprop on non-definition input"); + validateRequire(parent->isA() || parent->isA(), res, message, "Invalid defaultgeomprop on non-definition and non-nodegraph input"); validateRequire(getDefaultGeomProp() != nullptr, res, message, "Invalid defaultgeomprop string"); } if (parent->isA()) diff --git a/source/MaterialXCore/Interface.h b/source/MaterialXCore/Interface.h index c19bc82da5..599f85ed9d 100644 --- a/source/MaterialXCore/Interface.h +++ b/source/MaterialXCore/Interface.h @@ -129,7 +129,7 @@ class MX_CORE_API PortElement : public ValueElement void setConnectedOutput(ConstOutputPtr output); /// Return the output, if any, to which this input is connected. - virtual OutputPtr getConnectedOutput() const; + OutputPtr getConnectedOutput() const; /// Return the output string of this element. const string& getOutputString() const @@ -219,6 +219,28 @@ class MX_CORE_API Input : public PortElement /// for this input. InputPtr getInterfaceInput() const; + /// @} + /// @name Hints + /// @{ + + /// Return true if the input has a hint + bool hasHint() const + { + return hasAttribute(HINT_ATTRIBUTE); + } + + /// Return the code generation hint + const string& getHint() const + { + return getAttribute(HINT_ATTRIBUTE); + } + + // Set the code generation hint + void setHint(const string& hint) + { + setAttribute(HINT_ATTRIBUTE, hint); + } + /// @} /// @name Validation /// @{ @@ -232,6 +254,10 @@ class MX_CORE_API Input : public PortElement public: static const string CATEGORY; static const string DEFAULT_GEOM_PROP_ATTRIBUTE; + static const string HINT_ATTRIBUTE; + static const string TRANSPARENCY_HINT; + static const string OPACITY_HINT; + static const string ANISOTROPY_HINT; }; /// @class Output diff --git a/source/MaterialXCore/Library.h b/source/MaterialXCore/Library.h index 4d69b2d0ae..571644c098 100644 --- a/source/MaterialXCore/Library.h +++ b/source/MaterialXCore/Library.h @@ -21,6 +21,11 @@ #include +#define MATERIALX_GENERATE_INDEX(major, minor, build) \ + ((((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(build))) +#define MATERIALX_VERSION_INDEX \ + MATERIALX_GENERATE_INDEX(MATERIALX_MAJOR_VERSION, MATERIALX_MINOR_VERSION, MATERIALX_BUILD_VERSION) + /// Platform-specific macros for declaring imported and exported symbols. #if defined(MATERIALX_BUILD_SHARED_LIBS) #if defined(_WIN32) @@ -32,12 +37,10 @@ #define MATERIALX_EXPORT_EXTERN_TEMPLATE(...) template class MATERIALX_SYMBOL_EXPORT __VA_ARGS__ #define MATERIALX_IMPORT_EXTERN_TEMPLATE(...) extern template class MATERIALX_SYMBOL_IMPORT __VA_ARGS__ #else - // Presently non-Windows platforms just export all symbols from - // shared libraries rather than using the explicit declarations. - #define MATERIALX_SYMBOL_EXPORT - #define MATERIALX_SYMBOL_IMPORT - #define MATERIALX_EXPORT_EXTERN_TEMPLATE(...) - #define MATERIALX_IMPORT_EXTERN_TEMPLATE(...) + #define MATERIALX_SYMBOL_EXPORT __attribute__((__visibility__("default"))) + #define MATERIALX_SYMBOL_IMPORT __attribute__((__visibility__("default"))) + #define MATERIALX_EXPORT_EXTERN_TEMPLATE(...) template class MATERIALX_SYMBOL_EXPORT __VA_ARGS__ + #define MATERIALX_IMPORT_EXTERN_TEMPLATE(...) extern template class MATERIALX_SYMBOL_IMPORT __VA_ARGS__ #endif #else #define MATERIALX_SYMBOL_EXPORT diff --git a/source/MaterialXCore/Node.cpp b/source/MaterialXCore/Node.cpp index 7694bb6c6b..9080036c39 100644 --- a/source/MaterialXCore/Node.cpp +++ b/source/MaterialXCore/Node.cpp @@ -68,30 +68,6 @@ string Node::getConnectedNodeName(const string& inputName) const return input->getNodeName(); } -void Node::setConnectedOutput(const string& inputName, OutputPtr output) -{ - InputPtr input = getInput(inputName); - if (!input) - { - input = addInput(inputName, DEFAULT_TYPE_STRING); - } - if (output) - { - input->setType(output->getType()); - } - input->setConnectedOutput(output); -} - -OutputPtr Node::getConnectedOutput(const string& inputName) const -{ - InputPtr input = getInput(inputName); - if (!input) - { - return OutputPtr(); - } - return input->getConnectedOutput(); -} - NodeDefPtr Node::getNodeDef(const string& target, bool allowRoughMatch) const { if (hasNodeDefString()) diff --git a/source/MaterialXCore/Node.h b/source/MaterialXCore/Node.h index b42d18074e..5a6b7c4144 100644 --- a/source/MaterialXCore/Node.h +++ b/source/MaterialXCore/Node.h @@ -78,15 +78,6 @@ class MX_CORE_API Node : public InterfaceElement /// input is not present, then an empty string is returned. string getConnectedNodeName(const string& inputName) const; - /// Set the output to which the given input is connected, creating a - /// child input if needed. If the node argument is null, then any - /// existing output connection on the input will be cleared. - void setConnectedOutput(const string& inputName, OutputPtr output); - - /// Return the output connected to the given input. If the given input is - /// not present, then an empty OutputPtr is returned. - OutputPtr getConnectedOutput(const string& inputName) const; - /// @} /// @name NodeDef References /// @{ diff --git a/source/MaterialXCore/Traversal.cpp b/source/MaterialXCore/Traversal.cpp index c78b5825d4..285083da2e 100644 --- a/source/MaterialXCore/Traversal.cpp +++ b/source/MaterialXCore/Traversal.cpp @@ -113,7 +113,7 @@ GraphIterator& GraphIterator::operator++() // Traverse to the first upstream edge of this element. _stack.emplace_back(_upstreamElem, 0); Edge nextEdge = _upstreamElem->getUpstreamEdge(0); - if (nextEdge && nextEdge.getUpstreamElement()) + if (nextEdge && nextEdge.getUpstreamElement() && !skipOrMarkAsVisited(nextEdge)) { extendPathUpstream(nextEdge.getUpstreamElement(), nextEdge.getConnectingElement()); return *this; @@ -140,7 +140,7 @@ GraphIterator& GraphIterator::operator++() if (parentFrame.second + 1 < parentFrame.first->getUpstreamEdgeCount()) { Edge nextEdge = parentFrame.first->getUpstreamEdge(++parentFrame.second); - if (nextEdge && nextEdge.getUpstreamElement()) + if (nextEdge && nextEdge.getUpstreamElement() && !skipOrMarkAsVisited(nextEdge)) { extendPathUpstream(nextEdge.getUpstreamElement(), nextEdge.getConnectingElement()); return *this; @@ -177,6 +177,12 @@ void GraphIterator::returnPathDownstream(ElementPtr upstreamElem) _connectingElem = ElementPtr(); } +bool GraphIterator::skipOrMarkAsVisited(const Edge& edge) +{ + auto [it, inserted] = _visitedEdges.emplace(edge); + return !inserted; +} + // // InheritanceIterator methods // diff --git a/source/MaterialXCore/Traversal.h b/source/MaterialXCore/Traversal.h index a22d909cbe..08dcdaeaf8 100644 --- a/source/MaterialXCore/Traversal.h +++ b/source/MaterialXCore/Traversal.h @@ -316,12 +316,14 @@ class MX_CORE_API GraphIterator private: void extendPathUpstream(ElementPtr upstreamElem, ElementPtr connectingElem); void returnPathDownstream(ElementPtr upstreamElem); + bool skipOrMarkAsVisited(const Edge&); private: ElementPtr _upstreamElem; ElementPtr _connectingElem; ElementSet _pathElems; vector _stack; + std::set _visitedEdges; bool _prune; size_t _holdCount; }; diff --git a/source/MaterialXCore/Unit.cpp b/source/MaterialXCore/Unit.cpp index fc919c3609..266d317cee 100644 --- a/source/MaterialXCore/Unit.cpp +++ b/source/MaterialXCore/Unit.cpp @@ -154,10 +154,10 @@ int LinearUnitConverter::getUnitAsInteger(const string& unitName) const string LinearUnitConverter::getUnitFromInteger(int index) const { auto it = std::find_if(_unitEnumeration.begin(), _unitEnumeration.end(), - [&index](const std::pair &e)->bool - { - return (e.second == index); - }); + [&index](const std::pair& e) -> bool + { + return (e.second == index); + }); if (it != _unitEnumeration.end()) { diff --git a/source/MaterialXCore/Value.cpp b/source/MaterialXCore/Value.cpp index 3e8c1f4462..bb70aa04ae 100644 --- a/source/MaterialXCore/Value.cpp +++ b/source/MaterialXCore/Value.cpp @@ -3,6 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 // +#include +#include #include #include @@ -193,6 +195,60 @@ template T fromValueString(const string& value) return data; } +StringVec parseStructValueString(const string& value) +{ + static const char SEPARATOR = ';'; + static const char OPEN_BRACE = '{'; + static const char CLOSE_BRACE = '}'; + + if (value.empty()) + return StringVec(); + + // Validate the string is correctly formatted - must be at least 2 characters long and start and end with braces + if (value.size() < 2 || (value[0] != OPEN_BRACE || value[value.size()-1] != CLOSE_BRACE)) + { + return StringVec(); + } + + StringVec split; + + // Strip off the surrounding braces + string substring = value.substr(1, value.size()-2); + + // Sequentially examine each character to parse the list initializer. + string part = ""; + int braceDepth = 0; + for (const char c : substring) + { + if (c == OPEN_BRACE) + { + // We've already trimmed the starting brace, so any additional braces indicate members that are themselves list initializers. + // We will just return this as a string of the list initializer. + braceDepth += 1; + } + if (braceDepth > 0 && c == CLOSE_BRACE) + { + braceDepth -= 1; + } + + if (braceDepth == 0 && c == SEPARATOR) + { + // When we hit a separator we store the currently accumulated part, and clear to start collecting the next. + split.emplace_back(part); + part = ""; + } + else + { + part += c; + } + } + + if (!part.empty()) + split.emplace_back(part); + + return split; +} + // // TypedValue methods // @@ -213,12 +269,18 @@ template ValuePtr TypedValue::createFromString(const string& value) // Value methods // -ValuePtr Value::createValueFromStrings(const string& value, const string& type) +ValuePtr Value::createValueFromStrings(const string& value, const string& type, ConstTypeDefPtr typeDef) { CreatorMap::iterator it = _creatorMap.find(type); if (it != _creatorMap.end()) return it->second(value); + if (typeDef && !typeDef->getMembers().empty()) + { + // If we're given a TypeDef pointer that has child members, then we can create a new AggregateValue. + return AggregateValue::createAggregateValueFromString(value, type, typeDef); + } + return TypedValue::createFromString(value); } @@ -237,6 +299,69 @@ template const T& Value::asA() const return typedVal->getData(); } +template <> +MX_CORE_API bool Value::isA() const +{ + return dynamic_cast(this) != nullptr; +} + +template <> +MX_CORE_API const AggregateValue& Value::asA() const +{ + const AggregateValue* typedVal = dynamic_cast(this); + if (!typedVal) + { + throw ExceptionTypeError("Incorrect type specified for value"); + } + return *typedVal; +} + +string AggregateValue::getValueString() const +{ + if (_data.empty()) + return EMPTY_STRING; + + std::string result = "{"; + std::string separator = ""; + for (const auto& val : _data) + { + result += separator + val->getValueString(); + separator = ";"; + } + result += "}"; + + return result; +} + +AggregateValuePtr AggregateValue::createAggregateValueFromString(const string& value, const string& type, ConstTypeDefPtr typeDef) +{ + StringVec subValues = parseStructValueString(value); + + AggregateValuePtr result = AggregateValue::createAggregateValue(type); + const auto& members = typeDef->getMembers(); + + if (subValues.size() != members.size()) + { + std::stringstream ss; + ss << "Wrong number of initializers - expect " << members.size(); + throw Exception(ss.str()); + } + + auto doc = typeDef->getDocument(); + for (size_t i = 0; i < members.size(); ++i) + { + const auto& member = members[i]; + + // This will return nullptr if the type is not a listed typedef. + ConstTypeDefPtr subTypeDef = doc->getTypeDef(members[i]->getType()); + + // Calling Value::createValueFromStrings() here allows support for recursively nested structs. + result->appendValue(Value::createValueFromStrings(subValues[i], member->getType(), subTypeDef)); + } + + return result; +} + ScopedFloatFormatting::ScopedFloatFormatting(Value::FloatFormat format, int precision) : _format(Value::getFloatFormat()), _precision(Value::getFloatPrecision()) diff --git a/source/MaterialXCore/Value.h b/source/MaterialXCore/Value.h index 1bd29b1d2b..4dae4ab135 100644 --- a/source/MaterialXCore/Value.h +++ b/source/MaterialXCore/Value.h @@ -24,21 +24,22 @@ using BoolVec = vector; using FloatVec = vector; class Value; +class AggregateValue; /// A shared pointer to a Value using ValuePtr = shared_ptr; /// A shared pointer to a const Value using ConstValuePtr = shared_ptr; -template class TypedValue; +/// A shared pointer to an Aggregate Value +using AggregateValuePtr = shared_ptr; +/// A shared pointer to a const Aggregate Value +using ConstAggregateValuePtr = shared_ptr; -/// @class ExceptionTypeError -/// An exception that is thrown when a type mismatch is encountered. -class MX_CORE_API ExceptionTypeError : public Exception -{ - public: - using Exception::Exception; -}; +class TypeDef; +using ConstTypeDefPtr = shared_ptr; + +template class TypedValue; /// A generic, discriminated value, whose type may be queried dynamically. class MX_CORE_API Value @@ -73,7 +74,7 @@ class MX_CORE_API Value /// Create a new value instance from value and type strings. /// @return A shared pointer to a typed value, or an empty shared pointer /// if the conversion to the given data type cannot be performed. - static ValuePtr createValueFromStrings(const string& value, const string& type); + static ValuePtr createValueFromStrings(const string& value, const string& type, ConstTypeDefPtr typeDef = nullptr); /// Create a deep copy of the value. virtual ValuePtr copy() const = 0; @@ -193,6 +194,68 @@ template class MX_CORE_API TypedValue : public Value T _data; }; +/// A subclass for aggregate values with multiple members +class MX_CORE_API AggregateValue : public Value +{ + public: + AggregateValue(const string& typeName) : + _typeName(typeName) + { + } + virtual ~AggregateValue() { } + + /// Create a deep copy of the value. + ValuePtr copy() const override + { + auto result = createAggregateValue(_typeName); + for (const auto& val : _data) + { + result->appendValue(val->copy()); + } + return result; + } + + /// Append a member value to the aggregate. + void appendValue(ConstValuePtr valuePtr) + { + _data.emplace_back(valuePtr); + } + + const vector& getMembers() const + { + return _data; + } + + /// Query an indexed member value from the aggregate. + ConstValuePtr getMemberValue(size_t index) const + { + return _data[index]; + } + + /// Return type string. + const string& getTypeString() const override { return _typeName; } + + /// Return value string. + string getValueString() const override; + + // + // Static helper methods + // + + /// Create a new value from an object of any valid MaterialX type. + static AggregateValuePtr createAggregateValue(const string& typeName) + { + return std::make_shared(typeName); + } + + static AggregateValuePtr createAggregateValueFromString(const string& value, const string& type, ConstTypeDefPtr typeDefPtr); + + private: + const string _typeName; + + vector _data; +}; + /// @class ScopedFloatFormatting /// An RAII class for controlling the float formatting of values. class MX_CORE_API ScopedFloatFormatting @@ -216,6 +279,11 @@ template MX_CORE_API string toValueString(const T& data); /// @throws ExceptionTypeError if the conversion cannot be performed. template MX_CORE_API T fromValueString(const string& value); +/// Tokenize the string representation of a struct value i.e, "{1;2;3}" into a +/// vector of substrings. +/// Note: "{1;2;{3;4;5}}" will be split in to ["1", "2", "{3;4;5}"] +MX_CORE_API StringVec parseStructValueString(const string& value); + /// Forward declaration of specific template instantiations. /// Base types MX_CORE_EXTERN_TEMPLATE(TypedValue); diff --git a/source/MaterialXCore/Version.cpp b/source/MaterialXCore/Version.cpp index 9c0022bd6a..62f83a5660 100644 --- a/source/MaterialXCore/Version.cpp +++ b/source/MaterialXCore/Version.cpp @@ -992,16 +992,19 @@ void Document::upgradeVersion() { "color3", 3 }, { "color4", 4 }, { "vector2", 2 }, { "vector3", 3 }, { "vector4", 4 } }; - const StringSet CHANNEL_CONVERT_PATTERNS = - { - "rgb", "rgba", "xyz", "xyzw", "rrr", "xxx" - }; - const vector> CHANNEL_ATTRIBUTE_PATTERNS = - { + const std::array, 10> CHANNEL_CONVERT_PATTERNS = + { { + { "rgb", 3 }, { "rgb", 4 }, { "rgba", 4 }, + { "xyz", 3 }, { "xyz", 4 }, { "xyzw", 4 }, + { "rr", 1 }, { "rrr", 1 }, + { "xx", 1 }, { "xxx", 1 } + } }; + const std::array, 3> CHANNEL_ATTRIBUTE_PATTERNS = + { { { { "xx", "xxx", "xxxx" }, "float" }, { { "xyz", "x", "y", "z" }, "vector3" }, { { "rgba", "a" }, "color4" } - }; + } }; // Convert channels attributes to legacy swizzle nodes, which are then converted // to modern nodes in a second pass. @@ -1102,7 +1105,7 @@ void Document::upgradeVersion() NodePtr base = node->getConnectedNode("base"); if (top && base && top->getCategory() == "thin_film_bsdf") { - // Apply thin-film parameters to all supported BSDF's upstream. + // Apply thin-film parameters to all supported BSDF's upstream. const StringSet BSDF_WITH_THINFILM = { "dielectric_bsdf", "conductor_bsdf", "generalized_schlick_bsdf" }; for (Edge edge : node->traverseGraph()) { @@ -1169,11 +1172,13 @@ void Document::upgradeVersion() CHANNEL_COUNT_MAP.count(node->getType())) { string channelString = channelsInput ? channelsInput->getValueString() : EMPTY_STRING; - size_t sourceChannelCount = CHANNEL_COUNT_MAP.at(inInput->getType()); - size_t destChannelCount = CHANNEL_COUNT_MAP.at(node->getType()); - + string sourceType = inInput->getType(); + string destType = node->getType(); + size_t sourceChannelCount = CHANNEL_COUNT_MAP.at(sourceType); + size_t destChannelCount = CHANNEL_COUNT_MAP.at(destType); + // Resolve the invalid case of having both a connection and a value - // by removing the value attribute. + // by removing the value attribute. if (inInput->hasValue()) { if (inInput->hasNodeName() || inInput->hasNodeGraphString() || inInput->hasInterfaceName()) @@ -1228,7 +1233,8 @@ void Document::upgradeVersion() node->setInputValue("index", (int) CHANNEL_INDEX_MAP.at(channelString[0])); } } - else if (CHANNEL_CONVERT_PATTERNS.count(channelString)) + else if (sourceType != destType && std::find(CHANNEL_CONVERT_PATTERNS.begin(), CHANNEL_CONVERT_PATTERNS.end(), + std::make_pair(channelString, sourceChannelCount)) != CHANNEL_CONVERT_PATTERNS.end()) { // Replace swizzle with convert. node->setCategory("convert"); @@ -1240,21 +1246,13 @@ void Document::upgradeVersion() for (size_t i = 0; i < destChannelCount; i++) { InputPtr combineInInput = node->addInput(std::string("in") + std::to_string(i + 1), "float"); - if (i < channelString.size()) + if (i < channelString.size() && CHANNEL_CONSTANT_MAP.count(channelString[i])) { - if (CHANNEL_CONSTANT_MAP.count(channelString[i])) - { - combineInInput->setValue(CHANNEL_CONSTANT_MAP.at(channelString[i])); - } - else - { - copyInputWithBindings(node, inInput->getName(), node, combineInInput->getName()); - } + combineInInput->setValue(CHANNEL_CONSTANT_MAP.at(channelString[i])); } else { - combineInInput->setConnectedNode(node); - combineInInput->setOutputString(combineInInput->isColorType() ? "outr" : "outx"); + copyInputWithBindings(node, inInput->getName(), node, combineInInput->getName()); } } node->removeInput(inInput->getName()); @@ -1264,7 +1262,7 @@ void Document::upgradeVersion() // Replace swizzle with separate and combine. GraphElementPtr graph = node->getAncestorOfType(); NodePtr separateNode = graph->addNode(std::string("separate") + std::to_string(sourceChannelCount), - graph->createValidChildName("separate"), MULTI_OUTPUT_TYPE_STRING); + graph->createValidChildName("separate"), MULTI_OUTPUT_TYPE_STRING); int childIndex = graph->getChildIndex(node->getName()); if (childIndex != -1) { @@ -1316,10 +1314,34 @@ void Document::upgradeVersion() input2->setName("inx"); } } - else if (node->getNodeDefString() == "ND_normalmap") + else if (nodeCategory == "normalmap") { // ND_normalmap was renamed to ND_normalmap_float - node->setNodeDefString("ND_normalmap_float"); + NodeDefPtr nodeDef = getShaderNodeDef(node); + InputPtr scaleInput = node->getInput("scale"); + if ((nodeDef && nodeDef->getName() == "ND_normalmap") || + (scaleInput && scaleInput->getType() == "float")) + { + node->setNodeDefString("ND_normalmap_float"); + } + + node->removeInput("space"); + + // If the normal or tangent inputs are set, the bitangent input should be normalize(cross(N, T)) + InputPtr normalInput = node->getInput("normal"); + InputPtr tangentInput = node->getInput("tangent"); + if (normalInput || tangentInput) + { + GraphElementPtr graph = node->getAncestorOfType(); + NodePtr crossNode = graph->addNode("crossproduct", graph->createValidChildName("normalmap_cross"), "vector3"); + copyInputWithBindings(node, "normal", crossNode, "in1"); + copyInputWithBindings(node, "tangent", crossNode, "in2"); + + NodePtr normalizeNode = graph->addNode("normalize", graph->createValidChildName("normalmap_cross_norm"), "vector3"); + normalizeNode->addInput("in", "vector3")->setConnectedNode(crossNode); + + node->addInput("bitangent", "vector3")->setConnectedNode(normalizeNode); + } } } for (NodePtr node : unusedNodes) diff --git a/source/MaterialXFormat/CMakeLists.txt b/source/MaterialXFormat/CMakeLists.txt index b58ab0b166..65fb91fb63 100644 --- a/source/MaterialXFormat/CMakeLists.txt +++ b/source/MaterialXFormat/CMakeLists.txt @@ -1,12 +1,16 @@ -file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") -file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") +add_subdirectory(External/PugiXML) + +file(GLOB materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") +file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") mx_add_library(MaterialXFormat SOURCE_FILES ${materialx_source} + ${pugixml_source} HEADER_FILES ${materialx_headers} - LIBRARIES + ${pugixml_headers} + MTLX_MODULES MaterialXCore EXPORT_DEFINE MATERIALX_FORMAT_EXPORTS) diff --git a/source/MaterialXFormat/External/PugiXML/CMakeLists.txt b/source/MaterialXFormat/External/PugiXML/CMakeLists.txt new file mode 100644 index 0000000000..154a4e7a1c --- /dev/null +++ b/source/MaterialXFormat/External/PugiXML/CMakeLists.txt @@ -0,0 +1,16 @@ +# Don't actually build a library for PugiXML as if we are building MaterialX as a static library +# then we would also need to ship the PugiXML library, instead we just compile the sources +# directly into MaterialXFormat, but take care to hide the symbols. + +file(GLOB pugixml_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") +file(GLOB pugixml_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h") + +set_source_files_properties(${pugixml_source} PROPERTIES CXX_VISIBILITY_PRESET hidden) +set_source_files_properties(${pugixml_source} PROPERTIES CMAKE_VISIBILITY_INLINES_HIDDEN 1) + +set_source_files_properties(${pugixml_source} PROPERTIES FOLDER External) +set_source_files_properties(${pugixml_headers} PROPERTIES FOLDER External) + +set(pugixml_source ${pugixml_source} PARENT_SCOPE) +set(pugixml_headers ${pugixml_headers} PARENT_SCOPE) + diff --git a/source/MaterialXFormat/External/PugiXML/readme.txt b/source/MaterialXFormat/External/PugiXML/readme.txt index 5beb08a90a..522e7bf025 100644 --- a/source/MaterialXFormat/External/PugiXML/readme.txt +++ b/source/MaterialXFormat/External/PugiXML/readme.txt @@ -50,3 +50,11 @@ 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. + +---------------------------------------------------------------- + +These files are taken from https://github.com/zeux/pugixml/tree/v1.9 + +The following MaterialX-specific modifications have been applied the original source: + * Adding tracking for new-line characters + * Adding support for serialization of `<` and `>` instead of `<` and `>` diff --git a/source/MaterialXFormat/File.h b/source/MaterialXFormat/File.h index a1d1813e86..d58eb97946 100644 --- a/source/MaterialXFormat/File.h +++ b/source/MaterialXFormat/File.h @@ -146,7 +146,7 @@ class MX_FORMAT_API FilePath size_t i = baseName.rfind('.'); if (i != string::npos) { - baseName = baseName.substr(0, i); + baseName.resize(i); } } } diff --git a/source/MaterialXFormat/Util.cpp b/source/MaterialXFormat/Util.cpp index 48ded1d6b1..ee4e4067f5 100644 --- a/source/MaterialXFormat/Util.cpp +++ b/source/MaterialXFormat/Util.cpp @@ -9,6 +9,10 @@ #include #include +#if defined(__APPLE__) && defined(BUILD_APPLE_FRAMEWORK) + #include +#endif + MATERIALX_NAMESPACE_BEGIN string readFile(const FilePath& filePath) @@ -226,15 +230,36 @@ FileSearchPath getDefaultDataSearchPath() { const FilePath REQUIRED_LIBRARY_FOLDER("libraries/targets"); FilePath currentPath = FilePath::getModulePath(); + + FileSearchPath searchPath; + #if defined(BUILD_APPLE_FRAMEWORK) + #if defined(TARGET_OS_IPHONE) + const FilePath FRAMEWORK_RESOURCES("Assets"); + #else + const FilePath FRAMEWORK_RESOURCES("Resources"); + #endif + Dl_info info; + if (dladdr(reinterpret_cast(&getDefaultDataSearchPath), &info)) + { + FilePath path = FilePath(info.dli_fname); + if (!path.isEmpty()) + { + path = path.getParentPath(); + searchPath.append(path / FRAMEWORK_RESOURCES); + } + } + #endif + while (!currentPath.isEmpty()) { if ((currentPath / REQUIRED_LIBRARY_FOLDER).exists()) { - return FileSearchPath(currentPath); + searchPath.append(FileSearchPath(currentPath)); + break; } currentPath = currentPath.getParentPath(); } - return FileSearchPath(); + return searchPath; } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenGlsl/CMakeLists.txt b/source/MaterialXGenGlsl/CMakeLists.txt index bd03965b62..37e3a44252 100644 --- a/source/MaterialXGenGlsl/CMakeLists.txt +++ b/source/MaterialXGenGlsl/CMakeLists.txt @@ -6,7 +6,7 @@ mx_add_library(MaterialXGenGlsl ${materialx_source} HEADER_FILES ${materialx_headers} - LIBRARIES + MTLX_MODULES MaterialXGenShader MaterialXCore EXPORT_DEFINE diff --git a/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp b/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp index e8863da008..d29ee65851 100644 --- a/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp +++ b/source/MaterialXGenGlsl/GlslResourceBindingContext.cpp @@ -50,7 +50,7 @@ void GlslResourceBindingContext::emitDirectives(GenContext& context, ShaderStage } } - for (auto& extension : _requiredExtensions) + for (const string& extension : _requiredExtensions) { generator.emitLine("#extension " + extension + " : enable", stage, false); } @@ -153,9 +153,9 @@ void GlslResourceBindingContext::emitStructuredResourceBindings(GenContext& cont // Sort order from largest to smallest std::sort(memberOrder.begin(), memberOrder.end(), [](const std::pair& a, const std::pair& b) - { - return a.first > b.first; - }); + { + return a.first > b.first; + }); // Emit the struct generator.emitLine("struct " + uniforms.getName(), stage, false); @@ -181,8 +181,9 @@ void GlslResourceBindingContext::emitStructuredResourceBindings(GenContext& cont // Emit binding information generator.emitLineBreak(stage); generator.emitLine("layout (std140, binding=" + std::to_string(_hwUniformBindLocation++) + - ") " + syntax.getUniformQualifier() + " " + uniforms.getName() + "_" + - stage.getName(), stage, false); + ") " + syntax.getUniformQualifier() + " " + uniforms.getName() + "_" + + stage.getName(), + stage, false); generator.emitScopeBegin(stage); generator.emitLine(uniforms.getName() + " " + structInstanceName + arraySuffix, stage); generator.emitScopeEnd(stage, true); diff --git a/source/MaterialXGenGlsl/GlslSyntax.cpp b/source/MaterialXGenGlsl/GlslSyntax.cpp index f91305f1a6..7054725b76 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.cpp +++ b/source/MaterialXGenGlsl/GlslSyntax.cpp @@ -375,4 +375,41 @@ bool GlslSyntax::remapEnumeration(const string& value, TypeDesc type, const stri return true; } +StructTypeSyntaxPtr GlslSyntax::createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const +{ + return std::make_shared( + this, + structTypeName, + defaultValue, + uniformDefaultValue, + typeAlias, + typeDefinition); +} + +string GlslStructTypeSyntax::getValue(const Value& value, bool /* uniform */) const +{ + const AggregateValue& aggValue = static_cast(value); + + string result = aggValue.getTypeString() + "("; + + string separator = ""; + for (const auto& memberValue : aggValue.getMembers()) + { + result += separator; + separator = ","; + + const string& memberTypeName = memberValue->getTypeString(); + TypeDesc memberTypeDesc = TypeDesc::get(memberTypeName); + + // Recursively use the syntax to generate the output, so we can supported nested structs. + result += _parentSyntax->getValue(memberTypeDesc, *memberValue, true); + } + + result += ")"; + + return result; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenGlsl/GlslSyntax.h b/source/MaterialXGenGlsl/GlslSyntax.h index 8408534e7e..1e82e354bd 100644 --- a/source/MaterialXGenGlsl/GlslSyntax.h +++ b/source/MaterialXGenGlsl/GlslSyntax.h @@ -45,6 +45,20 @@ class MX_GENGLSL_API GlslSyntax : public Syntax static const StringVec VEC2_MEMBERS; static const StringVec VEC3_MEMBERS; static const StringVec VEC4_MEMBERS; + + protected: + StructTypeSyntaxPtr createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const override; +}; + +/// Specialization of TypeSyntax for aggregate types. +class MX_GENGLSL_API GlslStructTypeSyntax : public StructTypeSyntax +{ + public: + using StructTypeSyntax::StructTypeSyntax; + + string getValue(const Value& value, bool uniform) const override; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenGlsl/VkResourceBindingContext.cpp b/source/MaterialXGenGlsl/VkResourceBindingContext.cpp index 543b2c2e02..214cb75e25 100644 --- a/source/MaterialXGenGlsl/VkResourceBindingContext.cpp +++ b/source/MaterialXGenGlsl/VkResourceBindingContext.cpp @@ -140,7 +140,7 @@ void VkResourceBindingContext::emitStructuredResourceBindings(GenContext& contex // Sort order from largest to smallest std::sort(memberOrder.begin(), memberOrder.end(), [](const std::pair& a, const std::pair& b) - { + { return a.first > b.first; }); diff --git a/source/MaterialXGenMdl/CMakeLists.txt b/source/MaterialXGenMdl/CMakeLists.txt index 25e1e218a6..ef51a08376 100644 --- a/source/MaterialXGenMdl/CMakeLists.txt +++ b/source/MaterialXGenMdl/CMakeLists.txt @@ -6,8 +6,13 @@ mx_add_library(MaterialXGenMdl ${materialx_source} HEADER_FILES ${materialx_headers} - LIBRARIES + MTLX_MODULES MaterialXGenShader MaterialXCore EXPORT_DEFINE MATERIALX_GENMDL_EXPORTS) + +if(NOT SKBUILD) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/mdl + DESTINATION "${MATERIALX_INSTALL_MDL_MODULE_PATH}") +endif() diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index dbf1667d13..1bc65d5cc4 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -41,20 +42,22 @@ const vector DEFAULT_IMPORTS = "using ::materialx::sampling import *", }; -const vector DEFAULT_VERSIONED_IMPORTS = { +const vector DEFAULT_VERSIONED_IMPORTS = +{ "using ::materialx::stdlib_", "using ::materialx::pbrlib_", }; const string IMPORT_ALL = " import *"; - const string MDL_VERSION_1_6 = "1.6"; const string MDL_VERSION_1_7 = "1.7"; const string MDL_VERSION_1_8 = "1.8"; +const string MDL_VERSION_1_9 = "1.9"; const string MDL_VERSION_SUFFIX_1_6 = "1_6"; const string MDL_VERSION_SUFFIX_1_7 = "1_7"; const string MDL_VERSION_SUFFIX_1_8 = "1_8"; +const string MDL_VERSION_SUFFIX_1_9 = "1_9"; } // anonymous namespace @@ -155,6 +158,24 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G emitLineEnd(stage, true); } + // Emit custom node imports for nodes in the graph + for (ShaderNode* node : graph.getNodes()) + { + const ShaderNodeImpl& impl = node->getImplementation(); + const CustomCodeNodeMdl* customNode = dynamic_cast(&impl); + if (customNode) + { + const string& importName = customNode->getQualifiedModuleName(); + if (!importName.empty()) + { + emitString("import ", stage); + emitString(importName, stage); + emitString("::*", stage); + emitLineEnd(stage, true); + } + } + } + // Add global constants and type definitions emitTypeDefinitions(context, stage); @@ -191,6 +212,27 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G emitLineBreak(stage); } + // Emit shader inputs that have been filtered during printing of the public interface + const string uniformPrefix = _syntax->getUniformQualifier() + " "; + for (ShaderGraphInputSocket* inputSocket : graph.getInputSockets()) + { + if (inputSocket->getConnections().size() && + (inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_SHADER || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_CLOSURE || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_MATERIAL)) + { + const string& qualifier = inputSocket->isUniform() || inputSocket->getType() == Type::FILENAME + ? uniformPrefix + : EMPTY_STRING; + const string& type = _syntax->getTypeName(inputSocket->getType()); + + emitLineBegin(stage); + emitString(qualifier + type + " " + inputSocket->getVariable() + " = ", stage); + emitString(_syntax->getDefaultValue(inputSocket->getType(), true), stage); + emitLineEnd(stage, true); + } + } + // Emit all texturing nodes. These are inputs to any // closure/shader nodes and need to be emitted first. emitFunctionCalls(graph, context, stage, ShaderNode::Classification::TEXTURE); @@ -215,6 +257,7 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G const string result = getUpstreamResult(outputSocket, context); const TypeDesc outputType = outputSocket->getType(); + // Try to return some meaningful color in case the output is not a material if (graph.hasClassification(ShaderNode::Classification::TEXTURE)) { if (outputType == Type::DISPLACEMENTSHADER) @@ -223,12 +266,31 @@ ShaderPtr MdlShaderGenerator::generate(const string& name, ElementPtr element, G emitLine("color finalOutput__ = mk_color3(" "r: math::dot(displacement__, state::texture_tangent_u(0))," "g: math::dot(displacement__, state::texture_tangent_v(0))," - "b: math::dot(displacement__, state::normal()))", stage); + "b: math::dot(displacement__, state::normal()))", + stage); } else { emitLine("float3 displacement__ = float3(0.0)", stage); - emitLine("color finalOutput__ = mk_color3(" + result + ")", stage); + std::string finalOutput = "mk_color3(0.0)"; + if (outputType == Type::BOOLEAN) + finalOutput = result + " ? mk_color3(0.0, 1.0, 0.0) : mk_color3(1.0, 0.0, 0.0)"; + else if (outputType == Type::INTEGER) + finalOutput = "mk_color3(" + result + " / 100)"; // arbitrary + else if (outputType == Type::FLOAT) + finalOutput = "mk_color3(" + result + ")"; + else if (outputType == Type::VECTOR2) + finalOutput = "mk_color3(" + result + ".x, " + result + ".y, 0.0)"; + else if (outputType == Type::VECTOR3) + finalOutput = "mk_color3(" + result + ")"; + else if (outputType == Type::COLOR3) + finalOutput = result; + else if (outputType == Type::COLOR4) + finalOutput = result + ".rgb"; + else if (outputType == Type::MATRIX33 || outputType == Type::MATRIX44) + finalOutput = "mk_color3(" + result + "[0][0], " + result + "[1][1], " + result + "[2][2])"; + + emitLine("color finalOutput__ = " + finalOutput, stage); } // End shader body @@ -310,14 +372,31 @@ ShaderNodeImplPtr MdlShaderGenerator::getImplementation(const NodeDef& nodedef, impl = _implFactory.create(name); if (!impl) { - // Fall back to source code implementation. - if (outputType.isClosure()) + // When `file` and `function` are provided we consider this node a user node + const string file = implElement->getTypedAttribute("file"); + const string function = implElement->getTypedAttribute("function"); + // Or, if `sourcecode` is provided we consider this node a user node with inline implementation + // inline implementations are not supposed to have replacement markers + const string sourcecode = implElement->getTypedAttribute("sourcecode"); + if ((!file.empty() && !function.empty()) || (!sourcecode.empty() && sourcecode.find("{{") == string::npos)) + { + impl = CustomCodeNodeMdl::create(); + } + else if (file.empty() && sourcecode.empty()) { - impl = ClosureSourceCodeNodeMdl::create(); + throw ExceptionShaderGenError("No valid MDL implementation found for '" + name + "'"); } else { - impl = SourceCodeNodeMdl::create(); + // Fall back to source code implementation. + if (outputType.isClosure()) + { + impl = ClosureSourceCodeNodeMdl::create(); + } + else + { + impl = SourceCodeNodeMdl::create(); + } } } } @@ -343,6 +422,7 @@ string MdlShaderGenerator::getUpstreamResult(const ShaderInput* input, GenContex return ShaderGenerator::getUpstreamResult(input, context); } + const MdlSyntax& mdlSyntax = static_cast(getSyntax()); string variable; const ShaderNode* upstreamNode = upstreamOutput->getNode(); if (!upstreamNode->isAGraph() && upstreamNode->numOutputs() > 1) @@ -354,7 +434,18 @@ string MdlShaderGenerator::getUpstreamResult(const ShaderInput* input, GenContex } else { - variable = upstreamNode->getName() + "_result.mxp_" + upstreamOutput->getName(); + const string& fieldName = upstreamOutput->getName(); + const CustomCodeNodeMdl* upstreamCustomNodeMdl = dynamic_cast(&upstreamNode->getImplementation()); + if (upstreamCustomNodeMdl) + { + // Prefix the port name depending on the CustomCodeNode + variable = upstreamNode->getName() + "_result." + upstreamCustomNodeMdl->modifyPortName(fieldName, mdlSyntax); + } + else + { + // Existing implementations and none user defined structs will keep the prefix always to not break existing content + variable = upstreamNode->getName() + "_result." + mdlSyntax.modifyPortName(upstreamOutput->getName()); + } } } else @@ -526,6 +617,13 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen // and are editable by users. if (inputSocket->getConnections().size() && graph->isEditable(*inputSocket)) { + if (inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_SHADER || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_CLOSURE || + inputSocket->getType().getSemantic() == TypeDesc::SEMANTIC_MATERIAL) + { + continue; + } + inputs->add(inputSocket->getSelf()); } } @@ -536,7 +634,7 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen outputs->add(outputSocket->getSelf()); } - // MDL does not allow varying data connected to transmission IOR. + // MDL does not allow varying data connected to transmission IOR until MDL 1.9. // We must find all uses of transmission IOR and make sure we don't // have a varying connection to it. If a varying connection is found // we break that connection and revert to using default value on that @@ -551,8 +649,14 @@ ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr elemen // this fix will disconnect the transmission IOR on the inside, but // still support the connection to reflection IOR. // - if (graph->hasClassification(ShaderNode::Classification::SHADER) || - graph->hasClassification(ShaderNode::Classification::CLOSURE)) + GenMdlOptions::MdlVersion version = getMdlVersion(context); + bool uniformIorRequired = + version == GenMdlOptions::MdlVersion::MDL_1_6 || + version == GenMdlOptions::MdlVersion::MDL_1_7 || + version == GenMdlOptions::MdlVersion::MDL_1_8; + if (uniformIorRequired && ( + graph->hasClassification(ShaderNode::Classification::SHADER) || + graph->hasClassification(ShaderNode::Classification::CLOSURE))) { // Find dependencies on transmission IOR. std::set graphsWithIorDependency; @@ -602,7 +706,6 @@ void emitInputAnnotations(const MdlShaderGenerator& _this, const DocumentPtr doc } // anonymous namespace - void MdlShaderGenerator::emitShaderInputs(const DocumentPtr doc, const VariableBlock& inputs, ShaderStage& stage) const { const string uniformPrefix = _syntax->getUniformQualifier() + " "; @@ -641,11 +744,15 @@ void MdlShaderGenerator::emitShaderInputs(const DocumentPtr doc, const VariableB } } +GenMdlOptions::MdlVersion MdlShaderGenerator::getMdlVersion(GenContext& context) const +{ + GenMdlOptionsPtr options = context.getUserData(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY); + return options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; +} void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const { - GenMdlOptionsPtr options = context.getUserData(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY); - GenMdlOptions::MdlVersion version = options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; + GenMdlOptions::MdlVersion version = getMdlVersion(context); emitLineBegin(stage); emitString("mdl ", stage); @@ -657,19 +764,22 @@ void MdlShaderGenerator::emitMdlVersionNumber(GenContext& context, ShaderStage& case GenMdlOptions::MdlVersion::MDL_1_7: emitString(MDL_VERSION_1_7, stage); break; + case GenMdlOptions::MdlVersion::MDL_1_8: + emitString(MDL_VERSION_1_8, stage); + break; default: - // GenMdlOptions::MdlVersion::MDL_1_8 + // GenMdlOptions::MdlVersion::MDL_1_9 // GenMdlOptions::MdlVersion::MDL_LATEST - emitString(MDL_VERSION_1_8, stage); + emitString(MDL_VERSION_1_9, stage); break; } emitLineEnd(stage, true); } + const string& MdlShaderGenerator::getMdlVersionFilenameSuffix(GenContext& context) const { - GenMdlOptionsPtr options = context.getUserData(GenMdlOptions::GEN_CONTEXT_USER_DATA_KEY); - GenMdlOptions::MdlVersion version = options ? options->targetVersion : GenMdlOptions::MdlVersion::MDL_LATEST; + GenMdlOptions::MdlVersion version = getMdlVersion(context); switch (version) { @@ -677,14 +787,15 @@ const string& MdlShaderGenerator::getMdlVersionFilenameSuffix(GenContext& contex return MDL_VERSION_SUFFIX_1_6; case GenMdlOptions::MdlVersion::MDL_1_7: return MDL_VERSION_SUFFIX_1_7; + case GenMdlOptions::MdlVersion::MDL_1_8: + return MDL_VERSION_SUFFIX_1_8; default: - // GenMdlOptions::MdlVersion::MDL_1_8 + // GenMdlOptions::MdlVersion::MDL_1_9 // GenMdlOptions::MdlVersion::MDL_LATEST - return MDL_VERSION_SUFFIX_1_8; + return MDL_VERSION_SUFFIX_1_9; } } - void MdlShaderGenerator::emitMdlVersionFilenameSuffix(GenContext& context, ShaderStage& stage) const { emitString(getMdlVersionFilenameSuffix(context), stage); diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.h b/source/MaterialXGenMdl/MdlShaderGenerator.h index 3a24bcf87d..ef88fbc453 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.h +++ b/source/MaterialXGenMdl/MdlShaderGenerator.h @@ -25,7 +25,8 @@ class MX_GENMDL_API GenMdlOptions : public GenUserData MDL_1_6, MDL_1_7, MDL_1_8, - MDL_LATEST = MDL_1_8 + MDL_1_9, + MDL_LATEST = MDL_1_9 }; /// Create MDL code generator options with default values. @@ -76,7 +77,11 @@ class MX_GENMDL_API MdlShaderGenerator : public ShaderGenerator /// Map of code snippets for geomprops in MDL. static const std::unordered_map GEOMPROP_DEFINITIONS; - /// Add the MDL file header containing the version number of the generated module.. + /// Get the selected MDL target language version number from the context option. + /// If not set, the latest version supported by GenMdl is returned. + GenMdlOptions::MdlVersion getMdlVersion(GenContext& context) const; + + /// Add the MDL file header containing the version number of the generated module. void emitMdlVersionNumber(GenContext& context, ShaderStage& stage) const; /// Add the version number suffix appended to MDL modules that use versions. diff --git a/source/MaterialXGenMdl/MdlSyntax.cpp b/source/MaterialXGenMdl/MdlSyntax.cpp index 0244a8352f..c0859f5ae2 100644 --- a/source/MaterialXGenMdl/MdlSyntax.cpp +++ b/source/MaterialXGenMdl/MdlSyntax.cpp @@ -29,6 +29,8 @@ TYPEDESC_REGISTER_TYPE(MDL_SCATTER_MODE, "scatter_mode") namespace { +const string MARKER_MDL_VERSION_SUFFIX = "MDL_VERSION_SUFFIX"; + class MdlFilenameTypeSyntax : public ScalarTypeSyntax { public: @@ -195,6 +197,8 @@ const StringVec MdlSyntax::FILTERTYPE_MEMBERS = { "box", "gaussian" }; const StringVec MdlSyntax::DISTRIBUTIONTYPE_MEMBERS = { "ggx" }; const StringVec MdlSyntax::SCATTER_MODE_MEMBERS = { "R", "T", "RT" }; +const string MdlSyntax::PORT_NAME_PREFIX = "mxp_"; + // // MdlSyntax methods // @@ -202,22 +206,40 @@ const StringVec MdlSyntax::SCATTER_MODE_MEMBERS = { "R", "T", "RT" }; MdlSyntax::MdlSyntax() { // Add in all reserved words and keywords in MDL + // Formatted as in the MDL Specification 1.9.2 for easy comparing registerReservedWords( - { // Reserved words - "annotation", "bool", "bool2", "bool3", "bool4", "break", "bsdf", "bsdf_measurement", "case", "cast", "color", "const", - "continue", "default", "do", "double", "double2", "double2x2", "double2x3", "double3", "double3x2", "double3x3", "double3x4", - "double4", "double4x3", "double4x4", "double4x2", "double2x4", "edf", "else", "enum", "export", "false", "float", "float2", - "float2x2", "float2x3", "float3", "float3x2", "float3x3", "float3x4", "float4", "float4x3", "float4x4", "float4x2", "float2x4", - "for", "hair_bsdf", "if", "import", "in", "int", "int2", "int3", "int4", "intensity_mode", "intensity_power", "intensity_radiant_exitance", - "let", "light_profile", "material", "material_emission", "material_geometry", "material_surface", "material_volume", "mdl", "module", - "package", "return", "string", "struct", "switch", "texture_2d", "texture_3d", "texture_cube", "texture_ptex", "true", "typedef", "uniform", - "using", "varying", "vdf", "while", - // Reserved for future use - "auto", "catch", "char", "class", "const_cast", "delete", "dynamic_cast", "explicit", "extern", "external", "foreach", "friend", "goto", - "graph", "half", "half2", "half2x2", "half2x3", "half3", "half3x2", "half3x3", "half3x4", "half4", "half4x3", "half4x4", "half4x2", "half2x4", - "inline", "inout", "lambda", "long", "mutable", "namespace", "native", "new", "operator", "out", "phenomenon", "private", "protected", "public", - "reinterpret_cast", "sampler", "shader", "short", "signed", "sizeof", "static", "static_cast", "technique", "template", "this", "throw", "try", - "typeid", "typename", "union", "unsigned", "virtual", "void", "volatile", "wchar_t" }); + { // Reserved words + "annotation", "double2", "float", "in", "operator", + "auto", "double2x2", "float2", "int", "package", + "bool", "double2x3", "float2x2", "int2", "return", + "bool2", "double3", "float2x3", "int3", "string", + "bool3", "double3x2", "float3", "int4", "struct", + "bool4", "double3x3", "float3x2", "intensity_mode", "struct_category", + "break", "double3x4", "float3x3", "intensity_power", "switch", + "bsdf", "double4", "float3x4", "intensity_radiant_exitance", "texture_2d", + "bsdf_measurement", "double4x3", "float4", "let", "texture_3d", + "case", "double4x4", "float4x3", "light_profile", "texture_cube", + "cast", "double4x2", "float4x4", "material", "texture_ptex", + "color", "double2x4", "float4x2", "material_emission", "true", + "const", "edf", "float2x4", "material_geometry", "typedef", + "continue", "else", "for", "material_surface", "uniform", + "declarative", "enum", "hair_bsdf", "material_volume", "using", + "default", "export", "if", "mdl", "varying", + "do", "false", "import", "module", "vdf", + "double", "while", + + // Reserved for future use + "catch", "friend", "half3x4", "mutable", "sampler", "throw", + "char", "goto", "half4", "namespace", "shader", "try", + "class", "graph", "half4x3", "native", "short", "typeid", + "const_cast", "half", "half4x4", "new", "signed", "typename", + "delete", "half2", "half4x2", "out", "sizeof", "union", + "dynamic_cast", "half2x2", "half2x4", "phenomenon", "static", "unsigned", + "explicit", "half2x3", "inline", "private", "static_cast", "virtual", + "extern", "half3", "inout", "protected", "technique", "void", + "external", "half3x2", "lambda", "public", "template", "volatile", + "foreach", "half3x3", "long", "reinterpret_cast", "this", "wchar_t", + }); // Register restricted tokens in MDL StringMap tokens; @@ -533,4 +555,41 @@ void MdlSyntax::makeValidName(string& name) const } } +string MdlSyntax::modifyPortName(const string& word) const +{ + return PORT_NAME_PREFIX + word; +} + +string MdlSyntax::replaceSourceCodeMarkers(const string& nodeName, const string& soureCode, std::function lambda) const +{ + // An inline function call + // Replace tokens of the format "{{}}" + static const string prefix("{{"); + static const string postfix("}}"); + + size_t pos = 0; + size_t i = soureCode.find_first_of(prefix); + StringVec code; + while (i != string::npos) + { + code.push_back(soureCode.substr(pos, i - pos)); + size_t j = soureCode.find_first_of(postfix, i + 2); + if (j == string::npos) + { + throw ExceptionShaderGenError("Malformed inline expression in implementation for node " + nodeName); + } + const string marker = soureCode.substr(i + 2, j - i - 2); + code.push_back(lambda(marker)); + pos = j + 2; + i = soureCode.find_first_of(prefix, pos); + } + code.push_back(soureCode.substr(pos)); + return joinStrings(code, EMPTY_STRING); +} + +const string MdlSyntax::getMdlVersionSuffixMarker() const +{ + return MARKER_MDL_VERSION_SUFFIX; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/MdlSyntax.h b/source/MaterialXGenMdl/MdlSyntax.h index e282cefeca..48fd6214c0 100644 --- a/source/MaterialXGenMdl/MdlSyntax.h +++ b/source/MaterialXGenMdl/MdlSyntax.h @@ -53,6 +53,7 @@ class MX_GENMDL_API MdlSyntax : public Syntax static const StringVec FILTERTYPE_MEMBERS; static const StringVec DISTRIBUTIONTYPE_MEMBERS; static const StringVec SCATTER_MODE_MEMBERS; + static const string PORT_NAME_PREFIX; // Applied to input and output names to avoid collisions with reserved words in MDL /// Get an type description for an enumeration based on member value TypeDesc getEnumeratedType(const string& value) const; @@ -63,6 +64,16 @@ class MX_GENMDL_API MdlSyntax : public Syntax /// Modify the given name string to remove any invalid characters or tokens. void makeValidName(string& name) const override; + + /// To avoid collisions with reserved names in MDL, input and output names are prefixed. + string modifyPortName(const string& word) const; + + /// Replaces all markers in a source code string indicated by {{...}}. + /// The replacement is defined by a callback function. + string replaceSourceCodeMarkers(const string& nodeName, const string& soureCode, std::function lambda) const; + + /// Get the MDL language versing marker: {{MDL_VERSION_SUFFIX}}. + const string getMdlVersionSuffixMarker() const; }; namespace Type diff --git a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp index 0a2004cd71..59b488c875 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp @@ -4,6 +4,7 @@ // #include +#include #include #include @@ -29,6 +30,7 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& mdlSyntax = static_cast(shadergen.getSyntax()); // Emit functions for all child nodes shadergen.emitFunctionDefinitions(*_rootGraph, context, stage); @@ -146,7 +148,7 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC for (const ShaderGraphOutputSocket* output : _rootGraph->getOutputSockets()) { const string result = shadergen.getUpstreamResult(output, context); - shadergen.emitLine(resultVariableName + ".mxp_" + output->getName() + " = " + result, stage); + shadergen.emitLine(resultVariableName + mdlSyntax.modifyPortName(output->getName()) + " = " + result, stage); } shadergen.emitLine("return " + resultVariableName, stage); } diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp index 1dfa45317f..5b187f80aa 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.cpp @@ -16,6 +16,10 @@ MATERIALX_NAMESPACE_BEGIN const string StringConstantsMdl::TOP = "top"; const string StringConstantsMdl::BASE = "base"; +const string StringConstantsMdl::FG = "fg"; +const string StringConstantsMdl::BG = "bg"; +const string StringConstantsMdl::MIX = "mix"; +const string StringConstantsMdl::TOP_WEIGHT = "top_weight"; ShaderNodeImplPtr ClosureLayerNodeMdl::create() { @@ -69,8 +73,9 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& // Join the BSDF and VDF into a single material. shadergen.emitLine("material " + output->getVariable() + - " = material(surface: " + t + ".surface, backface: " + t + - ".backface, ior: " + t + ".ior, volume: " + b + ".volume)", stage); + " = material(surface: " + t + ".surface, backface: " + t + + ".backface, ior: " + t + ".ior, volume: " + b + ".volume)", + stage); return; } @@ -100,6 +105,7 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& // Transport the base bsdf further than one layer ShaderNode* baseReceiverNode = top; + ShaderNode* mixTopWeightNode = nullptr; while (true) { // If the top node is again a layer, we don't want to override the base @@ -110,6 +116,26 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& } else { + // TODO is there a more efficient way to check if the node is a mix_bsdf? + std::string name = top->getImplementation().getName(); + if (name == "IM_mix_bsdf_genmdl") + { + // handle one special case: the top node is a mix where either fg or bg is empty + // so basically a scale factor + ShaderOutput* fgOutput = top->getInput(StringConstantsMdl::FG)->getConnection(); + ShaderOutput* bgOutput = top->getInput(StringConstantsMdl::BG)->getConnection(); + ShaderOutput* mixOutput = top->getInput(StringConstantsMdl::MIX)->getConnection(); + ShaderNode* fg = fgOutput ? fgOutput->getNode() : nullptr; + ShaderNode* bg = bgOutput ? bgOutput->getNode() : nullptr; + ShaderNode* mix = mixOutput ? mixOutput->getNode() : nullptr; + if ((bool) fg != (bool) bg) + { + baseReceiverNode = fg ? fg : bg; // take the node that is valid + top = baseReceiverNode; + mixTopWeightNode = mix; + } + break; + } // we stop at elemental bsdfs // TODO handle mix, add, and multiply break; @@ -149,6 +175,11 @@ void ClosureLayerNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& // base BSDF connection and output variable name from the // layer operator itself. topNodeBaseInput->makeConnection(base->getOutput()); + if (mixTopWeightNode) + { + ShaderInput* topNodeTopWeightInput = baseReceiverNode->getInput(StringConstantsMdl::TOP_WEIGHT); + topNodeTopWeightInput->makeConnection(mixTopWeightNode->getOutput()); + } ScopedSetVariableName setVariable(output->getVariable(), top->getOutput()); // Make the call. @@ -170,6 +201,21 @@ void LayerableNodeMdl::addInputs(ShaderNode& node, GenContext& /*context*/) cons { // Add the input to hold base layer BSDF. node.addInput(StringConstantsMdl::BASE, Type::BSDF); + + // Set the top level weight default to 1.0 + ShaderInput* topWeightNode = node.addInput(StringConstantsMdl::TOP_WEIGHT, Type::FLOAT); + ValuePtr value = TypedValue::createValue(1.0f); + topWeightNode->setValue(value); +} + +bool LayerableNodeMdl::isEditable(const ShaderInput& input) const +{ + if (input.getName() == StringConstantsMdl::BASE || + input.getName() == StringConstantsMdl::TOP_WEIGHT) + { + return false; + } + return BASE::isEditable(input); } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h index bced5cfac1..8b6f987287 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/ClosureLayerNodeMdl.h @@ -23,6 +23,10 @@ class MX_GENMDL_API StringConstantsMdl /// String constants static const string TOP; ///< layer parameter name of the top component static const string BASE; ///< layer parameter name of the base component + static const string FG; ///< mix parameter name of the foreground + static const string BG; ///< mix parameter name of the background + static const string MIX; ///< mix parameter name of the amount + static const string TOP_WEIGHT; ///< mix amount forwarded into layer top component }; /// Closure layer node implementation for MDL. @@ -40,11 +44,14 @@ class MX_GENMDL_API ClosureLayerNodeMdl : public ShaderNodeImpl /// Note, not all elemental bsdfs support this kind of transformation. class MX_GENMDL_API LayerableNodeMdl : public SourceCodeNodeMdl { + using BASE = SourceCodeNodeMdl; + public: virtual ~LayerableNodeMdl() = default; static ShaderNodeImplPtr create(); void addInputs(ShaderNode& node, GenContext&) const override; + bool isEditable(const ShaderInput& input) const override; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp index 80c449e507..2dab721e24 100644 --- a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -46,6 +47,7 @@ void CompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenContext& DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); const bool isMaterialExpr = (_rootGraph->hasClassification(ShaderNode::Classification::CLOSURE) || _rootGraph->hasClassification(ShaderNode::Classification::SHADER)); @@ -83,7 +85,7 @@ void CompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenContext& for (const ShaderGraphOutputSocket* output : _rootGraph->getOutputSockets()) { const string result = shadergen.getUpstreamResult(output, context); - shadergen.emitLine(resultVariableName + ".mxp_" + output->getName() + " = " + result, stage); + shadergen.emitLine(resultVariableName + "." + syntax.modifyPortName(output->getName()) + " = " + result, stage); } shadergen.emitLine("return " + resultVariableName, stage); } @@ -180,7 +182,7 @@ void CompoundNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& conte void CompoundNodeMdl::emitFunctionSignature(const ShaderNode&, GenContext& context, ShaderStage& stage) const { const ShaderGenerator& shadergen = context.getShaderGenerator(); - const Syntax& syntax = shadergen.getSyntax(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); if (!_returnStruct.empty()) { @@ -208,7 +210,7 @@ void CompoundNodeMdl::emitFunctionSignature(const ShaderNode&, GenContext& conte shadergen.emitScopeBegin(stage, Syntax::CURLY_BRACKETS); for (const ShaderGraphOutputSocket* output : _rootGraph->getOutputSockets()) { - shadergen.emitLine(syntax.getTypeName(output->getType()) + " mxp_" + output->getName(), stage); + shadergen.emitLine(syntax.getTypeName(output->getType()) + " " + syntax.modifyPortName(output->getName()), stage); } shadergen.emitScopeEnd(stage, true); shadergen.emitLineBreak(stage); diff --git a/source/MaterialXGenMdl/Nodes/CustomNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.cpp new file mode 100644 index 0000000000..7215b90256 --- /dev/null +++ b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.cpp @@ -0,0 +1,278 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include + +#include +#include +#include +#include +#include + +MATERIALX_NAMESPACE_BEGIN + +ShaderNodeImplPtr CustomCodeNodeMdl::create() +{ + return std::make_shared(); +} + +const string& CustomCodeNodeMdl::getQualifiedModuleName() const +{ + return _qualifiedModuleName; +} + +string CustomCodeNodeMdl::modifyPortName(const string& name, const MdlSyntax& syntax) const +{ + if (_useExternalSourceCode) + { + const StringSet& reservedWords = syntax.getReservedWords(); + if (reservedWords.find(name) == reservedWords.end()) + { + // Use existing MDL parameter names if they don't collide with a reserved word. + // This allows us to reference MDL existing functions without changing the MDL source code. + return name; + } + } + return syntax.modifyPortName(name); +} + +void CustomCodeNodeMdl::initialize(const InterfaceElement& element, GenContext& context) +{ + SourceCodeNodeMdl::initialize(element, context); + if (_inlined) + { + _useExternalSourceCode = false; + initializeForInlineSourceCode(element, context); + } + else + { + _useExternalSourceCode = true; + initializeForExternalSourceCode(element, context); + } +} + +void CustomCodeNodeMdl::initializeForInlineSourceCode(const InterfaceElement& element, GenContext& context) +{ + const Implementation& impl = static_cast(element); + // Store the inline source because the `_functionSource` is used for the function call template string + // that matched the regular MaterialX to MDL function mapping. + _inlineSourceCode = impl.getAttribute("sourcecode"); + if (_inlineSourceCode.empty()) + { + throw ExceptionShaderGenError("No source code was specified for the implementation '" + impl.getName() + "'"); + } + if (_inlineSourceCode.find("//") != string::npos) + { + throw ExceptionShaderGenError("Source code contains unsupported comments '//', please use '/* comment */' instead in '" + impl.getName() + "'"); + } + + NodeDefPtr nodeDef = impl.getNodeDef(); + _inlineFunctionName = nodeDef->getName(); + _hash = std::hash{}(_inlineFunctionName); // make sure we emit the function definition only once + + const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); + // Construct the function call template string + initializeFunctionCallTemplateString(syntax, *nodeDef); + // Collect information about output names and defaults + initializeOutputDefaults(syntax, *nodeDef); +} + +void CustomCodeNodeMdl::initializeForExternalSourceCode(const InterfaceElement& element, GenContext& context) +{ + // Format the function source in a way that the ShaderCodeNodeMdl (the base class of the current one) can deal with it + const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); + const string uniformPrefix = syntax.getUniformQualifier() + " "; + + // Map `file` to a qualified MDL module name + const Implementation& impl = static_cast(element); + string moduleName = impl.getAttribute("file"); + if (moduleName.empty()) + { + throw ExceptionShaderGenError("No source file was specified for the implementation '" + impl.getName() + "'"); + } + if (_functionName.empty()) + { + throw ExceptionShaderGenError("No function name was specified for the implementation '" + impl.getName() + "'"); + } + + string mdlModuleName = replaceSubstrings(moduleName, { { "/", "::" } }); + if (!stringStartsWith(mdlModuleName, "::")) + { + mdlModuleName = "::" + mdlModuleName; + } + + if (!stringEndsWith(mdlModuleName, ".mdl")) + { + throw ExceptionShaderGenError("Referenced source file is not an MDL module: '" + moduleName + + "' used by implementation '" + impl.getName() + "'"); + } + else + { + mdlModuleName = mdlModuleName.substr(0, mdlModuleName.size() - 4); + } + const string versionSuffix = shadergenMdl.getMdlVersionFilenameSuffix(context); + _qualifiedModuleName = syntax.replaceSourceCodeMarkers(element.getName(), mdlModuleName, + [&versionSuffix, &syntax](const string& marker) + { + return marker == syntax.getMdlVersionSuffixMarker() ? versionSuffix : marker; + }); + + NodeDefPtr nodeDef = impl.getNodeDef(); + // Construct the function call template string + initializeFunctionCallTemplateString(syntax, *nodeDef); + // Collect information about output names and defaults + initializeOutputDefaults(syntax, *nodeDef); +} + +void CustomCodeNodeMdl::initializeFunctionCallTemplateString(const MdlSyntax& syntax, const NodeDef& nodeDef) +{ + // Construct the fully qualified function name for external functions + if (_useExternalSourceCode) + { + _functionSource = _qualifiedModuleName.substr(2) + "::" + _functionName + "("; + } + // or simple name for local functions + else + { + _functionSource = _inlineFunctionName + "("; + } + + // Function parameters + string delim = EMPTY_STRING; + for (const InputPtr& input : nodeDef.getInputs()) + { + string inputName = modifyPortName(input->getName(), syntax); + _functionSource += delim + inputName + ": {{" + input->getName() + "}}"; + if (delim == EMPTY_STRING) + delim = Syntax::COMMA + " "; + } + _functionSource += ")"; + _inlined = true; +} + +void CustomCodeNodeMdl::initializeOutputDefaults(const MdlSyntax&, const NodeDef& nodeDef) +{ + for (const OutputPtr& output : nodeDef.getOutputs()) + { + _outputDefaults.push_back(output->getValue()); + } +} + +void CustomCodeNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const +{ + // No source code printing for externally defined functions + if (_useExternalSourceCode) + { + return; + } + + const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); + shadergen.emitComment("generated code for implementation: '" + node.getImplementation().getName() + "'", stage); + + // Function return type + struct Field + { + string name; + string type_name; + string default_value; + }; + vector outputs; + size_t i = 0; + for (const ShaderOutput* output : node.getOutputs()) + { + string name = modifyPortName(output->getName(), syntax); + TypeDesc type = output->getType(); + const ValuePtr defaultValue = _outputDefaults[i]; + outputs.push_back({ + name, + syntax.getTypeName(type), + defaultValue ? syntax.getValue(type, *defaultValue.get()) : syntax.getDefaultValue(type) + }); + ++i; + } + + size_t numOutputs = node.getOutputs().size(); + string returnTypeName; + if (numOutputs == 1) + { + returnTypeName = outputs.back().type_name; + } + else + { + returnTypeName = _inlineFunctionName + "_return_type"; + shadergen.emitLine("struct " + returnTypeName, stage, false); + shadergen.emitScopeBegin(stage, Syntax::CURLY_BRACKETS); + for (const auto& field : outputs) + { + // ignore the default values here, they have to be initialized in the body + shadergen.emitLine(field.type_name + " " + field.name, stage); + } + shadergen.emitScopeEnd(stage, Syntax::CURLY_BRACKETS); + shadergen.emitLineEnd(stage, false); + } + // Signature + shadergen.emitString(returnTypeName + " " + _inlineFunctionName, stage); + { + // Function parameters + shadergen.emitScopeBegin(stage, Syntax::PARENTHESES); + size_t paramCount = node.getInputs().size(); + const string uniformPrefix = syntax.getUniformQualifier() + " "; + for (const ShaderInput* input : node.getInputs()) + { + const string& qualifier = input->isUniform() || input->getType() == Type::FILENAME ? uniformPrefix : EMPTY_STRING; + const string& type = syntax.getTypeName(input->getType()); + const string name = modifyPortName(input->getName(), syntax); + const string& delim = --paramCount == 0 ? EMPTY_STRING : Syntax::COMMA; + shadergen.emitString(" " + qualifier + type + " " + name + delim + Syntax::NEWLINE, stage); + } + shadergen.emitScopeEnd(stage, false, true); + } + { + // Function body + shadergen.emitScopeBegin(stage, Syntax::CURLY_BRACKETS); + + // Out variable initialization + shadergen.emitComment("initialize outputs:", stage); + for (const auto& field : outputs) + { + shadergen.emitLine(field.type_name + " " + field.name + " = " + field.default_value, stage); + } + + // User defined code + shadergen.emitComment("inlined shader source code:", stage); + shadergen.emitLine(_inlineSourceCode, stage, false); + + // Output packing + shadergen.emitComment("pack (in case of multiple outputs) and return outputs:", stage); + if (numOutputs == 1) + { + shadergen.emitLine("return " + outputs.back().name, stage, true); + } + else + { + // Return a constructor call of the return struct type + shadergen.emitString(" return " + returnTypeName + "(", stage); + string delim = EMPTY_STRING; + for (const auto& field : outputs) + { + shadergen.emitString(delim + field.name, stage); + if (delim == EMPTY_STRING) + delim = Syntax::COMMA + " "; + } + shadergen.emitString(")", stage); + shadergen.emitLineEnd(stage, true); + } + shadergen.emitScopeEnd(stage, false, true); + } + shadergen.emitLine("", stage, false); // empty line for spacing +} + +MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenMdl/Nodes/CustomNodeMdl.h b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.h new file mode 100644 index 0000000000..daf4c873a5 --- /dev/null +++ b/source/MaterialXGenMdl/Nodes/CustomNodeMdl.h @@ -0,0 +1,56 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef MATERIALX_CUSTOMNODEMDL_H +#define MATERIALX_CUSTOMNODEMDL_H + +#include + +MATERIALX_NAMESPACE_BEGIN + +class MdlSyntax; +class NodeDef; + +/// Node to handle user defined implementations in external MDL files or using the inline `sourcecode` attribute. +class MX_GENMDL_API CustomCodeNodeMdl : public SourceCodeNodeMdl +{ + public: + static ShaderNodeImplPtr create(); + void initialize(const InterfaceElement& element, GenContext& context) override; + void emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; + + /// Get the MDL qualified name of the externally references user module. + /// It's used for import statements and functions calls in the generated target code. + const string& getQualifiedModuleName() const; + + /// To avoid collisions with reserved names in MDL, input and output names are prefixed. + /// In the `sourcecode` case all inputs and outputs are prefixed so authors don't need knowledge about reserved words in MDL. + /// In the `file` and `function` case, only reserved names are prefixed to support existing MDL implementations without changes. + string modifyPortName(const string& name, const MdlSyntax& syntax) const; + + protected: + /// Initialize function for nodes that use the inline `sourcecode` attribute. + void initializeForInlineSourceCode(const InterfaceElement& element, GenContext& context); + + /// Initialize function for nodes that use the `file` and `function` attribute. + void initializeForExternalSourceCode(const InterfaceElement& element, GenContext& context); + + /// Computes the function call string with replacement markers use by base class. + void initializeFunctionCallTemplateString(const MdlSyntax& syntax, const NodeDef& node); + + /// Keep track of the default values needed for the inline `sourcecode` case. + void initializeOutputDefaults(const MdlSyntax& syntax, const NodeDef& node); + + std::vector _outputDefaults; ///< store default values of the node definition + + bool _useExternalSourceCode; // Indicates that `file` and `function` are used by this node implementation + string _inlineFunctionName; // Name of the functionDefinition to emit + string _inlineSourceCode; // The actual inline source code + string _qualifiedModuleName; // MDL qualified name derived from the `file` attribute +}; + +MATERIALX_NAMESPACE_END + +#endif diff --git a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h index fe88b2ce09..8363c6f4fa 100644 --- a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.h @@ -18,7 +18,7 @@ class MX_GENMDL_API ImageNodeMdl : public SourceCodeNodeMdl using BASE = SourceCodeNodeMdl; public: - static const string FLIP_V; ///< the empty string "" + static const string FLIP_V; ///< name of the additional parameter "flip_v" static ShaderNodeImplPtr create(); diff --git a/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp index d13aa2871f..6891fc1778 100644 --- a/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/MaterialNodeMdl.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,7 @@ void MaterialNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& cont const ShaderGenerator& shadergen = context.getShaderGenerator(); const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); + const MdlSyntax& mdlSyntax = static_cast(shadergen.getSyntax()); // Emit the function call for upstream surface shader. const ShaderNode* surfaceshaderNode = surfaceshaderInput->getConnection()->getNode(); @@ -50,8 +52,7 @@ void MaterialNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& cont for (ShaderInput* input : node.getInputs()) { shadergen.emitString(delim, stage); - shadergen.emitString("mxp_", stage); - shadergen.emitString(input->getName(), stage); + shadergen.emitString(mdlSyntax.modifyPortName(input->getName()), stage); shadergen.emitString(": ", stage); shadergen.emitInput(input, context, stage); delim = ", "; diff --git a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp index 8ce86263d4..5547ae309d 100644 --- a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp @@ -13,51 +13,28 @@ #include #include +#include + #include MATERIALX_NAMESPACE_BEGIN -namespace // anonymous -{ -const string MARKER_MDL_VERSION_SUFFIX = "MDL_VERSION_SUFFIX"; - -StringVec replaceSourceCodeMarkers(const string& nodeName, const string& soureCode, std::function lambda) +ShaderNodeImplPtr SourceCodeNodeMdl::create() { - // An inline function call - // Replace tokens of the format "{{}}" - static const string prefix("{{"); - static const string postfix("}}"); - - size_t pos = 0; - size_t i = soureCode.find_first_of(prefix); - StringVec code; - while (i != string::npos) - { - code.push_back(soureCode.substr(pos, i - pos)); - size_t j = soureCode.find_first_of(postfix, i + 2); - if (j == string::npos) - { - throw ExceptionShaderGenError("Malformed inline expression in implementation for node " + nodeName); - } - const string marker = soureCode.substr(i + 2, j - i - 2); - code.push_back(lambda(marker)); - pos = j + 2; - i = soureCode.find_first_of(prefix, pos); - } - code.push_back(soureCode.substr(pos)); - return code; + return std::make_shared(); } -} // anonymous namespace - -ShaderNodeImplPtr SourceCodeNodeMdl::create() +void SourceCodeNodeMdl::resolveSourceCode(const InterfaceElement& /*element*/, GenContext& /*context*/) { - return std::make_shared(); + // Initialize without fetching the source code from file. + // The resolution of MDL modules is done by the MDL compiler when loading the generated source code. + // All references MDL modules must be accessible via MDL search paths set up by the consuming application. } void SourceCodeNodeMdl::initialize(const InterfaceElement& element, GenContext& context) { SourceCodeNode::initialize(element, context); + const MdlSyntax& syntax = static_cast(context.getShaderGenerator().getSyntax()); const Implementation& impl = static_cast(element); NodeDefPtr nodeDef = impl.getNodeDef(); @@ -77,11 +54,10 @@ void SourceCodeNodeMdl::initialize(const InterfaceElement& element, GenContext& const ShaderGenerator& shadergen = context.getShaderGenerator(); const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); const string versionSuffix = shadergenMdl.getMdlVersionFilenameSuffix(context); - StringVec code = replaceSourceCodeMarkers(getName(), functionName, [&versionSuffix](const string& marker) - { - return marker == MARKER_MDL_VERSION_SUFFIX ? versionSuffix : EMPTY_STRING; - }); - functionName = std::accumulate(code.begin(), code.end(), EMPTY_STRING); + functionName = syntax.replaceSourceCodeMarkers(getName(), functionName, [&versionSuffix, syntax](const string& marker) + { + return marker == syntax.getMdlVersionSuffixMarker() ? versionSuffix : EMPTY_STRING; + }); _returnStruct = functionName + "__result"; } else @@ -103,35 +79,36 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con const MdlShaderGenerator& shadergenMdl = static_cast(shadergen); if (_inlined) { + const MdlSyntax& syntax = static_cast(shadergenMdl.getSyntax()); const string versionSuffix = shadergenMdl.getMdlVersionFilenameSuffix(context); - StringVec code = replaceSourceCodeMarkers(node.getName(), _functionSource, - [&shadergenMdl, &context, &node, &versionSuffix](const string& marker) + string code = syntax.replaceSourceCodeMarkers(node.getName(), _functionSource, + [&shadergenMdl, &context, &node, &versionSuffix, syntax](const string& marker) + { + // Special handling for the version suffix of MDL source code modules. + if (marker == syntax.getMdlVersionSuffixMarker()) { - // Special handling for the version suffix of MDL source code modules. - if (marker == MARKER_MDL_VERSION_SUFFIX) - { - return versionSuffix; - } - // Insert inputs based on parameter names. - else + return versionSuffix; + } + // Insert inputs based on parameter names. + else + { + const ShaderInput* input = node.getInput(marker); + if (!input) { - const ShaderInput* input = node.getInput(marker); - if (!input) - { - throw ExceptionShaderGenError("Could not find an input named '" + marker + - "' on node '" + node.getName() + "'"); - } - - return shadergenMdl.getUpstreamResult(input, context); + throw ExceptionShaderGenError("Could not find an input named '" + marker + + "' on node '" + node.getName() + "'"); } - }); + + return shadergenMdl.getUpstreamResult(input, context); + } + }); if (!_returnStruct.empty()) { // Emit the struct multioutput. const string resultVariableName = node.getName() + "_result"; shadergen.emitLineBegin(stage); - shadergen.emitString(_returnStruct + " " + resultVariableName + " = ", stage); + shadergen.emitString("auto " + resultVariableName + " = ", stage); } else { @@ -141,10 +118,7 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con shadergen.emitString(" = ", stage); } - for (const string& c : code) - { - shadergen.emitString(c, stage); - } + shadergen.emitString(code, stage); shadergen.emitLineEnd(stage); } else @@ -156,7 +130,7 @@ void SourceCodeNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& con // Emit the struct multioutput. const string resultVariableName = node.getName() + "_result"; shadergen.emitLineBegin(stage); - shadergen.emitString(_returnStruct + " " + resultVariableName + " = ", stage); + shadergen.emitString("auto " + resultVariableName + " = ", stage); } else { diff --git a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h index 23c47e6249..7f595704cc 100644 --- a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h @@ -25,6 +25,7 @@ class MX_GENMDL_API SourceCodeNodeMdl : public SourceCodeNode void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; protected: + void resolveSourceCode(const InterfaceElement& element, GenContext& context) override; string _returnStruct; }; diff --git a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp index 6477cd9ae8..8904d835f4 100644 --- a/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SurfaceNodeMdl.cpp @@ -6,6 +6,7 @@ #include #include +#include #include @@ -55,16 +56,22 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { const MdlShaderGenerator& shadergen = static_cast(context.getShaderGenerator()); + const MdlSyntax& mdlSyntax = static_cast(shadergen.getSyntax()); // Emit calls for the closure dependencies upstream from this node. shadergen.emitDependentFunctionCalls(node, context, stage, ShaderNode::Classification::CLOSURE); - // Check if transmission IOR is used for this shader. + // Check if transmission IOR is used for this shader for MDL versions before 1.9. // MDL only supports a single transmission IOR per material and // it is given as an input on the 'material' constructor. // So if used we must forward this value/connection to the surface // constructor. It's set as an extra input below. - const ShaderInput* ior = findTransmissionIOR(node); + GenMdlOptions::MdlVersion version = shadergen.getMdlVersion(context); + bool uniformIorRequired = + version == GenMdlOptions::MdlVersion::MDL_1_6 || + version == GenMdlOptions::MdlVersion::MDL_1_7 || + version == GenMdlOptions::MdlVersion::MDL_1_8; + const ShaderInput* ior = uniformIorRequired ? findTransmissionIOR(node) : nullptr; shadergen.emitLineBegin(stage); @@ -79,6 +86,8 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex for (ShaderInput* input : node.getInputs()) { shadergen.emitString(delim, stage); + shadergen.emitString(mdlSyntax.modifyPortName(input->getName()), stage); + shadergen.emitString(": ", stage); shadergen.emitInput(input, context, stage); delim = ", "; } @@ -87,6 +96,7 @@ void SurfaceNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& contex { // Emit the extra input for transmission IOR. shadergen.emitString(delim, stage); + shadergen.emitString("mxp_transmission_ior: ", stage); shadergen.emitInput(ior, context, stage); } diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl index 0c11ce3744..789b4cfa77 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib.mdl @@ -16,15 +16,15 @@ // MDL implementation of all types and nodes of // MaterialX Physically-Based Shading Nodes -// Document v1.37 REV2, July 16, 2019 (Revised October 17, 2019) +// Document version 1.39, June 29, 2024 // see www.materialx.org // in -// NVIDIA Material Definition Language 1.8 +// NVIDIA Material Definition Language 1.9 // Language Specification -// Document version 1.8.2, May 24, 2023 +// Document version 1.9.2, September 16, 2024 // www.nvidia.com/mdl -mdl 1.8; +mdl 1.9; // forward the latest version -export using .::pbrlib_1_8 import *; +export using .::pbrlib_1_9 import *; diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl index ef2e090a49..64102d6c27 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl @@ -82,7 +82,8 @@ export material mx_oren_nayar_diffuse_bsdf( float mxp_weight = 1.0, color mxp_color = color(0.18), float mxp_roughness = 0.0, - float3 mxp_normal = state::normal() + float3 mxp_normal = state::normal(), + uniform bool mxp_energy_compensation = false [[ anno::unused() ]] // MDL 1.10 ) [[ anno::usage( "materialx:bsdf") ]] @@ -152,7 +153,8 @@ export material mx_dielectric_bsdf( float3 mxp_tangent = state::texture_tangent_u(0), uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, - material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix float mxp_thinfilm_thickness = 0.0, float mxp_thinfilm_ior = 1.0 ) [[ @@ -174,8 +176,8 @@ export material mx_dielectric_bsdf( layer: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect), base: mxp_base.surface.scattering, @@ -186,8 +188,8 @@ export material mx_dielectric_bsdf( layer: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_transmit), normal: mxp_normal); @@ -200,8 +202,8 @@ export material mx_dielectric_bsdf( base: df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: mxp_tint, - multiscatter_tint: mxp_tint, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect_transmit)), normal: mxp_normal); @@ -258,12 +260,13 @@ export material mx_conductor_bsdf( ) ); -// TODO MDL 1.8 +// MDL 1.8 // * will add support for thin film above a color_custom_curve_layer node until then, thin_film will have no effect // * thin_film(thickness: 0.0, ior: < 1.0) will be handled properly export material mx_generalized_schlick_bsdf( float mxp_weight = 1.0, color mxp_color0 = color(1.0), + color mxp_color82 = color(1.0), // MDL 1.10 color mxp_color90 = color(1.0), float mxp_exponent = 5.0, float2 mxp_roughness = float2(0.05), @@ -271,7 +274,8 @@ export material mx_generalized_schlick_bsdf( float3 mxp_tangent = state::texture_tangent_u(0), uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, - material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix float mxp_thinfilm_thickness = 0.0, float mxp_thinfilm_ior = 1.0 ) [[ @@ -283,8 +287,8 @@ export material mx_generalized_schlick_bsdf( bsdf ggx_model_R = df::microfacet_ggx_smith_bsdf( roughness_u: mxp_roughness.x, roughness_v: mxp_roughness.y, - tint: color(1.0), - multiscatter_tint: color(1.0), + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, tangent_u: mxp_tangent, mode: df::scatter_reflect); @@ -302,7 +306,7 @@ export material mx_generalized_schlick_bsdf( layer: mxp_scatter_mode == mx_scatter_mode_T ? df::color_custom_curve_layer( normal_reflectivity: mxp_color0, - grazing_reflectivity: mxp_color90, + grazing_reflectivity: mxp_color82 * mxp_color90, exponent: mxp_exponent, layer: bsdf(), base: ggx_model_T, @@ -312,7 +316,7 @@ export material mx_generalized_schlick_bsdf( ior: color(coatIor), base: df::color_custom_curve_layer( normal_reflectivity: mxp_color0, - grazing_reflectivity: mxp_color90, + grazing_reflectivity: mxp_color82 * mxp_color90, exponent: mxp_exponent, layer: ggx_model_R, base: mxp_scatter_mode == mx_scatter_mode_R @@ -428,6 +432,35 @@ export material mx_thin_film_bsdf( volume: mxp_base.volume ); +export material mx_chiang_hair_bsdf( + // TODO: MDL's chiang_hair BSDF has no support tinting each lobes + color mxp_tint_R = color(1.0) [[ anno::unused() ]], + color mxp_tint_TT = color(1.0) [[ anno::unused() ]], + color mxp_tint_TRT = color(1.0) [[ anno::unused() ]], + float mxp_ior = 1.55, + float2 mxp_roughness_R = float2(0.1, 0.1), + float2 mxp_roughness_TT = float2(0.05, 0.05), + float2 mxp_roughness_TRT = float2(0.2, 0.2), + float mxp_cuticle_angle = 0.5, + float3 mxp_absorption_coefficient = float3(0.0), + // TODO: MDL's chiang_hair BSDF has no support user tangent vector + float3 mxp_curve_direction = state::texture_tangent_u(0) [[ anno::unused() ]] +) [[ + anno::usage( "materialx:bsdf") +]] += material( + hair: df::chiang_hair_bsdf( + diffuse_reflection_weight: 0.0, + diffuse_reflection_tint: color(0.0), + roughness_R: mxp_roughness_R, + roughness_TT: mxp_roughness_TT, + roughness_TRT: mxp_roughness_TRT, + cuticle_angle: mxp_cuticle_angle, + absorption_coefficient: color(mxp_absorption_coefficient), + ior: mxp_ior + ) +); + // EDF Nodes export material mx_uniform_edf( @@ -561,6 +594,7 @@ export material mx_surface( scattering: bsdf_node, emission: edf_node ), + hair: mxp_bsdf.hair, ior: mxp_transmission_ior > 0.0 ? color(mxp_transmission_ior) : mxp_bsdf.ior, volume: bsdf_volume, geometry: material_geometry( @@ -980,3 +1014,64 @@ export mx_artistic_ior__result mx_artistic_ior( color k = math::sqrt(k2); return mx_artistic_ior__result(n,k); } + +export float3 mx_deon_hair_absorption_from_melanin( + float mxp_melanin_concentration = 0.25, + float mxp_melanin_redness = 0.5, + color mxp_eumelanin_color = color(0.657704, 0.498077, 0.254107), + color mxp_pheomelanin_color = color(0.829444, 0.67032, 0.349938) +) { + float melanin = -math::log(math::max(1.0 - mxp_melanin_concentration, 0.0001)); + float eumelanin = melanin * (1.0 - mxp_melanin_redness); + float pheomelanin = melanin * mxp_melanin_redness; + return math::max( + eumelanin * -math::log(float3(mxp_eumelanin_color)) + pheomelanin * -math::log(float3(mxp_pheomelanin_color)), + float3(0.0) + ); +} + +export float3 mx_chiang_hair_absorption_from_color( + color mxp_color = color(1.0, 1.0, 1.0), + float mxp_azimuthal_roughness = 0.2 +) { + float r2 = mxp_azimuthal_roughness * mxp_azimuthal_roughness; + float r4 = r2 * r2; + float r_fac = + 5.969 - + (0.215 * mxp_azimuthal_roughness) + + (2.532 * r2) - + (10.73 * r2 * mxp_azimuthal_roughness) + + (5.574 * r4) + + (0.245 * r4 * mxp_azimuthal_roughness); + float3 sigma = math::log(math::min(math::max(float3(mxp_color), 0.001), float3(1.0))) / r_fac; + return (sigma * sigma); +} + +// Supportive struct type for the three outputs of mx_chiang_hair_roughness +export struct mx_chiang_hair_roughness__result { + float2 mxp_roughness_R; + float2 mxp_roughness_TT; + float2 mxp_roughness_TRT; +}; + +export mx_chiang_hair_roughness__result mx_chiang_hair_roughness( + float mxp_longitudinal = 0.1, + float mxp_azimuthal = 0.2, + float mxp_scale_TT = 0.5, + float mxp_scale_TRT = 2.0 +) { + float lr = math::clamp(mxp_longitudinal, 0.001, 1.0); + float ar = math::clamp(mxp_azimuthal, 0.001, 1.0); + + // longitudinal variance + float v = 0.726 * lr + 0.812 * lr * lr + 3.7 * math::pow(lr, 20); + v = v * v; + + float s = 0.265 * ar + 1.194 * ar * ar + 5.372 * math::pow(ar, 22); + + float2 roughness_R = float2(v, s); + float2 roughness_TT = float2(v * mxp_scale_TT * mxp_scale_TT, s); + float2 roughness_TRT = float2(v * mxp_scale_TRT * mxp_scale_TRT, s); + + return mx_chiang_hair_roughness__result(roughness_R, roughness_TT, roughness_TRT); +} diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl index 2d288ee8f2..bea4e59bf6 100644 --- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_7.mdl @@ -48,6 +48,7 @@ export using .::pbrlib_1_6 import mx_conductor_bsdf; export using .::pbrlib_1_6 import mx_generalized_schlick_bsdf; export using .::pbrlib_1_6 import mx_subsurface_bsdf; export using .::pbrlib_1_6 import mx_thin_film_bsdf; +export using .::pbrlib_1_6 import mx_chiang_hair_bsdf; export using .::pbrlib_1_6 import mx_uniform_edf; export using .::pbrlib_1_6 import mx_conical_edf; export using .::pbrlib_1_6 import mx_measured_edf; @@ -72,6 +73,10 @@ export using .::pbrlib_1_6 import mx_roughness_dual; export using .::pbrlib_1_6 import mx_blackbody; export using .::pbrlib_1_6 import mx_artistic_ior__result ; export using .::pbrlib_1_6 import mx_artistic_ior; +export using .::pbrlib_1_6 import mx_deon_hair_absorption_from_melanin; +export using .::pbrlib_1_6 import mx_chiang_hair_absorption_from_color; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness__result; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness; diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl new file mode 100644 index 0000000000..e8654380d3 --- /dev/null +++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// MDL implementation of all types and nodes of +// MaterialX Physically-Based Shading Nodes +// Document version 1.39, June 29, 2024 +// see www.materialx.org +// in +// NVIDIA Material Definition Language 1.9 +// Language Specification +// Document version 1.9.2, September 16, 2024 +// www.nvidia.com/mdl + +mdl 1.9; + +import ::anno::*; +import ::df::*; +import ::math::*; +import ::state::*; + +import .::core::*; + +// Changes since MDL 1.8 +// - lift the restriction of uniform IORs + +// forward unchanged definitions from the previous versions +export using .::pbrlib_1_6 import mx_scatter_mode; +export using .::pbrlib_1_6 import mx_map_scatter_mode; +export using .::pbrlib_1_6 import mx_oren_nayar_diffuse_bsdf; +export using .::pbrlib_1_6 import mx_burley_diffuse_bsdf; +export using .::pbrlib_1_6 import mx_translucent_bsdf; +export using .::pbrlib_1_6 import mx_subsurface_bsdf; +export using .::pbrlib_1_6 import mx_thin_film_bsdf; +export using .::pbrlib_1_6 import mx_chiang_hair_bsdf; +export using .::pbrlib_1_6 import mx_uniform_edf; +export using .::pbrlib_1_6 import mx_conical_edf; +export using .::pbrlib_1_6 import mx_measured_edf; +export using .::pbrlib_1_6 import mx_absorption_vdf; +export using .::pbrlib_1_6 import mx_anisotropic_vdf; +export using .::pbrlib_1_6 import mx_light; +export using .::pbrlib_1_6 import mx_displacement_float; +export using .::pbrlib_1_6 import mx_displacement_vector3; +export using .::pbrlib_1_6 import volume_mix_return; +export using .::pbrlib_1_6 import volume_mix; +export using .::pbrlib_1_6 import mx_multiply_bsdf_color3; +export using .::pbrlib_1_6 import mx_multiply_bsdf_float; +export using .::pbrlib_1_6 import mx_multiply_edf_color3; +export using .::pbrlib_1_6 import mx_multiply_edf_float; +export using .::pbrlib_1_6 import mx_multiply_vdf_color3; +export using .::pbrlib_1_6 import mx_multiply_vdf_float; +export using .::pbrlib_1_6 import mx_roughness_anisotropy; +export using .::pbrlib_1_6 import mx_roughness_dual; +export using .::pbrlib_1_6 import mx_blackbody; +export using .::pbrlib_1_6 import mx_artistic_ior__result; +export using .::pbrlib_1_6 import mx_artistic_ior; +export using .::pbrlib_1_6 import mx_deon_hair_absorption_from_melanin; +export using .::pbrlib_1_6 import mx_chiang_hair_absorption_from_color; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness__result; +export using .::pbrlib_1_6 import mx_chiang_hair_roughness; + +export using .::pbrlib_1_7 import mx_sheen_bsdf; +export using .::pbrlib_1_7 import mx_add_bsdf; +export using .::pbrlib_1_7 import mx_add_edf; +export using .::pbrlib_1_7 import mx_mix_edf; +export using .::pbrlib_1_7 import mx_add_vdf; +export using .::pbrlib_1_7 import mx_generalized_schlick_edf; +export using .::pbrlib_1_7 import mx_volume; + +export material mx_mix_bsdf( + material mxp_fg = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_bg = material() [[ anno::usage( "materialx:bsdf") ]], + float mxp_mix = 0.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float mix = math::saturate(mxp_mix); + volume_mix_return v = volume_mix( + mxp_fg.volume.scattering_coefficient, mix, + mxp_bg.volume.scattering_coefficient, (1.0f - mix)); +} in material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mix, + layer: mxp_fg.surface.scattering, + base: mxp_bg.surface.scattering + ) + ), + // we need to carry volume properties along for SSS + ior: mix * mxp_fg.ior + (1.0f - mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component(v.mix_weight1, mxp_fg.volume.scattering), + df::vdf_component(1.0 - v.mix_weight1, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: v.scattering_coefficient + ) +); + +export material mx_mix_vdf( + material mxp_fg = material() [[ anno::usage( "materialx:vdf") ]], + material mxp_bg = material() [[ anno::usage( "materialx:vdf") ]], + float mxp_mix = 0.0 +) [[ + anno::usage( "materialx:vdf") +]] += let { + float mix = math::saturate(mxp_mix); + volume_mix_return v = volume_mix( + mxp_fg.volume.scattering_coefficient, mix, + mxp_bg.volume.scattering_coefficient, (1.0f - mix)); +} in material( + ior: mix * mxp_fg.ior + (1.0f - mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component( v.mix_weight1, mxp_fg.volume.scattering), + df::vdf_component( 1.0 - v.mix_weight1, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: v.scattering_coefficient + ) +); + +// helper to compute ior for generalized_schlick +color mx_f0_to_ior(color F0) +{ + float3 sqrtF0 = math::sqrt(math::clamp(float3(F0), 0.01, 0.99)); + return color((float3(1.0) + sqrtF0) / (float3(1.0) - sqrtF0)); +} + +export material mx_generalized_schlick_bsdf( + float mxp_weight = 1.0, + color mxp_color0 = color(1.0), + color mxp_color82 = color(1.0), // MDL 1.10 + color mxp_color90 = color(1.0), + float mxp_exponent = 5.0, + float2 mxp_roughness = float2(0.05), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + bsdf ggx_model_R = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect); + + bsdf ggx_model_T = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0) * mxp_top_weight, + multiscatter_tint: color(1.0) * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_transmit); + +} in material( + surface: material_surface( + scattering: df::unbounded_mix( + df::bsdf_component[]( + df::bsdf_component( + mxp_weight, + mxp_scatter_mode == mx_scatter_mode_T + ? df::color_custom_curve_layer( + normal_reflectivity: mxp_color0, + grazing_reflectivity: mxp_color82 * mxp_color90, + exponent: mxp_exponent, + layer: bsdf(), + base: ggx_model_T, + normal: mxp_normal) + : df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: df::color_custom_curve_layer( + normal_reflectivity: mxp_color0, + grazing_reflectivity: mxp_color82 * mxp_color90, + exponent: mxp_exponent, + layer: ggx_model_R, + base: mxp_scatter_mode == mx_scatter_mode_R + ? mxp_base.surface.scattering + : ggx_model_T, + normal: mxp_normal)) + ), + df::bsdf_component( + 1.0 - mxp_weight, + mxp_base.surface.scattering) + ) + ) + ), + ior: mx_f0_to_ior(mxp_color0), + // we need to carry volume properties along for SSS + volume: mxp_base.volume +); + + +// TODO MDL 1.8 +// * will add support for thin film above a color_custom_curve_layer node until then, thin_film will have no effect +// * thin_film(thickness: 0.0, ior: < 1.0) will be handled properly +export material mx_dielectric_bsdf( + float mxp_weight = 1.0, + color mxp_tint = color(1.0), + float mxp_ior = 1.5, + float2 mxp_roughness = float2(0.0), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + uniform mx_scatter_mode mxp_scatter_mode = mx_scatter_mode_R, + material mxp_base = material() [[ anno::usage( "materialx:bsdf") ]], // layering + float mxp_top_weight = 1.0, // layering for cases where top is scaled using a mix + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + float grazing_refl = math::max((1.0 - math::average(mxp_roughness)), 0.0); + float root_r = (mxp_ior-1)/(mxp_ior+1); + bsdf bsdf_R = df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + // fresnel layer has issues if base is a diffuse transmission, use custom curve for now + // this will break thin_film but improves standard_surface with diffuse transmission + base: df::custom_curve_layer( + normal_reflectivity: root_r*root_r, + grazing_reflectivity: grazing_refl, + weight: mxp_weight, + layer: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect), + base: mxp_base.surface.scattering, + normal: mxp_normal)); + + bsdf bsdf_T = df::weighted_layer( + weight: mxp_weight, + layer: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_transmit), + normal: mxp_normal); + + bsdf bsdf_RT = df::weighted_layer( + weight: mxp_weight, + layer: df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: mxp_tint * mxp_top_weight, + multiscatter_tint: mxp_tint * mxp_top_weight, + tangent_u: mxp_tangent, + mode: df::scatter_reflect_transmit)), + normal: mxp_normal); + + bsdf bsdf_selected = (mxp_scatter_mode == mx_scatter_mode_R) ? bsdf_R : + ((mxp_scatter_mode == mx_scatter_mode_T) ? bsdf_T : bsdf_RT); +} in material( + surface: material_surface( + scattering: bsdf_selected + ), + // we need to carry volume properties along for SSS + ior: color(mxp_ior), + volume: mxp_base.volume +); + +export material mx_conductor_bsdf( + float mxp_weight = 1.0, + color mxp_ior = color(0.18, 0.42, 1.37), + color mxp_extinction = color(3.42, 2.35, 1.77), + float2 mxp_roughness = float2(0.0), + float3 mxp_normal = state::normal(), + float3 mxp_tangent = state::texture_tangent_u(0), + uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]], + float mxp_thinfilm_thickness = 0.0, + float mxp_thinfilm_ior = 1.0 +) [[ + anno::usage( "materialx:bsdf") +]] += let { + float coatIor = mxp_thinfilm_ior <= 0.0 ? 1.0 : mxp_thinfilm_ior; + bsdf ggx_model = df::microfacet_ggx_smith_bsdf( + roughness_u: mxp_roughness.x, + roughness_v: mxp_roughness.y, + tint: color(1.0), + multiscatter_tint: color(1.0), + tangent_u: mxp_tangent); + bsdf conductor = df::fresnel_factor( + ior: mxp_ior, + extinction_coefficient: mxp_extinction, + base: ggx_model); + bsdf thin_film_conductor = df::thin_film( + thickness: mxp_thinfilm_thickness, + ior: color(coatIor), + base: conductor); +} in material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mxp_weight, + layer: thin_film_conductor, + normal: mxp_normal + ) + ), + ior: mxp_ior, +); + +// Shader Nodes + +// NOTE: The MDL material with thin_walled == false uses the same material_surface +// properties for the front- and backface, the material will not be black +// from the backside as mandated by the MaterialX spec. +export material mx_surface( + material mxp_bsdf = material() [[ anno::usage( "materialx:bsdf") ]], + material mxp_edf = material() [[ anno::usage( "materialx:edf") ]], + float mxp_opacity = 1.0, + uniform bool mxp_thin_walled = false, + float mxp_transmission_ior = 0.0 // extra parameter for setting transmission IOR +) [[ + anno::usage( "materialx:surfaceshader") +]] += let { + bsdf bsdf_node = mxp_bsdf.surface.scattering; + material_emission edf_node = mxp_edf.surface.emission; + // we need to carry volume properties along for SSS + material_volume bsdf_volume = mxp_bsdf.volume; +} in material( + thin_walled: mxp_thin_walled, + surface: material_surface( + scattering: bsdf_node, + emission: edf_node + ), + ior: mxp_transmission_ior > 0.0 ? color(mxp_transmission_ior) : mxp_bsdf.ior, + volume: bsdf_volume, + geometry: material_geometry( + cutout_opacity: mxp_opacity + ) +); diff --git a/source/MaterialXGenMdl/mdl/materialx/sampling.mdl b/source/MaterialXGenMdl/mdl/materialx/sampling.mdl index 1809503653..15228efeca 100644 --- a/source/MaterialXGenMdl/mdl/materialx/sampling.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/sampling.mdl @@ -5,7 +5,9 @@ mdl 1.6; +import ::anno::*; import ::math::*; +import ::state::*; import .::core::*; @@ -15,14 +17,14 @@ export const int MX_MAX_SAMPLE_COUNT = 49; export const int MX_WEIGHT_ARRAY_SIZE = 84; // This is not available in MDL so just use a "small" number -float2 dFdx(float2 uv) +float2 dFdx(float2 uv [[anno::unused()]]) { - return uv+0.0001; + return float2(0.001, 0); } -float2 dFdy(float2 uv) +float2 dFdy(float2 uv [[anno::unused()]]) { - return uv+0.0001; + return float2(0, 0.001); } // @@ -49,11 +51,10 @@ export float2 mx_compute_sample_size_uv(float2 uv, float filterSize, float filte // export float3 mx_normal_from_samples_sobel(float[9] S, float scale) { - float nx = S[0] - S[2] + (2.0*S[3]) - (2.0*S[5]) + S[6] - S[8]; - float ny = S[0] + (2.0*S[1]) + S[2] - S[6] - (2.0*S[7]) - S[8]; - float nz = scale * ::math::sqrt(1.0 - nx*nx - ny*ny); - float3 norm = ::math::normalize(float3(nx, ny, nz)); - return (norm + 1.0) * 0.5; + float nx = S[0] - S[2] + (2.0*S[3]) - (2.0*S[5]) + S[6] - S[8]; + float ny = S[0] + (2.0*S[1]) + S[2] - S[6] - (2.0*S[7]) - S[8]; + float3 norm = math::normalize(float3(nx * scale, ny * scale, 0.125)); + return (norm + 1.0) * 0.5; } // Kernel weights for box filter diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl index 79ed3dff4f..a23c0150ed 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib.mdl @@ -4,15 +4,15 @@ // // MDL implementation of all Standard Source Nodes of // MaterialX: An Open Standard for Network-Based CG Object Looks -// Document v1.37 REV2, January 19, 2020 +// Document version 1.39, September 15, 2024 // www.materialx.org // in -// NVIDIA Material Definition Language 1.7 +// NVIDIA Material Definition Language 1.9 // Language Specification -// Document version 1.7.2, January 17, 2022 +// Document version 1.9.2, September 16, 2024 // www.nvidia.com/mdl -mdl 1.8; +mdl 1.9; // forward the latest version -export using .::stdlib_1_8 import *; +export using .::stdlib_1_9 import *; diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl index cd47e35d17..8de4534407 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_6.mdl @@ -42,6 +42,7 @@ export material mx_surfacematerial( = material( thin_walled: mxp_surfaceshader.thin_walled || mxp_backsurfaceshader.thin_walled, surface: mxp_surfaceshader.surface, + hair: mxp_surfaceshader.hair, backface: mxp_backsurfaceshader.surface, geometry: material_geometry( cutout_opacity: mxp_surfaceshader.geometry.cutout_opacity, @@ -88,6 +89,24 @@ export material mx_surface_unlit( } } +// Helper function provides texture lookup coordinate with `closest` lookup type support +float2 tex_lookup_coord(float2 st, int tex_width, int tex_height, core::mx_filterlookup_type lookup_type, bool flip_v) +{ + float2 coord = st; + + // `closest` lookup + if (lookup_type == core::mx_filterlookup_type_closest) + { + int2 tex_size(tex_width, tex_height); + coord = (math::floor(coord * tex_size) + float2(0.5)) / tex_size; + } + + // `linear` and `cubic` uses the original coord + coord = flip_v ? float2(coord.x, 1.0 - coord.y) : coord; + + return coord; +} + // NOTE: need to map MaterialX return type overloads to different function names // or we require the mx_default to be always set explicitly @@ -121,8 +140,7 @@ export float mx_image_float( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -160,9 +178,12 @@ export float mx_image_float( return mxp_default; float returnValue = ::tex::lookup_float(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -198,8 +219,7 @@ export color mx_image_color3( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -237,9 +257,12 @@ export color mx_image_color3( return mxp_default; color returnValue = ::tex::lookup_color(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -275,8 +298,7 @@ export core::color4 mx_image_color4( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -314,9 +336,12 @@ export core::color4 mx_image_color4( return mxp_default; core::color4 returnValue = core::mk_color4(::tex::lookup_float4(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode))); return returnValue; @@ -352,8 +377,7 @@ export float2 mx_image_vector2( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -391,9 +415,12 @@ export float2 mx_image_vector2( return mxp_default; float2 returnValue = ::tex::lookup_float2(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -429,8 +456,7 @@ export float3 mx_image_vector3( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -468,9 +494,12 @@ export float3 mx_image_vector3( return mxp_default; float3 returnValue = ::tex::lookup_float3(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -506,8 +535,7 @@ export float4 mx_image_vector4( uniform core::mx_filterlookup_type mxp_filtertype = core::mx_filterlookup_type(core::mx_filterlookup_type_linear) [[ anno::description("Enumeration {closest,linear,cubic}."), - anno::display_name("Filter Type"), - anno::unused() + anno::display_name("Filter Type") ]], uniform string mxp_framerange = string("") [[ @@ -545,9 +573,12 @@ export float4 mx_image_vector4( return mxp_default; float4 returnValue = ::tex::lookup_float4(tex: mxp_file, - coord: mxp_flip_v - ? float2(mxp_texcoord.x, 1.0f - mxp_texcoord.y) - : mxp_texcoord, + coord: tex_lookup_coord( + mxp_texcoord, + tex::width(mxp_file), + tex::height(mxp_file), + mxp_filtertype, + mxp_flip_v), wrap_u: map_addressmode(mxp_uaddressmode), wrap_v: map_addressmode(mxp_vaddressmode)); return returnValue; @@ -1340,23 +1371,6 @@ export float4 mx_geompropvalue_vector4( return defaultValue; } -export float mx_ambientocclusion_float( - float mxp_coneangle = float(90.0) - [[ - anno::description("Unit Type:angle. Unit:degrees."), - anno::unused() - ]], - float mxp_maxdistance = float(1e38) [[ anno::unused() ]] -) - [[ - anno::description("Node Group: global") - ]] -{ - // Not implemented: mx_ambientocclusion_float - float defaultValue = float(1.0); - return defaultValue; -} - export float mx_frame_float( ) [[ @@ -2094,46 +2108,32 @@ export float4 mx_transformmatrix_vector4( export float3 mx_normalmap_vector2( float3 mxp_in = float3(0.5, 0.5, 1.0), - uniform string mxp_space = string("tangent") - [[ - anno::description("Enumeration {tangent, object}.") - ]], float2 mxp_scale = float2(1.0, 1.0), float3 mxp_normal = float3(::state::transform_normal(::state::coordinate_internal,::state::coordinate_world,::state::normal())), - float3 mxp_tangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_u(0))) + float3 mxp_tangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_u(0))), + float3 mxp_bitangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_v(0))) ) [[ anno::description("Node Group: math") ]] { - if (mxp_space == "tangent") - { - float3 v = mxp_in * 2.0 - 1.0; - float3 binormal = ::math::normalize(::math::cross(mxp_normal, mxp_tangent)); - return ::math::normalize(mxp_tangent * v.x * mxp_scale.x + binormal * v.y * mxp_scale.y + mxp_normal * v.z); - } - else - { - float3 n = mxp_in * 2.0 - 1.0; - return ::math::normalize(n); - } + float3 v = (mxp_in == float3(0.0)) ? float3(0.0, 0.0, 1.0) : mxp_in * 2.0 - 1.0; + + return ::math::normalize(mxp_tangent * v.x * mxp_scale.x + mxp_bitangent * v.y * mxp_scale.y + mxp_normal * v.z); } export float3 mx_normalmap_float( float3 mxp_in = float3(0.5, 0.5, 1.0), - uniform string mxp_space = string("tangent") - [[ - anno::description("Enumeration {tangent, object}.") - ]], float mxp_scale = float(1.0), float3 mxp_normal = float3(::state::transform_normal(::state::coordinate_internal,::state::coordinate_world,::state::normal())), - float3 mxp_tangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_u(0))) + float3 mxp_tangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_u(0))), + float3 mxp_bitangent = float3(state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_v(0))) ) [[ anno::description("Node Group: math") ]] { - return mx_normalmap_vector2(mxp_in, mxp_space, float2(mxp_scale, mxp_scale), mxp_normal, mxp_tangent); + return mx_normalmap_vector2(mxp_in, float2(mxp_scale, mxp_scale), mxp_normal, mxp_tangent, mxp_bitangent); } export float3x3 mx_transpose_matrix33( @@ -4451,3 +4451,9 @@ export float3 mx_worleynoise3d_float3( { return noise::mx_worley_noise_float3(mxp_position, mxp_jitter, 0); } + +export core::color4 mx_combine2_color4CF(color in1, float in2) +{ + float3 in1_as_float3 = float3(in1); + return core::mk_color4(in1_as_float3.x, in1_as_float3.y, in1_as_float3.z, in2); +} diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl index b6e7174114..341e6ff40b 100644 --- a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_8.mdl @@ -80,7 +80,6 @@ export using .::stdlib_1_7 import mx_texcoord_vector3; export using .::stdlib_1_7 import mx_geomcolor_float; export using .::stdlib_1_7 import mx_geomcolor_color3; export using .::stdlib_1_7 import mx_geomcolor_color4; -export using .::stdlib_1_7 import mx_ambientocclusion_float; export using .::stdlib_1_7 import mx_frame_float; export using .::stdlib_1_7 import mx_time_float; export using .::stdlib_1_7 import mx_modulo_color3; @@ -321,6 +320,7 @@ export using .::stdlib_1_7 import mx_worleynoise2d_float3; export using .::stdlib_1_7 import mx_worleynoise3d_float; export using .::stdlib_1_7 import mx_worleynoise3d_float2; export using .::stdlib_1_7 import mx_worleynoise3d_float3; +export using .::stdlib_1_7 import mx_combine2_color4CF; // NOTE: Not planned to be implemented. export using .::stdlib_1_7 import mx_geompropvalue_string; diff --git a/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl new file mode 100644 index 0000000000..5756c2b1b1 --- /dev/null +++ b/source/MaterialXGenMdl/mdl/materialx/stdlib_1_9.mdl @@ -0,0 +1,386 @@ +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// +// MDL implementation of all Standard Source Nodes of +// MaterialX: An Open Standard for Network-Based CG Object Looks +// Document version 1.39, September 15, 2024 +// www.materialx.org +// in +// NVIDIA Material Definition Language 1.9 +// Language Specification +// Document version 1.9.2, September 16, 2024 +// www.nvidia.com/mdl + +mdl 1.9; + +import ::anno::*; +import ::df::*; +import ::math::*; +import ::scene::*; +import ::state::*; + +import .::core::*; +import .::noise::*; +import .::hsv::*; + +// Changes since MDL 1.8 +// - lift the restriction of uniform IORs + +// forward unchanged definitions from the previous version +export using .::stdlib_1_7 import mx_surfacematerial; +export using .::stdlib_1_7 import mx_surface_unlit; +export using .::stdlib_1_7 import mx_image_float; +export using .::stdlib_1_7 import mx_image_color3; +export using .::stdlib_1_7 import mx_image_color4; +export using .::stdlib_1_7 import mx_image_vector2; +export using .::stdlib_1_7 import mx_image_vector3; +export using .::stdlib_1_7 import mx_image_vector4; +export using .::stdlib_1_7 import mx_constant_float; +export using .::stdlib_1_7 import mx_constant_color3; +export using .::stdlib_1_7 import mx_constant_color4; +export using .::stdlib_1_7 import mx_constant_vector2; +export using .::stdlib_1_7 import mx_constant_vector3; +export using .::stdlib_1_7 import mx_constant_vector4; +export using .::stdlib_1_7 import mx_constant_boolean; +export using .::stdlib_1_7 import mx_constant_integer; +export using .::stdlib_1_7 import mx_constant_matrix33; +export using .::stdlib_1_7 import mx_constant_matrix44; +export using .::stdlib_1_7 import mx_constant_string; +export using .::stdlib_1_7 import mx_constant_filename; +export using .::stdlib_1_7 import mx_ramplr_float; +export using .::stdlib_1_7 import mx_ramplr_color3; +export using .::stdlib_1_7 import mx_ramplr_color4; +export using .::stdlib_1_7 import mx_ramplr_vector2; +export using .::stdlib_1_7 import mx_ramplr_vector3; +export using .::stdlib_1_7 import mx_ramplr_vector4; +export using .::stdlib_1_7 import mx_ramptb_float; +export using .::stdlib_1_7 import mx_ramptb_color3; +export using .::stdlib_1_7 import mx_ramptb_color4; +export using .::stdlib_1_7 import mx_ramptb_vector2; +export using .::stdlib_1_7 import mx_ramptb_vector3; +export using .::stdlib_1_7 import mx_ramptb_vector4; +export using .::stdlib_1_7 import mx_splitlr_float; +export using .::stdlib_1_7 import mx_splitlr_color3; +export using .::stdlib_1_7 import mx_splitlr_color4; +export using .::stdlib_1_7 import mx_splitlr_vector2; +export using .::stdlib_1_7 import mx_splitlr_vector3; +export using .::stdlib_1_7 import mx_splitlr_vector4; +export using .::stdlib_1_7 import mx_splittb_float; +export using .::stdlib_1_7 import mx_splittb_color3; +export using .::stdlib_1_7 import mx_splittb_color4; +export using .::stdlib_1_7 import mx_splittb_vector2; +export using .::stdlib_1_7 import mx_splittb_vector3; +export using .::stdlib_1_7 import mx_splittb_vector4; +export using .::stdlib_1_7 import mx_position_vector3; +export using .::stdlib_1_7 import mx_normal_vector3; +export using .::stdlib_1_7 import mx_tangent_vector3; +export using .::stdlib_1_7 import mx_bitangent_vector3; +export using .::stdlib_1_7 import mx_texcoord_vector2; +export using .::stdlib_1_7 import mx_texcoord_vector3; +export using .::stdlib_1_7 import mx_geomcolor_float; +export using .::stdlib_1_7 import mx_geomcolor_color3; +export using .::stdlib_1_7 import mx_geomcolor_color4; +export using .::stdlib_1_7 import mx_frame_float; +export using .::stdlib_1_7 import mx_time_float; +export using .::stdlib_1_7 import mx_modulo_color3; +export using .::stdlib_1_7 import mx_modulo_color4; +export using .::stdlib_1_7 import mx_modulo_color3FA; +export using .::stdlib_1_7 import mx_modulo_color4FA; +export using .::stdlib_1_7 import mx_invert_color4; +export using .::stdlib_1_7 import mx_invert_color4FA; +export using .::stdlib_1_7 import mx_absval_color4; +export using .::stdlib_1_7 import mx_floor_color3; +export using .::stdlib_1_7 import mx_floor_color4; +export using .::stdlib_1_7 import mx_ceil_color3; +export using .::stdlib_1_7 import mx_ceil_color4; +export using .::stdlib_1_7 import mx_round_color3; +export using .::stdlib_1_7 import mx_round_color4; +export using .::stdlib_1_7 import mx_power_color4; +export using .::stdlib_1_7 import mx_power_color4FA; +export using .::stdlib_1_7 import mx_sin_float; +export using .::stdlib_1_7 import mx_cos_float; +export using .::stdlib_1_7 import mx_tan_float; +export using .::stdlib_1_7 import mx_asin_float; +export using .::stdlib_1_7 import mx_acos_float; +export using .::stdlib_1_7 import mx_atan2_float; +export using .::stdlib_1_7 import mx_sin_vector2; +export using .::stdlib_1_7 import mx_cos_vector2; +export using .::stdlib_1_7 import mx_tan_vector2; +export using .::stdlib_1_7 import mx_asin_vector2; +export using .::stdlib_1_7 import mx_acos_vector2; +export using .::stdlib_1_7 import mx_atan2_vector2; +export using .::stdlib_1_7 import mx_sin_vector3; +export using .::stdlib_1_7 import mx_cos_vector3; +export using .::stdlib_1_7 import mx_tan_vector3; +export using .::stdlib_1_7 import mx_asin_vector3; +export using .::stdlib_1_7 import mx_acos_vector3; +export using .::stdlib_1_7 import mx_atan2_vector3; +export using .::stdlib_1_7 import mx_sin_vector4; +export using .::stdlib_1_7 import mx_cos_vector4; +export using .::stdlib_1_7 import mx_tan_vector4; +export using .::stdlib_1_7 import mx_asin_vector4; +export using .::stdlib_1_7 import mx_acos_vector4; +export using .::stdlib_1_7 import mx_atan2_vector4; +export using .::stdlib_1_7 import mx_sqrt_float; +export using .::stdlib_1_7 import mx_ln_float; +export using .::stdlib_1_7 import mx_exp_float; +export using .::stdlib_1_7 import mx_sqrt_vector2; +export using .::stdlib_1_7 import mx_ln_vector2; +export using .::stdlib_1_7 import mx_exp_vector2; +export using .::stdlib_1_7 import mx_sqrt_vector3; +export using .::stdlib_1_7 import mx_ln_vector3; +export using .::stdlib_1_7 import mx_exp_vector3; +export using .::stdlib_1_7 import mx_sqrt_vector4; +export using .::stdlib_1_7 import mx_ln_vector4; +export using .::stdlib_1_7 import mx_exp_vector4; +export using .::stdlib_1_7 import mx_sign_color3; +export using .::stdlib_1_7 import mx_sign_color4; +export using .::stdlib_1_7 import mx_clamp_color4; +export using .::stdlib_1_7 import mx_clamp_color4FA; +export using .::stdlib_1_7 import mx_min_color4; +export using .::stdlib_1_7 import mx_min_color4; +export using .::stdlib_1_7 import mx_max_color4; +export using .::stdlib_1_7 import mx_max_color4; +export using .::stdlib_1_7 import mx_transformpoint_vector3; +export using .::stdlib_1_7 import mx_transformvector_vector3; +export using .::stdlib_1_7 import mx_transformnormal_vector3; +export using .::stdlib_1_7 import mx_transformmatrix_vector2M3; +export using .::stdlib_1_7 import mx_transformmatrix_vector3; +export using .::stdlib_1_7 import mx_transformmatrix_vector3M4; +export using .::stdlib_1_7 import mx_transformmatrix_vector4; +export using .::stdlib_1_7 import mx_normalmap_float; +export using .::stdlib_1_7 import mx_normalmap_vector2; +export using .::stdlib_1_7 import mx_transpose_matrix33; +export using .::stdlib_1_7 import mx_transpose_matrix44; +export using .::stdlib_1_7 import mx_determinant_matrix33; +export using .::stdlib_1_7 import mx_determinant_matrix44; +export using .::stdlib_1_7 import mx_invertmatrix_matrix33; +export using .::stdlib_1_7 import mx_invertmatrix_matrix44; +export using .::stdlib_1_7 import mx_rotate2d_vector2; +export using .::stdlib_1_7 import mx_rotate3d_vector3; +export using .::stdlib_1_7 import mx_remap_float; +export using .::stdlib_1_7 import mx_remap_color3; +export using .::stdlib_1_7 import mx_remap_color4; +export using .::stdlib_1_7 import mx_remap_vector2; +export using .::stdlib_1_7 import mx_remap_vector3; +export using .::stdlib_1_7 import mx_remap_vector4; +export using .::stdlib_1_7 import mx_remap_color3FA; +export using .::stdlib_1_7 import mx_remap_color4FA; +export using .::stdlib_1_7 import mx_remap_vector2FA; +export using .::stdlib_1_7 import mx_remap_vector3FA; +export using .::stdlib_1_7 import mx_remap_vector4FA; +export using .::stdlib_1_7 import mx_smoothstep_float; +export using .::stdlib_1_7 import mx_smoothstep_color3; +export using .::stdlib_1_7 import mx_smoothstep_color4; +export using .::stdlib_1_7 import mx_smoothstep_vector2; +export using .::stdlib_1_7 import mx_smoothstep_vector3; +export using .::stdlib_1_7 import mx_smoothstep_vector4; +export using .::stdlib_1_7 import mx_smoothstep_color3FA; +export using .::stdlib_1_7 import mx_smoothstep_color4FA; +export using .::stdlib_1_7 import mx_smoothstep_vector2FA; +export using .::stdlib_1_7 import mx_smoothstep_vector3FA; +export using .::stdlib_1_7 import mx_smoothstep_vector4FA; +export using .::stdlib_1_7 import mx_curveadjust_float; +export using .::stdlib_1_7 import mx_curveadjust_color3; +export using .::stdlib_1_7 import mx_curveadjust_color4; +export using .::stdlib_1_7 import mx_curveadjust_vector2; +export using .::stdlib_1_7 import mx_curveadjust_vector3; +export using .::stdlib_1_7 import mx_curveadjust_vector4; +export using .::stdlib_1_7 import mx_luminance_color3; +export using .::stdlib_1_7 import mx_luminance_color4; +export using .::stdlib_1_7 import mx_rgbtohsv_color3; +export using .::stdlib_1_7 import mx_rgbtohsv_color4; +export using .::stdlib_1_7 import mx_hsvtorgb_color3; +export using .::stdlib_1_7 import mx_hsvtorgb_color4; +export using .::stdlib_1_7 import mx_premult_color4; +export using .::stdlib_1_7 import mx_unpremult_color4; +export using .::stdlib_1_7 import mx_plus_color4; +export using .::stdlib_1_7 import mx_minus_color4; +export using .::stdlib_1_7 import mx_difference_color4; +export using .::stdlib_1_7 import mx_burn_float; +export using .::stdlib_1_7 import mx_burn_color3; +export using .::stdlib_1_7 import mx_burn_color4; +export using .::stdlib_1_7 import mx_dodge_float; +export using .::stdlib_1_7 import mx_dodge_color3; +export using .::stdlib_1_7 import mx_dodge_color4; +export using .::stdlib_1_7 import mx_screen_color4; +export using .::stdlib_1_7 import mx_disjointover_color4; +export using .::stdlib_1_7 import mx_in_color4; +export using .::stdlib_1_7 import mx_mask_color4; +export using .::stdlib_1_7 import mx_matte_color4; +export using .::stdlib_1_7 import mx_out_color4; +export using .::stdlib_1_7 import mx_over_color4; +export using .::stdlib_1_7 import mx_mix_color4; +export using .::stdlib_1_7 import mx_mix_color4_color4; +export using .::stdlib_1_7 import mx_mix_volumeshader; +export using .::stdlib_1_7 import mx_mix_displacementshader; +export using .::stdlib_1_7 import mx_ifgreater_float; +export using .::stdlib_1_7 import mx_ifgreater_integer; +export using .::stdlib_1_7 import mx_ifgreater_color3; +export using .::stdlib_1_7 import mx_ifgreater_color4; +export using .::stdlib_1_7 import mx_ifgreater_vector2; +export using .::stdlib_1_7 import mx_ifgreater_vector3; +export using .::stdlib_1_7 import mx_ifgreater_vector4; +export using .::stdlib_1_7 import mx_ifgreater_matrix33; +export using .::stdlib_1_7 import mx_ifgreater_matrix44; +export using .::stdlib_1_7 import mx_ifgreater_boolean; +export using .::stdlib_1_7 import mx_ifgreater_floatI; +export using .::stdlib_1_7 import mx_ifgreater_integerI; +export using .::stdlib_1_7 import mx_ifgreater_color3I; +export using .::stdlib_1_7 import mx_ifgreater_color4I; +export using .::stdlib_1_7 import mx_ifgreater_vector2I; +export using .::stdlib_1_7 import mx_ifgreater_vector3I; +export using .::stdlib_1_7 import mx_ifgreater_vector4I; +export using .::stdlib_1_7 import mx_ifgreater_matrix33I; +export using .::stdlib_1_7 import mx_ifgreater_matrix44I; +export using .::stdlib_1_7 import mx_ifgreater_booleanI; +export using .::stdlib_1_7 import mx_ifgreatereq_float; +export using .::stdlib_1_7 import mx_ifgreatereq_integer; +export using .::stdlib_1_7 import mx_ifgreatereq_color3; +export using .::stdlib_1_7 import mx_ifgreatereq_color4; +export using .::stdlib_1_7 import mx_ifgreatereq_vector2; +export using .::stdlib_1_7 import mx_ifgreatereq_vector3; +export using .::stdlib_1_7 import mx_ifgreatereq_vector4; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix33; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix44; +export using .::stdlib_1_7 import mx_ifgreatereq_boolean; +export using .::stdlib_1_7 import mx_ifgreatereq_floatI; +export using .::stdlib_1_7 import mx_ifgreatereq_integerI; +export using .::stdlib_1_7 import mx_ifgreatereq_color3I; +export using .::stdlib_1_7 import mx_ifgreatereq_color4I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector2I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector3I; +export using .::stdlib_1_7 import mx_ifgreatereq_vector4I; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix33I; +export using .::stdlib_1_7 import mx_ifgreatereq_matrix44I; +export using .::stdlib_1_7 import mx_ifgreatereq_booleanI; +export using .::stdlib_1_7 import mx_ifequal_float; +export using .::stdlib_1_7 import mx_ifequal_integer; +export using .::stdlib_1_7 import mx_ifequal_color3; +export using .::stdlib_1_7 import mx_ifequal_color4; +export using .::stdlib_1_7 import mx_ifequal_vector2; +export using .::stdlib_1_7 import mx_ifequal_vector3; +export using .::stdlib_1_7 import mx_ifequal_vector4; +export using .::stdlib_1_7 import mx_ifequal_matrix33; +export using .::stdlib_1_7 import mx_ifequal_matrix44; +export using .::stdlib_1_7 import mx_ifequal_boolean; +export using .::stdlib_1_7 import mx_ifequal_floatI; +export using .::stdlib_1_7 import mx_ifequal_integerI; +export using .::stdlib_1_7 import mx_ifequal_color3I; +export using .::stdlib_1_7 import mx_ifequal_color4I; +export using .::stdlib_1_7 import mx_ifequal_vector2I; +export using .::stdlib_1_7 import mx_ifequal_vector3I; +export using .::stdlib_1_7 import mx_ifequal_vector4I; +export using .::stdlib_1_7 import mx_ifequal_matrix33I; +export using .::stdlib_1_7 import mx_ifequal_matrix44I; +export using .::stdlib_1_7 import mx_ifequal_booleanI; +export using .::stdlib_1_7 import mx_ifequal_floatB; +export using .::stdlib_1_7 import mx_ifequal_integerB; +export using .::stdlib_1_7 import mx_ifequal_color3B; +export using .::stdlib_1_7 import mx_ifequal_color4B; +export using .::stdlib_1_7 import mx_ifequal_vector2B; +export using .::stdlib_1_7 import mx_ifequal_vector3B; +export using .::stdlib_1_7 import mx_ifequal_vector4B; +export using .::stdlib_1_7 import mx_ifequal_matrix33B; +export using .::stdlib_1_7 import mx_ifequal_matrix44B; +export using .::stdlib_1_7 import mx_ifequal_booleanB; +export using .::stdlib_1_7 import mx_creatematrix_vector3_matrix33; +export using .::stdlib_1_7 import mx_creatematrix_vector3_matrix44; +export using .::stdlib_1_7 import mx_creatematrix_vector4_matrix44; +export using .::stdlib_1_7 import mx_extract_color3; +export using .::stdlib_1_7 import mx_extract_color4; +export using .::stdlib_1_7 import mx_extract_vector2; +export using .::stdlib_1_7 import mx_extract_vector3; +export using .::stdlib_1_7 import mx_extract_vector4; +export using .::stdlib_1_7 import mx_blur_float; +export using .::stdlib_1_7 import mx_blur_color3; +export using .::stdlib_1_7 import mx_blur_color4; +export using .::stdlib_1_7 import mx_blur_vector2; +export using .::stdlib_1_7 import mx_blur_vector3; +export using .::stdlib_1_7 import mx_blur_vector4; +export using .::stdlib_1_7 import mx_heighttonormal_vector3; +export using .::stdlib_1_7 import mx_noise2d_float; +export using .::stdlib_1_7 import mx_noise2d_float2; +export using .::stdlib_1_7 import mx_noise2d_float3; +export using .::stdlib_1_7 import mx_noise2d_float4; +export using .::stdlib_1_7 import mx_noise3d_float; +export using .::stdlib_1_7 import mx_noise3d_float2; +export using .::stdlib_1_7 import mx_noise3d_float3; +export using .::stdlib_1_7 import mx_noise3d_float4; +export using .::stdlib_1_7 import mx_fractal3d_float; +export using .::stdlib_1_7 import mx_fractal3d_float2; +export using .::stdlib_1_7 import mx_fractal3d_float3; +export using .::stdlib_1_7 import mx_fractal3d_float4; +export using .::stdlib_1_7 import mx_cellnoise2d_float; +export using .::stdlib_1_7 import mx_cellnoise3d_float; +export using .::stdlib_1_7 import mx_worleynoise2d_float; +export using .::stdlib_1_7 import mx_worleynoise2d_float2; +export using .::stdlib_1_7 import mx_worleynoise2d_float3; +export using .::stdlib_1_7 import mx_worleynoise3d_float; +export using .::stdlib_1_7 import mx_worleynoise3d_float2; +export using .::stdlib_1_7 import mx_worleynoise3d_float3; +export using .::stdlib_1_7 import mx_combine2_color4CF; + +export using .::stdlib_1_7 import mx_geompropvalue_string; +export using .::stdlib_1_8 import mx_geompropvalue_boolean; +export using .::stdlib_1_8 import mx_geompropvalue_integer; +export using .::stdlib_1_8 import mx_geompropvalue_float; +export using .::stdlib_1_8 import mx_geompropvalue_color3; +export using .::stdlib_1_8 import mx_geompropvalue_color4; +export using .::stdlib_1_8 import mx_geompropvalue_vector2; +export using .::stdlib_1_8 import mx_geompropvalue_vector3; +export using .::stdlib_1_8 import mx_geompropvalue_vector4; +export using .::stdlib_1_8 import mx_viewdirection_vector3; + + + +// mix all parts of the material, bsdf, edf, and vdf, geometry +export material mx_mix_surfaceshader( + material mxp_fg = material() [[ anno::usage( "materialx:surfaceshader") ]], + material mxp_bg = material() [[ anno::usage( "materialx:surfaceshader") ]], + float mxp_mix = 0.0 +) [[ + anno::description("Node Group: compositing"), + anno::usage( "materialx:surfaceshader") +]] += material( + surface: material_surface( + scattering: df::weighted_layer( + weight: mxp_mix, + layer: mxp_fg.surface.scattering, + base: mxp_bg.surface.scattering + ), + emission: material_emission( + emission: df::clamped_mix( + df::edf_component[]( + df::edf_component( mxp_mix, mxp_fg.surface.emission.emission), + df::edf_component( 1.0 - mxp_mix, mxp_bg.surface.emission.emission)) + ), + intensity: mxp_mix * mxp_fg.surface.emission.intensity + + (1.0 - mxp_mix) * mxp_bg.surface.emission.intensity + ) + ), + + // we need to carry volume properties along for SSS + ior: mxp_mix * mxp_fg.ior + (1.0 - mxp_mix) * mxp_bg.ior, + volume: material_volume( + scattering: df::clamped_mix( + df::vdf_component[]( + df::vdf_component( mxp_mix, mxp_fg.volume.scattering), + df::vdf_component( 1.0 - mxp_mix, mxp_bg.volume.scattering)) + ), + absorption_coefficient: mxp_mix * mxp_fg.volume.absorption_coefficient + + (1.0 - mxp_mix) * mxp_bg.volume.absorption_coefficient, + scattering_coefficient: mxp_mix * mxp_fg.volume.scattering_coefficient + + (1.0 - mxp_mix) * mxp_bg.volume.scattering_coefficient + ), + geometry: material_geometry( + displacement: mxp_mix * mxp_fg.geometry.displacement + + (1.0 - mxp_mix) * mxp_bg.geometry.displacement, + cutout_opacity: mxp_mix * mxp_fg.geometry.cutout_opacity + + (1.0 - mxp_mix) * mxp_bg.geometry.cutout_opacity, + normal: mxp_mix * mxp_fg.geometry.normal + + (1.0 - mxp_mix) * mxp_bg.geometry.normal + ) +); diff --git a/source/MaterialXGenMsl/CMakeLists.txt b/source/MaterialXGenMsl/CMakeLists.txt index 9dbfd666f7..317b7fa58e 100644 --- a/source/MaterialXGenMsl/CMakeLists.txt +++ b/source/MaterialXGenMsl/CMakeLists.txt @@ -6,7 +6,7 @@ mx_add_library(MaterialXGenMsl ${materialx_source} HEADER_FILES ${materialx_headers} - LIBRARIES + MTLX_MODULES MaterialXGenShader MaterialXCore EXPORT_DEFINE diff --git a/source/MaterialXGenMsl/MslShaderGenerator.cpp b/source/MaterialXGenMsl/MslShaderGenerator.cpp index 8db763d7e1..9511fac7ba 100644 --- a/source/MaterialXGenMsl/MslShaderGenerator.cpp +++ b/source/MaterialXGenMsl/MslShaderGenerator.cpp @@ -237,7 +237,29 @@ void MslShaderGenerator::MetalizeGeneratedShader(ShaderStage& shaderStage) const } size_t typename_end = pos; std::string typeName = sourceCode.substr(typename_beg, typename_end - typename_beg); - sourceCode.replace(beg, typename_end - beg, "thread " + typeName + "&"); + + while (std::isspace(sourceCode[pos])) + { + ++pos; + } + size_t varname_beg = pos; + while (!std::isspace(sourceCode[pos]) && sourceCode[pos] != '\n' && sourceCode[pos] != ',' && sourceCode[pos] != ')' ) + { + ++pos; + } + size_t varname_end = pos; + std::string varName = sourceCode.substr(varname_beg, varname_end - varname_beg); + + if (varName.find('[') != std::string::npos) + { + // if the variable is an array then we don't need to declare it as a reference, + // we will effectively just be passing the pointer to the array + sourceCode.replace(beg, typename_end - beg, "thread " + typeName); + } + else + { + sourceCode.replace(beg, typename_end - beg, "thread " + typeName + "&"); + } } pos = sourceCode.find(keyword, pos); } @@ -922,7 +944,6 @@ void MslShaderGenerator::emitPixelStage(const ShaderGraph& graph, GenContext& co emitLine("{}", stage, false); // Add common math functions - emitLine("#define __DECL_GL_MATH_FUNCTIONS__", stage, false); emitLibraryInclude("stdlib/genmsl/lib/mx_math.metal", context, stage); emitLineBreak(stage); diff --git a/source/MaterialXGenOsl/CMakeLists.txt b/source/MaterialXGenOsl/CMakeLists.txt index 398f390c64..c5b6079382 100644 --- a/source/MaterialXGenOsl/CMakeLists.txt +++ b/source/MaterialXGenOsl/CMakeLists.txt @@ -6,7 +6,7 @@ mx_add_library(MaterialXGenOsl ${materialx_source} HEADER_FILES ${materialx_headers} - LIBRARIES + MTLX_MODULES MaterialXGenShader MaterialXCore EXPORT_DEFINE diff --git a/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp b/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp index b77eebbd86..a72207c581 100644 --- a/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp +++ b/source/MaterialXGenOsl/Nodes/ClosureLayerNodeOsl.cpp @@ -37,51 +37,6 @@ void ClosureLayerNodeOsl::emitFunctionCall(const ShaderNode& _node, GenContext& ShaderNode* top = topInput->getConnection()->getNode(); ShaderNode* base = baseInput->getConnection()->getNode(); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - ClosureContext* cct = context.getClosureContext(); - - // Evaluate top and base nodes and combine their result - // according to throughput. - // - // TODO: In the BSDF over BSDF case should we emit code - // to check the top throughput amount before calling - // the base BSDF? - - // Make sure the connections are sibling nodes and not the graph interface. - if (top->getParent() == node.getParent()) - { - // If this layer node has closure parameters set, - // we pass this on to the top component only. - ScopedSetClosureParams setParams(&node, top, cct); - shadergen.emitFunctionCall(*top, context, stage); - } - if (base->getParent() == node.getParent()) - { - shadergen.emitFunctionCall(*base, context, stage); - } - - // Get the result variables. - const string& topResult = topInput->getConnection()->getVariable(); - const string& baseResult = baseInput->getConnection()->getVariable(); - - // Calculate the layering result. - emitOutputVariables(node, context, stage); - if (base->getOutput()->getType() == Type::VDF) - { - // Combining a surface closure with a volumetric closure is simply done with the add operator in OSL. - shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response + " + baseResult, stage); - // Just pass the throughput along. - shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput", stage); - } - else - { - shadergen.emitLine(output->getVariable() + ".response = " + topResult + ".response + " + baseResult + ".response * " + topResult + ".throughput", stage); - shadergen.emitLine(output->getVariable() + ".throughput = " + topResult + ".throughput * " + baseResult + ".throughput", stage); - } - -#else - // Emit the function call for top and base layer. // Make sure the connections are sibling nodes and not the graph interface. if (top->getParent() == node.getParent()) @@ -102,8 +57,6 @@ void ClosureLayerNodeOsl::emitFunctionCall(const ShaderNode& _node, GenContext& shadergen.emitOutput(output, true, false, context, stage); shadergen.emitString(" = layer(" + topResult + ", " + baseResult + ")", stage); shadergen.emitLineEnd(stage); - -#endif // MATERIALX_OSL_LEGACY_CLOSURES } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenOsl/OslShaderGenerator.cpp b/source/MaterialXGenOsl/OslShaderGenerator.cpp index f29719a39b..ff8cad36f5 100644 --- a/source/MaterialXGenOsl/OslShaderGenerator.cpp +++ b/source/MaterialXGenOsl/OslShaderGenerator.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -44,22 +45,6 @@ OslShaderGenerator::OslShaderGenerator() : registerImplementation("IM_layer_bsdf_" + OslShaderGenerator::TARGET, ClosureLayerNodeOsl::create); registerImplementation("IM_layer_vdf_" + OslShaderGenerator::TARGET, ClosureLayerNodeOsl::create); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - // - registerImplementation("IM_mix_bsdf_" + OslShaderGenerator::TARGET, ClosureMixNode::create); - registerImplementation("IM_mix_edf_" + OslShaderGenerator::TARGET, ClosureMixNode::create); - // - registerImplementation("IM_add_bsdf_" + OslShaderGenerator::TARGET, ClosureAddNode::create); - registerImplementation("IM_add_edf_" + OslShaderGenerator::TARGET, ClosureAddNode::create); - // - registerImplementation("IM_multiply_bsdfC_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_bsdfF_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_edfC_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_edfF_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - -#endif // MATERIALX_OSL_LEGACY_CLOSURES - // registerImplementation("IM_surface_" + OslShaderGenerator::TARGET, SurfaceNodeOsl::create); @@ -157,10 +142,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G const bool isSurfaceShaderOutput = singleOutput && singleOutput->getType() == Type::SURFACESHADER; -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - const bool isBsdfOutput = singleOutput && singleOutput->getType() == Type::BSDF; -#endif - if (isSurfaceShaderOutput) { // Special case for having 'surfaceshader' as final output type. @@ -169,16 +150,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G // to understand this output. emitLine("output closure color " + singleOutput->getVariable() + " = 0", stage, false); } -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - else if (isBsdfOutput) - { - // Special case for having 'BSDF' as final output type. - // For legacy closures this type is a struct internally (response, throughput, thickness, ior) - // so we must declare this as a single closure color type in order for renderers - // to understand this output. - emitLine("output closure color " + singleOutput->getVariable() + " = 0", stage, false); - } -#endif else { // Just emit all outputs the way they are declared. @@ -252,18 +223,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G emitLine(singleOutput->getVariable() + " = (" + result + ".bsdf + " + result + ".edf) * opacity_weight + transparent() * (1.0 - opacity_weight)", stage); emitScopeEnd(stage); } -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - else if (isBsdfOutput) - { - // Special case for having 'BSDF' as final output type. - // For legacy closures this type is a struct internally (response, throughput, thickness, ior) - // so we must declare this as a single closure color type in order for renderers - // to understand this output. - const ShaderGraphOutputSocket* socket = graph.getOutputSocket(0); - const string result = getUpstreamResult(socket, context); - emitLine(singleOutput->getVariable() + " = " + result + ".response", stage); - } -#endif else { // Assign results to final outputs. @@ -510,10 +469,10 @@ void OslShaderGenerator::emitMetadata(const ShaderPort* port, ShaderStage& stage { static const std::unordered_map UI_WIDGET_METADATA = { - { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) }, - { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) }, - { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("filename", Type::STRING.getName())) }, - { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("checkBox", Type::STRING.getName())) } + { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) }, + { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) }, + { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("filename")) }, + { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("checkBox")) } }; static const std::set METADATA_TYPE_BLACKLIST = diff --git a/source/MaterialXGenOsl/OslSyntax.cpp b/source/MaterialXGenOsl/OslSyntax.cpp index 797a891ce6..a85821c4fd 100644 --- a/source/MaterialXGenOsl/OslSyntax.cpp +++ b/source/MaterialXGenOsl/OslSyntax.cpp @@ -371,19 +371,6 @@ OslSyntax::OslSyntax() EMPTY_STRING, "struct textureresource { string filename; string colorspace; };")); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - registerTypeSyntax( - Type::BSDF, - std::make_shared( - "BSDF", - "BSDF(null_closure, color(1.0))", - "{ 0, color(1.0) }", - "closure color", - "struct BSDF { closure color response; color throughput; };")); - -#else - registerTypeSyntax( Type::BSDF, std::make_shared( @@ -393,8 +380,6 @@ OslSyntax::OslSyntax() "closure color", "#define BSDF closure color")); -#endif // MATERIALX_OSL_LEGACY_CLOSURES - registerTypeSyntax( Type::EDF, std::make_shared( diff --git a/source/MaterialXGenShader/CMakeLists.txt b/source/MaterialXGenShader/CMakeLists.txt index ebdf814234..78b5138486 100644 --- a/source/MaterialXGenShader/CMakeLists.txt +++ b/source/MaterialXGenShader/CMakeLists.txt @@ -6,7 +6,7 @@ mx_add_library(MaterialXGenShader ${materialx_source} HEADER_FILES ${materialx_headers} - LIBRARIES + MTLX_MODULES MaterialXFormat MaterialXCore EXPORT_DEFINE diff --git a/source/MaterialXGenShader/GenContext.h b/source/MaterialXGenShader/GenContext.h index 8ddf92771f..0f565ded6e 100644 --- a/source/MaterialXGenShader/GenContext.h +++ b/source/MaterialXGenShader/GenContext.h @@ -125,7 +125,7 @@ class MX_GENSHADER_API GenContext return _closureContexts.size() ? _closureContexts.back() : nullptr; } - /// Push a parent node onto the stack + /// Push a parent node onto the stack void pushParentNode(ConstNodePtr node) { _parentNodes.push_back(node); @@ -292,7 +292,7 @@ class MX_GENSHADER_API ClosureContext auto it = _suffix.find(nodeType); return it != _suffix.end() ? it->second : EMPTY_STRING; } - [[deprecated]] const string& getSuffix(const TypeDesc* nodeType) const { return getSuffix(*nodeType); } + [[deprecated]] const string& getSuffix(const TypeDesc* nodeType) const { return getSuffix(*nodeType); } /// Set extra parameters to use for evaluating a closure. void setClosureParams(const ShaderNode* closure, const ClosureParams* params) diff --git a/source/MaterialXGenShader/Nodes/BlurNode.h b/source/MaterialXGenShader/Nodes/BlurNode.h index 2d6d479a10..fa41d11678 100644 --- a/source/MaterialXGenShader/Nodes/BlurNode.h +++ b/source/MaterialXGenShader/Nodes/BlurNode.h @@ -35,8 +35,8 @@ class MX_GENSHADER_API BlurNode : public ConvolutionNode virtual void outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, TypeDesc inputType, const string& sampleName, const StringVec& sampleStrings) const; [[deprecated]] void outputSampleArray(const ShaderGenerator& shadergen, ShaderStage& stage, const TypeDesc* inputType, - const string& sampleName, const StringVec& sampleStrings) const - { + const string& sampleName, const StringVec& sampleStrings) const + { return outputSampleArray(shadergen, stage, *inputType, sampleName, sampleStrings); } diff --git a/source/MaterialXGenShader/Nodes/HwViewDirectionNode.cpp b/source/MaterialXGenShader/Nodes/HwViewDirectionNode.cpp index 819ac93029..9c92897be4 100644 --- a/source/MaterialXGenShader/Nodes/HwViewDirectionNode.cpp +++ b/source/MaterialXGenShader/Nodes/HwViewDirectionNode.cpp @@ -14,20 +14,31 @@ ShaderNodeImplPtr HwViewDirectionNode::create() return std::make_shared(); } -void HwViewDirectionNode::createVariables(const ShaderNode&, GenContext&, Shader& shader) const +void HwViewDirectionNode::createVariables(const ShaderNode& node, GenContext&, Shader& shader) const { ShaderStage& vs = shader.getStage(Stage::VERTEX); ShaderStage& ps = shader.getStage(Stage::PIXEL); addStageInput(HW::VERTEX_INPUTS, Type::VECTOR3, HW::T_IN_POSITION, vs); - addStageConnector(HW::VERTEX_DATA, Type::VECTOR3, HW::T_POSITION_WORLD, vs, ps); + + const ShaderInput* spaceInput = node.getInput(SPACE); + const int space = spaceInput ? spaceInput->getValue()->asA() : OBJECT_SPACE; + addStageUniform(HW::PRIVATE_UNIFORMS, Type::VECTOR3, HW::T_VIEW_POSITION, ps); + addStageConnector(HW::VERTEX_DATA, Type::VECTOR3, HW::T_POSITION_WORLD, vs, ps); + if (space == OBJECT_SPACE || space == MODEL_SPACE) + { + addStageUniform(HW::PRIVATE_UNIFORMS, Type::MATRIX44, HW::T_WORLD_INVERSE_TRANSPOSE_MATRIX, ps); + } } void HwViewDirectionNode::emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const { const HwShaderGenerator& shadergen = static_cast(context.getShaderGenerator()); + const ShaderInput* spaceInput = node.getInput(SPACE); + const int space = spaceInput ? spaceInput->getValue()->asA() : OBJECT_SPACE; + DEFINE_SHADER_STAGE(stage, Stage::VERTEX) { VariableBlock& vertexData = stage.getOutputBlock(HW::VERTEX_DATA); @@ -44,10 +55,17 @@ void HwViewDirectionNode::emitFunctionCall(const ShaderNode& node, GenContext& c { VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA); const string prefix = shadergen.getVertexDataPrefix(vertexData); - ShaderPort* position = vertexData[HW::T_POSITION_WORLD]; shadergen.emitLineBegin(stage); shadergen.emitOutput(node.getOutput(), true, false, context, stage); - shadergen.emitString(" = normalize(" + prefix + position->getVariable() + " - " + HW::T_VIEW_POSITION + ")", stage); + ShaderPort* position = vertexData[HW::T_POSITION_WORLD]; + if (space == WORLD_SPACE) + { + shadergen.emitString(" = normalize(" + prefix + position->getVariable() + " - " + HW::T_VIEW_POSITION + ")", stage); + } + else + { + shadergen.emitString(" = normalize((" + HW::T_WORLD_INVERSE_TRANSPOSE_MATRIX + " * vec4(" + prefix + position->getVariable() + " - " + HW::T_VIEW_POSITION + ", 0.0)).xyz)", stage); + } shadergen.emitLineEnd(stage); } } diff --git a/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp b/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp index 936edf9b46..32fc345354 100644 --- a/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp +++ b/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp @@ -25,6 +25,20 @@ ShaderNodeImplPtr SourceCodeNode::create() return std::make_shared(); } +void SourceCodeNode::resolveSourceCode(const InterfaceElement& element, GenContext& context) +{ + const Implementation& impl = static_cast(element); + + FilePath localPath = FilePath(impl.getActiveSourceUri()).getParentPath(); + _sourceFilename = context.resolveSourceFile(impl.getAttribute("file"), localPath); + _functionSource = readFile(_sourceFilename); + if (_functionSource.empty()) + { + throw ExceptionShaderGenError("Failed to get source code from file '" + _sourceFilename.asString() + + "' used by implementation '" + impl.getName() + "'"); + } +} + void SourceCodeNode::initialize(const InterfaceElement& element, GenContext& context) { ShaderNodeImpl::initialize(element, context); @@ -40,19 +54,13 @@ void SourceCodeNode::initialize(const InterfaceElement& element, GenContext& con _functionSource = impl.getAttribute("sourcecode"); if (_functionSource.empty()) { - FilePath localPath = FilePath(impl.getActiveSourceUri()).getParentPath(); - _sourceFilename = context.resolveSourceFile(impl.getAttribute("file"), localPath); - _functionSource = readFile(_sourceFilename); - if (_functionSource.empty()) - { - throw ExceptionShaderGenError("Failed to get source code from file '" + _sourceFilename.asString() + - "' used by implementation '" + impl.getName() + "'"); - } + resolveSourceCode(element, context); } // Find the function name to use // If no function is given the source will be inlined. _functionName = impl.getAttribute("function"); + _inlined = _functionName.empty(); if (!_inlined) { diff --git a/source/MaterialXGenShader/Nodes/SourceCodeNode.h b/source/MaterialXGenShader/Nodes/SourceCodeNode.h index a208185a8d..6169dc0f61 100644 --- a/source/MaterialXGenShader/Nodes/SourceCodeNode.h +++ b/source/MaterialXGenShader/Nodes/SourceCodeNode.h @@ -26,6 +26,9 @@ class MX_GENSHADER_API SourceCodeNode : public ShaderNodeImpl void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; protected: + /// Resolve the source file and read the source code during the initialization of the node. + virtual void resolveSourceCode(const InterfaceElement& element, GenContext& context); + bool _inlined; string _functionName; string _functionSource; diff --git a/source/MaterialXGenShader/ShaderGenerator.cpp b/source/MaterialXGenShader/ShaderGenerator.cpp index a37f0981bd..398232bf39 100644 --- a/source/MaterialXGenShader/ShaderGenerator.cpp +++ b/source/MaterialXGenShader/ShaderGenerator.cpp @@ -344,6 +344,47 @@ ShaderNodeImplPtr ShaderGenerator::getImplementation(const NodeDef& nodedef, Gen return impl; } +/// Load any struct type definitions from the document in to the type cache. +void ShaderGenerator::loadStructTypeDefs(const DocumentPtr& doc) +{ + for (const auto& mxTypeDef : doc->getTypeDefs()) + { + const auto& typeDefName = mxTypeDef->getName(); + const auto& members = mxTypeDef->getMembers(); + + // If we don't have any member children then we're not going to consider ourselves a struct. + if (members.empty()) + continue; + + StructTypeDesc newStructTypeDesc; + for (const auto& member : members) + { + auto memberName = member->getName(); + auto memberTypeName = member->getType(); + auto memberType = TypeDesc::get(memberTypeName); + auto memberDefaultValue = member->getValueString(); + + newStructTypeDesc.addMember(memberName, memberType, memberDefaultValue); + } + + auto structIndex = StructTypeDesc::emplace_back(newStructTypeDesc); + + TypeDesc structTypeDesc(typeDefName, TypeDesc::BASETYPE_STRUCT, TypeDesc::SEMANTIC_NONE, 1, structIndex); + + TypeDescRegistry(structTypeDesc, typeDefName); + + StructTypeDesc::get(structIndex).setTypeDesc(TypeDesc::get(typeDefName)); + } + + _syntax->registerStructTypeDescSyntax(); +} + +/// Clear any struct type definitions loaded +void ShaderGenerator::clearStructTypeDefs() +{ + StructTypeDesc::clear(); +} + namespace { @@ -383,7 +424,7 @@ void ShaderGenerator::registerShaderMetadata(const DocumentPtr& doc, GenContext& ShaderMetadata(ValueElement::UNIT_ATTRIBUTE, Type::STRING), ShaderMetadata(ValueElement::COLOR_SPACE_ATTRIBUTE, Type::STRING) }; - for (auto data : DEFAULT_METADATA) + for (const ShaderMetadata& data : DEFAULT_METADATA) { registry->addMetadata(data.name, data.type); } diff --git a/source/MaterialXGenShader/ShaderGenerator.h b/source/MaterialXGenShader/ShaderGenerator.h index fa60a4d63e..a2f54fec2e 100644 --- a/source/MaterialXGenShader/ShaderGenerator.h +++ b/source/MaterialXGenShader/ShaderGenerator.h @@ -191,6 +191,12 @@ class MX_GENSHADER_API ShaderGenerator return _tokenSubstitutions; } + /// Load any struct type definitions from the document in to the type cache. + void loadStructTypeDefs(const DocumentPtr& doc); + + /// Clear any struct type definitions loaded + void clearStructTypeDefs(); + /// Register metadata that should be exported to the generated shaders. /// Supported metadata includes standard UI attributes like "uiname", "uifolder", /// "uimin", "uimax", etc. diff --git a/source/MaterialXGenShader/ShaderGraph.cpp b/source/MaterialXGenShader/ShaderGraph.cpp index 0f39b46c32..c60910aaed 100644 --- a/source/MaterialXGenShader/ShaderGraph.cpp +++ b/source/MaterialXGenShader/ShaderGraph.cpp @@ -81,7 +81,7 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, ElementPtr connectingElement, GenContext& context) { - // Create the node if it doesn't exists + // Create the node if it doesn't exist. NodePtr upstreamNode = upstreamElement->asA(); if (!upstreamNode) { @@ -95,6 +95,22 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, newNode = createNode(upstreamNode, context); } + // Handle interface inputs with default geometric properties. + for (InputPtr activeInput : upstreamNode->getActiveInputs()) + { + if (!activeInput->hasInterfaceName() || activeInput->getConnectedNode()) + { + continue; + } + + InputPtr graphInput = activeInput->getInterfaceInput(); + if (graphInput && graphInput->hasDefaultGeomPropString()) + { + ShaderInput* shaderInput = getNode(upstreamNode->getName())->getInput(activeInput->getName()); + addDefaultGeomNode(shaderInput, *graphInput->getDefaultGeomProp(), context); + } + } + // // Make connections // @@ -122,19 +138,27 @@ void ShaderGraph::createConnectedNodes(const ElementPtr& downstreamElement, { // We have a node downstream ShaderNode* downstream = getNode(downstreamNode->getName()); - if (downstream && connectingElement) + if (downstream) { - ShaderInput* input = downstream->getInput(connectingElement->getName()); - if (!input) + if (downstream == newNode) { - throw ExceptionShaderGenError("Could not find an input named '" + connectingElement->getName() + - "' on downstream node '" + downstream->getName() + "'"); + throw ExceptionShaderGenError("Upstream node '" + downstream->getName() + "' has itself as downstream node, creating a loop"); + } + + if (connectingElement) + { + ShaderInput* input = downstream->getInput(connectingElement->getName()); + if (!input) + { + throw ExceptionShaderGenError("Could not find an input named '" + connectingElement->getName() + + "' on downstream node '" + downstream->getName() + "'"); + } + input->makeConnection(output); + } + else + { + throw ExceptionShaderGenError("Could not find downstream node ' " + downstreamNode->getName() + "'"); } - input->makeConnection(output); - } - else - { - throw ExceptionShaderGenError("Could not find downstream node ' " + downstreamNode->getName() + "'"); } } else @@ -900,7 +924,7 @@ void ShaderGraph::optimize() ShaderOutput* upstreamPort = outputSocket->getConnection(); if (upstreamPort && upstreamPort->getNode() != this) { - for (ShaderGraphEdge edge : ShaderGraph::traverseUpstream(upstreamPort)) + for (ShaderGraphEdge edge : traverseUpstream(upstreamPort)) { ShaderNode* node = edge.upstream->getNode(); if (usedNodesSet.count(node) == 0) @@ -1190,7 +1214,7 @@ ShaderGraphEdgeIterator& ShaderGraphEdgeIterator::operator++() ShaderInput* input = _upstream->getNode()->getInput(0); ShaderOutput* output = input->getConnection(); - if (output && !output->getNode()->isAGraph()) + if (output && !output->getNode()->isAGraph() && !skipOrMarkAsVisited({ output, input })) { extendPathUpstream(output, input); return *this; @@ -1218,7 +1242,7 @@ ShaderGraphEdgeIterator& ShaderGraphEdgeIterator::operator++() ShaderInput* input = parentFrame.first->getNode()->getInput(++parentFrame.second); ShaderOutput* output = input->getConnection(); - if (output && !output->getNode()->isAGraph()) + if (output && !output->getNode()->isAGraph() && !skipOrMarkAsVisited({ output, input })) { extendPathUpstream(output, input); return *this; @@ -1259,4 +1283,10 @@ void ShaderGraphEdgeIterator::returnPathDownstream(ShaderOutput* upstream) _downstream = nullptr; } +bool ShaderGraphEdgeIterator::skipOrMarkAsVisited(ShaderGraphEdge edge) +{ + auto [it, inserted] = _visitedEdges.emplace(edge); + return !inserted; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/ShaderGraph.h b/source/MaterialXGenShader/ShaderGraph.h index 2b1d3d5d0b..77fd090b66 100644 --- a/source/MaterialXGenShader/ShaderGraph.h +++ b/source/MaterialXGenShader/ShaderGraph.h @@ -104,7 +104,7 @@ class MX_GENSHADER_API ShaderGraph : public ShaderNode /// Add output sockets ShaderGraphOutputSocket* addOutputSocket(const string& name, TypeDesc type); - [[deprecated]] ShaderGraphOutputSocket* addOutputSocket(const string& name, const TypeDesc* type) { return addOutputSocket(name, *type); } + [[deprecated]] ShaderGraphOutputSocket* addOutputSocket(const string& name, const TypeDesc* type) { return addOutputSocket(name, *type); } /// Add a default geometric node and connect to the given input. void addDefaultGeomNode(ShaderInput* input, const GeomPropDef& geomprop, GenContext& context); @@ -209,6 +209,22 @@ class MX_GENSHADER_API ShaderGraphEdge downstream(down) { } + + bool operator==(const ShaderGraphEdge& rhs) const + { + return upstream == rhs.upstream && downstream == rhs.downstream; + } + + bool operator!=(const ShaderGraphEdge& rhs) const + { + return !(*this == rhs); + } + + bool operator<(const ShaderGraphEdge& rhs) const + { + return std::tie(upstream, downstream) < std::tie(rhs.upstream, rhs.downstream); + } + ShaderOutput* upstream; ShaderInput* downstream; }; @@ -254,12 +270,14 @@ class MX_GENSHADER_API ShaderGraphEdgeIterator private: void extendPathUpstream(ShaderOutput* upstream, ShaderInput* downstream); void returnPathDownstream(ShaderOutput* upstream); + bool skipOrMarkAsVisited(ShaderGraphEdge); ShaderOutput* _upstream; ShaderInput* _downstream; using StackFrame = std::pair; std::vector _stack; std::set _path; + std::set _visitedEdges; }; MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index 4e90fcbb2d..12b9bbf548 100644 --- a/source/MaterialXGenShader/ShaderNode.cpp +++ b/source/MaterialXGenShader/ShaderNode.cpp @@ -57,6 +57,13 @@ void ShaderInput::makeConnection(ShaderOutput* src) if (src) { // Make the new connection. + if (src->getNode() == getNode() && !getNode()->isAGraph()) + { + throw ExceptionShaderGenError( + "Tried to create looping connection on node " + getNode()->getName() + + " from output: " + src->getFullName() + " to input: " + getFullName()); + } + _connection = src; src->_connections.push_back(this); } @@ -437,7 +444,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context) const string& attrValue = nodeDef.getAttribute(nodedefAttr); if (!attrValue.empty()) { - ValuePtr value = Value::createValueFromStrings(attrValue, metadataEntry->type.getName()); + ValuePtr value = metadataEntry->type.createValueFromStrings(attrValue); if (!value) { value = metadataEntry->value; @@ -472,7 +479,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context) if (!attrValue.empty()) { const TypeDesc type = metadataEntry->type != Type::NONE ? metadataEntry->type : input->getType(); - ValuePtr value = Value::createValueFromStrings(attrValue, type.getName()); + ValuePtr value = type.createValueFromStrings(attrValue); if (!value) { value = metadataEntry->value; diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp index e270909e0f..81daa9e0a7 100644 --- a/source/MaterialXGenShader/Syntax.cpp +++ b/source/MaterialXGenShader/Syntax.cpp @@ -190,6 +190,35 @@ bool Syntax::remapEnumeration(const string&, TypeDesc, const string&, std::pair< return false; } +void Syntax::registerStructTypeDescSyntax() +{ + for (const auto& typeName : StructTypeDesc::getStructTypeNames()) + { + const auto& typeDesc = TypeDesc::get(typeName); + const auto& structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex()); + + string structTypeName = typeName; + string defaultValue = typeName + "( "; + string uniformDefaultValue = EMPTY_STRING; + string typeAlias = EMPTY_STRING; + string typeDefinition = "struct " + structTypeName + " { "; + + for (const auto& x : structTypeDesc.getMembers()) + { + string memberName = x._name; + string memberType = x._typeDesc.getName(); + string memberDefaultValue = x._defaultValueStr; + + defaultValue += memberDefaultValue + ", "; + typeDefinition += memberType + " " + memberName + "; "; + } + + typeDefinition += " };"; + defaultValue += " )"; + + registerTypeSyntax(typeDesc, createStructSyntax(structTypeName, defaultValue, uniformDefaultValue, typeAlias, typeDefinition)); + } +} const StringVec TypeSyntax::EMPTY_MEMBERS; @@ -247,4 +276,36 @@ string AggregateTypeSyntax::getValue(const Value& value, bool /*uniform*/) const return valueString.empty() ? valueString : getName() + "(" + valueString + ")"; } +StructTypeSyntax::StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue, + const string& typeAlias, const string& typeDefinition, const StringVec& members) : + TypeSyntax(name, defaultValue, uniformDefaultValue, typeAlias, typeDefinition, members), _parentSyntax(parentSyntax) +{ +} + +string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const +{ + const AggregateValue& aggValue = static_cast(value); + + string result = "{"; + + string separator = ""; + for (const auto& memberValue : aggValue.getMembers()) + { + result += separator; + separator = ";"; + + const string& memberTypeName = memberValue->getTypeString(); + TypeDesc memberTypeDesc = TypeDesc::get(memberTypeName); + + // Recursively use the syntax to generate the output, so we can support nested structs. + const string valueStr = _parentSyntax->getValue(memberTypeDesc, *memberValue, true); + + result += valueStr; + } + + result += "}"; + + return result; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/Syntax.h b/source/MaterialXGenShader/Syntax.h index a4bb7e49b5..6f16633b59 100644 --- a/source/MaterialXGenShader/Syntax.h +++ b/source/MaterialXGenShader/Syntax.h @@ -20,6 +20,7 @@ MATERIALX_NAMESPACE_BEGIN class Syntax; class TypeSyntax; +class StructTypeSyntax; class TypeDesc; class ShaderPort; @@ -29,6 +30,8 @@ using SyntaxPtr = shared_ptr; using ConstSyntaxPtr = shared_ptr; /// Shared pointer to a TypeSyntax using TypeSyntaxPtr = shared_ptr; +/// Shared pointer to a StructTypeSyntax +using StructTypeSyntaxPtr = shared_ptr; /// Map holding identifier names and a counter for /// creating unique names from them. @@ -67,6 +70,8 @@ class MX_GENSHADER_API Syntax /// Multiple calls will add to the internal set of tokens. void registerInvalidTokens(const StringMap& tokens); + virtual void registerStructTypeDescSyntax(); + /// Returns a set of names that are reserved words for this language syntax. const StringSet& getReservedWords() const { return _reservedWords; } @@ -199,6 +204,19 @@ class MX_GENSHADER_API Syntax /// Protected constructor Syntax(); + virtual StructTypeSyntaxPtr createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const + { + return std::make_shared( + this, + structTypeName, + defaultValue, + uniformDefaultValue, + typeAlias, + typeDefinition); + } + vector _typeSyntaxes; std::unordered_map _typeSyntaxIndexByType; @@ -292,6 +310,20 @@ class MX_GENSHADER_API AggregateTypeSyntax : public TypeSyntax string getValue(const Value& value, bool uniform) const override; }; +/// Specialization of TypeSyntax for aggregate types. +class MX_GENSHADER_API StructTypeSyntax : public TypeSyntax +{ + public: + StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue, + const string& typeAlias = EMPTY_STRING, const string& typeDefinition = EMPTY_STRING, + const StringVec& members = EMPTY_MEMBERS); + + string getValue(const Value& value, bool uniform) const override; + + protected: + const Syntax* _parentSyntax; +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXGenShader/TypeDesc.cpp b/source/MaterialXGenShader/TypeDesc.cpp index 5f631f67e3..5ea0e31764 100644 --- a/source/MaterialXGenShader/TypeDesc.cpp +++ b/source/MaterialXGenShader/TypeDesc.cpp @@ -5,27 +5,38 @@ #include -#include +#include MATERIALX_NAMESPACE_BEGIN namespace { - using TypeDescMap = std::unordered_map; - using TypeDescNameMap = std::unordered_map; - // Internal storage of registered type descriptors - TypeDescMap& typeMap() - { - static TypeDescMap map; - return map; - } +using TypeDescMap = std::unordered_map; +using TypeDescNameMap = std::unordered_map; - TypeDescNameMap& typeNameMap() - { - static TypeDescNameMap map; - return map; - } +// Internal storage of registered type descriptors +TypeDescMap& typeMap() +{ + static TypeDescMap map; + return map; +} + +TypeDescNameMap& typeNameMap() +{ + static TypeDescNameMap map; + return map; +} + +using StructTypeDescStorage = vector; +StructTypeDescStorage& structTypeStorage() +{ + // TODO: Our use of the singleton pattern for TypeDescMap and StructTypeDestStorage + // is not thread-safe, and we should consider replacing this with thread-local + // data in the GenContext object. + static StructTypeDescStorage storage; + return storage; +} } // anonymous namespace @@ -45,7 +56,52 @@ TypeDesc TypeDesc::get(const string& name) return it != types.end() ? it->second : Type::NONE; } -TypeDescRegistry::TypeDescRegistry(TypeDesc type, const std::string& name) +void TypeDesc::remove(const string& name) +{ + TypeDescNameMap& typenames = typeNameMap(); + + TypeDescMap& types = typeMap(); + + auto it = types.find(name); + if (it == types.end()) + return; + + typenames.erase(it->second.typeId()); + types.erase(it); +} + +ValuePtr TypeDesc::createValueFromStrings(const string& value) const +{ + ValuePtr newValue = Value::createValueFromStrings(value, getName()); + if (!isStruct()) + return newValue; + + // Value::createValueFromStrings() can only create a valid Value for a struct if it is passed + // the optional TypeDef argument, otherwise it just returns a "string" typed Value. + // So if this is a struct type we need to create a new AggregateValue. + + StringVec subValues = parseStructValueString(value); + + AggregateValuePtr result = AggregateValue::createAggregateValue(getName()); + auto structTypeDesc = StructTypeDesc::get(getStructIndex()); + const auto& members = structTypeDesc.getMembers(); + + if (subValues.size() != members.size()) + { + std::stringstream ss; + ss << "Wrong number of initializers - expect " << members.size(); + throw ExceptionShaderGenError(ss.str()); + } + + for (size_t i = 0; i < members.size(); ++i) + { + result->appendValue( members[i]._typeDesc.createValueFromStrings(subValues[i])); + } + + return result; +} + +TypeDescRegistry::TypeDescRegistry(TypeDesc type, const string& name) { TypeDescMap& types = typeMap(); TypeDescNameMap& typenames = typeNameMap(); @@ -56,7 +112,7 @@ TypeDescRegistry::TypeDescRegistry(TypeDesc type, const std::string& name) namespace Type { -/// +/// /// Register type descriptors for standard types. /// TYPEDESC_REGISTER_TYPE(NONE, "none") @@ -83,6 +139,76 @@ TYPEDESC_REGISTER_TYPE(DISPLACEMENTSHADER, "displacementshader") TYPEDESC_REGISTER_TYPE(LIGHTSHADER, "lightshader") TYPEDESC_REGISTER_TYPE(MATERIAL, "material") +} // namespace Type + +// +// StructTypeDesc methods +// + +void StructTypeDesc::addMember(const string& name, TypeDesc type, const string& defaultValueStr) +{ + _members.emplace_back(StructTypeDesc::StructMemberTypeDesc(name, type, defaultValueStr)); +} + +vector StructTypeDesc::getStructTypeNames() +{ + StructTypeDescStorage& structs = structTypeStorage(); + vector structNames; + for (const auto& x : structs) + { + structNames.emplace_back(x.typeDesc().getName()); + } + return structNames; +} + +StructTypeDesc& StructTypeDesc::get(unsigned int index) +{ + StructTypeDescStorage& structs = structTypeStorage(); + return structs[index]; +} + +uint16_t StructTypeDesc::emplace_back(StructTypeDesc structTypeDesc) +{ + StructTypeDescStorage& structs = structTypeStorage(); + if (structs.size() >= std::numeric_limits::max()) + { + throw ExceptionShaderGenError("Maximum number of custom struct types has been exceeded."); + } + uint16_t index = static_cast(structs.size()); + structs.emplace_back(structTypeDesc); + return index; +} + +void StructTypeDesc::clear() +{ + StructTypeDescStorage& structs = structTypeStorage(); + for (const auto& structType: structs) + { + // Need to add typeID to structTypeDesc - and use it here to reference back to typeDesc obj and remove it. + TypeDesc::remove(structType.typeDesc().getName()); + } + structs.clear(); +} + +const string& StructTypeDesc::getName() const +{ + return _typedesc.getName(); +} + +const vector& StructTypeDesc::getMembers() const +{ + return _members; +} + +TypeDesc createStructTypeDesc(std::string_view name) +{ + return {name, TypeDesc::BASETYPE_STRUCT}; +} + +void registerStructTypeDesc(std::string_view name) +{ + auto structTypeDesc = createStructTypeDesc(name); + TypeDescRegistry register_struct(structTypeDesc, string(name)); } MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/TypeDesc.h b/source/MaterialXGenShader/TypeDesc.h index 4560df8a0c..d19fea604a 100644 --- a/source/MaterialXGenShader/TypeDesc.h +++ b/source/MaterialXGenShader/TypeDesc.h @@ -10,6 +10,7 @@ /// Type descriptor for a MaterialX data type. #include +#include #include @@ -17,23 +18,23 @@ MATERIALX_NAMESPACE_BEGIN /// @class TypeDesc /// A type descriptor for MaterialX data types. -/// +/// /// All types need to have a type descriptor registered in order for shader generators /// to know about the type. It can be used for type comparisons as well as getting more /// information about the type. Type descriptors for all standard library data types are /// registered by default and can be accessed from the Type namespace, e.g. Type::FLOAT. /// /// To register custom types use the macro TYPEDESC_DEFINE_TYPE to define it in a header -/// and the macro TYPEDESC_REGISTER_TYPE to register it in the type registry. Registration +/// and the macro TYPEDESC_REGISTER_TYPE to register it in the type registry. Registration /// must be done in order to access the type's name later using getName() and to find the /// type by name using TypeDesc::get(). -/// +/// /// The class is a POD type of 64-bits and can efficiently be stored and passed by value. /// Type compare operations and hash operations are done using a precomputed hash value. /// class MX_GENSHADER_API TypeDesc { -public: + public: enum BaseType { BASETYPE_NONE, @@ -60,15 +61,24 @@ class MX_GENSHADER_API TypeDesc }; /// Empty constructor. - constexpr TypeDesc() noexcept : _id(0), _basetype(BASETYPE_NONE), _semantic(SEMANTIC_NONE), _size(0) {} + constexpr TypeDesc() noexcept : + _id(0), + _basetype(BASETYPE_NONE), + _semantic(SEMANTIC_NONE), + _size(0), + _structIndex(0) + { + } /// Constructor. - constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1) noexcept : + constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1, uint16_t structIndex = 0) noexcept : _id(constexpr_hash(name)), // Note: We only store the hash to keep the class size minimal. _basetype(basetype), _semantic(semantic), - _size(size) - {} + _size(size), + _structIndex(structIndex) + { + } /// Return the unique id assigned to this type. /// The id is a hash of the given type name. @@ -110,6 +120,12 @@ class MX_GENSHADER_API TypeDesc /// Return true if the type represents a closure. bool isClosure() const { return (_semantic == SEMANTIC_CLOSURE || _semantic == SEMANTIC_SHADER || _semantic == SEMANTIC_MATERIAL); } + /// Return true if the type represents a struct. + bool isStruct() const { return _basetype == BASETYPE_STRUCT; } + + /// Return the index for the struct member information in StructTypeDesc, the result is invalid if `isStruct()` returns false. + uint16_t getStructIndex() const { return _structIndex; } + /// Equality operator bool operator==(TypeDesc rhs) const { @@ -141,9 +157,15 @@ class MX_GENSHADER_API TypeDesc /// If no type is found Type::NONE is returned. static TypeDesc get(const string& name); + /// Remove a type description by name, if it exists. + static void remove(const string& name); + static const string NONE_TYPE_NAME; -private: + /// Create a Value from a string for a given typeDesc + ValuePtr createValueFromStrings(const string& value) const; + + private: /// Simple constexpr hash function, good enough for the small set of short strings that /// are used for our data type names. constexpr uint32_t constexpr_hash(std::string_view str, uint32_t n = 0, uint32_t h = 2166136261) @@ -155,13 +177,14 @@ class MX_GENSHADER_API TypeDesc uint8_t _basetype; uint8_t _semantic; uint16_t _size; + uint16_t _structIndex; }; /// @class TypeDescRegistry /// Helper class for type registration. class MX_GENSHADER_API TypeDescRegistry { -public: + public: TypeDescRegistry(TypeDesc type, const string& name); }; @@ -206,6 +229,58 @@ TYPEDESC_DEFINE_TYPE(MATERIAL, "material", TypeDesc::BASETYPE_NONE, TypeDesc::SE } // namespace Type + +/// @class StructTypeDesc +/// A type descriptor for MaterialX struct types. +/// +/// All types need to have a type descriptor registered in order for shader generators +/// to know about the type. If the type represented is of basetype=BASETYPE_STRUCT then +/// the type also needs to have an associated StructTypeDesc that describes the members +/// of the struct. +/// +class MX_GENSHADER_API StructTypeDesc +{ + public: + struct StructMemberTypeDesc + { + StructMemberTypeDesc(string name, TypeDesc typeDesc, string defaultValueStr) : + _name(name), _typeDesc(typeDesc), _defaultValueStr(defaultValueStr) + { + } + string _name; + TypeDesc _typeDesc; + string _defaultValueStr; + }; + + /// Empty constructor. + StructTypeDesc() noexcept{} + + void addMember(const string& name, TypeDesc type, const string& defaultValueStr); + void setTypeDesc(TypeDesc typedesc) { _typedesc = typedesc; } + + /// Return a type description by index. + static StructTypeDesc& get(unsigned int index); + static vector getStructTypeNames(); + static uint16_t emplace_back(StructTypeDesc structTypeDesc); + static void clear(); + + TypeDesc typeDesc() const { return _typedesc; } + + const string& getName() const; + + const vector& getMembers() const; + + private: + TypeDesc _typedesc; + vector _members; +}; + +class MX_GENSHADER_API StructTypeDescRegistry +{ + public: + StructTypeDescRegistry(); +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXGenShader/Util.cpp b/source/MaterialXGenShader/Util.cpp index 9722952390..af34fa1b2a 100644 --- a/source/MaterialXGenShader/Util.cpp +++ b/source/MaterialXGenShader/Util.cpp @@ -16,10 +16,10 @@ using OpaqueTestPair = std::pair; using OpaqueTestPairList = vector; // Inputs on a surface shader which are checked for transparency -const OpaqueTestPairList inputPairList = { { "opacity", 1.0f }, - { "existence", 1.0f }, - { "alpha", 1.0f }, - { "transmission", 0.0f } }; +const OpaqueTestPairList DEFAULT_INPUT_PAIR_LIST = { { "opacity", 1.0f }, + { "existence", 1.0f }, + { "alpha", 1.0f }, + { "transmission", 0.0f } }; const string MIX_CATEGORY("mix"); const string MIX_FG_INPUT("fg"); @@ -116,6 +116,23 @@ bool isTransparentShaderNode(NodePtr node, NodePtr interfaceNode) return false; } + // Check against nodedef input hints + OpaqueTestPairList inputPairList = DEFAULT_INPUT_PAIR_LIST; + NodeDefPtr nodeDef = node->getNodeDef(); + StringMap nodeDefList = nodeDef ? nodeDef->getInputHints() : StringMap(); + for (auto &item : nodeDefList) + { + string inputName = item.first; + if (item.second == Input::TRANSPARENCY_HINT) + { + inputPairList.push_back(std::make_pair(inputName, 0.0f) ); + } + else if (item.second == Input::OPACITY_HINT) + { + inputPairList.push_back(std::make_pair(inputName, 1.0f)); + } + } + // Check against the interface if a node is passed in to check against OpaqueTestPairList interfaceNames; if (interfaceNode) @@ -167,8 +184,8 @@ bool isTransparentShaderNode(NodePtr node, NodePtr interfaceNode) NodePtr inputNode = checkInput->getConnectedNode(); if (inputNode) { - NodeDefPtr nodeDef = inputNode->getNodeDef(); - string nodeGroup = nodeDef ? nodeDef->getAttribute(NodeDef::NODE_GROUP_ATTRIBUTE) : EMPTY_STRING; + NodeDefPtr inputNodeDef = inputNode->getNodeDef(); + string nodeGroup = inputNodeDef ? inputNodeDef->getAttribute(NodeDef::NODE_GROUP_ATTRIBUTE) : EMPTY_STRING; if (nodeGroup != NodeDef::ADJUSTMENT_NODE_GROUP && nodeGroup != NodeDef::CHANNEL_NODE_GROUP) { diff --git a/source/MaterialXGenShader/Util.h b/source/MaterialXGenShader/Util.h index bb0586a214..23a59e0437 100644 --- a/source/MaterialXGenShader/Util.h +++ b/source/MaterialXGenShader/Util.h @@ -90,8 +90,8 @@ MX_GENSHADER_API bool hasElementAttributes(OutputPtr output, const StringVec& at // These are deprecated wrappers for older versions of the function interfaces in this module. // Clients using these interfaces should update them to the latest API. // -MX_GENSHADER_API [[deprecated]] void findRenderableMaterialNodes(ConstDocumentPtr doc, vector& elements, bool, std::unordered_set&); -MX_GENSHADER_API [[deprecated]] void findRenderableElements(ConstDocumentPtr doc, vector& elements, bool includeReferencedGraphs = false); +[[deprecated]] MX_GENSHADER_API void findRenderableMaterialNodes(ConstDocumentPtr doc, vector& elements, bool, std::unordered_set&); +[[deprecated]] MX_GENSHADER_API void findRenderableElements(ConstDocumentPtr doc, vector& elements, bool includeReferencedGraphs = false); MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGraphEditor/CMakeLists.txt b/source/MaterialXGraphEditor/CMakeLists.txt index 495213bfb6..00acfc6902 100644 --- a/source/MaterialXGraphEditor/CMakeLists.txt +++ b/source/MaterialXGraphEditor/CMakeLists.txt @@ -18,8 +18,7 @@ file(GLOB materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") if (APPLE) - list(APPEND materialx_source ${CMAKE_CURRENT_SOURCE_DIR}/FileDialog.mm) - set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/FileDialog.mm" PROPERTIES LANGUAGE CXX) + list(APPEND materialx_source ${CMAKE_CURRENT_SOURCE_DIR}/FileDialog_Darwin.mm) endif () file(GLOB imgui_source "${DEAR_IMGUI_PREFIX}/*.cpp") @@ -62,6 +61,7 @@ set(GLFW_INSTALL OFF) set(BUILD_SHARED_LIBS OFF) add_subdirectory(External/Glfw) +set_property(TARGET glfw_minimal PROPERTY FOLDER "External") if(MSVC) SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:mainCRTStartup") diff --git a/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt b/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt index 2ec553856f..0bd2ffe59c 100644 --- a/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt +++ b/source/MaterialXGraphEditor/External/Glfw/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(GLFW VERSION 3.4.0 LANGUAGES C) diff --git a/source/MaterialXGraphEditor/FileDialog.mm b/source/MaterialXGraphEditor/FileDialog_Darwin.mm similarity index 100% rename from source/MaterialXGraphEditor/FileDialog.mm rename to source/MaterialXGraphEditor/FileDialog_Darwin.mm diff --git a/source/MaterialXGraphEditor/Graph.cpp b/source/MaterialXGraphEditor/Graph.cpp index f2382e288e..aa04339469 100644 --- a/source/MaterialXGraphEditor/Graph.cpp +++ b/source/MaterialXGraphEditor/Graph.cpp @@ -171,7 +171,7 @@ Graph::Graph(const std::string& materialFilename, // Create a renderer using the initial startup document. mx::FilePath captureFilename = "resources/Materials/Examples/example.png"; std::string envRadianceFilename = "resources/Lights/san_giuseppe_bridge_split.hdr"; - _renderer = std::make_shared(_graphDoc, meshFilename, envRadianceFilename, + _renderer = std::make_shared(_graphDoc, _stdLib, meshFilename, envRadianceFilename, _searchPath, viewWidth, viewHeight); _renderer->initialize(); for (const std::string& ext : _renderer->getImageHandler()->supportedExtensions()) @@ -249,7 +249,7 @@ mx::DocumentPtr Graph::loadDocument(const mx::FilePath& filename) if (!filename.isEmpty()) { mx::readFromXmlFile(doc, filename, _searchPath, &readOptions); - doc->importLibrary(_stdLib); + doc->setDataLibrary(_stdLib); std::string message; if (!doc->validate(&message)) { @@ -926,7 +926,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert if (val && val->isA()) { // Update the value to the default for new nodes - float prev = val->asA(), temp = val->asA(); + float prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA() : 0.f; float max = maxVal ? maxVal->asA() : 100.f; float speed = (max - min) / 1000.0f; @@ -946,7 +947,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - int prev = val->asA(), temp = val->asA(); + int prev, temp; + prev = temp = val->asA(); int min = minVal ? minVal->asA() : 0; int max = maxVal ? maxVal->asA() : 100; float speed = (max - min) / 100.0f; @@ -966,7 +968,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Color3 prev = val->asA(), temp = val->asA(); + mx::Color3 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -990,7 +993,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Color4 prev = val->asA(), temp = val->asA(); + mx::Color4 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1016,7 +1020,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Vector2 prev = val->asA(), temp = val->asA(); + mx::Vector2 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1036,7 +1041,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Vector3 prev = val->asA(), temp = val->asA(); + mx::Vector3 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1056,7 +1062,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - mx::Vector4 prev = val->asA(), temp = val->asA(); + mx::Vector4 prev, temp; + prev = temp = val->asA(); float min = minVal ? minVal->asA()[0] : 0.f; float max = maxVal ? maxVal->asA()[0] : 100.f; float speed = (max - min) / 1000.0f; @@ -1076,7 +1083,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - std::string prev = val->asA(), temp = val->asA(); + std::string prev, temp; + prev = temp = val->asA(); ImGui::InputText("##constant", &temp); // Set input value and update materials if different from previous value @@ -1094,7 +1102,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert if (val && val->isA()) { - std::string temp = val->asA(), prev = val->asA(); + std::string prev, temp; + prev = temp = val->asA(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.15f, .15f, .15f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.2f, .4f, .6f, 1.0f)); @@ -1121,7 +1130,7 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert temp = fileName; // Need to clear the file prefix so that it can find the new file - input->setAttribute(input->FILE_PREFIX_ATTRIBUTE, ""); + input->setFilePrefix(mx::EMPTY_STRING); _fileDialogImage.clearSelected(); _fileDialogImage.setTypeFilters(std::vector()); _fileDialogImageInputName = ""; @@ -1142,7 +1151,8 @@ void Graph::setConstant(UiNodePtr node, mx::InputPtr& input, const mx::UIPropert mx::ValuePtr val = input->getValue(); if (val && val->isA()) { - bool prev = val->asA(), temp = val->asA(); + bool prev, temp; + prev = temp = val->asA(); ImGui::Checkbox("", &temp); // Set input value and update materials if different from previous value @@ -2752,6 +2762,10 @@ void Graph::deleteLinkInfo(int startAttr, int endAttr) { int upNode = getNodeId(startAttr); int downNode = getNodeId(endAttr); + if (upNode == -1 || downNode == -1) + { + return; + } // Change input to default value if (_graphNodes[downNode]->getNode()) @@ -3036,7 +3050,7 @@ void Graph::clearGraph() _newLinks.clear(); _currPins.clear(); _graphDoc = mx::createDocument(); - _graphDoc->importLibrary(_stdLib); + _graphDoc->setDataLibrary(_stdLib); _currGraphElem = _graphDoc; if (_currUiNode != nullptr) @@ -3236,6 +3250,15 @@ void Graph::graphButtons() ImGui::BeginChild("Selection", ImVec2(paneWidth, 0), false, windowFlags); ImVec2 windowPos = ImGui::GetWindowPos(); + // Update cursorInRenderView to account for other windows overlapping the Render View (e.g. Menu dropdown). + cursorInRenderView &= ImGui::IsWindowHovered(ImGuiHoveredFlags_None); + + // Update cursorInRenderView to account for visible scrollbar and scroll amount. + ImGuiContext* context = ImGui::GetCurrentContext(); + bool hasScrollbar = context->CurrentWindow->ScrollbarY; + cursorInRenderView &= hasScrollbar ? mousePos.x < (tempWindowPos.x + screenSize.x - ImGui::GetStyle().ScrollbarSize) : true; + cursorInRenderView &= hasScrollbar ? mousePos.y < (tempWindowPos.y + screenSize.y - ImGui::GetScrollY()) : true; + // RenderView window ImVec2 wsize = ImVec2((float) _renderer->getViewWidth(), (float) _renderer->getViewHeight()); _renderer->setViewWidth((int) screenSize[0]); @@ -3265,7 +3288,20 @@ void Graph::graphButtons() void Graph::propertyEditor() { + // Get parent dimensions + ImVec2 textPos = ImGui::GetCursorScreenPos(); // Position for the background + float parentWidth = ImGui::GetContentRegionAvail().x; // Available width in the parent + + // Draw the title bar + const ImGuiStyle& style = ImGui::GetStyle(); + ImVec4 menuBarBgColor = style.Colors[ImGuiCol_MenuBarBg]; + ImU32 bgColor = ImGui::ColorConvertFloat4ToU32(menuBarBgColor); // Convert to 32-bit color + ImDrawList* drawList = ImGui::GetWindowDrawList(); + drawList->AddRectFilled(textPos, + ImVec2(textPos.x + parentWidth, textPos.y + ImGui::GetTextLineHeight()), + bgColor); ImGui::Text("Node Property Editor"); + if (_currUiNode) { // Set and edit name @@ -3273,7 +3309,11 @@ void Graph::propertyEditor() ImGui::SameLine(); std::string original = _currUiNode->getName(); std::string temp = original; + float availableWidth = ImGui::GetContentRegionAvail().x; + ImGui::PushItemWidth(availableWidth); ImGui::InputText("##edit", &temp); + ImGui::PopItemWidth(); + std::string docString = "NodeDef Doc String: \n"; if (_currUiNode->getNode()) { @@ -3354,6 +3394,23 @@ void Graph::propertyEditor() std::string name = _currUiNode->getNodeGraph()->getParent()->createValidChildName(temp); _currUiNode->getNodeGraph()->setName(name); _currUiNode->setName(name); + + for (UiNodePtr node : _graphNodes) + { + if (!node->getInput()) + { + std::vector inputs = node->inputPins; + for (size_t i = 0; i < inputs.size(); i++) + { + const std::string& inputName = inputs[i]->_name; + UiNodePtr inputNode = node->getConnectedNode(inputName); + if (inputNode && inputNode->getName() == name && node->getNode()) + { + node->getNode()->getInput(inputName)->setAttribute("nodegraph", name); + } + } + } + } } } @@ -3383,7 +3440,8 @@ void Graph::propertyEditor() ImGui::SetTooltip("%s", _currUiNode->getNode()->getNodeDef()->getDocString().c_str()); } - ImGui::Text("Inputs:"); + ImGui::Checkbox("Show all inputs", &_currUiNode->_showAllInputs); + int count = 0; for (UiPinPtr input : _currUiNode->inputPins) { @@ -3447,14 +3505,12 @@ void Graph::propertyEditor() ImGui::SetWindowFontScale(1.0f); } } - ImGui::Checkbox("Show all inputs", &_currUiNode->_showAllInputs); } else if (_currUiNode->getInput() != nullptr) { ImGui::Text("%s", _currUiNode->getCategory().c_str()); std::vector inputs = _currUiNode->inputPins; - ImGui::Text("Inputs:"); int count = static_cast(inputs.size()); if (count) @@ -3505,7 +3561,6 @@ void Graph::propertyEditor() { std::vector inputs = _currUiNode->inputPins; ImGui::Text("%s", _currUiNode->getCategory().c_str()); - ImGui::Text("Inputs:"); int count = 0; for (UiPinPtr input : inputs) { diff --git a/source/MaterialXGraphEditor/Main.cpp b/source/MaterialXGraphEditor/Main.cpp index 38c755cdd9..0c550dbdd1 100644 --- a/source/MaterialXGraphEditor/Main.cpp +++ b/source/MaterialXGraphEditor/Main.cpp @@ -30,6 +30,8 @@ const std::string options = " --path [FILEPATH] Specify an additional data search path location (e.g. '/projects/MaterialX'). This absolute path will be queried when locating data libraries, XInclude references, and referenced images.\n" " --library [FILEPATH] Specify an additional data library folder (e.g. 'vendorlib', 'studiolib'). This relative path will be appended to each location in the data search path when loading data libraries.\n" " --uiScale [FACTOR] Manually specify a UI scaling factor\n" + " --font [FILENAME] Specify the name of the custom font file to use. If not specified the default font will be used.\n" + " --fontSize [SIZE] Specify font size to use for the custom font. If not specified a default of 18 will be used.\n" " --captureFilename [FILENAME] Specify the filename to which the first rendered frame should be written\n" " --help Display the complete list of command-line options\n"; @@ -67,6 +69,8 @@ int main(int argc, char* const argv[]) int viewWidth = 256; int viewHeight = 256; float uiScale = 0.0f; + std::string fontFilename; + int fontSize = 18; std::string captureFilename; for (size_t i = 0; i < tokens.size(); i++) @@ -102,6 +106,14 @@ int main(int argc, char* const argv[]) { parseToken(nextToken, "float", uiScale); } + else if (token == "--font") + { + parseToken(nextToken, "string", fontFilename); + } + else if (token == "--fontSize") + { + parseToken(nextToken, "integer", fontSize); + } else if (token == "--captureFilename") { parseToken(nextToken, "string", captureFilename); @@ -172,7 +184,15 @@ int main(int argc, char* const argv[]) io.IniFilename = NULL; io.LogFilename = NULL; - io.Fonts->AddFontDefault(); + ImFont* customFont = nullptr; + if (!fontFilename.empty()) + { + customFont = io.Fonts->AddFontFromFileTTF(fontFilename.c_str(), fontSize); + } + if (!customFont) + { + io.Fonts->AddFontDefault(); + } // Setup Dear ImGui style ImGui::StyleColorsDark(); diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp index 3c2e01dff9..fe419c7908 100644 --- a/source/MaterialXGraphEditor/RenderView.cpp +++ b/source/MaterialXGraphEditor/RenderView.cpp @@ -108,6 +108,7 @@ void RenderView::setDocument(mx::DocumentPtr document) } RenderView::RenderView(mx::DocumentPtr doc, + mx::DocumentPtr stdLib, const std::string& meshFilename, const std::string& envRadianceFilename, const mx::FileSearchPath& searchPath, @@ -162,6 +163,7 @@ RenderView::RenderView(mx::DocumentPtr doc, _genContext.getOptions().shaderInterfaceType = mx::SHADER_INTERFACE_COMPLETE; setDocument(doc); + _stdLib = stdLib; } void RenderView::initialize() @@ -214,18 +216,6 @@ void RenderView::assignMaterial(mx::MeshPartitionPtr geometry, mx::GlslMaterialP } } -mx::ElementPredicate RenderView::getElementPredicate() -{ - return [this](mx::ConstElementPtr elem) - { - if (elem->hasSourceUri()) - { - return (_xincludeFiles.count(elem->getSourceUri()) == 0); - } - return true; - }; -} - void RenderView::updateGeometrySelections() { _geometryList.clear(); @@ -630,6 +620,9 @@ void RenderView::initContext(mx::GenContext& context) unitSystem->setUnitConverterRegistry(_unitRegistry); context.getShaderGenerator().setUnitSystem(unitSystem); context.getOptions().targetDistanceUnit = "meter"; + + // Register struct type definitions + context.getShaderGenerator().loadStructTypeDefs(_document); } void RenderView::drawContents() @@ -932,7 +925,7 @@ mx::ImagePtr RenderView::getShadowMap() { try { - mx::ShaderPtr hwShader = mx::createDepthShader(_genContext, _document, "__SHADOW_SHADER__"); + mx::ShaderPtr hwShader = mx::createDepthShader(_genContext, _stdLib, "__SHADOW_SHADER__"); _shadowMaterial = mx::GlslMaterial::create(); _shadowMaterial->generateShader(hwShader); } @@ -946,7 +939,7 @@ mx::ImagePtr RenderView::getShadowMap() { try { - mx::ShaderPtr hwShader = mx::createBlurShader(_genContext, _document, "__SHADOW_BLUR_SHADER__", "gaussian", 1.0f); + mx::ShaderPtr hwShader = mx::createBlurShader(_genContext, _stdLib, "__SHADOW_BLUR_SHADER__", "gaussian", 1.0f); _shadowBlurMaterial = mx::GlslMaterial::create(); _shadowBlurMaterial->generateShader(hwShader); } diff --git a/source/MaterialXGraphEditor/RenderView.h b/source/MaterialXGraphEditor/RenderView.h index 354e898ce1..c4c709dc9f 100644 --- a/source/MaterialXGraphEditor/RenderView.h +++ b/source/MaterialXGraphEditor/RenderView.h @@ -29,6 +29,7 @@ class RenderView { public: RenderView(mx::DocumentPtr doc, + mx::DocumentPtr stdLib, const std::string& meshFilename, const std::string& envRadianceFilename, const mx::FileSearchPath& searchPath, @@ -159,7 +160,6 @@ class RenderView { return _xincludeFiles; } - mx::ElementPredicate getElementPredicate(); // Request a capture of the current frame, writing it to the given filename. void requestFrameCapture(const mx::FilePath& filename) @@ -232,7 +232,6 @@ class RenderView void updateGeometrySelections(); mx::ImagePtr getShadowMap(); - mx::ImagePtr _renderMap; void renderFrame(); void renderScreenSpaceQuad(mx::GlslMaterialPtr material); @@ -268,6 +267,7 @@ class RenderView // Document management mx::DocumentPtr _document; + mx::DocumentPtr _stdLib; DocumentModifiers _modifiers; mx::StringSet _xincludeFiles; diff --git a/source/MaterialXRender/CMakeLists.txt b/source/MaterialXRender/CMakeLists.txt index d96fc203e7..9cb1bcaa04 100644 --- a/source/MaterialXRender/CMakeLists.txt +++ b/source/MaterialXRender/CMakeLists.txt @@ -8,10 +8,12 @@ endif() mx_add_library(MaterialXRender SOURCE_FILES - ${materialx_source} ${materialx_inlined} + ${materialx_source} + INLINED_FILES + ${materialx_inlined} HEADER_FILES ${materialx_headers} - LIBRARIES + MTLX_MODULES MaterialXGenShader EXPORT_DEFINE MATERIALX_RENDER_EXPORTS) @@ -27,5 +29,5 @@ if(MATERIALX_BUILD_OIIO) set(OPENIMAGEIO_ROOT_DIR ${MATERIALX_OIIO_DIR}) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/External/OpenImageIO") find_package(OpenImageIO CONFIG REQUIRED) - target_link_libraries(${TARGET_NAME} OpenImageIO::OpenImageIO OpenImageIO::OpenImageIO_Util) + target_link_libraries(${TARGET_NAME} PRIVATE OpenImageIO::OpenImageIO OpenImageIO::OpenImageIO_Util) endif() diff --git a/source/MaterialXRender/OiioImageLoader.h b/source/MaterialXRender/OiioImageLoader.h index 5a81e69051..05a8d20e2c 100644 --- a/source/MaterialXRender/OiioImageLoader.h +++ b/source/MaterialXRender/OiioImageLoader.h @@ -5,8 +5,9 @@ #ifndef MATERIALX_OIIOIMAGELOADER_H #define MATERIALX_OIIOIMAGELOADER_H - + #if MATERIALX_BUILD_OIIO + /// @file /// Image loader wrapper using OpenImageIO @@ -56,5 +57,7 @@ class MX_RENDER_API OiioImageLoader : public ImageLoader }; MATERIALX_NAMESPACE_END -#endif //MATERIALX_BUILD_OIIO + +#endif // MATERIALX_BUILD_OIIO + #endif diff --git a/source/MaterialXRender/ShaderMaterial.cpp b/source/MaterialXRender/ShaderMaterial.cpp index c61c6d3c04..6fcc1a661d 100644 --- a/source/MaterialXRender/ShaderMaterial.cpp +++ b/source/MaterialXRender/ShaderMaterial.cpp @@ -68,10 +68,8 @@ bool ShaderMaterial::generateEnvironmentShader(GenContext& context, { // Read in the environment nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); - DocumentPtr envDoc = createDocument(); - readFromXmlFile(envDoc, filename); - doc->importLibrary(envDoc); + doc->setDataLibrary(stdLib); + readFromXmlFile(doc, filename); NodeGraphPtr envGraph = doc->getNodeGraph("envMap"); if (!envGraph) diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index 5a9b116d59..9aab6b4811 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -24,7 +24,7 @@ ShaderPtr createConstantShader(GenContext& context, { // Construct the constant color nodegraph DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); constant->setInputValue("value", color); @@ -41,7 +41,7 @@ ShaderPtr createDepthShader(GenContext& context, { // Construct a dummy nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); OutputPtr output = nodeGraph->addOutput(); @@ -61,7 +61,7 @@ ShaderPtr createAlbedoTableShader(GenContext& context, { // Construct a dummy nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); OutputPtr output = nodeGraph->addOutput(); @@ -77,12 +77,12 @@ ShaderPtr createAlbedoTableShader(GenContext& context, } ShaderPtr createEnvPrefilterShader(GenContext& context, - DocumentPtr stdLib, - const string& shaderName) + DocumentPtr stdLib, + const string& shaderName) { // Construct a dummy nodegraph. DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr constant = nodeGraph->addNode("constant"); OutputPtr output = nodeGraph->addOutput(); @@ -104,7 +104,7 @@ ShaderPtr createBlurShader(GenContext& context, { // Construct the blur nodegraph DocumentPtr doc = createDocument(); - doc->importLibrary(stdLib); + doc->setDataLibrary(stdLib); NodeGraphPtr nodeGraph = doc->addNodeGraph(); NodePtr imageNode = nodeGraph->addNode("image", "image"); NodePtr blurNode = nodeGraph->addNode("blur", "blur"); @@ -170,7 +170,7 @@ unsigned int getUIProperties(InputPtr input, const string& target, UIProperties& else { valueString += val; - uiProperties.enumerationValues.push_back(Value::createValueFromStrings(valueString, input->getType())); + uiProperties.enumerationValues.push_back(typeDesc.createValueFromStrings(valueString)); valueString.clear(); index = 0; } @@ -318,7 +318,7 @@ void createUIPropertyGroups(DocumentPtr doc, const VariableBlock& block, UIPrope // Prepend a parent label for unlabeled node inputs. ElementPtr parent = pair.first->getParent(); - if (item.ui.uiFolder.empty() && parent && parent->isA()) + if (item.ui.uiName.empty() && parent && parent->isA()) { item.label = parent->getName() + pathSeparator + item.label; } diff --git a/source/MaterialXRenderGlsl/CMakeLists.txt b/source/MaterialXRenderGlsl/CMakeLists.txt index 2f0cefde1f..32e68a5f36 100644 --- a/source/MaterialXRenderGlsl/CMakeLists.txt +++ b/source/MaterialXRenderGlsl/CMakeLists.txt @@ -28,7 +28,7 @@ mx_add_library(MaterialXRenderGlsl ${materialx_source} HEADER_FILES ${materialx_headers} - LIBRARIES + MTLX_MODULES MaterialXRenderHw MaterialXGenGlsl EXPORT_DEFINE @@ -53,25 +53,25 @@ endif() if(WIN32) if(MSVC) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC Opengl32) elseif(MINGW) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC Opengl32 gdi32) endif() elseif(APPLE) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC "-framework OpenGL" "-framework Foundation" "-framework Cocoa" "-framework Metal") elseif(UNIX) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC OpenGL::GL X11::X11 X11::Xt) diff --git a/source/MaterialXRenderGlsl/GLTextureHandler.cpp b/source/MaterialXRenderGlsl/GLTextureHandler.cpp index cd130654f6..47536243cf 100644 --- a/source/MaterialXRenderGlsl/GLTextureHandler.cpp +++ b/source/MaterialXRenderGlsl/GLTextureHandler.cpp @@ -53,7 +53,7 @@ bool GLTextureHandler::bindImage(ImagePtr image, const ImageSamplingProperties& { std::cerr << "Exceeded maximum number of bound textures in GLTextureHandler::bindImage" << std::endl; return false; - } + } _boundTextureLocations[textureUnit] = image->getResourceId(); glActiveTexture(GL_TEXTURE0 + textureUnit); @@ -116,10 +116,10 @@ bool GLTextureHandler::createRenderResources(ImagePtr image, bool generateMipMap int glType, glFormat, glInternalFormat; mapTextureFormatToGL(image->getBaseType(), image->getChannelCount(), false, - glType, glFormat, glInternalFormat); + glType, glFormat, glInternalFormat); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, image->getWidth(), image->getHeight(), - 0, glFormat, glType, image->getResourceBuffer()); + 0, glFormat, glType, image->getResourceBuffer()); if (image->getChannelCount() == 1) { GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; @@ -134,7 +134,7 @@ bool GLTextureHandler::createRenderResources(ImagePtr image, bool generateMipMap return true; } - + void GLTextureHandler::releaseRenderResources(ImagePtr image) { if (!image) diff --git a/source/MaterialXRenderGlsl/GlslMaterial.cpp b/source/MaterialXRenderGlsl/GlslMaterial.cpp index 2586cc4ef8..064ab898ff 100644 --- a/source/MaterialXRenderGlsl/GlslMaterial.cpp +++ b/source/MaterialXRenderGlsl/GlslMaterial.cpp @@ -327,11 +327,10 @@ ShaderPort* GlslMaterial::findUniform(const std::string& path) const if (publicUniforms) { // Scan block based on path match predicate - port = publicUniforms->find( - [path](ShaderPort* port) - { - return (port && stringEndsWith(port->getPath(), path)); - }); + port = publicUniforms->find([path](ShaderPort* port) + { + return (port && stringEndsWith(port->getPath(), path)); + }); // Check if the uniform exists in the shader program if (port && !_glProgram->getUniformsList().count(port->getVariable())) @@ -361,7 +360,7 @@ void GlslMaterial::modifyUniform(const std::string& path, ConstValuePtr value, s { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); + uniform->setValue(uniform->getType().createValueFromStrings(valueString)); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); diff --git a/source/MaterialXRenderGlsl/GlslProgram.cpp b/source/MaterialXRenderGlsl/GlslProgram.cpp index b2ca0aa66e..b63e1faecc 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.cpp +++ b/source/MaterialXRenderGlsl/GlslProgram.cpp @@ -508,7 +508,7 @@ ImagePtr GlslProgram::bindTexture(unsigned int uniformType, int uniformLocation, return nullptr; } -MaterialX::ValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList) +MaterialX::ConstValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList) { auto uniform = uniformList.find(uniformName); if (uniform != uniformList.end()) @@ -946,47 +946,87 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() for (size_t i = 0; i < uniforms.size(); ++i) { const ShaderPort* v = uniforms[i]; - int glType = mapTypeToOpenGLType(v->getType()); - // There is no way to match with an unnamed variable - if (v->getVariable().empty()) - { - continue; - } - - // Ignore types which are unsupported in GLSL. - if (glType == Input::INVALID_OPENGL_TYPE) - { - continue; - } + const auto& variablePath = v->getPath(); + const auto& variableUnit = v->getUnit(); + const auto& variableColorspace = v->getColorSpace(); + const auto& variableSemantic = v->getSemantic(); - auto inputIt = _uniformList.find(v->getVariable()); - if (inputIt != _uniformList.end()) + const auto populateUniformInput = + [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound] + (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue) -> void { - Input* input = inputIt->second.get(); - input->path = v->getPath(); - input->unit = v->getUnit(); - input->colorspace = v->getColorSpace(); - input->value = v->getValue(); - if (input->gltype == glType) - { - input->typeString = v->getType().getName(); - } - else + auto populateUniformInput_impl = + [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound] + (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void { - errors.push_back( - "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " - + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType().getName() - + "\". Semantic: \"" + v->getSemantic() - + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") - + "\". Unit: \"" + (!v->getUnit().empty() ? v->getUnit() : "") - + "\". Colorspace: \"" + (!v->getColorSpace().empty() ? v->getColorSpace() : "") - + "\". GLType: " + std::to_string(mapTypeToOpenGLType(v->getType())) - ); - uniformTypeMismatchFound = true; - } - } + if (!typedesc.isStruct()) + { + // Handle non-struct types + int glType = mapTypeToOpenGLType(typedesc); + + // There is no way to match with an unnamed variable + if (variableName.empty()) + { + return; + } + + // Ignore types which are unsupported in GLSL. + if (glType == Input::INVALID_OPENGL_TYPE) + { + return; + } + + auto inputIt = _uniformList.find(variableName); + if (inputIt != _uniformList.end()) + { + Input* input = inputIt->second.get(); + input->path = variablePath; + input->unit = variableUnit; + input->colorspace = variableColorspace; + input->value = variableValue; + if (input->gltype == glType) + { + input->typeString = typedesc.getName(); + } + else + { + errors.push_back( + "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + + "Name: \"" + variableName + + "\". Type: \"" + typedesc.getName() + + "\". Semantic: \"" + variableSemantic + + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "") + + "\". Unit: \"" + (!variableUnit.empty() ? variableUnit : "") + + "\". Colorspace: \"" + (!variableColorspace.empty() ? variableColorspace : "") + + "\". GLType: " + std::to_string(glType)); + uniformTypeMismatchFound = true; + } + } + } + else + { + // If we're a struct - we need to loop over each member + auto structTypeDesc = StructTypeDesc::get(typedesc.getStructIndex()); + auto aggregateValue = std::static_pointer_cast(variableValue); + + const auto& members = structTypeDesc.getMembers(); + for (size_t i = 0, n = members.size(); i < n; ++i) + { + const auto& member = members[i]; + auto memberTypeDesc = member._typeDesc; + auto memberVariableName = variableName + "." + member._name; + auto memberVariableValue = aggregateValue->getMemberValue(i); + + populateUniformInput_ref(memberTypeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref); + } + } + }; + + return populateUniformInput_impl(typedesc, variableName, variableValue, populateUniformInput_impl); + }; + + populateUniformInput(v->getType(), v->getVariable(), v->getValue()); } } @@ -1100,12 +1140,12 @@ const GlslProgram::InputMap& GlslProgram::updateAttributesList() if (string::npos != sattributeName.find(colorSet)) { string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } else if (string::npos != sattributeName.find(uvSet)) { string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } _attributeList[sattributeName] = inputPtr; diff --git a/source/MaterialXRenderGlsl/GlslProgram.h b/source/MaterialXRenderGlsl/GlslProgram.h index 7d58dbaca7..4addd7d54b 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.h +++ b/source/MaterialXRenderGlsl/GlslProgram.h @@ -102,7 +102,7 @@ class MX_RENDERGLSL_API GlslProgram string typeString; /// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during /// shader generation. - MaterialX::ValuePtr value; + MaterialX::ConstValuePtr value; /// Is this a constant bool isConstant; /// Element path (if any) @@ -223,7 +223,7 @@ class MX_RENDERGLSL_API GlslProgram // Utility to find a uniform value in an uniform list. // If uniform cannot be found a null pointer will be return. - ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); + ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); // Bind an individual texture to a program uniform location ImagePtr bindTexture(unsigned int uniformType, int uniformLocation, const FilePath& filePath, diff --git a/source/MaterialXRenderHw/CMakeLists.txt b/source/MaterialXRenderHw/CMakeLists.txt index ac9b20e2bf..d3adfb5b8f 100644 --- a/source/MaterialXRenderHw/CMakeLists.txt +++ b/source/MaterialXRenderHw/CMakeLists.txt @@ -3,7 +3,7 @@ file(GLOB materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*") if(APPLE) - if (NOT MATERIALX_BUILD_IOS) + if (NOT MATERIALX_BUILD_APPLE_EMBEDDED) find_library(COCOA_FRAMEWORK Cocoa) endif() elseif(UNIX) @@ -20,26 +20,26 @@ mx_add_library(MaterialXRenderHw ${materialx_source} HEADER_FILES ${materialx_headers} - LIBRARIES + MTLX_MODULES MaterialXRender EXPORT_DEFINE MATERIALX_RENDERHW_EXPORTS ADD_OBJECTIVE_C_CODE) if(APPLE) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC "-framework Foundation" "-framework Metal") - if (NOT MATERIALX_BUILD_IOS) - target_link_libraries( - ${TARGET_NAME} + if (NOT MATERIALX_BUILD_APPLE_EMBEDDED) + target_link_libraries(${TARGET_NAME} + PUBLIC "-framework Cocoa" ) endif() elseif(UNIX) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC X11::X11 X11::Xt) endif() diff --git a/source/MaterialXRenderHw/SimpleWindowIOS.cpp b/source/MaterialXRenderHw/SimpleWindowIOS.cpp index 1d4189b2ab..4efcebfa64 100644 --- a/source/MaterialXRenderHw/SimpleWindowIOS.cpp +++ b/source/MaterialXRenderHw/SimpleWindowIOS.cpp @@ -5,7 +5,7 @@ #if defined(__APPLE__) -#ifdef TARGET_OS_IOS +#ifdef TARGET_OS_IPHONE #include diff --git a/source/MaterialXRenderHw/SimpleWindowMac.cpp b/source/MaterialXRenderHw/SimpleWindowMac.cpp index a04d1f49ae..d7035f8191 100644 --- a/source/MaterialXRenderHw/SimpleWindowMac.cpp +++ b/source/MaterialXRenderHw/SimpleWindowMac.cpp @@ -5,7 +5,7 @@ #if defined(__APPLE__) -#ifndef TARGET_OS_IOS +#ifndef TARGET_OS_IPHONE #include #include diff --git a/source/MaterialXRenderHw/WindowCocoaWrappers.m b/source/MaterialXRenderHw/WindowCocoaWrappers.m index a012966a8f..3283008300 100644 --- a/source/MaterialXRenderHw/WindowCocoaWrappers.m +++ b/source/MaterialXRenderHw/WindowCocoaWrappers.m @@ -5,7 +5,7 @@ #if defined (__APPLE__) -#ifndef TARGET_OS_IOS +#ifndef TARGET_OS_IPHONE #import #import diff --git a/source/MaterialXRenderHw/WindowWrapper.cpp b/source/MaterialXRenderHw/WindowWrapper.cpp index 654498d5cd..e2c059799c 100644 --- a/source/MaterialXRenderHw/WindowWrapper.cpp +++ b/source/MaterialXRenderHw/WindowWrapper.cpp @@ -84,7 +84,7 @@ WindowWrapper::WindowWrapper(ExternalWindowHandle externalHandle, DisplayHandle display) { _externalHandle = externalHandle; -#ifndef TARGET_OS_IOS +#ifndef TARGET_OS_IPHONE // Cache a pointer to the window. _internalHandle = NSUtilGetView(externalHandle); #else diff --git a/source/MaterialXRenderMsl/CMakeLists.txt b/source/MaterialXRenderMsl/CMakeLists.txt index 7807251ad9..741ce9d62a 100644 --- a/source/MaterialXRenderMsl/CMakeLists.txt +++ b/source/MaterialXRenderMsl/CMakeLists.txt @@ -6,7 +6,7 @@ if(POLICY CMP0072) endif() if(APPLE) - if(NOT MATERIALX_BUILD_IOS) + if(NOT MATERIALX_BUILD_APPLE_EMBEDDED) find_library(COCOA_FRAMEWORK Cocoa) find_package(OpenGL REQUIRED) endif() @@ -26,7 +26,7 @@ mx_add_library(MaterialXRenderMsl ${materialx_source} HEADER_FILES ${materialx_headers} - LIBRARIES + MTLX_MODULES MaterialXRenderHw MaterialXGenMsl EXPORT_DEFINE @@ -46,23 +46,24 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() if(MSVC) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC Opengl32) elseif(APPLE) - if(NOT MATERIALX_BUILD_IOS) - target_link_libraries( - ${TARGET_NAME} + if(NOT MATERIALX_BUILD_APPLE_EMBEDDED) + target_link_libraries(${TARGET_NAME} + PUBLIC "-framework Cocoa" "-framework OpenGL") endif() - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC "-framework Foundation" - "-framework Metal") + "-framework Metal" + "-framework MetalPerformanceShaders") elseif(UNIX) - target_link_libraries( - ${TARGET_NAME} + target_link_libraries(${TARGET_NAME} + PUBLIC OpenGL::GL X11::X11 X11::Xt) diff --git a/source/MaterialXRenderMsl/MetalFramebuffer.h b/source/MaterialXRenderMsl/MetalFramebuffer.h index ba38365da4..6c8f061a12 100644 --- a/source/MaterialXRenderMsl/MetalFramebuffer.h +++ b/source/MaterialXRenderMsl/MetalFramebuffer.h @@ -48,7 +48,7 @@ class MX_RENDERMSL_API MetalFramebuffer /// to the framebuffer are encoded to the sRGB color space. void setEncodeSrgb(bool encode) { - if(encode != _encodeSrgb) + if (encode != _encodeSrgb) { _encodeSrgb = encode; resize(_width, _height, true); @@ -60,13 +60,13 @@ class MX_RENDERMSL_API MetalFramebuffer { return _encodeSrgb; } - + /// Return the framebuffer width unsigned int getWidth() const { return _width; } /// Return the framebuffer height unsigned int getHeight() const { return _height; } - + /// Bind the framebuffer for rendering. void bind(MTLRenderPassDescriptor* renderpassDesc); @@ -78,18 +78,18 @@ class MX_RENDERMSL_API MetalFramebuffer { return _colorTexture; } - + void setColorTexture(id newColorTexture) { auto sameDim = [](id tex0, id tex1) -> bool { - return [tex0 width] == [tex1 width] && - [tex0 height] == [tex1 height]; + return [tex0 width] == [tex1 width] && + [tex0 height] == [tex1 height]; }; - if((!_colorTextureOwned || sameDim(_colorTexture, newColorTexture)) && - sameDim(newColorTexture, _depthTexture)) + if ((!_colorTextureOwned || sameDim(_colorTexture, newColorTexture)) && + sameDim(newColorTexture, _depthTexture)) { - if(_colorTextureOwned) + if (_colorTextureOwned) [_colorTexture release]; _colorTexture = newColorTexture; } @@ -122,10 +122,10 @@ class MX_RENDERMSL_API MetalFramebuffer Image::BaseType _baseType; bool _encodeSrgb; - id _device = nil; + id _device = nil; id _colorTexture = nil; id _depthTexture = nil; - + bool _colorTextureOwned = false; }; diff --git a/source/MaterialXRenderMsl/MetalFramebuffer.mm b/source/MaterialXRenderMsl/MetalFramebuffer.mm index 432d533fd3..7309da6bfe 100644 --- a/source/MaterialXRenderMsl/MetalFramebuffer.mm +++ b/source/MaterialXRenderMsl/MetalFramebuffer.mm @@ -71,19 +71,19 @@ if (width != _width || _height != height || forceRecreate) { // Convert texture format to Metal - MTLDataType dataType; - if(pixelFormat == MTLPixelFormatInvalid) + MTLDataType dataType; + if (pixelFormat == MTLPixelFormatInvalid) MetalTextureHandler::mapTextureFormatToMetal(_baseType, _channelCount, _encodeSrgb, dataType, pixelFormat); MTLTextureDescriptor* texDescriptor = [MTLTextureDescriptor - texture2DDescriptorWithPixelFormat:pixelFormat - width:width - height:height - mipmapped:NO]; + texture2DDescriptorWithPixelFormat:pixelFormat + width:width + height:height + mipmapped:NO]; [texDescriptor setStorageMode:MTLStorageModePrivate]; - [texDescriptor setUsage:MTLTextureUsageRenderTarget|MTLTextureUsageShaderRead]; - - if(extColorTexture == nil) + [texDescriptor setUsage:MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite]; + + if (extColorTexture == nil) { _colorTexture = [_device newTextureWithDescriptor:texDescriptor]; _colorTextureOwned = true; @@ -93,7 +93,7 @@ _colorTexture = extColorTexture; _colorTextureOwned = false; } - + texDescriptor.pixelFormat = MTLPixelFormatDepth32Float; [texDescriptor setUsage:MTLTextureUsageRenderTarget]; _depthTexture = [_device newTextureWithDescriptor:texDescriptor]; @@ -108,13 +108,13 @@ [renderpassDesc.colorAttachments[0] setTexture:getColorTexture()]; [renderpassDesc.colorAttachments[0] setLoadAction:MTLLoadActionClear]; [renderpassDesc.colorAttachments[0] setStoreAction:MTLStoreActionStore]; - + [renderpassDesc.depthAttachment setTexture:getDepthTexture()]; [renderpassDesc.depthAttachment setClearDepth:1.0]; [renderpassDesc.depthAttachment setLoadAction:MTLLoadActionClear]; [renderpassDesc.depthAttachment setStoreAction:MTLStoreActionStore]; [renderpassDesc setStencilAttachment:nil]; - + [renderpassDesc setRenderTargetWidth:_width]; [renderpassDesc setRenderTargetHeight:_height]; } @@ -130,45 +130,45 @@ image = Image::create(_width, _height, _channelCount, _baseType); image->createResourceBuffer(); } - - if(cmdQueue == nil) + + if (cmdQueue == nil) { return image; } - - size_t bytesPerRow = _width*_channelCount*MetalTextureHandler::getTextureBaseTypeSize(_baseType); + + size_t bytesPerRow = _width * _channelCount * MetalTextureHandler::getTextureBaseTypeSize(_baseType); size_t bytesPerImage = _height * bytesPerRow; - + id buffer = [_device newBufferWithLength:bytesPerImage options:MTLResourceStorageModeShared]; - + id cmdBuffer = [cmdQueue commandBuffer]; - + id blitCmdEncoder = [cmdBuffer blitCommandEncoder]; [blitCmdEncoder copyFromTexture:_colorTexture sourceSlice:0 sourceLevel:0 sourceOrigin:MTLOriginMake(0, 0, 0) sourceSize:MTLSizeMake(_width, _height, 1) - toBuffer:buffer destinationOffset:0 + toBuffer:buffer + destinationOffset:0 destinationBytesPerRow:bytesPerRow destinationBytesPerImage:bytesPerImage options:MTLBlitOptionNone]; - - + [blitCmdEncoder endEncoding]; - + [cmdBuffer commit]; [cmdBuffer waitUntilCompleted]; std::vector imageData(bytesPerImage); memcpy(imageData.data(), [buffer contents], bytesPerImage); - - if([_colorTexture pixelFormat] == MTLPixelFormatBGRA8Unorm) + + if ([_colorTexture pixelFormat] == MTLPixelFormatBGRA8Unorm) { - for(unsigned int j = 0; j < _height; ++j) + for (unsigned int j = 0; j < _height; ++j) { unsigned int rawStart = j * (_width * _channelCount); - for(unsigned int i = 0; i < _width; ++i) + for (unsigned int i = 0; i < _width; ++i) { unsigned int offset = rawStart + _channelCount * i; unsigned char tmp = imageData[offset + 0]; @@ -177,7 +177,7 @@ } } } - + memcpy(image->getResourceBuffer(), imageData.data(), bytesPerImage); [buffer release]; diff --git a/source/MaterialXRenderMsl/MetalState.h b/source/MaterialXRenderMsl/MetalState.h index 15eacc360a..ff742b857c 100644 --- a/source/MaterialXRenderMsl/MetalState.h +++ b/source/MaterialXRenderMsl/MetalState.h @@ -11,29 +11,29 @@ #include #include -#import +#import #include +#include MATERIALX_NAMESPACE_BEGIN class MetalFramebuffer; // Shared pointer to a MetalFramebuffer using MetalFramebufferPtr = std::shared_ptr; -MATERIALX_NAMESPACE_END -struct MetalState +struct MX_RENDERMSL_API MetalState { static MetalState* getSingleton() { - if(!singleton) + if (!singleton) { singleton = std::unique_ptr(new MetalState()); } return singleton.get(); } - + MetalState(); - + void initialize(id mtlDevice, id mtlCmdQueue); void initLinearToSRGBKernel(); void triggerProgrammaticCapture(); @@ -42,36 +42,38 @@ struct MetalState void beginEncoder(MTLRenderPassDescriptor* renderpassDesc); void endEncoder(); void endCommandBuffer(); - - void waitForComplition(); - + + void waitForCompletion(); + MaterialX::MetalFramebufferPtr currentFramebuffer(); - + static std::unique_ptr singleton; - - id device = nil; - id cmdQueue = nil; - id cmdBuffer = nil; - id linearToSRGB_pso = nil; - id renderCmdEncoder = nil; + + id device = nil; + id cmdQueue = nil; + id cmdBuffer = nil; + id linearToSRGB_pso = nil; + id renderCmdEncoder = nil; std::stack framebufferStack; - + bool supportsTiledPipeline; - + id opaqueDepthStencilState = nil; id transparentDepthStencilState = nil; id envMapDepthStencilState = nil; - + std::condition_variable inFlightCV; - std::mutex inFlightMutex; - std::atomic inFlightCommandBuffers; + std::mutex inFlightMutex; + std::atomic inFlightCommandBuffers; }; -#define MTL(a) (MetalState::getSingleton()->a) -#define MTL_DEPTHSTENCIL_STATE(a) (MetalState::getSingleton()->a##DepthStencilState) -#define MTL_TRIGGER_CAPTURE MetalState::getSingleton()->triggerProgrammaticCapture() -#define MTL_STOP_CAPTURE MetalState::getSingleton()->stopProgrammaticCapture() -#define MTL_PUSH_FRAMEBUFFER(a) MetalState::getSingleton()->framebufferStack.push(a) -#define MTL_POP_FRAMEBUFFER(a) MetalState::getSingleton()->framebufferStack.pop() +MATERIALX_NAMESPACE_END + +#define MTL(a) (MaterialX::MetalState::getSingleton()->a) +#define MTL_DEPTHSTENCIL_STATE(a) (MaterialX::MetalState::getSingleton()->a##DepthStencilState) +#define MTL_TRIGGER_CAPTURE MaterialX::MetalState::getSingleton()->triggerProgrammaticCapture() +#define MTL_STOP_CAPTURE MaterialX::MetalState::getSingleton()->stopProgrammaticCapture() +#define MTL_PUSH_FRAMEBUFFER(a) MaterialX::MetalState::getSingleton()->framebufferStack.push(a) +#define MTL_POP_FRAMEBUFFER(a) MaterialX::MetalState::getSingleton()->framebufferStack.pop() #endif // MATERIALXVIEW_METALSTATE_H diff --git a/source/MaterialXRenderMsl/MetalState.mm b/source/MaterialXRenderMsl/MetalState.mm index 941b00c526..4ce170a6ba 100644 --- a/source/MaterialXRenderMsl/MetalState.mm +++ b/source/MaterialXRenderMsl/MetalState.mm @@ -8,6 +8,8 @@ #include +MATERIALX_NAMESPACE_BEGIN + std::unique_ptr MetalState::singleton = nullptr; MetalState::MetalState() @@ -18,7 +20,7 @@ { device = mtlDevice; cmdQueue = mtlCmdQueue; - + #ifdef MAC_OS_VERSION_11_0 if (@available(macOS 11.0, ios 14.0, *)) { @@ -27,20 +29,20 @@ #else supportsTiledPipeline = false; #endif - + MTLDepthStencilDescriptor* depthStencilDesc = [MTLDepthStencilDescriptor new]; - depthStencilDesc.depthWriteEnabled = true; + depthStencilDesc.depthWriteEnabled = true; depthStencilDesc.depthCompareFunction = MTLCompareFunctionLess; opaqueDepthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDesc]; - - depthStencilDesc.depthWriteEnabled = false; + + depthStencilDesc.depthWriteEnabled = false; depthStencilDesc.depthCompareFunction = MTLCompareFunctionLess; transparentDepthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDesc]; - - depthStencilDesc.depthWriteEnabled = true; + + depthStencilDesc.depthWriteEnabled = true; depthStencilDesc.depthCompareFunction = MTLCompareFunctionAlways; envMapDepthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDesc]; - + initLinearToSRGBKernel(); } @@ -55,52 +57,52 @@ #endif options.languageVersion = MTLLanguageVersion2_0; options.fastMathEnabled = true; - + #ifdef MAC_OS_VERSION_11_0 bool useTiledPipeline = supportsTiledPipeline; - if(useTiledPipeline) + if (useTiledPipeline) { - if(@available(macOS 11.0, ios 14.0, *)) + if (@available(macOS 11.0, ios 14.0, *)) { NSString* linearToSRGB_kernel = - @"#include \n" - "#include \n" - " \n" - "using namespace metal; \n" - " \n" - "struct RenderTarget { \n" - " half4 colorTarget [[color(0)]]; \n" - "}; \n" - " \n" - " \n" - " \n" - "half4 linearToSRGB(half4 color_linear) \n" - "{ \n" - " half4 color_srgb; \n" - " for(int i = 0; i < 3; ++i) \n" - " color_srgb[i] = (color_linear[i] < 0.0031308) ? \n" - " (12.92 * color_linear[i]) : \n" - " (1.055 * pow(color_linear[i], 1.0h / 2.2h) - 0.055); \n" - " color_srgb[3] = color_linear[3]; \n" - " return color_srgb; \n" - "} \n" - " \n" - "kernel void LinearToSRGB_kernel( \n" - " imageblock imageBlock, \n" - " ushort2 tid [[ thread_position_in_threadgroup ]]) \n" - "{ \n" - " RenderTarget linearValue = imageBlock.read(tid); \n" - " RenderTarget srgbValue; \n" - " srgbValue.colorTarget = linearToSRGB(linearValue.colorTarget); \n" - " imageBlock.write(srgbValue, tid); \n" - "} \n"; - + @"#include \n" + "#include \n" + " \n" + "using namespace metal; \n" + " \n" + "struct RenderTarget { \n" + " half4 colorTarget [[color(0)]]; \n" + "}; \n" + " \n" + " \n" + " \n" + "half4 linearToSRGB(half4 color_linear) \n" + "{ \n" + " half4 color_srgb; \n" + " for(int i = 0; i < 3; ++i) \n" + " color_srgb[i] = (color_linear[i] < 0.0031308) ? \n" + " (12.92 * color_linear[i]) : \n" + " (1.055 * pow(color_linear[i], 1.0h / 2.2h) - 0.055); \n" + " color_srgb[3] = color_linear[3]; \n" + " return color_srgb; \n" + "} \n" + " \n" + "kernel void LinearToSRGB_kernel( \n" + " imageblock imageBlock, \n" + " ushort2 tid [[ thread_position_in_threadgroup ]]) \n" + "{ \n" + " RenderTarget linearValue = imageBlock.read(tid); \n" + " RenderTarget srgbValue; \n" + " srgbValue.colorTarget = linearToSRGB(linearValue.colorTarget); \n" + " imageBlock.write(srgbValue, tid); \n" + "} \n"; + id library = [device newLibraryWithSource:linearToSRGB_kernel options:options error:&error]; id function = [library newFunctionWithName:@"LinearToSRGB_kernel"]; - + MTLTileRenderPipelineDescriptor* renderPipelineDescriptor = [MTLTileRenderPipelineDescriptor new]; [renderPipelineDescriptor setRasterSampleCount:1]; - [[renderPipelineDescriptor colorAttachments][0] setPixelFormat:MTLPixelFormatBGRA8Unorm]; + [[renderPipelineDescriptor colorAttachments][0] setPixelFormat:MTLPixelFormatRGBA16Float]; [renderPipelineDescriptor setTileFunction:function]; linearToSRGB_pso = [device newRenderPipelineStateWithTileDescriptor:renderPipelineDescriptor options:0 reflection:nil error:&error]; } @@ -109,67 +111,67 @@ useTiledPipeline = false; } } - - if(!useTiledPipeline) + + if (!useTiledPipeline) #endif { NSString* linearToSRGB_kernel = - @"#include \n" - "#include \n" - " \n" - "using namespace metal; \n" - " \n" - "struct VSOutput \n" - "{ \n" - " float4 position [[position]]; \n" - "}; \n" - " \n" - "vertex VSOutput VertexMain(uint vertexId [[ vertex_id ]]) \n" - "{ \n" - " VSOutput vsOut; \n" - " \n" - " switch(vertexId) \n" - " { \n" - " case 0: vsOut.position = float4(-1, -1, 0.5, 1); break; \n" - " case 1: vsOut.position = float4(-1, 3, 0.5, 1); break; \n" - " case 2: vsOut.position = float4( 3, -1, 0.5, 1); break; \n" - " }; \n" - " \n" - " return vsOut; \n" - "} \n" - " \n" - "half4 linearToSRGB(half4 color_linear) \n" - "{ \n" - " half4 color_srgb; \n" - " for(int i = 0; i < 3; ++i) \n" - " color_srgb[i] = (color_linear[i] < 0.0031308) ? \n" - " (12.92 * color_linear[i]) : \n" - " (1.055 * pow(color_linear[i], 1.0h / 2.2h) - 0.055);\n" - " color_srgb[3] = color_linear[3]; \n" - " return color_srgb; \n" - "} \n" - " \n" - "fragment half4 FragmentMain( \n" - " texture2d inputTex [[ texture(0) ]], \n" - " float4 fragCoord [[ position ]] \n" - ") \n" - "{ \n" - " constexpr sampler ss( \n" - " coord::pixel, \n" - " address::clamp_to_border, \n" - " filter::linear); \n" - " return linearToSRGB(inputTex.sample(ss, fragCoord.xy)); \n" - "} \n"; + @"#include \n" + "#include \n" + " \n" + "using namespace metal; \n" + " \n" + "struct VSOutput \n" + "{ \n" + " float4 position [[position]]; \n" + "}; \n" + " \n" + "vertex VSOutput VertexMain(uint vertexId [[ vertex_id ]]) \n" + "{ \n" + " VSOutput vsOut; \n" + " \n" + " switch(vertexId) \n" + " { \n" + " case 0: vsOut.position = float4(-1, -1, 0.5, 1); break; \n" + " case 1: vsOut.position = float4(-1, 3, 0.5, 1); break; \n" + " case 2: vsOut.position = float4( 3, -1, 0.5, 1); break; \n" + " }; \n" + " \n" + " return vsOut; \n" + "} \n" + " \n" + "half4 linearToSRGB(half4 color_linear) \n" + "{ \n" + " half4 color_srgb; \n" + " for(int i = 0; i < 3; ++i) \n" + " color_srgb[i] = (color_linear[i] < 0.0031308) ? \n" + " (12.92 * color_linear[i]) : \n" + " (1.055 * pow(color_linear[i], 1.0h / 2.2h) - 0.055);\n" + " color_srgb[3] = color_linear[3]; \n" + " return color_srgb; \n" + "} \n" + " \n" + "fragment half4 FragmentMain( \n" + " texture2d inputTex [[ texture(0) ]], \n" + " float4 fragCoord [[ position ]] \n" + ") \n" + "{ \n" + " constexpr sampler ss( \n" + " coord::pixel, \n" + " address::clamp_to_border, \n" + " filter::linear); \n" + " return linearToSRGB(inputTex.sample(ss, fragCoord.xy)); \n" + "} \n"; id library = [device newLibraryWithSource:linearToSRGB_kernel options:options error:&error]; id vertexfunction = [library newFunctionWithName:@"VertexMain"]; id Fragmentfunction = [library newFunctionWithName:@"FragmentMain"]; - + MTLRenderPipelineDescriptor* renderPipelineDesc = [MTLRenderPipelineDescriptor new]; [renderPipelineDesc setVertexFunction:vertexfunction]; [renderPipelineDesc setFragmentFunction:Fragmentfunction]; - [[renderPipelineDesc colorAttachments][0] setPixelFormat:MTLPixelFormatBGRA8Unorm]; + [[renderPipelineDesc colorAttachments][0] setPixelFormat:MTLPixelFormatRGBA16Float]; [renderPipelineDesc setDepthAttachmentPixelFormat:MTLPixelFormatDepth32Float]; linearToSRGB_pso = [device newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&error]; } @@ -177,13 +179,13 @@ void MetalState::triggerProgrammaticCapture() { - MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager]; + MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager]; MTLCaptureDescriptor* captureDescriptor = [MTLCaptureDescriptor new]; - + [captureDescriptor setCaptureObject:device]; - + NSError* error = nil; - if(![captureManager startCaptureWithDescriptor:captureDescriptor error:&error]) + if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error]) { NSLog(@"Failed to start capture, error %@", error); } @@ -204,7 +206,7 @@ void MetalState::beginEncoder(MTLRenderPassDescriptor* renderpassDesc) { renderCmdEncoder = [cmdBuffer - renderCommandEncoderWithDescriptor:renderpassDesc]; + renderCommandEncoderWithDescriptor:renderpassDesc]; } void MetalState::endEncoder() @@ -216,18 +218,22 @@ { endEncoder(); [cmdBuffer addCompletedHandler:^(id _Nonnull) { - inFlightCommandBuffers--; - inFlightCV.notify_one(); + inFlightCommandBuffers--; + inFlightCV.notify_one(); }]; [cmdBuffer commit]; [cmdBuffer waitUntilCompleted]; } -void MetalState::waitForComplition() +void MetalState::waitForCompletion() { std::unique_lock lock(inFlightMutex); - while (inFlightCommandBuffers != 0){ - inFlightCV.wait(lock, [this]{ return inFlightCommandBuffers.load() == 0; }); + while (inFlightCommandBuffers != 0) + { + inFlightCV.wait(lock, [this] + { + return inFlightCommandBuffers.load() == 0; + }); } } @@ -235,3 +241,5 @@ { return framebufferStack.top(); } + +MATERIALX_NAMESPACE_END diff --git a/source/MaterialXRenderMsl/MetalTextureHandler.h b/source/MaterialXRenderMsl/MetalTextureHandler.h index c78469a4ce..7504c951ea 100644 --- a/source/MaterialXRenderMsl/MetalTextureHandler.h +++ b/source/MaterialXRenderMsl/MetalTextureHandler.h @@ -28,34 +28,35 @@ using MetalTextureHandlerPtr = std::shared_ptr; class MX_RENDERMSL_API MetalTextureHandler : public ImageHandler { friend class MslProgram; + public: static MetalTextureHandlerPtr create(id device, ImageLoaderPtr imageLoader) { return MetalTextureHandlerPtr(new MetalTextureHandler(device, imageLoader)); } - /// This method binds image and its corresponding sampling properties. /// It also creates the underlying resource if needed. /// Actual binding of texture and sampler to command encoder happens autoamt bool bindImage(ImagePtr image, const ImageSamplingProperties& samplingProperties) override; - -protected: + + protected: /// Bind an image. This method will bind the texture to an active texture /// unit as defined by the corresponding image description. The method /// will fail if there are not enough available image units to bind to. bool bindImage(id renderCmdEncoder, int textureUnit, ImagePtr image); -public: + + public: id getSamplerState(const ImageSamplingProperties& samplingProperties); - + /// Unbind an image. bool unbindImage(ImagePtr image) override; - id getMTLTextureForImage(unsigned int index) const; + id getMTLTextureForImage(unsigned int index) const; id getMTLSamplerStateForImage(unsigned int index); - + /// Create rendering resources for the given image. bool createRenderResources(ImagePtr image, bool generateMipMaps, bool useAsRenderTarget = false) override; @@ -75,9 +76,9 @@ class MX_RENDERMSL_API MetalTextureHandler : public ImageHandler /// Utility to map generic texture properties to Metal texture formats. static void mapTextureFormatToMetal(Image::BaseType baseType, unsigned int channelCount, bool srgb, MTLDataType& dataType, MTLPixelFormat& pixelFormat); - + static size_t getTextureBaseTypeSize(Image::BaseType baseType); - + id getAssociatedMetalTexture(ImagePtr image); protected: @@ -86,11 +87,11 @@ class MX_RENDERMSL_API MetalTextureHandler : public ImageHandler protected: std::vector _boundTextureLocations; - + std::unordered_map> _metalTextureMap; std::unordered_map> _imageBindingInfo; std::unordered_map, ImageSamplingKeyHasher> _imageSamplerStateMap; - + id _device = nil; }; diff --git a/source/MaterialXRenderMsl/MetalTextureHandler.mm b/source/MaterialXRenderMsl/MetalTextureHandler.mm index ab8da46f1f..6a8b5c2ef4 100644 --- a/source/MaterialXRenderMsl/MetalTextureHandler.mm +++ b/source/MaterialXRenderMsl/MetalTextureHandler.mm @@ -35,7 +35,7 @@ id MetalTextureHandler::getSamplerState(const ImageSamplingProperties& samplingProperties) { - if(_imageSamplerStateMap.find(samplingProperties) == _imageSamplerStateMap.end()) + if (_imageSamplerStateMap.find(samplingProperties) == _imageSamplerStateMap.end()) { MTLSamplerDescriptor* samplerDesc = [MTLSamplerDescriptor new]; [samplerDesc setSAddressMode:mapAddressModeToMetal(samplingProperties.uaddressMode)]; @@ -43,17 +43,17 @@ [samplerDesc setTAddressMode:mapAddressModeToMetal(samplingProperties.vaddressMode)]; [samplerDesc setBorderColor:samplingProperties.defaultColor[0] == 0 ? MTLSamplerBorderColorOpaqueBlack : MTLSamplerBorderColorOpaqueWhite]; MTLSamplerMinMagFilter minmagFilter; - MTLSamplerMipFilter mipFilter; + MTLSamplerMipFilter mipFilter; mapFilterTypeToMetal(samplingProperties.filterType, samplingProperties.enableMipmaps, minmagFilter, mipFilter); // Magnification filters are more restrictive than minification [samplerDesc setMagFilter:MTLSamplerMinMagFilterLinear]; [samplerDesc setMinFilter:minmagFilter]; [samplerDesc setMipFilter:mipFilter]; [samplerDesc setMaxAnisotropy:16]; - + _imageSamplerStateMap[samplingProperties] = [_device newSamplerStateWithDescriptor:samplerDesc]; } - + return _imageSamplerStateMap[samplingProperties]; } @@ -70,7 +70,7 @@ } _boundTextureLocations[textureUnit] = image->getResourceId(); - + [renderCmdEncoder setFragmentTexture:_metalTextureMap[image->getResourceId()] atIndex:textureUnit]; [renderCmdEncoder setFragmentSamplerState:getSamplerState(_imageBindingInfo[image->getResourceId()].second) atIndex:textureUnit]; @@ -79,10 +79,10 @@ id MetalTextureHandler::getAssociatedMetalTexture(ImagePtr image) { - if(image) + if (image) { auto tex = _metalTextureMap.find(image->getResourceId()); - if(tex != _metalTextureMap.end()) + if (tex != _metalTextureMap.end()) return (tex->second); } return nil; @@ -91,23 +91,23 @@ id MetalTextureHandler::getMTLTextureForImage(unsigned int index) const { auto imageInfo = _imageBindingInfo.find(index); - if(imageInfo != _imageBindingInfo.end()) + if (imageInfo != _imageBindingInfo.end()) { - if(!imageInfo->second.first) + if (!imageInfo->second.first) return nil; - + auto metalTexture = _metalTextureMap.find(imageInfo->second.first->getResourceId()); - if(metalTexture != _metalTextureMap.end()) + if (metalTexture != _metalTextureMap.end()) return metalTexture->second; } - + return nil; } id MetalTextureHandler::getMTLSamplerStateForImage(unsigned int index) { auto imageInfo = _imageBindingInfo.find(index); - if(imageInfo != _imageBindingInfo.end()) + if (imageInfo != _imageBindingInfo.end()) { return getSamplerState(imageInfo->second.second); } @@ -131,44 +131,44 @@ bool MetalTextureHandler::createRenderResources(ImagePtr image, bool generateMipMaps, bool useAsRenderTarget) { id texture = nil; - + MTLPixelFormat pixelFormat; - MTLDataType dataType; - + MTLDataType dataType; + if (image->getResourceId() == MslProgram::UNDEFINED_METAL_RESOURCE_ID) { static unsigned int resourceId = 0; ++resourceId; - + mapTextureFormatToMetal(image->getBaseType(), image->getChannelCount(), false, dataType, pixelFormat); - + MTLTextureDescriptor* texDesc = [MTLTextureDescriptor new]; [texDesc setTextureType:MTLTextureType2D]; texDesc.width = image->getWidth(); texDesc.height = image->getHeight(); texDesc.mipmapLevelCount = generateMipMaps ? image->getMaxMipCount() : 1; texDesc.usage = MTLTextureUsageShaderRead | - (useAsRenderTarget ? MTLTextureUsageRenderTarget : 0); + (useAsRenderTarget ? MTLTextureUsageRenderTarget : 0); texDesc.resourceOptions = MTLResourceStorageModePrivate; texDesc.pixelFormat = pixelFormat; - if(generateMipMaps) + if (generateMipMaps) { - if(image->getChannelCount() == 1) + if (image->getChannelCount() == 1) { texDesc.swizzle = MTLTextureSwizzleChannelsMake( - MTLTextureSwizzleRed, - MTLTextureSwizzleRed, - MTLTextureSwizzleRed, - MTLTextureSwizzleRed); + MTLTextureSwizzleRed, + MTLTextureSwizzleRed, + MTLTextureSwizzleRed, + MTLTextureSwizzleRed); } - else if(image->getChannelCount() == 2) + else if (image->getChannelCount() == 2) { texDesc.swizzle = MTLTextureSwizzleChannelsMake( - MTLTextureSwizzleRed, - MTLTextureSwizzleGreen, - MTLTextureSwizzleRed, - MTLTextureSwizzleGreen); + MTLTextureSwizzleRed, + MTLTextureSwizzleGreen, + MTLTextureSwizzleRed, + MTLTextureSwizzleGreen); } } texture = [_device newTextureWithDescriptor:texDesc]; @@ -179,18 +179,17 @@ { mapTextureFormatToMetal(image->getBaseType(), image->getChannelCount(), false, dataType, pixelFormat); - + texture = _metalTextureMap[image->getResourceId()]; } - id cmdQueue = [_device newCommandQueue]; id cmdBuffer = [cmdQueue commandBuffer]; - + id blitCmdEncoder = [cmdBuffer blitCommandEncoder]; - + NSUInteger channelCount = image->getChannelCount(); - + NSUInteger sourceBytesPerRow = image->getWidth() * channelCount * @@ -198,63 +197,64 @@ NSUInteger sourceBytesPerImage = sourceBytesPerRow * image->getHeight(); - - std::vector rearrangedDataF; + + std::vector rearrangedDataF; std::vector rearrangedDataC; void* imageData = image->getResourceBuffer(); - + if ((pixelFormat == MTLPixelFormatRGBA32Float || pixelFormat == MTLPixelFormatRGBA8Unorm) && channelCount == 3) { bool isFloat = pixelFormat == MTLPixelFormatRGBA32Float; - - sourceBytesPerRow = sourceBytesPerRow / 3 * 4; + + sourceBytesPerRow = sourceBytesPerRow / 3 * 4; sourceBytesPerImage = sourceBytesPerImage / 3 * 4; - + size_t srcIdx = 0; - - if(isFloat) + + if (isFloat) { rearrangedDataF.resize(sourceBytesPerImage / sizeof(float)); - for(size_t dstIdx = 0; dstIdx < rearrangedDataF.size(); ++dstIdx) + for (size_t dstIdx = 0; dstIdx < rearrangedDataF.size(); ++dstIdx) { - if((dstIdx & 0x3) == 3) + if ((dstIdx & 0x3) == 3) { rearrangedDataF[dstIdx] = 1.0f; continue; } - - rearrangedDataF[dstIdx] = ((float*)imageData)[srcIdx++]; + + rearrangedDataF[dstIdx] = ((float*) imageData)[srcIdx++]; } - + imageData = rearrangedDataF.data(); } else { rearrangedDataC.resize(sourceBytesPerImage); - for(size_t dstIdx = 0; dstIdx < rearrangedDataC.size(); ++dstIdx) + for (size_t dstIdx = 0; dstIdx < rearrangedDataC.size(); ++dstIdx) { - if((dstIdx & 0x3) == 3) + if ((dstIdx & 0x3) == 3) { rearrangedDataC[dstIdx] = 255; continue; } - - rearrangedDataC[dstIdx] = ((unsigned char*)imageData)[srcIdx++]; + + rearrangedDataC[dstIdx] = ((unsigned char*) imageData)[srcIdx++]; } - + imageData = rearrangedDataC.data(); } - + channelCount = 4; } - + id buffer = nil; - if(imageData) + if (imageData) { buffer = [_device newBufferWithBytes:imageData - length:sourceBytesPerImage - options:MTLStorageModeShared]; - [blitCmdEncoder copyFromBuffer:buffer sourceOffset:0 + length:sourceBytesPerImage + options:MTLStorageModeShared]; + [blitCmdEncoder copyFromBuffer:buffer + sourceOffset:0 sourceBytesPerRow:sourceBytesPerRow sourceBytesPerImage:sourceBytesPerImage sourceSize:MTLSizeMake(image->getWidth(), image->getHeight(), 1) @@ -263,26 +263,26 @@ destinationLevel:0 destinationOrigin:MTLOriginMake(0, 0, 0)]; } - - if(generateMipMaps && image->getMaxMipCount() > 1) + + if (generateMipMaps && image->getMaxMipCount() > 1) [blitCmdEncoder generateMipmapsForTexture:texture]; - + [blitCmdEncoder endEncoding]; - + [cmdBuffer commit]; [cmdBuffer waitUntilCompleted]; - - if(buffer) + + if (buffer) [buffer release]; - + return true; } - + void MetalTextureHandler::releaseRenderResources(ImagePtr image) { - if(!image) + if (!image) return; - + if (image->getResourceId() == MslProgram::UNDEFINED_METAL_RESOURCE_ID) { return; @@ -291,7 +291,7 @@ unbindImage(image); unsigned int resourceId = image->getResourceId(); auto tex = _metalTextureMap.find(resourceId); - if(tex != _metalTextureMap.end()) + if (tex != _metalTextureMap.end()) { [tex->second release]; } @@ -339,11 +339,11 @@ void MetalTextureHandler::mapFilterTypeToMetal(ImageSamplingProperties::FilterType filterTypeEnum, bool enableMipmaps, MTLSamplerMinMagFilter& minMagFilter, MTLSamplerMipFilter& mipFilter) { - if(enableMipmaps) + if (enableMipmaps) { - if(filterTypeEnum == ImageSamplingProperties::FilterType::LINEAR || - filterTypeEnum == ImageSamplingProperties::FilterType::CUBIC || - filterTypeEnum == ImageSamplingProperties::FilterType::UNSPECIFIED) + if (filterTypeEnum == ImageSamplingProperties::FilterType::LINEAR || + filterTypeEnum == ImageSamplingProperties::FilterType::CUBIC || + filterTypeEnum == ImageSamplingProperties::FilterType::UNSPECIFIED) { minMagFilter = MTLSamplerMinMagFilterLinear; mipFilter = MTLSamplerMipFilterLinear; @@ -356,9 +356,9 @@ } else { - if(filterTypeEnum == ImageSamplingProperties::FilterType::LINEAR || - filterTypeEnum == ImageSamplingProperties::FilterType::CUBIC || - filterTypeEnum == ImageSamplingProperties::FilterType::UNSPECIFIED) + if (filterTypeEnum == ImageSamplingProperties::FilterType::LINEAR || + filterTypeEnum == ImageSamplingProperties::FilterType::CUBIC || + filterTypeEnum == ImageSamplingProperties::FilterType::UNSPECIFIED) { minMagFilter = MTLSamplerMinMagFilterLinear; mipFilter = MTLSamplerMipFilterNotMipmapped; @@ -372,7 +372,7 @@ } void MetalTextureHandler::mapTextureFormatToMetal(Image::BaseType baseType, unsigned int channelCount, bool srgb, - MTLDataType& dataType, MTLPixelFormat& pixelFormat) + MTLDataType& dataType, MTLPixelFormat& pixelFormat) { if (baseType == Image::BaseType::UINT8) { @@ -413,7 +413,7 @@ switch (channelCount) { case 4: pixelFormat = MTLPixelFormatRGBA32Float; dataType = MTLDataTypeFloat4; break; - case 3: pixelFormat = MTLPixelFormatRGBA32Float; dataType = MTLDataTypeFloat3; break; + case 3: pixelFormat = MTLPixelFormatRGBA32Float; dataType = MTLDataTypeFloat3; break; case 2: pixelFormat = MTLPixelFormatRG32Float; dataType = MTLDataTypeFloat2; break; case 1: pixelFormat = MTLPixelFormatR32Float; dataType = MTLDataTypeFloat; break; default: throw Exception("Unsupported channel count in mapTextureFormatToMetal"); @@ -445,5 +445,4 @@ } } - MATERIALX_NAMESPACE_END diff --git a/source/MaterialXRenderMsl/MslMaterial.h b/source/MaterialXRenderMsl/MslMaterial.h index cc80af1e18..0f6e45a9ce 100644 --- a/source/MaterialXRenderMsl/MslMaterial.h +++ b/source/MaterialXRenderMsl/MslMaterial.h @@ -26,7 +26,8 @@ using MslMaterialPtr = std::shared_ptr; class MX_RENDERMSL_API MslMaterial : public ShaderMaterial { public: - MslMaterial() : ShaderMaterial() + MslMaterial() : + ShaderMaterial() { } ~MslMaterial() { } @@ -47,7 +48,7 @@ class MX_RENDERMSL_API MslMaterial : public ShaderMaterial /// Generate a shader from the given hardware shader. bool generateShader(ShaderPtr hwShader) override; - + /// Copy shader from one material to this one void copyShader(MaterialPtr material) override { @@ -113,9 +114,10 @@ class MX_RENDERMSL_API MslMaterial : public ShaderMaterial GeometryHandlerPtr geometryHandler, ImageHandlerPtr imageHandler, LightHandlerPtr lightHandler); + protected: void clearShader() override; - + protected: MslProgramPtr _glProgram; }; diff --git a/source/MaterialXRenderMsl/MslMaterial.mm b/source/MaterialXRenderMsl/MslMaterial.mm index 4177403a99..eb13ea7900 100644 --- a/source/MaterialXRenderMsl/MslMaterial.mm +++ b/source/MaterialXRenderMsl/MslMaterial.mm @@ -38,7 +38,7 @@ } // TODO: - // Here we set new source code on the _glProgram without rebuilding + // Here we set new source code on the _glProgram without rebuilding // the _hwShader instance. So the _hwShader is not in sync with the // _glProgram after this operation. _glProgram = MslProgram::create(); @@ -105,19 +105,19 @@ } void MslMaterial::prepareUsedResources(CameraPtr cam, - GeometryHandlerPtr geometryHandler, - ImageHandlerPtr imageHandler, - LightHandlerPtr lightHandler) + GeometryHandlerPtr geometryHandler, + ImageHandlerPtr imageHandler, + LightHandlerPtr lightHandler) { if (!_glProgram) { return; } - + _glProgram->prepareUsedResources(MTL(renderCmdEncoder), - cam, geometryHandler, - imageHandler, - lightHandler); + cam, geometryHandler, + imageHandler, + lightHandler); } void MslMaterial::bindMesh(MeshPtr mesh) @@ -176,14 +176,14 @@ _boundImages.clear(); _glProgram->setEnableMipMaps(enableMipmaps); - + // Texture and Samplers being bound to the right texture and sampler in MslPipelineStateObject automatically. } ImagePtr MslMaterial::bindImage(const FilePath& filePath, - const std::string& uniformName, - ImageHandlerPtr imageHandler, - const ImageSamplingProperties& samplingProperties) + const std::string& uniformName, + ImageHandlerPtr imageHandler, + const ImageSamplingProperties& samplingProperties) { if (!_glProgram) { @@ -203,8 +203,8 @@ } void MslMaterial::bindLighting(LightHandlerPtr lightHandler, - ImageHandlerPtr imageHandler, - const ShadowState& shadowState) + ImageHandlerPtr imageHandler, + const ShadowState& shadowState) { if (!_glProgram) { @@ -239,7 +239,7 @@ _glProgram->bindTexture(imageHandler, TEXTURE_NAME(HW::AMB_OCC_MAP), shadowState.ambientOcclusionMap, samplingProperties); - + _glProgram->bindUniform(HW::AMB_OCC_GAIN, Value::createValue(shadowState.ambientOcclusionGain)); } } @@ -253,10 +253,10 @@ MeshIndexBuffer& indexData = part->getIndices(); [MTL(renderCmdEncoder) drawIndexedPrimitives:MTLPrimitiveTypeTriangle - indexCount:indexData.size() - indexType:MTLIndexTypeUInt32 - indexBuffer:_glProgram->getIndexBuffer(part) - indexBufferOffset:0]; + indexCount:indexData.size() + indexType:MTLIndexTypeUInt32 + indexBuffer:_glProgram->getIndexBuffer(part) + indexBufferOffset:0]; } void MslMaterial::unbindGeometry() @@ -288,16 +288,15 @@ if (publicUniforms) { // Scan block based on path match predicate - port = publicUniforms->find( - [path](ShaderPort* port) - { - return (port && stringEndsWith(port->getPath(), path)); - }); + port = publicUniforms->find([path](ShaderPort* port) + { + return (port && stringEndsWith(port->getPath(), path)); + }); // Check if the uniform exists in the shader program if (port && !_glProgram->getUniformsList().count( - publicUniforms->getInstance() + "." + - port->getVariable())) + publicUniforms->getInstance() + "." + + port->getVariable())) { port = nullptr; } @@ -319,7 +318,7 @@ { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); + uniform->setValue(uniform->getType().createValueFromStrings(valueString)); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); @@ -335,4 +334,3 @@ } MATERIALX_NAMESPACE_END - diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.h b/source/MaterialXRenderMsl/MslPipelineStateObject.h index 2f54abea22..a823662f5f 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.h +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.h @@ -99,14 +99,14 @@ class MX_RENDERMSL_API MslProgram string typeString; /// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during /// shader generation. - MaterialX::ValuePtr value; + MaterialX::ConstValuePtr value; /// Is this a constant bool isConstant; /// Element path (if any) string path; /// Unit string unit; - /// Colorspace + /// Colorspace string colorspace; /// Program input constructor @@ -116,7 +116,8 @@ class MX_RENDERMSL_API MslProgram size(inputSize), isConstant(false), path(inputPath) - { } + { + } }; /// Program input structure shared pointer type using InputPtr = std::shared_ptr; @@ -153,7 +154,7 @@ class MX_RENDERMSL_API MslProgram /// @param renderCmdEncoder encoder that binds the pipeline state object. /// @return False if failed bool bind(id renderCmdEncoder); - + /// Bind inputs /// @param renderCmdEncoder encoder that inputs will be bound to. /// @param cam Camera object use to view the object @@ -162,10 +163,10 @@ class MX_RENDERMSL_API MslProgram /// @param lightHandler /// @return void - No return value void prepareUsedResources(id renderCmdEncoder, - CameraPtr cam, - GeometryHandlerPtr geometryHandler, - ImageHandlerPtr imageHandler, - LightHandlerPtr lightHandler); + CameraPtr cam, + GeometryHandlerPtr geometryHandler, + ImageHandlerPtr imageHandler, + LightHandlerPtr lightHandler); /// Return true if a uniform with the given name is present. bool hasUniform(const string& name); @@ -188,15 +189,15 @@ class MX_RENDERMSL_API MslProgram /// Bind input geometry streams void bindMesh(id renderCmdEncoder, MeshPtr mesh); - + /// Queries the index buffer assinged to a mesh partition - id getIndexBuffer(MeshPartitionPtr mesh) { - if(_indexBufferIds.find(mesh) != _indexBufferIds.end()) + id getIndexBuffer(MeshPartitionPtr mesh) + { + if (_indexBufferIds.find(mesh) != _indexBufferIds.end()) return _indexBufferIds[mesh]; return nil; } - /// Unbind any bound geometry void unbindGeometry(); @@ -204,7 +205,7 @@ class MX_RENDERMSL_API MslProgram void bindTextures(id renderCmdEncoder, LightHandlerPtr lightHandler, ImageHandlerPtr imageHandler); - + void bindTexture(ImageHandlerPtr imageHandler, string shaderTextureName, ImagePtr imagePtr, @@ -215,17 +216,17 @@ class MX_RENDERMSL_API MslProgram /// Bind view information void bindViewInformation(CameraPtr camera); - + /// Bind time and frame void bindTimeAndFrame(float time = 1.0f, float frame = 1.0f); /// @} /// @name Utilities /// @{ - + /// Returns if alpha blending is enabled. bool isTransparent() const { return _alphaBlendingEnabled; } - + /// Specify textures bound to this program shouldn't be mip mapped. void setEnableMipMaps(bool enableMipMapping) { _enableMipMapping = enableMipMapping; } @@ -255,7 +256,7 @@ class MX_RENDERMSL_API MslProgram // Utility to find a uniform value in an uniform list. // If uniform cannot be found a null pointer will be return. - ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); + ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); // Bind an individual texture to a program uniform location ImagePtr bindTexture(id renderCmdEncoder, @@ -263,13 +264,13 @@ class MX_RENDERMSL_API MslProgram const FilePath& filePath, ImageSamplingProperties samplingProperties, ImageHandlerPtr imageHandler); - + // Bind an individual texture to a program uniform location ImagePtr bindTexture(id renderCmdEncoder, unsigned int uniformLocation, ImagePtr imagePtr, ImageHandlerPtr imageHandler); - + void bindUniformBuffers(id renderCmdEncoder, LightHandlerPtr lightHandler, CameraPtr camera); @@ -294,7 +295,7 @@ class MX_RENDERMSL_API MslProgram std::unordered_map _globalUniformNameList; // List of program input attributes InputMap _attributeList; - + std::unordered_map _explicitBoundImages; // Hardware shader (if any) used for program creation @@ -309,18 +310,18 @@ class MX_RENDERMSL_API MslProgram // Program texture map std::unordered_map _programTextures; - + // Metal Device Object id _device = nil; - + // Currently bound mesh MeshPtr _boundMesh = nullptr; bool _alphaBlendingEnabled = false; - + float _time = 0.0f; float _frame = 0.0f; - + bool _enableMipMapping = true; }; diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.mm b/source/MaterialXRenderMsl/MslPipelineStateObject.mm index c570b68fc4..470fa549b2 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.mm +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.mm @@ -61,7 +61,7 @@ // Extract out the shader code per stage _shader = shader; - for (size_t i =0; inumStages(); ++i) + for (size_t i = 0; i < shader->numStages(); ++i) { const ShaderStage& stage = shader->getStage(i); addStage(stage.getName(), stage.getSourceCode()); @@ -96,7 +96,7 @@ MTLVertexFormat GetMetalFormatFromMetalType(MTLDataType type) { - switch(type) + switch (type) { case MTLDataTypeFloat : return MTLVertexFormatFloat; case MTLDataTypeFloat2: return MTLVertexFormatFloat2; @@ -113,10 +113,10 @@ MTLVertexFormat GetMetalFormatFromMetalType(MTLDataType type) int GetStrideOfMetalType(MTLDataType type) { - switch(type) + switch (type) { case MTLDataTypeInt: - case MTLDataTypeFloat : return 1 * 4; + case MTLDataTypeFloat: return 1 * 4; case MTLDataTypeInt2: case MTLDataTypeFloat2: return 2 * 4; case MTLDataTypeInt3: @@ -125,7 +125,7 @@ int GetStrideOfMetalType(MTLDataType type) case MTLDataTypeFloat4: return 4 * 4; default: return 0; } - + return 0; } @@ -135,9 +135,9 @@ int GetStrideOfMetalType(MTLDataType type) const string errorType("MSL program creation error."); NSError* error = nil; - + reset(); - + _device = device; unsigned int stagesBuilt = 0; @@ -147,7 +147,7 @@ int GetStrideOfMetalType(MTLDataType type) if (it.second.length()) desiredStages++; } - + MTLCompileOptions* options = [MTLCompileOptions new]; #ifdef MAC_OS_VERSION_11_0 if (@available(macOS 11.0, ios 14.0, *)) @@ -160,31 +160,31 @@ int GetStrideOfMetalType(MTLDataType type) // Create vertex shader id vertexShaderId = nil; { - string &vertexShaderSource = _stages[Stage::VERTEX]; + string& vertexShaderSource = _stages[Stage::VERTEX]; if (vertexShaderSource.length() < 1) { errors.push_back("Vertex Shader is empty."); return nil; } - + NSString* sourcCode = [NSString stringWithUTF8String:vertexShaderSource.c_str()]; id library = [device newLibraryWithSource:sourcCode options:options error:&error]; - - if(library == nil) + + if (library == nil) { errors.push_back("Error in compiling vertex shader:"); - if(error) + if (error) { errors.push_back([[error localizedDescription] UTF8String]); } return nil; } - + vertexShaderId = [library newFunctionWithName:@"VertexMain"]; - - if(vertexShaderId) + + if (vertexShaderId) { stagesBuilt++; } @@ -197,16 +197,16 @@ int GetStrideOfMetalType(MTLDataType type) errors.push_back("Fragment Shader is empty."); return nil; } - + // Fragment shader compilation code id fragmentShaderId = nil; { - NSString* sourcCode = [NSString stringWithUTF8String:fragmentShaderSource.c_str()]; + NSString* sourcCode = [NSString stringWithUTF8String:fragmentShaderSource.c_str()]; id library = [device newLibraryWithSource:sourcCode options:options error:&error]; - if(!library) + if (!library) { errors.push_back("Error in compiling fragment shader:"); - if(error) + if (error) { std::string libCompilationError = [[error localizedDescription] UTF8String]; printf("Compilation Errors:%s\n", libCompilationError.c_str()); @@ -214,16 +214,15 @@ int GetStrideOfMetalType(MTLDataType type) return nil; } } - + fragmentShaderId = [library newFunctionWithName:@"FragmentMain"]; assert(fragmentShaderId); - - if(library) + + if (library) { stagesBuilt++; } } - // Link stages to a programs if (stagesBuilt == desiredStages) @@ -231,28 +230,28 @@ int GetStrideOfMetalType(MTLDataType type) MTLRenderPipelineDescriptor* psoDesc = [MTLRenderPipelineDescriptor new]; psoDesc.vertexFunction = vertexShaderId; psoDesc.fragmentFunction = fragmentShaderId; - psoDesc.colorAttachments[0].pixelFormat = framebuffer->getColorTexture().pixelFormat; + psoDesc.colorAttachments[0].pixelFormat = framebuffer->getColorTexture().pixelFormat; psoDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float; - + if (_shader->hasAttribute(HW::ATTR_TRANSPARENT)) { - psoDesc.colorAttachments[0].blendingEnabled = YES; + psoDesc.colorAttachments[0].blendingEnabled = YES; psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; psoDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; - + _alphaBlendingEnabled = true; } - - MTLVertexDescriptor *vd = [MTLVertexDescriptor new]; - - for( int i = 0; i < vertexShaderId.vertexAttributes.count; ++i) + + MTLVertexDescriptor* vd = [MTLVertexDescriptor new]; + + for (int i = 0; i < vertexShaderId.vertexAttributes.count; ++i) { MTLVertexAttribute* vertexAttrib = vertexShaderId.vertexAttributes[i]; - + vd.attributes[i].bufferIndex = i; vd.attributes[i].format = GetMetalFormatFromMetalType(vertexAttrib.attributeType); vd.attributes[i].offset = 0; @@ -266,32 +265,31 @@ int GetStrideOfMetalType(MTLDataType type) if (string::npos != sattributeName.find(colorSet)) { string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } else if (string::npos != sattributeName.find(uvSet)) { string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } _attributeList[sattributeName] = inputPtr; - - vd.layouts[i].stride = GetStrideOfMetalType(vertexAttrib.attributeType);; + + vd.layouts[i].stride = GetStrideOfMetalType(vertexAttrib.attributeType); vd.layouts[i].stepFunction = MTLVertexStepFunctionPerVertex; - } - + psoDesc.vertexDescriptor = vd; - + _pso = [device newRenderPipelineStateWithDescriptor:psoDesc - options:MTLPipelineOptionArgumentInfo|MTLPipelineOptionBufferTypeInfo - reflection:&_psoReflection error:&error]; - + options:MTLPipelineOptionArgumentInfo | MTLPipelineOptionBufferTypeInfo + reflection:&_psoReflection + error:&error]; + [_pso retain]; [_psoReflection retain]; - - - if(error) + + if (error) { errors.push_back("Error in linking program:"); errors.push_back([[error localizedDescription] UTF8String]); @@ -327,10 +325,10 @@ int GetStrideOfMetalType(MTLDataType type) } void MslProgram::prepareUsedResources(id renderCmdEncoder, - CameraPtr cam, - GeometryHandlerPtr geometryHandler, - ImageHandlerPtr imageHandler, - LightHandlerPtr lightHandler) + CameraPtr cam, + GeometryHandlerPtr geometryHandler, + ImageHandlerPtr imageHandler, + LightHandlerPtr lightHandler) { // Bind the program to use if (!bind(renderCmdEncoder)) @@ -344,7 +342,7 @@ int GetStrideOfMetalType(MTLDataType type) // Parse for uniforms and attributes getUniformsList(); getAttributesList(); - + // Bind based on inputs found bindViewInformation(cam); bindTimeAndFrame(); @@ -392,25 +390,25 @@ int GetStrideOfMetalType(MTLDataType type) std::vector restructuredData; const void* bufferData = nullptr; size_t bufferSize = 0; - + int shaderStride = input.second->size / FLOAT_SIZE; - - if(shaderStride == stride) + + if (shaderStride == stride) { bufferData = &attributeData[0]; - bufferSize = attributeData.size()*FLOAT_SIZE; + bufferSize = attributeData.size() * FLOAT_SIZE; } else { - size_t nElements = attributeData.size()/stride; - bufferSize = nElements*shaderStride*FLOAT_SIZE; + size_t nElements = attributeData.size() / stride; + bufferSize = nElements * shaderStride * FLOAT_SIZE; restructuredData.resize(bufferSize, 0.0f); size_t j = 0; - for(int i = 0; i < nElements; ++i) + for (int i = 0; i < nElements; ++i) { memcpy(&restructuredData[j], - &attributeData[i*stride], - stride*FLOAT_SIZE); + &attributeData[i * stride], + stride * FLOAT_SIZE); j += shaderStride * FLOAT_SIZE; } bufferData = &restructuredData[0]; @@ -420,7 +418,7 @@ int GetStrideOfMetalType(MTLDataType type) id buffer = [_device newBufferWithBytes:bufferData length:bufferSize options:MTLResourceStorageModeShared]; _attributeBufferIds[input.first] = buffer; } - + [renderCmdEncoder setVertexBuffer:_attributeBufferIds[input.first] offset:0 atIndex:location]; } } @@ -490,6 +488,13 @@ int GetStrideOfMetalType(MTLDataType type) bindAttribute(renderCmdEncoder, foundList, mesh); } + // Bind bitangents + findInputs(HW::IN_BITANGENT, attributeList, foundList, true); + if (foundList.size()) + { + bindAttribute(renderCmdEncoder, foundList, mesh); + } + // Bind colors // Search for anything that starts with the color prefix findInputs(HW::IN_COLOR + "_", attributeList, foundList, false); @@ -554,17 +559,15 @@ int GetStrideOfMetalType(MTLDataType type) { // Acquire the image. string error; - if (static_cast(imageHandler.get())->bindImage( - renderCmdEncoder, uniformLocation, image)) + if (static_cast(imageHandler.get())->bindImage(renderCmdEncoder, uniformLocation, image)) { return image; } return nullptr; } -MaterialX::ValuePtr MslProgram::findUniformValue( - const string& uniformName, - const MslProgram::InputMap& uniformList) +MaterialX::ConstValuePtr MslProgram::findUniformValue(const string& uniformName, + const MslProgram::InputMap& uniformList) { auto uniform = uniformList.find(uniformName); if (uniform != uniformList.end()) @@ -583,71 +586,69 @@ int GetStrideOfMetalType(MTLDataType type) ImageHandlerPtr imageHandler) { const VariableBlock& publicUniforms = _shader->getStage(Stage::PIXEL).getUniformBlock(HW::PUBLIC_UNIFORMS); - for (MTLArgument *arg in _psoReflection.fragmentArguments) + for (MTLArgument* arg in _psoReflection.fragmentArguments) { if (arg.type == MTLArgumentTypeTexture) { bool found = false; - - if(lightHandler) + + if (lightHandler) { // Bind environment lights. ImageMap envLights = { - { HW::ENV_RADIANCE, lightHandler->getUsePrefilteredMap() ? lightHandler->getEnvPrefilteredMap() : lightHandler->getEnvRadianceMap() }, + { HW::ENV_RADIANCE, lightHandler->getUsePrefilteredMap() ? lightHandler->getEnvPrefilteredMap() : lightHandler->getEnvRadianceMap() }, { HW::ENV_IRRADIANCE, lightHandler->getEnvIrradianceMap() } }; for (const auto& env : envLights) { std::string str(arg.name.UTF8String); size_t loc = str.find(env.first); - if(loc != std::string::npos && env.second) + if (loc != std::string::npos && env.second) { ImageSamplingProperties samplingProperties; samplingProperties.uaddressMode = ImageSamplingProperties::AddressMode::PERIODIC; samplingProperties.vaddressMode = ImageSamplingProperties::AddressMode::CLAMP; samplingProperties.filterType = ImageSamplingProperties::FilterType::LINEAR; - - static_cast - (imageHandler.get())->bindImage(env.second, samplingProperties); - bindTexture(renderCmdEncoder, (unsigned int)arg.index, env.second, imageHandler); + + static_cast(imageHandler.get())->bindImage(env.second, samplingProperties); + bindTexture(renderCmdEncoder, (unsigned int) arg.index, env.second, imageHandler); found = true; } - } } - - if(!found) + + if (!found) { ImagePtr image = nullptr; - if(_explicitBoundImages.find(arg.name.UTF8String) != _explicitBoundImages.end()) + if (_explicitBoundImages.find(arg.name.UTF8String) != _explicitBoundImages.end()) { image = _explicitBoundImages[arg.name.UTF8String]; } - if(image && (image->getWidth() > 1 || image->getHeight() > 1)) + if (image && (image->getWidth() > 1 || image->getHeight() > 1)) { - bindTexture(renderCmdEncoder, (unsigned int)arg.index, image, imageHandler); + bindTexture(renderCmdEncoder, (unsigned int) arg.index, image, imageHandler); found = true; } } - - if(!found) + + if (!found) { auto uniform = _uniformList.find(arg.name.UTF8String); - if(uniform != _uniformList.end()) + if (uniform != _uniformList.end()) { string fileName = uniform->second->value ? uniform->second->value->getValueString() : ""; ImageSamplingProperties samplingProperties; string uniformNameWithoutPostfix = uniform->first; { size_t pos = uniformNameWithoutPostfix.find_last_of(IMAGE_PROPERTY_SEPARATOR); - if(pos != std::string::npos) + if (pos != std::string::npos) uniformNameWithoutPostfix = uniformNameWithoutPostfix.substr(0, pos); } samplingProperties.setProperties(uniformNameWithoutPostfix, publicUniforms); samplingProperties.enableMipmaps = _enableMipMapping; - bindTexture(renderCmdEncoder, (unsigned int)arg.index, fileName, samplingProperties, imageHandler); + bindTexture(renderCmdEncoder, (unsigned int) arg.index, fileName, samplingProperties, imageHandler); } } } @@ -659,7 +660,7 @@ int GetStrideOfMetalType(MTLDataType type) ImagePtr imagePtr, ImageSamplingProperties samplingProperties) { - if(imageHandler->bindImage(imagePtr, samplingProperties)) + if (imageHandler->bindImage(imagePtr, samplingProperties)) { _explicitBoundImages[shaderTextureName] = imagePtr; } @@ -813,9 +814,9 @@ int GetStrideOfMetalType(MTLDataType type) bool MslProgram::hasUniform(const string& name) { const MslProgram::InputMap& uniformList = getUniformsList(); - if(uniformList.find(name) != uniformList.end()) + if (uniformList.find(name) != uniformList.end()) return true; - if(_globalUniformNameList.find(name) != _globalUniformNameList.end() && uniformList.find(_globalUniformNameList[name]) != uniformList.end()) + if (_globalUniformNameList.find(name) != _globalUniformNameList.end() && uniformList.find(_globalUniformNameList[name]) != uniformList.end()) return true; return false; } @@ -831,7 +832,7 @@ int GetStrideOfMetalType(MTLDataType type) else { auto globalNameMapping = _globalUniformNameList.find(name); - if(globalNameMapping != _globalUniformNameList.end()) + if (globalNameMapping != _globalUniformNameList.end()) { bindUniform(globalNameMapping->second, value, errorIfMissing); } @@ -904,57 +905,80 @@ int GetStrideOfMetalType(MTLDataType type) errors.push_back("Cannot parse for uniforms without a valid program"); throw ExceptionRenderError(errorType, errors); } - - for (MTLArgument *arg in _psoReflection.vertexArguments) + + for (MTLArgument* arg in _psoReflection.vertexArguments) { if (arg.bufferDataType == MTLDataTypeStruct) { for (MTLStructMember* member in arg.bufferStructType.members) { InputPtr inputPtr = std::make_shared(arg.index, member.dataType, arg.bufferDataSize, EMPTY_STRING); - std::string memberName = member.name.UTF8String; + std::string memberName = member.name.UTF8String; std::string uboDotMemberName = std::string(arg.name.UTF8String) + "." + member.name.UTF8String; _uniformList[uboDotMemberName] = inputPtr; _globalUniformNameList[member.name.UTF8String] = uboDotMemberName; } } } - - for (MTLArgument *arg in _psoReflection.fragmentArguments) + + for (MTLArgument* arg in _psoReflection.fragmentArguments) { if (arg.type == MTLArgumentTypeBuffer && arg.bufferDataType == MTLDataTypeStruct) { - for (MTLStructMember* member in arg.bufferStructType.members) + const auto uboObjectName = string(arg.name.UTF8String); + + const auto addUniformToList = + [this, uboObjectName] + (MTLStructMember* member, int index, int size, const string& memberNamePrefix) -> void { - std::string uboObjectName = std::string(arg.name.UTF8String); - std::string memberName = member.name.UTF8String; - std::string uboDotMemberName = uboObjectName + "." + memberName; - - InputPtr inputPtr = std::make_shared(arg.index, member.dataType, arg.bufferDataSize, EMPTY_STRING); - _uniformList[uboDotMemberName] = inputPtr; - _globalUniformNameList[memberName] = uboDotMemberName; - - if(MTLArrayType* arrayMember = member.arrayType) + auto addUniformToList_impl = + [this, uboObjectName] + (MTLStructMember* member, int index, int size, const string& memberNamePrefix, auto& addUniformToList_ref) -> void { - for(int i = 0; i < arrayMember.arrayLength; ++i) + auto memberName = memberNamePrefix + member.name.UTF8String; + + if (MTLStructType* structMember = member.structType) { - for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + for (MTLStructMember* subMember in structMember.members) { - std::string memberNameDotSubmember = memberName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; - std::string uboDotMemberNameDotSubmemberName = uboObjectName + "." + memberNameDotSubmember; - - InputPtr inputPtr = std::make_shared(ArrayOfStructMember.argumentIndex, ArrayOfStructMember.dataType, ArrayOfStructMember.offset, EMPTY_STRING); - _uniformList[uboDotMemberNameDotSubmemberName] = inputPtr; - _globalUniformNameList[memberNameDotSubmember] = uboDotMemberNameDotSubmemberName; + auto namePrefix = memberName + "."; + addUniformToList_ref(subMember, subMember.argumentIndex, subMember.offset, namePrefix, addUniformToList_ref); } } - } + else + { + auto uboDotMemberName = uboObjectName + "." + memberName; + + InputPtr inputPtr = std::make_shared(index, member.dataType, size, EMPTY_STRING); + this->_uniformList[uboDotMemberName] = inputPtr; + this->_globalUniformNameList[memberName] = uboDotMemberName; + + if (MTLArrayType* arrayMember = member.arrayType) + { + for (int i = 0; i < arrayMember.arrayLength; ++i) + { + for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + { + auto namePrefix = memberName + "[" + std::to_string(i) + "]."; + addUniformToList_ref(ArrayOfStructMember, ArrayOfStructMember.argumentIndex, ArrayOfStructMember.offset, namePrefix, addUniformToList_ref); + } + } + } + } + }; + + return addUniformToList_impl(member, index, size, memberNamePrefix, addUniformToList_impl); + }; + + for (MTLStructMember* member in arg.bufferStructType.members) + { + addUniformToList(member, arg.index, arg.bufferDataSize, ""); } } - - if(arg.type == MTLArgumentTypeTexture) + + if (arg.type == MTLArgumentTypeTexture) { - if(HW::ENV_RADIANCE != arg.name.UTF8String && HW::ENV_IRRADIANCE != arg.name.UTF8String) + if (HW::ENV_RADIANCE != arg.name.UTF8String && HW::ENV_IRRADIANCE != arg.name.UTF8String) { std::string texture_name = arg.name.UTF8String; InputPtr inputPtr = std::make_shared(arg.index, MTLDataTypeTexture, -1, EMPTY_STRING); @@ -974,7 +998,7 @@ int GetStrideOfMetalType(MTLDataType type) // Process constants const VariableBlock& constants = ps.getConstantBlock(); - for (size_t i=0; i< constants.size(); ++i) + for (size_t i = 0; i < constants.size(); ++i) { const ShaderPort* v = constants[i]; // There is no way to match with an unnamed variable @@ -1005,55 +1029,90 @@ int GetStrideOfMetalType(MTLDataType type) for (size_t i = 0; i < uniforms.size(); ++i) { const ShaderPort* v = uniforms[i]; - MTLDataType resourceType = mapTypeToMetalType(v->getType()); - // There is no way to match with an unnamed variable - if (v->getVariable().empty()) - { - continue; - } - - // Ignore types which are unsupported in MSL. - if (resourceType == MTLDataTypeNone) - { - continue; - } + const string& variablePath = v->getPath(); + const string& variableSemantic = v->getSemantic(); - auto inputIt = _uniformList.find(v->getVariable()); - if (inputIt == _uniformList.end()) + const auto populateUniformInput = + [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound] + (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue) -> void { - if (v->getType() == Type::FILENAME) + auto populateUniformInput_impl = + [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound] + (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void { - inputIt = _uniformList.find(TEXTURE_NAME(v->getVariable())); - } - else - { - inputIt = _uniformList.find(uniforms.getInstance() + "." + v->getVariable()); - } - } + // There is no way to match with an unnamed variable + if (variableName.empty()) + { + return; + } - if (inputIt != _uniformList.end()) - { - Input* input = inputIt->second.get(); - input->path = v->getPath(); - input->value = v->getValue(); - if (input->resourceType == resourceType) - { - input->typeString = v->getType().getName(); - } - else - { - errors.push_back( - "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " - + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType().getName() - + "\". Semantic: \"" + v->getSemantic() - + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") - + "\". resourceType: " + std::to_string(mapTypeToMetalType(v->getType())) - ); - uniformTypeMismatchFound = true; - } - } + MTLDataType resourceType = mapTypeToMetalType(variableTypeDesc); + // Ignore types which are unsupported in MSL. + if (resourceType == MTLDataTypeNone) + { + return; + } + + if (!variableTypeDesc.isStruct()) + { + auto inputIt = _uniformList.find(variableName); + + if (inputIt == _uniformList.end()) { + if(variableTypeDesc == Type::FILENAME) + { + inputIt = _uniformList.find(TEXTURE_NAME(variableName)); + } + else + { + inputIt = _uniformList.find(uniforms.getInstance() + "." + variableName); + } + } + + if (inputIt != _uniformList.end()) + { + Input* input = inputIt->second.get(); + input->path = variablePath; + input->value = variableValue; + if (input->resourceType == resourceType) + { + input->typeString = variableTypeDesc.getName(); + } + else + { + errors.push_back( + "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + + "Name: \"" + variableName + + "\". Type: \"" + variableTypeDesc.getName() + + "\". Semantic: \"" + variableSemantic + + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "") + + "\". resourceType: " + std::to_string(mapTypeToMetalType(variableTypeDesc)) + ); + uniformTypeMismatchFound = true; + } + } + } + else + { + auto structTypeDesc = StructTypeDesc::get(variableTypeDesc.getStructIndex()); + auto aggregateValue = std::static_pointer_cast(variableValue); + + const auto& members = structTypeDesc.getMembers(); + for (size_t i = 0, n = members.size(); i < n; ++i) + { + const auto& structMember = members[i]; + auto memberVariableName = variableName+"."+structMember._name; + auto memberVariableValue = aggregateValue->getMemberValue(i); + + populateUniformInput_ref(structMember._typeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref); + } + } + }; + + return populateUniformInput_impl(variableTypeDesc, variableName, variableValue, populateUniformInput_impl); + }; + + populateUniformInput(v->getType(), v->getVariable(), v->getValue()); } } @@ -1111,73 +1170,72 @@ int GetStrideOfMetalType(MTLDataType type) { Matrix44 viewInverse = cam->getViewMatrix().getInverse(); MaterialX::Vector3 viewPosition(viewInverse[3][0], viewInverse[3][1], viewInverse[3][2]); - memcpy((void*)&data[offset], viewPosition.data(), 3 * sizeof(float)); + memcpy((void*) &data[offset], viewPosition.data(), 3 * sizeof(float)); return true; } if (uniformName == HW::VIEW_DIRECTION) { - memcpy((void*)&data[offset], cam->getViewPosition().data(), 3 * sizeof(float)); + memcpy((void*) &data[offset], cam->getViewPosition().data(), 3 * sizeof(float)); return true; } - + // World matrix variants const Matrix44& world = cam->getWorldMatrix(); Matrix44 invWorld = world.getInverse(); Matrix44 invTransWorld = invWorld.getTranspose(); if (uniformName == HW::WORLD_MATRIX) { - memcpy((void*)&data[offset], world.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], world.data(), 4 * 4 * sizeof(float)); return false; } if (uniformName == HW::WORLD_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], world.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], world.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::WORLD_INVERSE_MATRIX) { - memcpy((void*)&data[offset], invWorld.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], invWorld.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::WORLD_INVERSE_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], invTransWorld.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], invTransWorld.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } - if(uniformName == HW::FRAME) + if (uniformName == HW::FRAME) { - memcpy((void*)&data[offset], (const void*)&_frame, sizeof(float)); + memcpy((void*) &data[offset], (const void*) &_frame, sizeof(float)); return true; } - if(uniformName == HW::TIME) + if (uniformName == HW::TIME) { - memcpy((void*)&data[offset], (const void*)&_time, sizeof(float)); + memcpy((void*) &data[offset], (const void*) &_time, sizeof(float)); return true; } - // Projection matrix variants const Matrix44& proj = cam->getProjectionMatrix(); if (uniformName == HW::PROJ_MATRIX) { - memcpy((void*)&data[offset], proj.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], proj.data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::PROJ_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], proj.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], proj.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } - const Matrix44& projInverse= proj.getInverse(); + const Matrix44& projInverse = proj.getInverse(); if (uniformName == HW::PROJ_INVERSE_MATRIX) { - memcpy((void*)&data[offset], projInverse.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], projInverse.data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::PROJ_INVERSE_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], projInverse.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], projInverse.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } @@ -1186,105 +1244,105 @@ int GetStrideOfMetalType(MTLDataType type) Matrix44 viewInverse = view.getInverse(); if (uniformName == HW::VIEW_MATRIX) { - memcpy((void*)&data[offset], view.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], view.data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::VIEW_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], view.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], view.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::VIEW_INVERSE_MATRIX) { - memcpy((void*)&data[offset], viewInverse.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], viewInverse.data(), 4 * 4 * sizeof(float)); return true; } if (uniformName == HW::VIEW_INVERSE_TRANSPOSE_MATRIX) { - memcpy((void*)&data[offset], viewInverse.getTranspose().data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], viewInverse.getTranspose().data(), 4 * 4 * sizeof(float)); return true; } - + // View-projection matrix const Matrix44& viewProj = view * proj; if (uniformName == HW::VIEW_PROJECTION_MATRIX) { - memcpy((void*)&data[offset], viewProj.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], viewProj.data(), 4 * 4 * sizeof(float)); return true; } - + // View-projection-world matrix const Matrix44& viewProjWorld = viewProj * world; if (uniformName == HW::WORLD_VIEW_PROJECTION_MATRIX) { - memcpy((void*)&data[offset], viewProjWorld.data(), 4 * 4 * sizeof(float)); + memcpy((void*) &data[offset], viewProjWorld.data(), 4 * 4 * sizeof(float)); return true; } - + if (uniformName == HW::ENV_RADIANCE_MIPS) { unsigned int maxMipCount = lightHandler->getEnvRadianceMap()->getMaxMipCount(); - memcpy((void*)&data[offset], &maxMipCount, sizeof(maxMipCount)); + memcpy((void*) &data[offset], &maxMipCount, sizeof(maxMipCount)); return true; } - + return false; }; - auto setValue = [](MaterialX::ValuePtr value, std::vector& data, size_t offset) + auto setValue = [](MaterialX::ConstValuePtr value, std::vector& data, size_t offset) { if (value->getTypeString() == "float") { float v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(float)); + memcpy((void*) &data[offset], &v, sizeof(float)); } else if (value->getTypeString() == "integer") { int v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(int)); + memcpy((void*) &data[offset], &v, sizeof(int)); } else if (value->getTypeString() == "boolean") { bool v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(bool)); + memcpy((void*) &data[offset], &v, sizeof(bool)); } else if (value->getTypeString() == "color3") { Color3 v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(Color3)); + memcpy((void*) &data[offset], &v, sizeof(Color3)); } else if (value->getTypeString() == "color4") { Color4 v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(Color4)); + memcpy((void*) &data[offset], &v, sizeof(Color4)); } else if (value->getTypeString() == "vector2") { Vector2 v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(Vector2)); + memcpy((void*) &data[offset], &v, sizeof(Vector2)); } else if (value->getTypeString() == "vector3") { Vector3 v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(Vector3)); + memcpy((void*) &data[offset], &v, sizeof(Vector3)); } else if (value->getTypeString() == "vector4") { Vector4 v = value->asA(); - memcpy((void*)&data[offset], &v, sizeof(Vector4)); + memcpy((void*) &data[offset], &v, sizeof(Vector4)); } else if (value->getTypeString() == "matrix33") { Matrix33 m = value->asA(); - float tmp[12] = {m[0][0], m[0][1], m[0][2], 0.0f, - m[1][0], m[1][1], m[1][2], 0.0f, - m[2][0], m[2][1], m[2][2], 0.0f}; - memcpy((void*)&data[offset], &tmp, sizeof(tmp)); + float tmp[12] = { m[0][0], m[0][1], m[0][2], 0.0f, + m[1][0], m[1][1], m[1][2], 0.0f, + m[2][0], m[2][1], m[2][2], 0.0f }; + memcpy((void*) &data[offset], &tmp, sizeof(tmp)); } else if (value->getTypeString() == "matrix44") { Matrix44 m = value->asA(); - memcpy((void*)&data[offset], &m, sizeof(Matrix44)); + memcpy((void*) &data[offset], &m, sizeof(Matrix44)); } else if (value->getTypeString() == "string") { @@ -1294,84 +1352,103 @@ int GetStrideOfMetalType(MTLDataType type) { throw ExceptionRenderError( "MSL input binding error.", - { "Unsupported data type when setting uniform value" } - ); + { "Unsupported data type when setting uniform value" }); } }; - - for (MTLArgument *arg in _psoReflection.vertexArguments) + + for (MTLArgument* arg in _psoReflection.vertexArguments) { if (arg.type == MTLArgumentTypeBuffer && arg.bufferDataType == MTLDataTypeStruct) { std::vector uniformBufferData(arg.bufferDataSize); for (MTLStructMember* member in arg.bufferStructType.members) { - if(!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) + if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { - MaterialX::ValuePtr value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value; - if(value) + auto value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value; + if (value) { setValue(value, uniformBufferData, member.offset); } } } - - if(arg.bufferStructType) - [renderCmdEncoder setVertexBytes:(void*)uniformBufferData.data() length:arg.bufferDataSize atIndex:arg.index]; + + if (arg.bufferStructType) + [renderCmdEncoder setVertexBytes:(void*) uniformBufferData.data() length:arg.bufferDataSize atIndex:arg.index]; } } - - for (MTLArgument *arg in _psoReflection.fragmentArguments) + + for (MTLArgument* arg in _psoReflection.fragmentArguments) { if (arg.type == MTLArgumentTypeBuffer && arg.bufferDataType == MTLDataTypeStruct) { std::vector uniformBufferData(arg.bufferDataSize); - + for (MTLStructMember* member in arg.bufferStructType.members) { string uniformName = string(arg.name.UTF8String) + "." + member.name.UTF8String; - - if(!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) - { - auto uniformInfo = _uniformList.find(uniformName); - if (uniformInfo != _uniformList.end()) - { - MaterialX::ValuePtr value = uniformInfo->second->value; - if(value) - { - setValue(value, uniformBufferData, member.offset); - } - } - else - { - - } - } - - if(MTLArrayType* arrayMember = member.arrayType) + + if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { - for(int i = 0; i < arrayMember.arrayLength; ++i) + const auto setUniformValue = + [this, setValue] + (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset ) -> void { - for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + auto setUniformValue_impl = + [this, setValue] + (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset, auto &setUniformValue_ref ) -> void { - string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; - - auto uniformInfo = _uniformList.find(uniformNameSubArray); - if (uniformInfo != _uniformList.end()) + if(MTLArrayType* arrayMember = member.arrayType) { - MaterialX::ValuePtr value = uniformInfo->second->value; - if(value) + for(int i = 0; i < arrayMember.arrayLength; ++i) { - setValue(value, uniformBufferData, member.offset + i * arrayMember.stride + ArrayOfStructMember.offset); + for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + { + string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; + auto uniformInfo = _uniformList.find(uniformNameSubArray); + if (uniformInfo != _uniformList.end()) + { + auto value = uniformInfo->second->value; + if(value) + { + setValue(value, uniformBufferData, offset + i * arrayMember.stride + ArrayOfStructMember.offset); + } + } + } } } - } - } + else if (MTLStructType* structMember = member.structType) + { + // this code does not support struct recursion yet.... + for (MTLStructMember* subMember in structMember.members) + { + string subUniformName = uniformName+"."+subMember.name.UTF8String; + setUniformValue_ref(subMember, subUniformName, uniformBufferData, offset+subMember.offset, setUniformValue_ref); + } + } + else + { + auto uniformInfo = _uniformList.find(uniformName); + if (uniformInfo != _uniformList.end()) + { + auto value = uniformInfo->second->value; + if(value) + { + setValue(value, uniformBufferData, offset); + } + } + } + }; + + return setUniformValue_impl(member, uniformName, uniformBufferData, offset, setUniformValue_impl); + }; + + setUniformValue(member, uniformName, uniformBufferData, member.offset); } } - - if(arg.bufferStructType) - [renderCmdEncoder setFragmentBytes:(void*)uniformBufferData.data() length:arg.bufferDataSize atIndex:arg.index]; + + if (arg.bufferStructType) + [renderCmdEncoder setFragmentBytes:(void*) uniformBufferData.data() length:arg.bufferDataSize atIndex:arg.index]; } } } @@ -1380,13 +1457,13 @@ throw ExceptionRenderError( { if (_pso != nil) { - [_pso release]; + [_pso release]; } _pso = nil; - - if(_psoReflection != nil) + + if (_psoReflection != nil) { - [_psoReflection release]; + [_psoReflection release]; } _psoReflection = nil; @@ -1424,7 +1501,8 @@ throw ExceptionRenderError( type == Type::VDF || type == Type::SURFACESHADER || type == Type::LIGHTSHADER || - type == Type::VOLUMESHADER) + type == Type::VOLUMESHADER || + type.isStruct()) return MTLDataTypeStruct; return MTLDataTypeNone; @@ -1453,11 +1531,11 @@ throw ExceptionRenderError( for (size_t i = 0; i < vertexInputs.size(); ++i) { const ShaderPort* v = vertexInputs[i]; - + string variableName = v->getVariable(); size_t dotPos = variableName.find('.'); string variableMemberName = variableName.substr(dotPos + 1); - + auto inputIt = _attributeList.find(variableMemberName); if (inputIt != _attributeList.end()) { @@ -1493,9 +1571,9 @@ throw ExceptionRenderError( } void MslProgram::findInputs(const string& variable, - const InputMap& variableList, - InputMap& foundList, - bool exactMatch) + const InputMap& variableList, + InputMap& foundList, + bool exactMatch) { foundList.clear(); @@ -1542,9 +1620,9 @@ throw ExceptionRenderError( string colorspace = input.second->colorspace; bool isConstant = input.second->isConstant; outputStream << "Program Uniform: \"" << input.first - << "\". Location:" << location - << ". ResourceType: " << std::hex << resourceType - << ". Size: " << std::dec << size; + << "\". Location:" << location + << ". ResourceType: " << std::hex << resourceType + << ". Size: " << std::dec << size; if (!type.empty()) outputStream << ". TypeString: \"" << type << "\""; if (!value.empty()) @@ -1562,7 +1640,6 @@ throw ExceptionRenderError( } } - void MslProgram::printAttributes(std::ostream& outputStream) { updateAttributesList(); @@ -1574,9 +1651,9 @@ throw ExceptionRenderError( string type = input.second->typeString; string value = input.second->value ? input.second->value->getValueString() : EMPTY_STRING; outputStream << "Program Attribute: \"" << input.first - << "\". Location:" << location - << ". ResourceType: " << std::hex << resourceType - << ". Size: " << std::dec << size; + << "\". Location:" << location + << ". ResourceType: " << std::hex << resourceType + << ". Size: " << std::dec << size; if (!type.empty()) outputStream << ". TypeString: \"" << type << "\""; if (!value.empty()) diff --git a/source/MaterialXRenderMsl/MslRenderer.h b/source/MaterialXRenderMsl/MslRenderer.h index ca87d9dd3e..f18afd683f 100644 --- a/source/MaterialXRenderMsl/MslRenderer.h +++ b/source/MaterialXRenderMsl/MslRenderer.h @@ -45,13 +45,13 @@ class MX_RENDERMSL_API MslRenderer : public ShaderRenderer public: /// Create a MSL renderer instance static MslRendererPtr create(unsigned int width = 512, unsigned int height = 512, Image::BaseType baseType = Image::BaseType::UINT8); - + /// Create a texture handler for Metal textures ImageHandlerPtr createImageHandler(ImageLoaderPtr imageLoader) { return MetalTextureHandler::create(_device, imageLoader); } - + /// Returns Metal Device used for rendering id getMetalDevice() const; @@ -84,13 +84,13 @@ class MX_RENDERMSL_API MslRenderer : public ShaderRenderer /// Update the program with value of the uniform. void updateUniform(const string& name, ConstValuePtr value) override; - + /// Set the size of the rendered image void setSize(unsigned int width, unsigned int height) override; /// Render the current program to an offscreen buffer. void render() override; - + /// Render the current program in texture space to an off-screen buffer. void renderTextureSpace(const Vector2& uvMin, const Vector2& uvMax); @@ -126,23 +126,23 @@ class MX_RENDERMSL_API MslRenderer : public ShaderRenderer } /// @} - + protected: MslRenderer(unsigned int width, unsigned int height, Image::BaseType baseType); - + void triggerProgrammaticCapture(); void stopProgrammaticCapture(); - + void createFrameBuffer(bool encodeSrgb); - + private: - MslProgramPtr _program; + MslProgramPtr _program; - id _device = nil; - id _cmdQueue = nil; + id _device = nil; + id _cmdQueue = nil; id _cmdBuffer = nil; - - MetalFramebufferPtr _framebuffer; + + MetalFramebufferPtr _framebuffer; bool _initialized; diff --git a/source/MaterialXRenderMsl/MslRenderer.mm b/source/MaterialXRenderMsl/MslRenderer.mm index f5e794c2b3..1a01b8bebf 100644 --- a/source/MaterialXRenderMsl/MslRenderer.mm +++ b/source/MaterialXRenderMsl/MslRenderer.mm @@ -54,7 +54,7 @@ _device = MTLCreateSystemDefaultDevice(); _cmdQueue = [_device newCommandQueue]; createFrameBuffer(true); - + _initialized = true; } } @@ -78,22 +78,22 @@ void MslRenderer::renderTextureSpace(const Vector2& uvMin, const Vector2& uvMax) { bool captureRenderTextureSpace = false; - if(captureRenderTextureSpace) + if (captureRenderTextureSpace) triggerProgrammaticCapture(); - + MTLRenderPassDescriptor* desc = [MTLRenderPassDescriptor new]; _framebuffer->bind(desc); - + _cmdBuffer = [_cmdQueue commandBuffer]; - + id rendercmdEncoder = [_cmdBuffer renderCommandEncoderWithDescriptor:desc]; _program->bind(rendercmdEncoder); _program->prepareUsedResources(rendercmdEncoder, - _camera, - _geometryHandler, - _imageHandler, - _lightHandler); - + _camera, + _geometryHandler, + _imageHandler, + _lightHandler); + MeshPtr mesh = _geometryHandler->createQuadMesh(uvMin, uvMax, true); _program->bindMesh(rendercmdEncoder, mesh); MeshPartitionPtr part = mesh->getPartition(0); @@ -104,16 +104,16 @@ indexType:MTLIndexTypeUInt32 indexBuffer:_program->getIndexBuffer(part) indexBufferOffset:0]; - + _framebuffer->unbind(); [rendercmdEncoder endEncoding]; - + [_cmdBuffer commit]; [_cmdBuffer waitUntilCompleted]; - + [desc release]; - - if(captureRenderTextureSpace) + + if (captureRenderTextureSpace) stopProgrammaticCapture(); } @@ -149,17 +149,16 @@ _height = height; createFrameBuffer(true); } - } void MslRenderer::triggerProgrammaticCapture() { - MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager]; + MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager]; MTLCaptureDescriptor* captureDescriptor = [MTLCaptureDescriptor new]; captureDescriptor.captureObject = _device; - + NSError* error = nil; - if(![captureManager startCaptureWithDescriptor:captureDescriptor error:&error]) + if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error]) { NSLog(@"Failed to start capture, error %@", error); } @@ -174,26 +173,25 @@ void MslRenderer::render() { bool captureFrame = false; - if(captureFrame) + if (captureFrame) triggerProgrammaticCapture(); - + _cmdBuffer = [_cmdQueue commandBuffer]; MTLRenderPassDescriptor* renderpassDesc = [MTLRenderPassDescriptor new]; - + _framebuffer->bind(renderpassDesc); [renderpassDesc.colorAttachments[0] setClearColor: - MTLClearColorMake(_screenColor[0], _screenColor[1], _screenColor[2], 1.0f)]; - + MTLClearColorMake(_screenColor[0], _screenColor[1], _screenColor[2], 1.0f)]; + id renderCmdEncoder = [_cmdBuffer renderCommandEncoderWithDescriptor:renderpassDesc]; MTLDepthStencilDescriptor* depthStencilDesc = [MTLDepthStencilDescriptor new]; - depthStencilDesc.depthWriteEnabled = !(_program->isTransparent()); + depthStencilDesc.depthWriteEnabled = !(_program->isTransparent()); depthStencilDesc.depthCompareFunction = MTLCompareFunctionLess; - + id depthStencilState = [_device newDepthStencilStateWithDescriptor:depthStencilDesc]; [renderCmdEncoder setDepthStencilState:depthStencilState]; - [renderCmdEncoder setCullMode:MTLCullModeBack]; try @@ -215,15 +213,15 @@ auto part = mesh->getPartition(i); _program->bindPartition(part); MeshIndexBuffer& indexData = part->getIndices(); - - if(_program->isTransparent()) + + if (_program->isTransparent()) { [renderCmdEncoder setCullMode:MTLCullModeFront]; - [renderCmdEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:(int)indexData.size() indexType:MTLIndexTypeUInt32 indexBuffer:_program->getIndexBuffer(part) indexBufferOffset:0]; + [renderCmdEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:(int) indexData.size() indexType:MTLIndexTypeUInt32 indexBuffer:_program->getIndexBuffer(part) indexBufferOffset:0]; [renderCmdEncoder setCullMode:MTLCullModeBack]; } - - [renderCmdEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:(int)indexData.size() indexType:MTLIndexTypeUInt32 indexBuffer:_program->getIndexBuffer(part) indexBufferOffset:0]; + + [renderCmdEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexCount:(int) indexData.size() indexType:MTLIndexTypeUInt32 indexBuffer:_program->getIndexBuffer(part) indexBufferOffset:0]; } } } @@ -233,18 +231,18 @@ _framebuffer->unbind(); throw e; } - + [renderCmdEncoder endEncoding]; - + _framebuffer->unbind(); - + [_cmdBuffer commit]; [_cmdBuffer waitUntilCompleted]; - + [_cmdBuffer release]; _cmdBuffer = nil; - - if(captureFrame) + + if (captureFrame) stopProgrammaticCapture(); } diff --git a/source/MaterialXRenderOsl/CMakeLists.txt b/source/MaterialXRenderOsl/CMakeLists.txt index 033558fcaa..3b02984ab1 100644 --- a/source/MaterialXRenderOsl/CMakeLists.txt +++ b/source/MaterialXRenderOsl/CMakeLists.txt @@ -6,7 +6,7 @@ mx_add_library(MaterialXRenderOsl ${materialx_source} HEADER_FILES ${materialx_headers} - LIBRARIES + MTLX_MODULES MaterialXRender EXPORT_DEFINE MATERIALX_RENDEROSL_EXPORTS) diff --git a/source/MaterialXRenderOsl/OslRenderer.cpp b/source/MaterialXRenderOsl/OslRenderer.cpp index 14dd81a090..bcddb08123 100644 --- a/source/MaterialXRenderOsl/OslRenderer.cpp +++ b/source/MaterialXRenderOsl/OslRenderer.cpp @@ -48,10 +48,6 @@ void OslRenderer::setSize(unsigned int width, unsigned int height) void OslRenderer::initialize(RenderContextHandle) { - if (_oslIncludePath.isEmpty()) - { - throw ExceptionRenderError("OSL validation include path is empty"); - } if (_oslTestShadeExecutable.isEmpty() && _oslCompilerExecutable.isEmpty()) { throw ExceptionRenderError("OSL validation executables not set"); @@ -61,7 +57,7 @@ void OslRenderer::initialize(RenderContextHandle) void OslRenderer::renderOSL(const FilePath& dirPath, const string& shaderName, const string& outputName) { // If command options missing, skip testing. - if (_oslTestRenderExecutable.isEmpty() || _oslIncludePath.isEmpty() || + if (_oslTestRenderExecutable.isEmpty() || _oslTestRenderSceneTemplateFile.isEmpty() || _oslUtilityOSOPath.isEmpty()) { throw ExceptionRenderError("Command input arguments are missing"); @@ -218,7 +214,7 @@ void OslRenderer::renderOSL(const FilePath& dirPath, const string& shaderName, c void OslRenderer::shadeOSL(const FilePath& dirPath, const string& shaderName, const string& outputName) { // If no command and include path specified then skip checking. - if (_oslTestShadeExecutable.isEmpty() || _oslIncludePath.isEmpty()) + if (_oslTestShadeExecutable.isEmpty()) { return; } @@ -252,7 +248,7 @@ void OslRenderer::shadeOSL(const FilePath& dirPath, const string& shaderName, co StringVec results; string line; string successfulOutputSubString("Output " + outputName + " to " + - outputFileName); + outputFileName); while (std::getline(errorStream, line)) { if (!line.empty() && @@ -279,7 +275,7 @@ void OslRenderer::shadeOSL(const FilePath& dirPath, const string& shaderName, co void OslRenderer::compileOSL(const FilePath& oslFilePath) { // If no command and include path specified then skip checking. - if (_oslCompilerExecutable.isEmpty() || _oslIncludePath.isEmpty()) + if (_oslCompilerExecutable.isEmpty()) { return; } @@ -295,7 +291,7 @@ void OslRenderer::compileOSL(const FilePath& oslFilePath) // Run the command and get back the result. If non-empty string throw exception with error string command = _oslCompilerExecutable.asString() + " -q "; for (FilePath p : _oslIncludePath) - { + { command += " -I\"" + p.asString() + "\" "; } command += oslFilePath.asString() + " -o " + outputFileName.asString() + " > " + errorFile + redirectString; @@ -320,7 +316,7 @@ void OslRenderer::compileOSL(const FilePath& oslFilePath) void OslRenderer::createProgram(ShaderPtr shader) { - StageMap stages = { {Stage::PIXEL, shader->getStage(Stage::PIXEL).getSourceCode()} }; + StageMap stages = { { Stage::PIXEL, shader->getStage(Stage::PIXEL).getSourceCode() } }; createProgram(stages); } @@ -333,7 +329,7 @@ void OslRenderer::createProgram(const StageMap& stages) throw ExceptionRenderError("No shader code to validate"); } - bool haveCompiler = !_oslCompilerExecutable.isEmpty() && !_oslIncludePath.isEmpty(); + bool haveCompiler = !_oslCompilerExecutable.isEmpty(); if (!haveCompiler) { throw ExceptionRenderError("No OSL compiler specified for validation"); @@ -341,7 +337,7 @@ void OslRenderer::createProgram(const StageMap& stages) // Dump string to disk. For OSL assume shader is in stage 0 slot. FilePath filePath(_oslOutputFilePath); - filePath = filePath / _oslShaderName; + filePath = filePath / _oslShaderName; string fileName = filePath.asString(); if (fileName.empty()) { diff --git a/source/MaterialXTest/CMakeLists.txt b/source/MaterialXTest/CMakeLists.txt index 4835787ed8..c3fae603dc 100644 --- a/source/MaterialXTest/CMakeLists.txt +++ b/source/MaterialXTest/CMakeLists.txt @@ -96,11 +96,6 @@ endif() add_custom_command(TARGET MaterialXTest POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/../../libraries ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries) -if(MATERIALX_OSL_LEGACY_CLOSURES) - add_custom_command(TARGET MaterialXTest POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rename - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx) -endif() if(MATERIALX_BUILD_GEN_MDL) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../source/MaterialXGenMdl/mdl/" diff --git a/source/MaterialXTest/MaterialXCore/CoreUtil.cpp b/source/MaterialXTest/MaterialXCore/CoreUtil.cpp index 11aa826d4f..4bc174a690 100644 --- a/source/MaterialXTest/MaterialXCore/CoreUtil.cpp +++ b/source/MaterialXTest/MaterialXCore/CoreUtil.cpp @@ -10,6 +10,12 @@ namespace mx = MaterialX; +TEST_CASE("Version comparison", "[coreutil]") +{ + // Test for version comparison + REQUIRE(MATERIALX_VERSION_INDEX > MATERIALX_GENERATE_INDEX(1, 38, 8)); +} + TEST_CASE("String utilities", "[coreutil]") { std::string invalidName("test.name"); diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index fb35e58ccb..223aae5694 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -104,7 +104,11 @@ TEST_CASE("Document", "[document]") REQUIRE(customLibrary->validate()); // Import the custom library. - doc->importLibrary(customLibrary); + mx::DocumentPtr customDatalibrary = mx::createDocument(); + customDatalibrary->importLibrary(customLibrary); + + // Set data library + doc->setDataLibrary(customDatalibrary); mx::NodeGraphPtr importedNodeGraph = doc->getNodeGraph("custom:NG_custom"); mx::NodeDefPtr importedNodeDef = doc->getNodeDef("custom:ND_simpleSrf"); mx::ImplementationPtr importedImpl = doc->getImplementation("custom:IM_custom"); @@ -116,3 +120,154 @@ TEST_CASE("Document", "[document]") // Validate the combined document. REQUIRE(doc->validate()); } + +TEST_CASE("Document equivalence", "[document]") +{ + mx::DocumentPtr doc = mx::createDocument(); + std::unordered_multimap inputMap; + + inputMap.insert({ "color3", " 1.0, +2.0, 3.0 " }); + inputMap.insert({ "color4", "1.0, 2.00, 0.3000, -4" }); + inputMap.insert({ "integer", " 12 " }); + inputMap.insert({ "matrix33", + "01.0, 2.0, 0000.2310, " + " 01.0, 2.0, 0000.2310, " + "01.0, 2.0, 0000.2310 " }); + inputMap.insert({ "matrix44", + "01.0, 2.0, 0000.2310, 0.100, " + "01.0, 2.0, 0000.2310, 0.100, " + "01.0, 2.0, 0000.2310, 0.100, " + "01.0, 2.0, 0000.2310, 0.100" }); + inputMap.insert({ "vector2", "1.0, 0.012345608" }); // For precision check + inputMap.insert({ "vector3", " 1.0, +2.0, 3.0 " }); + inputMap.insert({ "vector4", "1.0, 2.00, 0.3000, -4" }); + inputMap.insert({ "string", "mystring" }); + inputMap.insert({ "boolean", "false" }); + inputMap.insert({ "filename", "filename1" }); + inputMap.insert({ "float", " 1.2e-10 " }); + inputMap.insert({ "float", " 00.1000 " }); + + unsigned int index = 0; + mx::ElementPtr child = doc->addNodeGraph("mygraph"); + mx::NodeGraphPtr graph = child->asA(); + // Add comment block at the start of the first doc to check skipping + mx::ElementPtr comment = doc->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 1"); + for (auto it = inputMap.begin(); it != inputMap.end(); ++it) + { + const std::string inputType = (*it).first; + mx::InputPtr input = graph->addInput("input_" + std::to_string(index), inputType); + if (inputType == "float") + { + input->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, " 0.0100 "); + input->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, " 01.0100 "); + index++; + } + else + { + input->setName("input_" + inputType); // Set by name for difference in order test + } + input->setValueString((*it).second); + } + + mx::DocumentPtr doc2 = mx::createDocument(); + std::unordered_multimap inputMap2; + inputMap2.insert({ "color4", "1, 2, 0.3, -4" }); + inputMap2.insert({ "integer", "12" }); + inputMap2.insert({ "matrix33", "1, 2, 0.231, 1, 2, 0.231, 1, 2, 0.231, 1, 2, 0.231" }); + inputMap2.insert({ "matrix44", "1, 2, 0.231, 0.1, 1, 2, 0.231, 0.1, 1, 2, 0.231, 0.1, 1, 2, 0.231, 0.1" }); + inputMap2.insert({ "vector2", "1, 0.012345611" }); // For precision check + inputMap2.insert({ "string", "mystring" }); + inputMap2.insert({ "boolean", "false" }); + inputMap2.insert({ "color3", "1, 2, 3" }); + inputMap2.insert({ "vector3", "1, 2, 3" }); + inputMap2.insert({ "vector4", "1, 2, 0.3, -4" }); + inputMap2.insert({ "filename", "filename1" }); + inputMap2.insert({ "float", "1.2e-10" }); + inputMap2.insert({ "float", "0.1" }); + + index = 0; + child = doc2->addNodeGraph("mygraph"); + graph = child->asA(); + std::vector floatInputs; + for (auto it = inputMap2.begin(); it != inputMap2.end(); ++it) + { + const std::string inputType = (*it).first; + mx::InputPtr input = graph->addInput("input_" + std::to_string(index), inputType); + // Note: order of value and ui attributes is different for ordering comparison + input->setValueString((*it).second); + if (inputType == "float") + { + input->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, " 0.01"); + input->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, " 1.01"); + floatInputs.push_back(input); + index++; + } + else + { + input->setName("input_" + inputType); + } + } + // Add comment blocks at end of second doc to check value and count checks + comment = doc2->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 2"); + comment = doc2->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 3"); + + mx::ElementEquivalenceOptions options; + std::string message; + + // Check that this fails when not performing value comparisons + options.performValueComparisons = false; + bool equivalent = doc->isEquivalent(doc2, options, &message); + REQUIRE(!equivalent); + + // Check attibute values + options.performValueComparisons = true; + equivalent = doc->isEquivalent(doc2, options, &message); + REQUIRE(equivalent); + + unsigned int currentPrecision = mx::Value::getFloatPrecision(); + // This will compare 0.012345608 versus: 1, 0.012345611 for input10 + options.floatPrecision = 8; + equivalent = doc->isEquivalent(doc2, options); + REQUIRE(!equivalent); + options.floatPrecision = currentPrecision; + + // Check attribute filtering of inputs + options.attributeExclusionList = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; + for (mx::InputPtr floatInput : floatInputs) + { + floatInput->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, "0.9"); + floatInput->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, "100.0"); + } + equivalent = doc->isEquivalent(doc2, options, &message); + REQUIRE(equivalent); + for (mx::InputPtr floatInput : floatInputs) + { + floatInput->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, " 0.01"); + floatInput->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, " 1.01"); + } + + // Check for child name mismatch + mx::ElementPtr mismatchElement = doc->getDescendant("mygraph/input_color4"); + std::string previousName = mismatchElement->getName(); + mismatchElement->setName("mismatch_color4"); + equivalent = doc->isEquivalent(doc2, options, &message); + REQUIRE(!equivalent); + mismatchElement->setName(previousName); + equivalent = doc->isEquivalent(doc2, options, &message); + REQUIRE(equivalent); + + // Check for functional nodegraphs + mx::NodeGraphPtr nodeGraph = doc->getNodeGraph("mygraph"); + REQUIRE(nodeGraph); + doc->addNodeDef("ND_mygraph"); + nodeGraph->setNodeDefString("ND_mygraph"); + mx::NodeGraphPtr nodeGraph2 = doc2->getNodeGraph("mygraph"); + REQUIRE(nodeGraph2); + doc2->addNodeDef("ND_mygraph"); + nodeGraph2->setNodeDefString("ND_mygraph"); + equivalent = doc->isEquivalent(doc2, options, &message); + REQUIRE(!equivalent); +} diff --git a/source/MaterialXTest/MaterialXCore/Node.cpp b/source/MaterialXTest/MaterialXCore/Node.cpp index b72cd65328..f3ce7d40de 100644 --- a/source/MaterialXTest/MaterialXCore/Node.cpp +++ b/source/MaterialXTest/MaterialXCore/Node.cpp @@ -159,12 +159,12 @@ TEST_CASE("Node", "[node]") REQUIRE(typeDef->getMembers().size() == scalarCount); // Reference the custom type. - std::string d65("400.0,82.75,500.0,109.35,600.0,90.01,700.0,71.61,800.0,59.45"); + std::string d65("{400;82.75;500;109.35;600;90.01;700;71.61;800;59.45}"); constant->setInputValue("value", d65, "spectrum"); REQUIRE(constant->getInput("value")->getType() == "spectrum"); REQUIRE(constant->getInput("value")->getValueString() == d65); - REQUIRE(constant->getInputValue("value")->isA()); - REQUIRE(constant->getInputValue("value")->asA() == d65); + REQUIRE(constant->getInputValue("value")->isA()); + REQUIRE(constant->getInputValue("value")->asA().getValueString() == d65); // Validate the document. REQUIRE(doc->validate()); @@ -627,43 +627,6 @@ TEST_CASE("Organization", "[nodegraph]") CHECK(nodeGraph->getBackdrops().empty()); } -TEST_CASE("Tokens", "[nodegraph]") -{ - mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); - mx::DocumentPtr stdlib = mx::createDocument(); - mx::loadLibraries({ "libraries" }, searchPath, stdlib); - - mx::DocumentPtr doc = mx::createDocument(); - mx::readFromXmlFile(doc, "resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx", searchPath); - - mx::StringVec graphNames = { "Tokenized_Image_2k_png", "Tokenized_Image_4k_jpg" }; - mx::StringVec resolutionStrings = { "2k", "4k" }; - mx::StringVec extensionStrings = { "png", "jpg" }; - for (size_t i=0; igetNodeGraph(graphNames[i]); - REQUIRE(graph); - std::vector tokens = graph->getActiveTokens(); - - mx::NodePtr imagePtr = graph->getNode("tiledimage"); - REQUIRE(imagePtr); - - mx::InputPtr input = imagePtr->getInput("file"); - REQUIRE(input); - - // Test file name substitution creation. - mx::StringResolverPtr resolver = input->createStringResolver(); - const mx::StringMap& substitutions = resolver->getFilenameSubstitutions(); - const std::string DELIMITER_PREFIX("["); - const std::string DELIMITER_POSTFIX("]"); - for (auto token : tokens) - { - const std::string tokenString = DELIMITER_PREFIX + token->getName() + DELIMITER_POSTFIX; - REQUIRE(substitutions.count(tokenString)); - } - } -} - TEST_CASE("Node Definition Creation", "[nodedef]") { mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); @@ -672,7 +635,7 @@ TEST_CASE("Node Definition Creation", "[nodedef]") mx::DocumentPtr doc = mx::createDocument(); mx::readFromXmlFile(doc, "resources/Materials/TestSuite/stdlib/definition/definition_from_nodegraph.mtlx", searchPath); - doc->importLibrary(stdlib); + doc->setDataLibrary(stdlib); mx::NodeGraphPtr graph = doc->getNodeGraph("test_colorcorrect"); REQUIRE(graph); diff --git a/source/MaterialXTest/MaterialXCore/Value.cpp b/source/MaterialXTest/MaterialXCore/Value.cpp index 40d6b120e7..31c333d211 100644 --- a/source/MaterialXTest/MaterialXCore/Value.cpp +++ b/source/MaterialXTest/MaterialXCore/Value.cpp @@ -78,6 +78,15 @@ TEST_CASE("Value strings", "[value]") REQUIRE_THROWS_AS(mx::fromValueString("text"), mx::ExceptionTypeError); REQUIRE_THROWS_AS(mx::fromValueString("1"), mx::ExceptionTypeError); REQUIRE_THROWS_AS(mx::fromValueString("1"), mx::ExceptionTypeError); + + // Parse value strings using structure syntax features. + REQUIRE(mx::parseStructValueString("{{1;2;3};4}") == (std::vector{"{1;2;3}","4"})); + REQUIRE(mx::parseStructValueString("{1;2;3;4}") == (std::vector{"1","2","3","4"})); + REQUIRE(mx::parseStructValueString("{1;{2;3};4}") == (std::vector{"1","{2;3}","4"})); + REQUIRE(mx::parseStructValueString("{1;{2;3;4}}") == (std::vector{"1","{2;3;4}"})); + REQUIRE(mx::parseStructValueString("{1;{2;{3;4}}}") == (std::vector{"1","{2;{3;4}}"})); + REQUIRE(mx::parseStructValueString("{1;2;{3};4}") == (std::vector{"1","2","{3}","4"})); + REQUIRE(mx::parseStructValueString("{1;2;{3};4}") == (std::vector{"1","2","{3}","4"})); } TEST_CASE("Typed values", "[value]") diff --git a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp index 2a9a0bb6fa..979320bd91 100644 --- a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp +++ b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp @@ -81,7 +81,7 @@ TEST_CASE("GenShader: GLSL Implementation Check", "[genglsl]") mx::StringSet generatorSkipNodeTypes; mx::StringSet generatorSkipNodeDefs; - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 30); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs); } TEST_CASE("GenShader: GLSL Unique Names", "[genglsl]") diff --git a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h index 97ad62f0e4..8d3e8c8720 100644 --- a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h +++ b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h @@ -51,10 +51,9 @@ class GlslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "ambientocclusion", "arrayappend", "screen", "curveadjust", "displacementshader", "volumeshader", - "IM_constant_", "IM_dot_", "IM_geompropvalue_boolean", "IM_geompropvalue_string", - "IM_light_genglsl", "IM_point_light_genglsl", "IM_spot_light_genglsl", "IM_directional_light_genglsl", - "IM_angle", "volumematerial", "ND_volumematerial" + "volumeshader", "volumematerial", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue_boolean", "IM_geompropvalue_string", + "IM_light_", "IM_point_light_", "IM_spot_light_", "IM_directional_light_" }; ShaderGeneratorTester::getImplementationWhiteList(whiteList); } diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index db75a5ddf6..610b237163 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -91,9 +91,10 @@ TEST_CASE("GenShader: MDL Implementation Check", "[genmdl]") mx::StringSet generatorSkipNodeTypes; generatorSkipNodeTypes.insert("light"); + mx::StringSet generatorSkipNodeDefs; - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 31); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs); } @@ -224,15 +225,9 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so moduleToTest = moduleToTest.substr(0, moduleToTest.size() - sourceCodePaths[0].getExtension().length() - 1); std::string renderExec(MATERIALX_MDL_RENDER_EXECUTABLE); - bool testMDLC = renderExec.empty(); - if (testMDLC) + std::string mdlcExec(MATERIALX_MDLC_EXECUTABLE); + if (!mdlcExec.empty()) // always run compiler { - std::string mdlcExec(MATERIALX_MDLC_EXECUTABLE); - if (mdlcExec.empty()) - { - return; - } - std::string mdlcCommand = mdlcExec; // use the same paths as the resolver @@ -263,12 +258,19 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so _logFile << "\tReturn code: " << std::to_string(returnValue) << std::endl; writeErrorCode = true; } - _logFile << "\tError: " << line << std::endl; + if (line.find(": Warning ") != std::string::npos) + { + _logFile << "\tWarning: " << line << std::endl; + } + else + { + _logFile << "\tError: " << line << std::endl; + } } CHECK(returnValue == 0); } - else + if (!renderExec.empty()) // render if renderer is available { std::string renderCommand = renderExec; @@ -357,6 +359,7 @@ TEST_CASE("GenShader: MDL Shader Generation", "[genmdl]") mx::FilePathVec testRootPaths; testRootPaths.push_back(searchPath.find("resources/Materials/TestSuite")); testRootPaths.push_back(searchPath.find("resources/Materials/Examples/StandardSurface")); + testRootPaths.push_back(searchPath.find("resources/Materials/Examples/UsdPreviewSurface")); const mx::FilePath logPath("genmdl_mdl_generate_test.txt"); diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h index f40254c5f4..ff2be4205d 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h @@ -49,6 +49,7 @@ class MdlShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester // df_cuda will currently hang on rendering one of the shaders in this file _skipFiles.insert("heighttonormal_in_nodegraph.mtlx"); } + ShaderGeneratorTester::addSkipFiles(); } @@ -75,9 +76,8 @@ class MdlShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "ambientocclusion", "arrayappend", "backfacing", "screen", "curveadjust", "displacementshader", - "volumeshader", "IM_constant_", "IM_dot_", "IM_geomattrvalue", "IM_angle", - "geompropvalue", "surfacematerial", "volumematerial", + "displacementshader", "volumeshader", "surfacematerial", "volumematerial", "geompropvalue", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geomattrvalue", "IM_absorption_vdf_", "IM_mix_vdf_", "IM_add_vdf_", "IM_multiply_vdf", "IM_measured_edf_", "IM_blackbody_", "IM_conical_edf_", "IM_displacement_", "IM_volume_", "IM_light_" diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp index b0309ea44d..32baaec5f0 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp @@ -84,7 +84,7 @@ TEST_CASE("GenShader: MSL Implementation Check", "[genmsl]") mx::StringSet generatorSkipNodeTypes; mx::StringSet generatorSkipNodeDefs; - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 30); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs); } TEST_CASE("GenShader: MSL Unique Names", "[genmsl]") diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h index 78cb7a8f4e..eea7b86acb 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h @@ -41,6 +41,10 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester ParentClass::addSkipNodeDefs(); } + void addSkipFiles() override + { + } + void setupDependentLibraries() override { ParentClass::setupDependentLibraries(); @@ -66,10 +70,10 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "ambientocclusion", "arrayappend", "backfacing", "screen", "curveadjust", "displacementshader", - "volumeshader", "IM_constant_", "IM_dot_", "IM_geompropvalue_boolean", "IM_geompropvalue_string", - "IM_light_genmsl", "IM_point_light_genmsl", "IM_spot_light_genmsl", "IM_directional_light_genmsl", - "IM_angle", "surfacematerial", "volumematerial", "ND_surfacematerial", "ND_volumematerial", "ND_backface_util", "IM_backface_util_genmsl" + "displacementshader", "volumeshader", "surfacematerial", "volumematerial", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue_boolean", "IM_geompropvalue_string", + "IM_light_", "IM_point_light_", "IM_spot_light_", "IM_directional_light_", + "ND_surfacematerial", "ND_volumematerial" }; } }; diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp index f31c3d2a9b..6e613c85b8 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp @@ -87,9 +87,10 @@ TEST_CASE("GenShader: OSL Implementation Check", "[genosl]") mx::StringSet generatorSkipNodeTypes; generatorSkipNodeTypes.insert("light"); + mx::StringSet generatorSkipNodeDefs; - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 31); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs); } TEST_CASE("GenShader: OSL Unique Names", "[genosl]") diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h index a4ccdc2003..aa84a62218 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h @@ -42,6 +42,11 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { _skipLibraryFiles.insert( "pbrlib_genosl_arnold_impl.mtlx" ); } + + void addSkipFiles() override + { + } + // Ignore light shaders in the document for OSL void findLights(mx::DocumentPtr /*doc*/, std::vector& lights) override { @@ -58,8 +63,8 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "ambientocclusion", "arrayappend", "backfacing", "screen", "curveadjust", "displacementshader", - "volumeshader", "IM_constant_", "IM_dot_", "IM_geompropvalue", "IM_angle", "ND_backface_util" + "displacementshader", "volumeshader", + "IM_constant_", "IM_dot_", "IM_angle", "IM_geompropvalue" }; ShaderGeneratorTester::getImplementationWhiteList(whiteList); } diff --git a/source/MaterialXTest/MaterialXGenShader/GenShader.cpp b/source/MaterialXTest/MaterialXGenShader/GenShader.cpp index 22afffbff4..a959283aad 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShader.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShader.cpp @@ -161,7 +161,7 @@ TEST_CASE("GenShader: Transparency Regression Check", "[genshader]") bool testValue = transparencyTest[i]; mx::DocumentPtr testDoc = mx::createDocument(); - testDoc->importLibrary(libraries); + testDoc->setDataLibrary(libraries); try { @@ -207,7 +207,7 @@ void testDeterministicGeneration(mx::DocumentPtr libraries, mx::GenContext& cont { mx::DocumentPtr testDoc = mx::createDocument(); mx::readFromXmlFile(testDoc, testFile); - testDoc->importLibrary(libraries); + testDoc->setDataLibrary(libraries); // Keep the document alive to make sure // new memory is allocated for each run @@ -272,7 +272,7 @@ void checkPixelDependencies(mx::DocumentPtr libraries, mx::GenContext& context) mx::DocumentPtr testDoc = mx::createDocument(); mx::readFromXmlFile(testDoc, testFile); - testDoc->importLibrary(libraries); + testDoc->setDataLibrary(libraries); mx::ElementPtr element = testDoc->getChild(testElement); CHECK(element); @@ -385,7 +385,7 @@ TEST_CASE("GenShader: Track Application Variables", "[genshader]") mx::DocumentPtr testDoc = mx::createDocument(); mx::readFromXmlString(testDoc, testDocumentString); - testDoc->importLibrary(libraries); + testDoc->setDataLibrary(libraries); mx::ElementPtr element = testDoc->getChild(testElement); CHECK(element); diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 848348066c..40f89c001f 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -67,8 +67,7 @@ bool getShaderSource(mx::GenContext& context, // Check that implementations exist for all nodedefs supported per generator void checkImplementations(mx::GenContext& context, const mx::StringSet& generatorSkipNodeTypes, - const mx::StringSet& generatorSkipNodeDefs, - unsigned int expectedSkipCount) + const mx::StringSet& generatorSkipNodeDefs) { const mx::ShaderGenerator& shadergen = context.getShaderGenerator(); @@ -90,10 +89,8 @@ void checkImplementations(mx::GenContext& context, // Node types to explicitly skip temporarily. mx::StringSet skipNodeTypes = { - "ambientocclusion", "displacement", "volume", - "curveadjust", "conical_edf", "measured_edf", "absorption_vdf", @@ -268,7 +265,6 @@ void checkImplementations(mx::GenContext& context, std::cerr << (std::string("Missing list: ") + missing_str) << std::endl; } REQUIRE(missing == 0); - REQUIRE(skipped == expectedSkipCount); implDumpBuffer.close(); } @@ -316,8 +312,7 @@ void testUniqueNames(mx::GenContext& context, const std::string& stage) void shaderGenPerformanceTest(mx::GenContext& context) { mx::DocumentPtr nodeLibrary = mx::createDocument(); - mx::FilePath currentPath = mx::FilePath::getCurrentPath(); - const mx::FileSearchPath libSearchPath(currentPath); + const mx::FileSearchPath libSearchPath(mx::getDefaultDataSearchPath()); // Load the standard libraries. loadLibraries({ "libraries" }, libSearchPath, nodeLibrary); @@ -351,8 +346,9 @@ void shaderGenPerformanceTest(mx::GenContext& context) } // Read mtlx documents + mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); mx::FilePathVec testRootPaths; - testRootPaths.push_back("resources/Materials/Examples/StandardSurface"); + testRootPaths.push_back(searchPath.find("resources/Materials/Examples/StandardSurface")); std::vector loadedDocuments; mx::StringVec documentsPaths; @@ -367,12 +363,12 @@ void shaderGenPerformanceTest(mx::GenContext& context) REQUIRE(loadedDocuments.size() > 0); REQUIRE(loadedDocuments.size() == documentsPaths.size()); - // Shuffle the order of documents and perform document library import validatation and shadergen + // Shuffle the order of documents and perform document library import validation and shadergen std::mt19937 rng(0); std::shuffle(loadedDocuments.begin(), loadedDocuments.end(), rng); for (const auto& doc : loadedDocuments) { - doc->importLibrary(nodeLibrary); + doc->setDataLibrary(nodeLibrary); std::vector elements = mx::findRenderableElements(doc); REQUIRE(elements.size() > 0); @@ -649,6 +645,9 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons addColorManagement(); addUnitSystem(); + // Register struct typedefs from the library files. + _shaderGenerator->loadStructTypeDefs(_dependLib); + // Test suite setup addSkipFiles(); @@ -705,6 +704,8 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons preprocessDocument(doc); _shaderGenerator->registerShaderMetadata(doc, context); + _shaderGenerator->loadStructTypeDefs(doc); + // For each new file clear the implementation cache. // Since the new file might contain implementations with names // colliding with implementations in previous test cases. @@ -721,7 +722,7 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons bool importedLibrary = false; try { - doc->importLibrary(_dependLib); + doc->setDataLibrary(_dependLib); importedLibrary = true; } catch (mx::Exception& e) @@ -734,8 +735,8 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons } // Find and register lights - findLights(doc, _lights); - registerLights(doc, _lights, context); + findLights(_dependLib, _lights); + registerLights(_dependLib, _lights, context); // Find elements to render in the document std::vector elements; diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h index 2bac14e435..d4876a03f7 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h @@ -46,8 +46,7 @@ bool generateCode(mx::GenContext& context, const std::string& shaderName, mx::Ty // Check that implementations exist for all nodedefs supported per generator void checkImplementations(mx::GenContext& context, const mx::StringSet& generatorSkipNodeTypes, - const mx::StringSet& generatorSkipNodeDefs, - unsigned int expectedSkipCount); + const mx::StringSet& generatorSkipNodeDefs); // Utility test to check unique name generation on a shader generator void testUniqueNames(mx::GenContext& context, const std::string& stage); diff --git a/source/MaterialXTest/MaterialXRender/RenderUtil.cpp b/source/MaterialXTest/MaterialXRender/RenderUtil.cpp index d8265a4050..e3e5e8033e 100644 --- a/source/MaterialXTest/MaterialXRender/RenderUtil.cpp +++ b/source/MaterialXTest/MaterialXRender/RenderUtil.cpp @@ -223,7 +223,7 @@ bool ShaderRenderTester::validate(const mx::FilePath optionsFilePath) // colliding with implementations in previous test cases. context.clearNodeImplementations(); - doc->importLibrary(dependLib); + doc->setDataLibrary(dependLib); ioTimer.endTimer(); validateTimer.startTimer(); diff --git a/source/MaterialXTest/MaterialXRenderOsl/CMakeLists.txt b/source/MaterialXTest/MaterialXRenderOsl/CMakeLists.txt index b132376c95..9e4c464b98 100644 --- a/source/MaterialXTest/MaterialXRenderOsl/CMakeLists.txt +++ b/source/MaterialXTest/MaterialXRenderOsl/CMakeLists.txt @@ -3,6 +3,12 @@ file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h") target_sources(MaterialXTest PUBLIC ${source} ${headers}) +target_compile_definitions(MaterialXTest PRIVATE + MATERIALX_OSL_BINARY_OSLC=\"${MATERIALX_OSL_BINARY_OSLC}\" + MATERIALX_OSL_BINARY_TESTRENDER=\"${MATERIALX_OSL_BINARY_TESTRENDER}\" + MATERIALX_OSL_INCLUDE_PATH=\"${MATERIALX_OSL_INCLUDE_PATH}\" +) + add_tests("${source}") assign_source_group("Source Files" ${source}) diff --git a/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp b/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp index a7f7293755..05c83ae82e 100644 --- a/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp +++ b/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp @@ -33,8 +33,12 @@ TEST_CASE("GenReference: OSL Reference", "[genreference]") { oslRenderer = mx::OslRenderer::create(); oslRenderer->setOslCompilerExecutable(MATERIALX_OSL_BINARY_OSLC); - mx::FileSearchPath oslIncludePaths; - oslIncludePaths.append(mx::FilePath(MATERIALX_OSL_INCLUDE_PATH)); + mx::FileSearchPath oslIncludePaths; + mx::FilePath oslStandardIncludePath = mx::FilePath(MATERIALX_OSL_INCLUDE_PATH); + if (!oslStandardIncludePath.isEmpty()) + { + oslIncludePaths.append(oslStandardIncludePath); + } // Add in library include path for compile testing as the generated // shader's includes are not added with absolute paths. oslIncludePaths.append(searchPath.find("libraries/stdlib/genosl/include")); @@ -61,8 +65,7 @@ TEST_CASE("GenReference: OSL Reference", "[genreference]") // Generate reference shaders. // Ignore the following nodes: const mx::StringSet ignoreNodeList = { "surfacematerial", "volumematerial", - "constant_filename", "arrayappend", - "dot_filename"}; + "constant_filename", "dot_filename"}; bool failedGeneration = false; for (const mx::NodeDefPtr& nodedef : stdlib->getNodeDefs()) diff --git a/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp b/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp index c23f74cba3..4dad5227b1 100644 --- a/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp +++ b/source/MaterialXTest/MaterialXRenderOsl/RenderOsl.cpp @@ -126,7 +126,11 @@ void OslShaderRenderTester::createRenderer(std::ostream& log) _renderer->setOslCompilerExecutable(oslcExecutable); const std::string testRenderExecutable(MATERIALX_OSL_BINARY_TESTRENDER); _renderer->setOslTestRenderExecutable(testRenderExecutable); - _renderer->setOslIncludePath(mx::FileSearchPath(MATERIALX_OSL_INCLUDE_PATH)); + mx::FilePath oslStandardIncludePath = mx::FilePath(MATERIALX_OSL_INCLUDE_PATH); + if (!oslStandardIncludePath.isEmpty()) + { + _renderer->setOslIncludePath(mx::FileSearchPath(oslStandardIncludePath)); + } try { diff --git a/source/MaterialXTest/README.md b/source/MaterialXTest/README.md index 8cd732f2cf..6de3064ec8 100644 --- a/source/MaterialXTest/README.md +++ b/source/MaterialXTest/README.md @@ -82,3 +82,13 @@ When rendering tests are enabled through the `MATERIALX_TEST_RENDER` option, the #### HTML Render Comparisons - A `tests_to_html` Python script is provided in the [`python/MaterialXTest`](../../python/MaterialXTest) folder, which can be run to generate an HTML file comparing the rendered results in each shading language. - Example render comparisons may be found in [commits to the MaterialX repository](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1164), and we encourage developers to post their own results when making changes that have the potential to impact generated shaders. + +#### Benchmark Tests + +Processing MaterialX documents and generating shaders is an integral part of many pipelines. MaterialX benchmark testing using [Catch2 benchmark framework](https://github.com/catchorg/Catch2/blob/devel/docs/benchmarks.md) and can be enabled using `MATERIALX_BUILD_BENCHMARK_TESTS` CMake macro. + +Here is an example of how to run the benchmark test + + `MaterialXTest.exe "GenShader: GLSL Performance Test" --benchmark-samples 10` + +This will iterate and gather 10 samples of the test case and report low, mean and high timing results. diff --git a/source/MaterialXView/Editor.cpp b/source/MaterialXView/Editor.cpp index 090937d6e5..6d64c55b30 100644 --- a/source/MaterialXView/Editor.cpp +++ b/source/MaterialXView/Editor.cpp @@ -18,11 +18,11 @@ namespace class EditorColorPicker : public ng::ColorPicker { public: - EditorColorPicker(ng::Widget* parent, const ng::Color& color) : + EditorColorPicker(ng::ref parent, const ng::Color& color) : ng::ColorPicker(parent, color) { - ng::Popup* popup = this->popup(); - ng::Widget* floatGroup = new ng::Widget(popup); + ng::ref popup = this->popup(); + ng::ref floatGroup = new ng::Widget(popup); auto layout = new ng::GridLayout(ng::Orientation::Horizontal, 2, ng::Alignment::Middle, 2, 2); layout->set_col_alignment({ ng::Alignment::Fill, ng::Alignment::Fill }); @@ -60,7 +60,7 @@ class EditorColorPicker : public ng::ColorPicker protected: // Additional numeric entry / feedback widgets - ng::FloatBox* _colorWidgets[4]; + ng::ref> _colorWidgets[4]; }; } // anonymous namespace @@ -70,10 +70,6 @@ class EditorColorPicker : public ng::ColorPicker // PropertyEditor::PropertyEditor() : - _window(nullptr), - _container(nullptr), - _gridLayout2(nullptr), - _gridLayout3(nullptr), _visible(false), _fileDialogsForImages(true) { @@ -81,7 +77,7 @@ PropertyEditor::PropertyEditor() : void PropertyEditor::create(Viewer& parent) { - ng::Window* parentWindow = parent.getWindow(); + ng::ref parentWindow = parent.getWindow(); // Remove the window associated with the form. // This is done by explicitly creating and owning the window @@ -110,7 +106,7 @@ void PropertyEditor::create(Viewer& parent) _window->set_position(previousPosition); _window->set_visible(_visible); - ng::VScrollPanel* scroll_panel = new ng::VScrollPanel(_window); + ng::ref scroll_panel = new ng::VScrollPanel(_window); scroll_panel->set_fixed_height(300); _container = new ng::Widget(scroll_panel); _container->set_layout(new ng::GroupLayout(1, 1, 1, 1)); @@ -127,7 +123,7 @@ void PropertyEditor::create(Viewer& parent) } void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::string& group, - ng::Widget* container, Viewer* viewer, bool editable) + ng::ref container, Viewer* viewer, bool editable) { const mx::UIProperties& ui = item.ui; mx::ValuePtr value = item.variable->getValue(); @@ -148,9 +144,9 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st if (!group.empty()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); - ng::Label* groupLabel = new ng::Label(twoColumns, group); + ng::ref groupLabel = new ng::Label(twoColumns, group); groupLabel->set_font_size(20); groupLabel->set_font("sans-bold"); new ng::Label(twoColumns, ""); @@ -187,11 +183,11 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st const size_t valueIndex = indexInEnumeration(); if (INVALID_INDEX != valueIndex) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); - ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, { "" }); + ng::ref comboBox = new ng::ComboBox(twoColumns, { "" }); comboBox->set_enabled(editable); comboBox->set_items(enumeration); comboBox->set_selected_index(static_cast(valueIndex)); @@ -215,7 +211,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st } else { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); @@ -252,9 +248,9 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Float widget else if (value->isA()) { - ng::Widget* threeColumns = new ng::Widget(container); + ng::ref threeColumns = new ng::Widget(container); threeColumns->set_layout(_gridLayout3); - ng::FloatBox* floatBox = createFloatWidget(threeColumns, label, value->asA(), &ui, [viewer, path](float value) + ng::ref> floatBox = createFloatWidget(threeColumns, label, value->asA(), &ui, [viewer, path](float value) { mx::MaterialPtr material = viewer->getSelectedMaterial(); if (material) @@ -269,12 +265,12 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Boolean widget else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); bool v = value->asA(); new ng::Label(twoColumns, label); - ng::CheckBox* boolVar = new ng::CheckBox(twoColumns, ""); + ng::ref boolVar = new ng::CheckBox(twoColumns, ""); boolVar->set_checked(v); boolVar->set_font_size(15); boolVar->set_callback([path, viewer](bool v) @@ -290,7 +286,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Color3 input. Can map to a combo box if an enumeration else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); // Determine if there is an enumeration for this @@ -312,7 +308,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Create a combo box. The items are the enumerations in order. if (index >= 0) { - ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, { "" }); + ng::ref comboBox = new ng::ComboBox(twoColumns, { "" }); comboBox->set_enabled(editable); comboBox->set_items(enumeration); comboBox->set_selected_index(index); @@ -353,7 +349,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Color4 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); @@ -376,7 +372,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 2 widget else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector2 v = value->asA(); @@ -415,7 +411,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 3 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector3 v = value->asA(); @@ -470,7 +466,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 4 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector4 v = value->asA(); @@ -542,16 +538,17 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st std::string v = value->asA(); if (!v.empty()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); if (item.variable->getType() == mx::Type::FILENAME) { new ng::Label(twoColumns, label); - ng::Button* buttonVar = new ng::Button(twoColumns, mx::FilePath(v).getBaseName()); + ng::ref buttonVar = new ng::Button(twoColumns, mx::FilePath(v).getBaseName()); buttonVar->set_enabled(editable); buttonVar->set_font_size(15); - buttonVar->set_callback([buttonVar, path, viewer]() + auto buttonVarPtr = buttonVar.get(); + buttonVar->set_callback([buttonVarPtr, path, viewer]() { mx::MaterialPtr material = viewer->getSelectedMaterial(); mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; @@ -572,7 +569,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st if (!filename.empty()) { uniform->setValue(mx::Value::createValue(filename)); - buttonVar->set_caption(mx::FilePath(filename).getBaseName()); + buttonVarPtr->set_caption(mx::FilePath(filename).getBaseName()); viewer->perform_layout(); } } @@ -583,7 +580,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st else { new ng::Label(twoColumns, label); - ng::TextBox* stringVar = new ng::TextBox(twoColumns, v); + ng::ref stringVar = new ng::TextBox(twoColumns, v); stringVar->set_fixed_size({ 100, 20 }); stringVar->set_font_size(15); stringVar->set_callback([path, viewer](const std::string& v) @@ -629,12 +626,12 @@ void PropertyEditor::updateContents(Viewer* viewer) } if (!shaderName.empty() && shaderName != "surface") { - ng::Widget* twoColumns = new ng::Widget(_container); + ng::ref twoColumns = new ng::Widget(_container); twoColumns->set_layout(_gridLayout2); - ng::Label* modelLabel = new ng::Label(twoColumns, "Shading Model"); + ng::ref modelLabel = new ng::Label(twoColumns, "Shading Model"); modelLabel->set_font_size(20); modelLabel->set_font("sans-bold"); - ng::Label* nameLabel = new ng::Label(twoColumns, shaderName); + ng::ref nameLabel = new ng::Label(twoColumns, shaderName); nameLabel->set_font_size(20); } } @@ -686,15 +683,15 @@ void PropertyEditor::updateContents(Viewer* viewer) viewer->perform_layout(); } -ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& label, float value, - const mx::UIProperties* ui, std::function callback) +ng::ref> createFloatWidget(ng::ref parent, const std::string& label, float value, + const mx::UIProperties* ui, std::function callback) { new ng::Label(parent, label); - ng::Slider* slider = new ng::Slider(parent); + ng::ref slider = new ng::Slider(parent); slider->set_value(value); - ng::FloatBox* box = new ng::FloatBox(parent, value); + ng::ref> box = new ng::FloatBox(parent, value); box->set_fixed_width(60); box->set_font_size(15); box->set_alignment(ng::TextBox::Alignment::Right); @@ -732,29 +729,31 @@ ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& la } } - slider->set_callback([box, callback](float value) + auto sliderPtr = slider.get(); + auto boxPtr = box.get(); + slider->set_callback([boxPtr, callback](float value) { - box->set_value(value); + boxPtr->set_value(value); callback(value); }); - box->set_callback([slider, callback](float value) + box->set_callback([sliderPtr, callback](float value) { - slider->set_value(value); + sliderPtr->set_value(value); callback(value); }); return box; } -ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, - const mx::UIProperties* ui, std::function callback) +ng::ref> createIntWidget(ng::ref parent, const std::string& label, int value, + const mx::UIProperties* ui, std::function callback) { new ng::Label(parent, label); - ng::Slider* slider = new ng::Slider(parent); + ng::ref slider = new ng::Slider(parent); slider->set_value((float) value); - ng::IntBox* box = new ng::IntBox(parent, value); + ng::ref> box = new ng::IntBox(parent, value); box->set_fixed_width(60); box->set_font_size(15); box->set_alignment(ng::TextBox::Alignment::Right); @@ -792,14 +791,16 @@ ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, i } } - slider->set_callback([box, callback](float value) + auto sliderPtr = slider.get(); + auto boxPtr = box.get(); + slider->set_callback([boxPtr, callback](float value) { - box->set_value((int) value); + boxPtr->set_value((int) value); callback((int) value); }); - box->set_callback([slider, callback](int value) + box->set_callback([sliderPtr, callback](int value) { - slider->set_value((float) value); + sliderPtr->set_value((float) value); callback(value); }); diff --git a/source/MaterialXView/Editor.h b/source/MaterialXView/Editor.h index b1fb4a3ade..b99f1f160c 100644 --- a/source/MaterialXView/Editor.h +++ b/source/MaterialXView/Editor.h @@ -39,7 +39,7 @@ class PropertyEditor } } - ng::Window* getWindow() + ng::ref getWindow() { return _window; } @@ -47,19 +47,19 @@ class PropertyEditor protected: void create(Viewer& parent); void addItemToForm(const mx::UIPropertyItem& item, const std::string& group, - ng::Widget* container, Viewer* viewer, bool editable); + ng::ref container, Viewer* viewer, bool editable); - ng::Window* _window; - ng::Widget* _container; - ng::GridLayout* _gridLayout2; - ng::GridLayout* _gridLayout3; + ng::ref _window; + ng::ref _container; + ng::ref _gridLayout2; + ng::ref _gridLayout3; bool _visible; bool _fileDialogsForImages; }; -ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& label, float value, - const mx::UIProperties* ui, std::function callback = nullptr); -ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, - const mx::UIProperties* ui, std::function callback); +ng::ref> createFloatWidget(ng::ref parent, const std::string& label, float value, + const mx::UIProperties* ui, std::function callback = nullptr); +ng::ref> createIntWidget(ng::ref parent, const std::string& label, int value, + const mx::UIProperties* ui, std::function callback); #endif // MATERIALXVIEW_EDITOR_H diff --git a/source/MaterialXView/RenderPipelineMetal.mm b/source/MaterialXView/RenderPipelineMetal.mm index 872ec8e10d..59da87a847 100644 --- a/source/MaterialXView/RenderPipelineMetal.mm +++ b/source/MaterialXView/RenderPipelineMetal.mm @@ -15,6 +15,8 @@ #include +#include + namespace { @@ -59,10 +61,10 @@ MTL(device), width * _viewer->m_pixel_ratio, height * _viewer->m_pixel_ratio, - 4, mx::Image::BaseType::UINT8, + 4, mx::Image::BaseType::HALF, MTL(supportsTiledPipeline) ? (id)color_texture : nil, - false, MTLPixelFormatBGRA8Unorm)); + false, MTLPixelFormatRGBA16Float)); } void MetalRenderPipeline::resizeFramebuffer(int width, int height, @@ -697,16 +699,30 @@ unsigned int width = MTL(currentFramebuffer())->getWidth(); unsigned int height = MTL(currentFramebuffer())->getHeight(); - MTL(waitForComplition()); + MTL(waitForCompletion()); + + id srcTexture = MTL(supportsTiledPipeline) ? + (id)_viewer->_colorTexture : + MTL(currentFramebuffer())->getColorTexture(); + mx::MetalFramebufferPtr framebuffer = mx::MetalFramebuffer::create( MTL(device), width, height, 4, mx::Image::BaseType::UINT8, - MTL(supportsTiledPipeline) ? - (id)_viewer->_colorTexture : - MTL(currentFramebuffer())->getColorTexture(), + nil, false, MTLPixelFormatBGRA8Unorm); - mx::ImagePtr frame = framebuffer->getColorImage(MTL(cmdQueue)); + id dstTexture = framebuffer->getColorTexture(); + + id cmdQueue = MTL(cmdQueue); + + // Copy with format conversion + MPSImageConversion* conversion = [[MPSImageConversion alloc] initWithDevice:MTL(device)]; + id cmdBuffer = [cmdQueue commandBuffer]; + [conversion encodeToCommandBuffer:cmdBuffer sourceTexture:srcTexture destinationTexture:dstTexture]; + [cmdBuffer commit]; + [cmdBuffer waitUntilCompleted]; + + mx::ImagePtr frame = framebuffer->getColorImage(cmdQueue); // Flips the captured image std::vector tmp(frame->getRowStride()); diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index c3910c4f1e..aefdf2d401 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -52,6 +52,11 @@ const float DEFAULT_CAMERA_ZOOM = 1.0f; namespace { +#ifdef MATERIALXVIEW_METAL_BACKEND +const bool USE_FLOAT_BUFFER = true; +#else +const bool USE_FLOAT_BUFFER = false; +#endif const int MIN_ENV_SAMPLE_COUNT = 4; const int MAX_ENV_SAMPLE_COUNT = 1024; @@ -152,8 +157,7 @@ Viewer::Viewer(const std::string& materialFilename, int screenHeight, const mx::Color3& screenColor) : ng::Screen(ng::Vector2i(screenWidth, screenHeight), "MaterialXView", - true, false, true, true, false, 4, 0), - _window(nullptr), + true, false, true, true, USE_FLOAT_BUFFER, 4, 0), _materialFilename(materialFilename), _meshFilename(meshFilename), _envRadianceFilename(envRadianceFilename), @@ -179,11 +183,7 @@ Viewer::Viewer(const std::string& materialFilename, _shadowSoftness(1), _ambientOcclusionGain(0.6f), _selectedGeom(0), - _geomLabel(nullptr), - _geometrySelectionBox(nullptr), _selectedMaterial(0), - _materialLabel(nullptr), - _materialSelectionBox(nullptr), _identityCamera(mx::Camera::create()), _viewCamera(mx::Camera::create()), _envCamera(mx::Camera::create()), @@ -227,9 +227,6 @@ Viewer::Viewer(const std::string& materialFilename, _bakeHeight(0), _bakeDocumentPerMaterial(false), _frameTiming(false), - _timingLabel(nullptr), - _timingPanel(nullptr), - _timingText(nullptr), _avgFrameTime(0.0) { // Resolve input filenames, taking both the provided search path and @@ -290,11 +287,11 @@ void Viewer::initialize() _imageHandler->setSearchPath(_searchPath); // Initialize user interfaces. - createLoadMeshInterface(_window, "Load Mesh"); - createLoadMaterialsInterface(_window, "Load Material"); - createLoadEnvironmentInterface(_window, "Load Environment"); - createPropertyEditorInterface(_window, "Property Editor"); - createAdvancedSettings(_window); + createLoadMeshInterface((ng::ref) _window, "Load Mesh"); + createLoadMaterialsInterface((ng::ref) _window, "Load Material"); + createLoadEnvironmentInterface((ng::ref) _window, "Load Environment"); + createPropertyEditorInterface((ng::ref) _window, "Property Editor"); + createAdvancedSettings((ng::ref) _window); // Create geometry selection box. _geomLabel = new ng::Label(_window, "Select Geometry"); @@ -557,10 +554,11 @@ mx::ElementPredicate Viewer::getElementPredicate() }; } -void Viewer::createLoadMeshInterface(Widget* parent, const std::string& label) +void Viewer::createLoadMeshInterface(ng::ref parent, const std::string& label) { - ng::Button* meshButton = new ng::Button(parent, label); + ng::ref meshButton = new ng::Button(parent, label); meshButton->set_icon(FA_FOLDER); + meshButton->set_tooltip("Load a new geometry in the OBJ or glTF format."); meshButton->set_callback([this]() { m_process_events = false; @@ -584,10 +582,11 @@ void Viewer::createLoadMeshInterface(Widget* parent, const std::string& label) }); } -void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& label) +void Viewer::createLoadMaterialsInterface(ng::ref parent, const std::string& label) { - ng::Button* materialButton = new ng::Button(parent, label); + ng::ref materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_FOLDER); + materialButton->set_tooltip("Load a material document in the MTLX format."); materialButton->set_callback([this]() { m_process_events = false; @@ -601,10 +600,11 @@ void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& lab }); } -void Viewer::createLoadEnvironmentInterface(Widget* parent, const std::string& label) +void Viewer::createLoadEnvironmentInterface(ng::ref parent, const std::string& label) { - ng::Button* envButton = new ng::Button(parent, label); + ng::ref envButton = new ng::Button(parent, label); envButton->set_icon(FA_FOLDER); + envButton->set_tooltip("Load a lat-long environment light in the HDR format."); envButton->set_callback([this]() { m_process_events = false; @@ -626,10 +626,11 @@ void Viewer::createLoadEnvironmentInterface(Widget* parent, const std::string& l }); } -void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& label) +void Viewer::createSaveMaterialsInterface(ng::ref parent, const std::string& label) { - ng::Button* materialButton = new ng::Button(parent, label); + ng::ref materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_SAVE); + materialButton->set_tooltip("Save a material document in the MTLX format."); materialButton->set_callback([this]() { m_process_events = false; @@ -655,10 +656,11 @@ void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& lab }); } -void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& label) +void Viewer::createPropertyEditorInterface(ng::ref parent, const std::string& label) { - ng::Button* editorButton = new ng::Button(parent, label); + ng::ref editorButton = new ng::Button(parent, label); editorButton->set_flags(ng::Button::ToggleButton); + editorButton->set_tooltip("View or edit properties of the current material."); editorButton->set_change_callback([this](bool state) { _propertyEditor.setVisible(state); @@ -666,56 +668,136 @@ void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& la }); } -void Viewer::createAdvancedSettings(Widget* parent) +void Viewer::createDocumentationInterface(ng::ref parent) { - ng::PopupButton* advancedButton = new ng::PopupButton(parent, "Advanced Settings"); + ng::ref documentationLayout = new ng::GridLayout(ng::Orientation::Vertical, 3, + ng::Alignment::Minimum, 13, 5); + documentationLayout->set_row_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); + + ng::ref documentationGroup = new ng::Widget(parent); + documentationGroup->set_layout(documentationLayout); + ng::ref documentationLabel = new ng::Label(documentationGroup, "Documentation"); + documentationLabel->set_font_size(20); + documentationLabel->set_font("sans-bold"); + + _shortcutsButton = new ng::Button(documentationGroup, "Keyboard Shortcuts"); + _shortcutsButton->set_flags(ng::Button::ToggleButton); + _shortcutsButton->set_icon(FA_CARET_RIGHT); + _shortcutsButton->set_fixed_width(230); + + _shortcutsTable = new ng::Widget(documentationGroup); + _shortcutsTable->set_layout(new ng::GroupLayout(13)); + _shortcutsTable->set_visible(false); + + // Recompute layout when showing/hiding shortcuts. + _shortcutsButton->set_change_callback([this](bool state) + { + _shortcutsButton->set_icon(state ? FA_CARET_DOWN : FA_CARET_RIGHT); + _shortcutsTable->set_visible(state); + perform_layout(); + }); + + // 2 cell layout for (key, description) pair. + ng::ref gridLayout2 = new ng::GridLayout(ng::Orientation::Horizontal, 2, + ng::Alignment::Minimum, 2, 2); + gridLayout2->set_col_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); + + const std::array, 16> KEYBOARD_SHORTCUTS = + { + std::make_pair("R", "Reload the current material from file. " + "Hold SHIFT to reload all standard libraries as well."), + std::make_pair("G", "Save the current GLSL shader source to file."), + std::make_pair("O", "Save the current OSL shader source to file."), + std::make_pair("M", "Save the current MDL shader source to file."), + std::make_pair("L", "Load GLSL shader source from file. " + "Editing the source files before loading provides a way " + "to debug and experiment with shader source code."), + std::make_pair("D", "Save each node graph in the current material as a DOT file. " + "See www.graphviz.org for more details on this format."), + std::make_pair("F", "Capture the current frame and save to file."), + std::make_pair("W", "Create a wedge rendering and save to file. " + "See Advanced Settings for additional controls."), + std::make_pair("T", "Translate the current material to a different shading model. " + "See Advanced Settings for additional controls."), + std::make_pair("B", "Bake the current material to textures. " + "See Advanced Settings for additional controls."), + std::make_pair("UP","Select the previous geometry."), + std::make_pair("DOWN","Select the next geometry."), + std::make_pair("RIGHT", "Switch to the next material."), + std::make_pair("LEFT", "Switch to the previous material."), + std::make_pair("+", "Zoom in with the camera."), + std::make_pair("-", "Zoom out with the camera.") + }; + + for (const auto& shortcut : KEYBOARD_SHORTCUTS) + { + ng::ref twoColumns = new ng::Widget(_shortcutsTable); + twoColumns->set_layout(gridLayout2); + + ng::ref keyLabel = new ng::Label(twoColumns, shortcut.first); + keyLabel->set_font("sans-bold"); + keyLabel->set_font_size(16); + keyLabel->set_fixed_width(40); + + ng::ref descriptionLabel = new ng::Label(twoColumns, shortcut.second); + descriptionLabel->set_font_size(16); + descriptionLabel->set_fixed_width(160); + } +} + +void Viewer::createAdvancedSettings(ng::ref parent) +{ + ng::ref advancedButton = new ng::PopupButton(parent, "Advanced Settings"); advancedButton->set_icon(FA_TOOLS); advancedButton->set_chevron_icon(-1); - ng::Popup* advancedPopupParent = advancedButton->popup(); + advancedButton->set_tooltip("Asset and rendering options."); + ng::ref advancedPopupParent = advancedButton->popup(); advancedPopupParent->set_layout(new ng::GroupLayout()); - ng::VScrollPanel* scrollPanel = new ng::VScrollPanel(advancedPopupParent); + ng::ref scrollPanel = new ng::VScrollPanel(advancedPopupParent); scrollPanel->set_fixed_height(500); - ng::Widget* advancedPopup = new ng::Widget(scrollPanel); - advancedPopup->set_layout(new ng::GroupLayout(13)); + ng::ref advancedPopup = new ng::Widget(scrollPanel); + advancedPopup->set_layout(new ng::BoxLayout(ng::Orientation::Vertical)); - ng::Label* viewLabel = new ng::Label(advancedPopup, "Viewing Options"); + ng::ref settingsGroup = new ng::Widget(advancedPopup); + settingsGroup->set_layout(new ng::GroupLayout(13)); + ng::ref viewLabel = new ng::Label(settingsGroup, "Viewing Options"); viewLabel->set_font_size(20); viewLabel->set_font("sans-bold"); - ng::CheckBox* drawEnvironmentBox = new ng::CheckBox(advancedPopup, "Draw Environment"); + ng::ref drawEnvironmentBox = new ng::CheckBox(settingsGroup, "Draw Environment"); drawEnvironmentBox->set_checked(_drawEnvironment); drawEnvironmentBox->set_callback([this](bool enable) { _drawEnvironment = enable; }); - ng::CheckBox* outlineSelectedGeometryBox = new ng::CheckBox(advancedPopup, "Outline Selected Geometry"); + ng::ref outlineSelectedGeometryBox = new ng::CheckBox(settingsGroup, "Outline Selected Geometry"); outlineSelectedGeometryBox->set_checked(_outlineSelection); outlineSelectedGeometryBox->set_callback([this](bool enable) { _outlineSelection = enable; }); - ng::Label* renderLabel = new ng::Label(advancedPopup, "Render Options"); + ng::ref renderLabel = new ng::Label(settingsGroup, "Render Options"); renderLabel->set_font_size(20); renderLabel->set_font("sans-bold"); - ng::CheckBox* transparencyBox = new ng::CheckBox(advancedPopup, "Render Transparency"); + ng::ref transparencyBox = new ng::CheckBox(settingsGroup, "Render Transparency"); transparencyBox->set_checked(_renderTransparency); transparencyBox->set_callback([this](bool enable) { _renderTransparency = enable; }); - ng::CheckBox* doubleSidedBox = new ng::CheckBox(advancedPopup, "Render Double-Sided"); + ng::ref doubleSidedBox = new ng::CheckBox(settingsGroup, "Render Double-Sided"); doubleSidedBox->set_checked(_renderDoubleSided); doubleSidedBox->set_callback([this](bool enable) { _renderDoubleSided = enable; }); - ng::CheckBox* importanceSampleBox = new ng::CheckBox(advancedPopup, "Environment FIS"); + ng::ref importanceSampleBox = new ng::CheckBox(settingsGroup, "Environment FIS"); importanceSampleBox->set_checked(_genContext.getOptions().hwSpecularEnvironmentMethod == mx::SPECULAR_ENVIRONMENT_FIS); _lightHandler->setUsePrefilteredMap(_genContext.getOptions().hwSpecularEnvironmentMethod != mx::SPECULAR_ENVIRONMENT_FIS); importanceSampleBox->set_callback([this](bool enable) @@ -728,7 +810,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionBox = new ng::CheckBox(advancedPopup, "Transmission Refraction"); + ng::ref refractionBox = new ng::CheckBox(settingsGroup, "Transmission Refraction"); refractionBox->set_checked(_genContext.getOptions().hwTransmissionRenderMethod == mx::TRANSMISSION_REFRACTION); refractionBox->set_callback([this](bool enable) { @@ -739,14 +821,14 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionSidedBox = new ng::CheckBox(advancedPopup, "Refraction Two-Sided"); + ng::ref refractionSidedBox = new ng::CheckBox(settingsGroup, "Refraction Two-Sided"); refractionSidedBox->set_checked(_lightHandler->getRefractionTwoSided()); refractionSidedBox->set_callback([this](bool enable) { _lightHandler->setRefractionTwoSided(enable); }); - ng::CheckBox* shaderInterfaceBox = new ng::CheckBox(advancedPopup, "Reduce Shader Interface"); + ng::ref shaderInterfaceBox = new ng::CheckBox(settingsGroup, "Reduce Shader Interface"); shaderInterfaceBox->set_checked(_genContext.getOptions().shaderInterfaceType == mx::SHADER_INTERFACE_REDUCED); shaderInterfaceBox->set_callback([this](bool enable) { @@ -754,11 +836,11 @@ void Viewer::createAdvancedSettings(Widget* parent) setShaderInterfaceType(interfaceType); }); - Widget* albedoGroup = new Widget(advancedPopup); + ng::ref albedoGroup = new Widget(settingsGroup); albedoGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(albedoGroup, "Albedo Method:"); mx::StringVec albedoOptions = { "Analytic", "Table", "MC" }; - ng::ComboBox* albedoBox = new ng::ComboBox(albedoGroup, albedoOptions); + ng::ref albedoBox = new ng::ComboBox(albedoGroup, albedoOptions); albedoBox->set_chevron_icon(-1); albedoBox->set_selected_index((int) _genContext.getOptions().hwDirectionalAlbedoMethod ); albedoBox->set_callback([this](int index) @@ -785,7 +867,7 @@ void Viewer::createAdvancedSettings(Widget* parent) } }); - Widget* sampleGroup = new Widget(advancedPopup); + ng::ref sampleGroup = new Widget(settingsGroup); sampleGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(sampleGroup, "Environment Samples:"); mx::StringVec sampleOptions; @@ -795,7 +877,7 @@ void Viewer::createAdvancedSettings(Widget* parent) sampleOptions.push_back(std::to_string(i)); m_process_events = true; } - ng::ComboBox* sampleBox = new ng::ComboBox(sampleGroup, sampleOptions); + ng::ref sampleBox = new ng::ComboBox(sampleGroup, sampleOptions); sampleBox->set_chevron_icon(-1); sampleBox->set_selected_index((int)std::log2(_lightHandler->getEnvSampleCount() / MIN_ENV_SAMPLE_COUNT) / 2); sampleBox->set_callback([this](int index) @@ -803,30 +885,30 @@ void Viewer::createAdvancedSettings(Widget* parent) _lightHandler->setEnvSampleCount(MIN_ENV_SAMPLE_COUNT * (int) std::pow(4, index)); }); - ng::Label* lightingLabel = new ng::Label(advancedPopup, "Lighting Options"); + ng::ref lightingLabel = new ng::Label(settingsGroup, "Lighting Options"); lightingLabel->set_font_size(20); lightingLabel->set_font("sans-bold"); - ng::CheckBox* directLightingBox = new ng::CheckBox(advancedPopup, "Direct Lighting"); + ng::ref directLightingBox = new ng::CheckBox(settingsGroup, "Direct Lighting"); directLightingBox->set_checked(_lightHandler->getDirectLighting()); directLightingBox->set_callback([this](bool enable) { _lightHandler->setDirectLighting(enable); }); - ng::CheckBox* indirectLightingBox = new ng::CheckBox(advancedPopup, "Indirect Lighting"); + ng::ref indirectLightingBox = new ng::CheckBox(settingsGroup, "Indirect Lighting"); indirectLightingBox->set_checked(_lightHandler->getIndirectLighting()); indirectLightingBox->set_callback([this](bool enable) { _lightHandler->setIndirectLighting(enable); }); - ng::Widget* lightRotationRow = new ng::Widget(advancedPopup); + ng::ref lightRotationRow = new ng::Widget(settingsGroup); lightRotationRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties ui; ui.uiMin = mx::Value::createValue(0.0f); ui.uiMax = mx::Value::createValue(360.0f); - ng::FloatBox* lightRotationBox = createFloatWidget(lightRotationRow, "Light Rotation:", + ng::ref> lightRotationBox = createFloatWidget(lightRotationRow, "Light Rotation:", _lightRotation, &ui, [this](float value) { _lightRotation = value; @@ -834,11 +916,11 @@ void Viewer::createAdvancedSettings(Widget* parent) }); lightRotationBox->set_editable(true); - ng::Label* shadowingLabel = new ng::Label(advancedPopup, "Shadowing Options"); + ng::ref shadowingLabel = new ng::Label(settingsGroup, "Shadowing Options"); shadowingLabel->set_font_size(20); shadowingLabel->set_font("sans-bold"); - ng::CheckBox* shadowMapBox = new ng::CheckBox(advancedPopup, "Shadow Map"); + ng::ref shadowMapBox = new ng::CheckBox(settingsGroup, "Shadow Map"); shadowMapBox->set_checked(_genContext.getOptions().hwShadowMap); shadowMapBox->set_callback([this](bool enable) { @@ -846,7 +928,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* ambientOcclusionBox = new ng::CheckBox(advancedPopup, "Ambient Occlusion"); + ng::ref ambientOcclusionBox = new ng::CheckBox(settingsGroup, "Ambient Occlusion"); ambientOcclusionBox->set_checked(_genContext.getOptions().hwAmbientOcclusion); ambientOcclusionBox->set_callback([this](bool enable) { @@ -854,23 +936,23 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::Widget* ambientOcclusionGainRow = new ng::Widget(advancedPopup); + ng::ref ambientOcclusionGainRow = new ng::Widget(settingsGroup); ambientOcclusionGainRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); - ng::FloatBox* ambientOcclusionGainBox = createFloatWidget(ambientOcclusionGainRow, "AO Gain:", + ng::ref> ambientOcclusionGainBox = createFloatWidget(ambientOcclusionGainRow, "AO Gain:", _ambientOcclusionGain, nullptr, [this](float value) { _ambientOcclusionGain = value; }); ambientOcclusionGainBox->set_editable(true); - ng::Label* sceneLabel = new ng::Label(advancedPopup, "Scene Options"); + ng::ref sceneLabel = new ng::Label(settingsGroup, "Scene Options"); sceneLabel->set_font_size(20); sceneLabel->set_font("sans-bold"); - Widget* unitGroup = new Widget(advancedPopup); + ng::ref unitGroup = new Widget(settingsGroup); unitGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(unitGroup, "Distance Unit:"); - ng::ComboBox* distanceUnitBox = new ng::ComboBox(unitGroup, _distanceUnitOptions); + ng::ref distanceUnitBox = new ng::ComboBox(unitGroup, _distanceUnitOptions); distanceUnitBox->set_fixed_size(ng::Vector2i(100, 20)); distanceUnitBox->set_chevron_icon(-1); if (_distanceUnitConverter) @@ -894,68 +976,68 @@ void Viewer::createAdvancedSettings(Widget* parent) m_process_events = true; }); - ng::Label* meshLoading = new ng::Label(advancedPopup, "Mesh Loading Options"); + ng::ref meshLoading = new ng::Label(settingsGroup, "Mesh Loading Options"); meshLoading->set_font_size(20); meshLoading->set_font("sans-bold"); - ng::CheckBox* splitUdimsBox = new ng::CheckBox(advancedPopup, "Split By UDIMs"); + ng::ref splitUdimsBox = new ng::CheckBox(settingsGroup, "Split By UDIMs"); splitUdimsBox->set_checked(_splitByUdims); splitUdimsBox->set_callback([this](bool enable) { _splitByUdims = enable; }); - ng::Label* materialLoading = new ng::Label(advancedPopup, "Material Loading Options"); + ng::ref materialLoading = new ng::Label(settingsGroup, "Material Loading Options"); materialLoading->set_font_size(20); materialLoading->set_font("sans-bold"); - ng::CheckBox* mergeMaterialsBox = new ng::CheckBox(advancedPopup, "Merge Materials"); + ng::ref mergeMaterialsBox = new ng::CheckBox(settingsGroup, "Merge Materials"); mergeMaterialsBox->set_checked(_mergeMaterials); mergeMaterialsBox->set_callback([this](bool enable) { _mergeMaterials = enable; }); - ng::CheckBox* showInputsBox = new ng::CheckBox(advancedPopup, "Show All Inputs"); + ng::ref showInputsBox = new ng::CheckBox(settingsGroup, "Show All Inputs"); showInputsBox->set_checked(_showAllInputs); showInputsBox->set_callback([this](bool enable) { _showAllInputs = enable; }); - ng::CheckBox* flattenBox = new ng::CheckBox(advancedPopup, "Flatten Subgraphs"); + ng::ref flattenBox = new ng::CheckBox(settingsGroup, "Flatten Subgraphs"); flattenBox->set_checked(_flattenSubgraphs); flattenBox->set_callback([this](bool enable) { _flattenSubgraphs = enable; }); - ng::Label* envLoading = new ng::Label(advancedPopup, "Environment Loading Options"); + ng::ref envLoading = new ng::Label(settingsGroup, "Environment Loading Options"); envLoading->set_font_size(20); envLoading->set_font("sans-bold"); - ng::CheckBox* normalizeEnvBox = new ng::CheckBox(advancedPopup, "Normalize Environment"); + ng::ref normalizeEnvBox = new ng::CheckBox(settingsGroup, "Normalize Environment"); normalizeEnvBox->set_checked(_normalizeEnvironment); normalizeEnvBox->set_callback([this](bool enable) { _normalizeEnvironment = enable; }); - ng::CheckBox* splitDirectLightBox = new ng::CheckBox(advancedPopup, "Split Direct Light"); + ng::ref splitDirectLightBox = new ng::CheckBox(settingsGroup, "Split Direct Light"); splitDirectLightBox->set_checked(_splitDirectLight); splitDirectLightBox->set_callback([this](bool enable) { _splitDirectLight = enable; }); - ng::Label* translationLabel = new ng::Label(advancedPopup, "Translation Options (T)"); + ng::ref translationLabel = new ng::Label(settingsGroup, "Translation Options (T)"); translationLabel->set_font_size(20); translationLabel->set_font("sans-bold"); - ng::Widget* targetShaderGroup = new ng::Widget(advancedPopup); + ng::ref targetShaderGroup = new ng::Widget(settingsGroup); targetShaderGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(targetShaderGroup, "Target Shader"); - ng::TextBox* targetShaderBox = new ng::TextBox(targetShaderGroup, _targetShader); + ng::ref targetShaderBox = new ng::TextBox(targetShaderGroup, _targetShader); targetShaderBox->set_callback([this](const std::string& choice) { _targetShader = choice; @@ -964,46 +1046,46 @@ void Viewer::createAdvancedSettings(Widget* parent) targetShaderBox->set_font_size(16); targetShaderBox->set_editable(true); - ng::Label* textureLabel = new ng::Label(advancedPopup, "Texture Baking Options (B)"); + ng::ref textureLabel = new ng::Label(settingsGroup, "Texture Baking Options (B)"); textureLabel->set_font_size(20); textureLabel->set_font("sans-bold"); - ng::CheckBox* bakeHdrBox = new ng::CheckBox(advancedPopup, "Bake HDR Textures"); + ng::ref bakeHdrBox = new ng::CheckBox(settingsGroup, "Bake HDR Textures"); bakeHdrBox->set_checked(_bakeHdr); bakeHdrBox->set_callback([this](bool enable) { _bakeHdr = enable; }); - ng::CheckBox* bakeAverageBox = new ng::CheckBox(advancedPopup, "Bake Averaged Textures"); + ng::ref bakeAverageBox = new ng::CheckBox(settingsGroup, "Bake Averaged Textures"); bakeAverageBox->set_checked(_bakeAverage); bakeAverageBox->set_callback([this](bool enable) { _bakeAverage = enable; }); - ng::CheckBox* bakeOptimized = new ng::CheckBox(advancedPopup, "Optimize Baked Constants"); + ng::ref bakeOptimized = new ng::CheckBox(settingsGroup, "Optimize Baked Constants"); bakeOptimized->set_checked(_bakeOptimize); bakeOptimized->set_callback([this](bool enable) { _bakeOptimize = enable; }); - ng::CheckBox* bakeDocumentPerMaterial= new ng::CheckBox(advancedPopup, "Bake Document Per Material"); + ng::ref bakeDocumentPerMaterial= new ng::CheckBox(settingsGroup, "Bake Document Per Material"); bakeDocumentPerMaterial->set_checked(_bakeDocumentPerMaterial); bakeDocumentPerMaterial->set_callback([this](bool enable) { _bakeDocumentPerMaterial = enable; }); - ng::Label* wedgeLabel = new ng::Label(advancedPopup, "Wedge Render Options (W)"); + ng::ref wedgeLabel = new ng::Label(settingsGroup, "Wedge Render Options (W)"); wedgeLabel->set_font_size(20); wedgeLabel->set_font("sans-bold"); - ng::Widget* wedgeNameGroup = new ng::Widget(advancedPopup); + ng::ref wedgeNameGroup = new ng::Widget(settingsGroup); wedgeNameGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(wedgeNameGroup, "Property Name"); - ng::TextBox* wedgeNameBox = new ng::TextBox(wedgeNameGroup, _wedgePropertyName); + ng::ref wedgeNameBox = new ng::TextBox(wedgeNameGroup, _wedgePropertyName); wedgeNameBox->set_callback([this](const std::string& choice) { _wedgePropertyName = choice; @@ -1012,12 +1094,12 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeNameBox->set_font_size(16); wedgeNameBox->set_editable(true); - ng::Widget* wedgeMinGroup = new ng::Widget(advancedPopup); + ng::ref wedgeMinGroup = new ng::Widget(settingsGroup); wedgeMinGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeProp; wedgeProp.uiSoftMin = mx::Value::createValue(0.0f); wedgeProp.uiSoftMax = mx::Value::createValue(1.0f); - ng::FloatBox* wedgeMinBox = createFloatWidget(wedgeMinGroup, "Property Min:", + ng::ref> wedgeMinBox = createFloatWidget(wedgeMinGroup, "Property Min:", _wedgePropertyMax, &wedgeProp, [this](float value) { _wedgePropertyMin = value; @@ -1025,9 +1107,9 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMinBox->set_value(0.0); wedgeMinBox->set_editable(true); - ng::Widget* wedgeMaxGroup = new ng::Widget(advancedPopup); + ng::ref wedgeMaxGroup = new ng::Widget(settingsGroup); wedgeMaxGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); - ng::FloatBox* wedgeMaxBox = createFloatWidget(wedgeMaxGroup, "Property Max:", + ng::ref> wedgeMaxBox = createFloatWidget(wedgeMaxGroup, "Property Max:", _wedgePropertyMax, &wedgeProp, [this](float value) { _wedgePropertyMax = value; @@ -1035,19 +1117,21 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMaxBox->set_value(1.0); wedgeMaxBox->set_editable(true); - ng::Widget* wedgeCountGroup = new ng::Widget(advancedPopup); + ng::ref wedgeCountGroup = new ng::Widget(settingsGroup); wedgeCountGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeCountProp; wedgeCountProp.uiMin = mx::Value::createValue(1); wedgeCountProp.uiSoftMax = mx::Value::createValue(8); wedgeCountProp.uiStep = mx::Value::createValue(1); - ng::IntBox* wedgeCountBox = createIntWidget(wedgeCountGroup, "Image Count:", + ng::ref> wedgeCountBox = createIntWidget(wedgeCountGroup, "Image Count:", _wedgeImageCount, &wedgeCountProp, [this](int value) { _wedgeImageCount = value; }); wedgeCountBox->set_value(8); wedgeCountBox->set_editable(true); + + createDocumentationInterface(advancedPopup); } void Viewer::updateGeometrySelections() @@ -1222,8 +1306,8 @@ void Viewer::loadDocument(const mx::FilePath& filename, mx::DocumentPtr librarie mx::readFromXmlFile(doc, filename, _searchPath, &readOptions); _materialSearchPath = mx::getSourceSearchPath(doc); - // Import libraries. - doc->importLibrary(libraries); + // Store data library reference. + doc->setDataLibrary(libraries); // Apply direct lights. applyDirectLights(doc); @@ -1675,6 +1759,9 @@ void Viewer::initContext(mx::GenContext& context) unitSystem->setUnitConverterRegistry(_unitRegistry); context.getShaderGenerator().setUnitSystem(unitSystem); context.getOptions().targetDistanceUnit = "meter"; + + // Initialize the struct typedefs from the stdlib + context.getShaderGenerator().loadStructTypeDefs(_stdLib); } void Viewer::loadStandardLibraries() @@ -2344,7 +2431,7 @@ void Viewer::updateCameras() void Viewer::updateDisplayedProperties() { _propertyEditor.updateContents(this); - createSaveMaterialsInterface(_propertyEditor.getWindow(), "Save Material"); + createSaveMaterialsInterface((ng::ref) _propertyEditor.getWindow(), "Save Material"); perform_layout(); } diff --git a/source/MaterialXView/Viewer.h b/source/MaterialXView/Viewer.h index c3f4bb48da..8f0257e1e1 100644 --- a/source/MaterialXView/Viewer.h +++ b/source/MaterialXView/Viewer.h @@ -16,7 +16,6 @@ #include #include - #include namespace mx = MaterialX; @@ -180,7 +179,7 @@ class Viewer : public ng::Screen } // Return the underlying NanoGUI window. - ng::Window* getWindow() const + ng::ref getWindow() const { return _window; } @@ -284,12 +283,13 @@ class Viewer : public ng::Screen void updateMaterialSelectionUI(); void updateDisplayedProperties(); - void createLoadMeshInterface(Widget* parent, const std::string& label); - void createLoadMaterialsInterface(Widget* parent, const std::string& label); - void createLoadEnvironmentInterface(Widget* parent, const std::string& label); - void createSaveMaterialsInterface(Widget* parent, const std::string& label); - void createPropertyEditorInterface(Widget* parent, const std::string& label); - void createAdvancedSettings(Widget* parent); + void createLoadMeshInterface(ng::ref parent, const std::string& label); + void createLoadMaterialsInterface(ng::ref parent, const std::string& label); + void createLoadEnvironmentInterface(ng::ref parent, const std::string& label); + void createSaveMaterialsInterface(ng::ref parent, const std::string& label); + void createPropertyEditorInterface(ng::ref parent, const std::string& label); + void createAdvancedSettings(ng::ref parent); + void createDocumentationInterface(ng::ref parent); // Return the ambient occlusion image, if any, associated with the given material. mx::ImagePtr getAmbientOcclusionImage(mx::MaterialPtr material); @@ -318,7 +318,7 @@ class Viewer : public ng::Screen void setShaderInterfaceType(mx::ShaderInterfaceType interfaceType); private: - ng::Window* _window; + ng::ref _window; RenderPipelinePtr _renderPipeline; mx::FilePath _materialFilename; @@ -380,15 +380,15 @@ class Viewer : public ng::Screen // Geometry selections std::vector _geometryList; size_t _selectedGeom; - ng::Label* _geomLabel; - ng::ComboBox* _geometrySelectionBox; + ng::ref _geomLabel; + ng::ref _geometrySelectionBox; // Material selections std::vector _materials; mx::MaterialPtr _wireMaterial; size_t _selectedMaterial; - ng::Label* _materialLabel; - ng::ComboBox* _materialSelectionBox; + ng::ref _materialLabel; + ng::ref _materialSelectionBox; PropertyEditor _propertyEditor; // Material assignments @@ -475,11 +475,15 @@ class Viewer : public ng::Screen // Frame timing bool _frameTiming; - ng::Label* _timingLabel; - ng::Widget* _timingPanel; - ng::TextBox* _timingText; + ng::ref _timingLabel; + ng::ref _timingPanel; + ng::ref _timingText; mx::ScopedTimer _frameTimer; double _avgFrameTime; + + // Documentation UI + ng::ref _shortcutsButton; + ng::ref _shortcutsTable; }; extern const mx::Vector3 DEFAULT_CAMERA_POSITION; diff --git a/source/PyMaterialX/PyMaterialXCore/PyDocument.cpp b/source/PyMaterialX/PyMaterialXCore/PyDocument.cpp index 3f4403c673..e021bc92de 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyDocument.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyDocument.cpp @@ -29,6 +29,9 @@ void bindPyDocument(py::module& mod) py::class_(mod, "Document") .def("initialize", &mx::Document::initialize) .def("copy", &mx::Document::copy) + .def("setDataLibrary", &mx::Document::setDataLibrary) + .def("getDataLibrary", &mx::Document::getDataLibrary) + .def("hasDataLibrary", &mx::Document::hasDataLibrary) .def("importLibrary", &mx::Document::importLibrary) .def("getReferencedSourceUris", &mx::Document::getReferencedSourceUris) .def("addNodeGraph", &mx::Document::addNodeGraph, diff --git a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp index 6e846c120e..05f858d4c3 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp @@ -29,6 +29,12 @@ void bindPyElement(py::module& mod) py::class_(mod, "Element") .def(py::self == py::self) .def(py::self != py::self) + .def("isEquivalent", [](const mx::Element& elem, mx::ConstElementPtr& rhs, const mx::ElementEquivalenceOptions& options) + { + std::string message; + bool res = elem.isEquivalent(rhs, options, &message); + return std::pair(res, message); + }) .def("setCategory", &mx::Element::setCategory) .def("getCategory", &mx::Element::getCategory) .def("setName", &mx::Element::setName) @@ -103,6 +109,15 @@ void bindPyElement(py::module& mod) py::arg("geom") = mx::EMPTY_STRING) .def("asString", &mx::Element::asString) .def("__str__", &mx::Element::asString) + .def_readonly_static("NAME_ATTRIBUTE", &mx::Element::NAME_ATTRIBUTE) + .def_readonly_static("FILE_PREFIX_ATTRIBUTE", &mx::Element::FILE_PREFIX_ATTRIBUTE) + .def_readonly_static("GEOM_PREFIX_ATTRIBUTE", &mx::Element::GEOM_PREFIX_ATTRIBUTE) + .def_readonly_static("COLOR_SPACE_ATTRIBUTE", &mx::Element::COLOR_SPACE_ATTRIBUTE) + .def_readonly_static("INHERIT_ATTRIBUTE", &mx::Element::INHERIT_ATTRIBUTE) + .def_readonly_static("NAMESPACE_ATTRIBUTE", &mx::Element::NAMESPACE_ATTRIBUTE) + .def_readonly_static("DOC_ATTRIBUTE", &mx::Element::DOC_ATTRIBUTE) + .def_readonly_static("XPOS_ATTRIBUTE", &mx::Element::XPOS_ATTRIBUTE) + .def_readonly_static("YPOS_ATTRIBUTE", &mx::Element::YPOS_ATTRIBUTE) BIND_ELEMENT_FUNC_INSTANCE(Collection) BIND_ELEMENT_FUNC_INSTANCE(Document) BIND_ELEMENT_FUNC_INSTANCE(GeomInfo) @@ -196,6 +211,13 @@ void bindPyElement(py::module& mod) py::class_(mod, "GenericElement") .def_readonly_static("CATEGORY", &mx::GenericElement::CATEGORY); + py::class_(mod, "ElementEquivalenceOptions") + .def_readwrite("performValueComparisons", &mx::ElementEquivalenceOptions::performValueComparisons) + .def_readwrite("floatFormat", &mx::ElementEquivalenceOptions::floatFormat) + .def_readwrite("floatPrecision", &mx::ElementEquivalenceOptions::floatPrecision) + .def_readwrite("attributeExclusionList", &mx::ElementEquivalenceOptions::attributeExclusionList) + .def(py::init<>()); + py::class_(mod, "StringResolver") .def("setFilePrefix", &mx::StringResolver::setFilePrefix) .def("getFilePrefix", &mx::StringResolver::getFilePrefix) diff --git a/source/PyMaterialX/PyMaterialXCore/PyModule.cpp b/source/PyMaterialX/PyMaterialXCore/PyModule.cpp index e2e8a0080f..c22b7de841 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyModule.cpp @@ -26,7 +26,7 @@ void bindPyVariant(py::module& mod); PYBIND11_MODULE(PyMaterialXCore, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXCore library"; + mod.doc() = "Core MaterialX elements and graph traversal."; bindPyElement(mod); bindPyTraversal(mod); diff --git a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp index 501f9d5f04..c36bd6c288 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp @@ -6,6 +6,7 @@ #include #include +#include #define BIND_TYPE_INSTANCE(NAME, T) \ py::class_, std::shared_ptr< mx::TypedValue >, mx::Value>(mod, "TypedValue_" #NAME) \ @@ -22,7 +23,10 @@ void bindPyValue(py::module& mod) py::class_(mod, "Value") .def("getValueString", &mx::Value::getValueString) .def("getTypeString", &mx::Value::getTypeString) - .def_static("createValueFromStrings", &mx::Value::createValueFromStrings); + .def_static("createValueFromStrings", &mx::Value::createValueFromStrings, + py::arg("value"), + py::arg("type"), + py::arg("typeDefPtr") = nullptr); BIND_TYPE_INSTANCE(integer, int) BIND_TYPE_INSTANCE(boolean, bool) diff --git a/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp b/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp index 3965f48753..469ec43590 100644 --- a/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXFormat/PyModule.cpp @@ -13,7 +13,7 @@ void bindPyUtil(py::module& mod); PYBIND11_MODULE(PyMaterialXFormat, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXFormat library"; + mod.doc() = "Cross-platform support for document serialization and file utilities."; // PyMaterialXFormat depends on types defined in PyMaterialXCore PYMATERIALX_IMPORT_MODULE(PyMaterialXCore); diff --git a/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp index 9ab46e514d..448e1f4321 100644 --- a/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenGlsl/PyModule.cpp @@ -14,7 +14,7 @@ void bindPyVkShaderGenerator(py::module& mod); PYBIND11_MODULE(PyMaterialXGenGlsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXGenGlsl library"; + mod.doc() = "Shader generation using the OpenGL Shading Language."; // PyMaterialXGenGlsl depends on types defined in PyMaterialXGenShader PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); diff --git a/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp index a34b28a729..f656f9a395 100644 --- a/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenMdl/PyModule.cpp @@ -11,7 +11,7 @@ void bindPyMdlShaderGenerator(py::module& mod); PYBIND11_MODULE(PyMaterialXGenMdl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXGenMdl library"; + mod.doc() = "Shader generation using the Material Definition Language."; // PyMaterialXGenMdl depends on types defined in PyMaterialXGenShader PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); diff --git a/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp index b3dcdb10a8..454f04c9ee 100644 --- a/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenMsl/PyModule.cpp @@ -12,7 +12,7 @@ void bindPyMslResourceBindingContext(py::module &mod); PYBIND11_MODULE(PyMaterialXGenMsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXGenMsl library"; + mod.doc() = "Shader generation using the Metal Shading Language."; // PyMaterialXGenMsl depends on types defined in PyMaterialXGenShader PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); diff --git a/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp index 54d7d2439a..a503bacab5 100644 --- a/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenOsl/PyModule.cpp @@ -11,7 +11,7 @@ void bindPyOslShaderGenerator(py::module& mod); PYBIND11_MODULE(PyMaterialXGenOsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXGenOsl library"; + mod.doc() = "Shader generation using Open Shading Language."; // PyMaterialXGenOsl depends on types defined in PyMaterialXGenShader PYMATERIALX_IMPORT_MODULE(PyMaterialXGenShader); diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyModule.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyModule.cpp index f3dc613bff..a3f9911f33 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyModule.cpp @@ -24,7 +24,7 @@ void bindPyUnitSystem(py::module& mod); PYBIND11_MODULE(PyMaterialXGenShader, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXGenShader library"; + mod.doc() = "Core shader generation support for MaterialX."; bindPyColorManagement(mod); bindPyShaderPort(mod); diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp index b952bd4651..0c8a086e58 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp @@ -22,5 +22,7 @@ void bindPyShaderGenerator(py::module& mod) .def("setUnitSystem", &mx::ShaderGenerator::setUnitSystem) .def("getUnitSystem", &mx::ShaderGenerator::getUnitSystem) .def("getTokenSubstitutions", &mx::ShaderGenerator::getTokenSubstitutions) + .def("loadStructTypeDefs", &mx::ShaderGenerator::loadStructTypeDefs) + .def("clearStructTypeDefs", &mx::ShaderGenerator::clearStructTypeDefs) .def("registerShaderMetadata", &mx::ShaderGenerator::registerShaderMetadata); } diff --git a/source/PyMaterialX/PyMaterialXRender/PyModule.cpp b/source/PyMaterialX/PyMaterialXRender/PyModule.cpp index bbf9688403..450b1dda69 100644 --- a/source/PyMaterialX/PyMaterialXRender/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXRender/PyModule.cpp @@ -23,7 +23,7 @@ void bindPyCgltfLoader(py::module& mod); PYBIND11_MODULE(PyMaterialXRender, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXRender library"; + mod.doc() = "Core rendering support for MaterialX."; // PyMaterialXRender depends on types defined in PyMaterialXCore PYMATERIALX_IMPORT_MODULE(PyMaterialXCore); diff --git a/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp index d0ef04158d..69f5b3d353 100644 --- a/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXRenderGlsl/PyModule.cpp @@ -14,7 +14,7 @@ void bindPyTextureBaker(py::module& mod); PYBIND11_MODULE(PyMaterialXRenderGlsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXRenderGlsl library"; + mod.doc() = "Rendering support for the OpenGL Shading Language."; // PyMaterialXRenderGlsl depends on types defined in PyMaterialXRender PYMATERIALX_IMPORT_MODULE(PyMaterialXRender); diff --git a/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm b/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm index f4d0dbeaeb..63bd933591 100644 --- a/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm +++ b/source/PyMaterialX/PyMaterialXRenderMsl/PyModule.mm @@ -14,7 +14,7 @@ PYBIND11_MODULE(PyMaterialXRenderMsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXRenderMsl library"; + mod.doc() = "Rendering support for the Metal Shading Language."; // PyMaterialXRenderMsl depends on types defined in PyMaterialXRender PYMATERIALX_IMPORT_MODULE(PyMaterialXRender); diff --git a/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp b/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp index 4019d364ab..c013afef89 100644 --- a/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp +++ b/source/PyMaterialX/PyMaterialXRenderOsl/PyModule.cpp @@ -11,7 +11,7 @@ void bindPyOslRenderer(py::module& mod); PYBIND11_MODULE(PyMaterialXRenderOsl, mod) { - mod.doc() = "Module containing Python bindings for the MaterialXRenderOsl library"; + mod.doc() = "Rendering support for Open Shading Language."; // PyMaterialXRenderOsl depends on types defined in PyMaterialXRender PYMATERIALX_IMPORT_MODULE(PyMaterialXRender);