diff --git a/MaterialX/documents/CMakeLists.txt b/MaterialX/documents/CMakeLists.txt old mode 100644 new mode 100755 index c58bb4d..d270eb7 --- a/MaterialX/documents/CMakeLists.txt +++ b/MaterialX/documents/CMakeLists.txt @@ -1,46 +1,45 @@ -set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) -set(DOXYGEN_HTML_OUTPUT_DIR ${DOXYGEN_OUTPUT_DIR}/html) -set(DOXYGEN_INPUT_LIST ${CMAKE_CURRENT_BINARY_DIR}/MainPage.md) - -set(MATERIALX_DOXYGEN_SOURCE_FOLDERS - ${PROJECT_SOURCE_DIR}/source/MaterialXCore - ${PROJECT_SOURCE_DIR}/source/MaterialXFormat - ${PROJECT_SOURCE_DIR}/source/MaterialXGenShader - ${PROJECT_SOURCE_DIR}/source/MaterialXGenShader/Nodes - ${PROJECT_SOURCE_DIR}/source/MaterialXGenGlsl - ${PROJECT_SOURCE_DIR}/source/MaterialXGenGlsl/Nodes - ${PROJECT_SOURCE_DIR}/source/MaterialXGenSlang - ${PROJECT_SOURCE_DIR}/source/MaterialXGenOsl - ${PROJECT_SOURCE_DIR}/source/MaterialXGenMdl - ${PROJECT_SOURCE_DIR}/source/MaterialXRender - ${PROJECT_SOURCE_DIR}/source/MaterialXRenderHw - ${PROJECT_SOURCE_DIR}/source/MaterialXRenderGlsl - ${PROJECT_SOURCE_DIR}/source/MaterialXRenderOsl) - -find_package(Doxygen REQUIRED) - -foreach(FOLDER ${MATERIALX_DOXYGEN_SOURCE_FOLDERS}) - file(GLOB FOLDER_HEADERS ${FOLDER}/*.h) - list(APPEND DOXYGEN_INPUT_LIST ${FOLDER_HEADERS}) -endforeach() - -string (REPLACE ";" " " DOXYGEN_INPUT_STR "${DOXYGEN_INPUT_LIST}") - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - -add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/MainPage.md - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/DeveloperGuide/MainPage.md ${CMAKE_CURRENT_BINARY_DIR} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/DeveloperGuide/MainPage.md) - -add_custom_command(OUTPUT ${DOXYGEN_HTML_OUTPUT_DIR}/index.html - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/DoxygenAwesome ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/Images ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${DOXYGEN_INPUT_LIST} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - COMMENT "Generating HTML documentation: ${DOXYGEN_HTML_OUTPUT_DIR}/index.html") -add_custom_target(MaterialXDocs ALL DEPENDS ${DOXYGEN_HTML_OUTPUT_DIR}/index.html) - -install(DIRECTORY ${DOXYGEN_HTML_OUTPUT_DIR} - DESTINATION "documents" MESSAGE_NEVER) +set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +set(DOXYGEN_HTML_OUTPUT_DIR ${DOXYGEN_OUTPUT_DIR}/html) +set(DOXYGEN_INPUT_LIST ${CMAKE_CURRENT_BINARY_DIR}/MainPage.md) + +set(MATERIALX_DOXYGEN_SOURCE_FOLDERS + ${CMAKE_SOURCE_DIR}/source/MaterialXCore + ${CMAKE_SOURCE_DIR}/source/MaterialXFormat + ${CMAKE_SOURCE_DIR}/source/MaterialXGenShader + ${CMAKE_SOURCE_DIR}/source/MaterialXGenShader/Nodes + ${CMAKE_SOURCE_DIR}/source/MaterialXGenGlsl + ${CMAKE_SOURCE_DIR}/source/MaterialXGenGlsl/Nodes + ${CMAKE_SOURCE_DIR}/source/MaterialXGenOsl + ${CMAKE_SOURCE_DIR}/source/MaterialXGenMdl + ${CMAKE_SOURCE_DIR}/source/MaterialXRender + ${CMAKE_SOURCE_DIR}/source/MaterialXRenderHw + ${CMAKE_SOURCE_DIR}/source/MaterialXRenderGlsl + ${CMAKE_SOURCE_DIR}/source/MaterialXRenderOsl) + +find_package(Doxygen REQUIRED) + +foreach(FOLDER ${MATERIALX_DOXYGEN_SOURCE_FOLDERS}) + file(GLOB FOLDER_HEADERS ${FOLDER}/*.h) + list(APPEND DOXYGEN_INPUT_LIST ${FOLDER_HEADERS}) +endforeach() + +string (REPLACE ";" " " DOXYGEN_INPUT_STR "${DOXYGEN_INPUT_LIST}") + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/MainPage.md + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/DeveloperGuide/MainPage.md ${CMAKE_CURRENT_BINARY_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/DeveloperGuide/MainPage.md) + +add_custom_command(OUTPUT ${DOXYGEN_HTML_OUTPUT_DIR}/index.html + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/DoxygenAwesome ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/Images ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${DOXYGEN_INPUT_LIST} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + COMMENT "Generating HTML documentation: ${DOXYGEN_HTML_OUTPUT_DIR}/index.html") +add_custom_target(MaterialXDocs ALL DEPENDS ${DOXYGEN_HTML_OUTPUT_DIR}/index.html) + +install(DIRECTORY ${DOXYGEN_HTML_OUTPUT_DIR} + DESTINATION "documents" MESSAGE_NEVER) diff --git a/MaterialX/documents/DeveloperGuide/GraphEditor.md b/MaterialX/documents/DeveloperGuide/GraphEditor.md old mode 100644 new mode 100755 index 43b7f03..2375410 --- a/MaterialX/documents/DeveloperGuide/GraphEditor.md +++ b/MaterialX/documents/DeveloperGuide/GraphEditor.md @@ -1,82 +1,81 @@ -# MaterialX Graph Editor - -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 - -**Figure 1:** MaterialX Graph Editor with procedural marble example - -![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 - -1. **`Load Material`**: Load a material document in the MTLX format. -2. **`Save Material`**: Save out a graph as a material 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 - -To display a new material and graph, click the `Load Material` button 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 - -The MaterialX document is displayed as nodes in the Editor window. When a file is initially 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. - -The current graph hierarchy is displayed above the editor. To back up and out of a subgraph click the `<` button to the left of the graph names. - -Each node and nodegraph displays its name and pins for all of its inputs and outputs. Nodes can be connected by clicking on the output pin of one node and connecting it to the input pin of another node, thus creating a link. Links can only be created if the input and output pins have the same type, as designated by the color of the pin. When a new link is created the material in the render view will automatically be updated. - -Using the tab key on the editor allows the user to add a certain node by bringing up the `Add Node` pop-up. The nodes are organized in the pop-up window based on their node group but a specific node can also be searched for by name. To create a nodegraph select `Node Graph` in the `Add Node` popup and dive into the node in order to add nodes inside of it and populate it. - -In order to connect to the nodegraph to a shader add output nodes inside the nodegraph then travel back up outside the nodegraph and connect the corresponding output pin to the surface shader. By default, the nodegraph does not contain any output nodes or pins. - -Another type of node present in the `Add Node` pop-up is the group, or background node. This background node can be used to group specific nodes and label by them by dragging them on to the background node. - -To search the editor window for a specific node use `CTRL` + `F` to bring up the search bar. - -## 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 -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 - -- `TAB`: Add Node Popup -- `Right Click`: pan along the editor -- `Double Click on Node`: Dive into node's subgraph if it has one -- `U`: Go up and out of a subgraph -- `F`: Frame selected node(s) -- `Ctrl + F` to search for a node in the editor by name -- `Ctrl/Cmd + C` for Copying Nodes -- `Ctrl/Cmd+X` for Cutting Nodes -- `Ctrl/Cmd+V` for Pasting Nodes -- `+` : 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 - -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 -- `--mesh [FILENAME]` : Specify the filename of the OBJ or glTF mesh to be displayed in the graph editor -- `--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. -- `--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 - -- 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. +# MaterialX Graph Editor + +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 + +**Figure 1:** MaterialX Graph Editor with procedural marble example + + +## 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 + +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 + +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 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 + +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. + +The current graph hierarchy is displayed above the editor. To back up and out of a subgraph click the `<` button to the left of the graph names. + +Each node and nodegraph displays its name and pins for all of its inputs and outputs. Nodes can be connected by clicking on the output pin of one node and connecting it to the input pin of another node, thus creating a link. Links can only be created if the input and output pins have the same type, as designated by the color of the pin. When a new link is created the material in the render view will automatically be updated. + +Using the tab key on the editor allows the user to add a certain node by bringing up the `Add Node` pop-up. The nodes are organized in the pop-up window based on their node group but a specfic node can also be searched for by name. To create a nodegraph select `Node Graph` in the `Add Node` popup and dive into the node in order to add nodes inside of it and populate it. + +In order to connect to the nodegraph to a shader add output nodes inside the nodegraph then travel back up outside the nodegraph and connect the corresponding output pin to the surface shader. By default, the nodegraph does not contain any output nodes or pins. + +Another type of node present in the `Add Node` pop-up is the group, or background node. This background node can be used to group specific nodes and label by them by dragging them on to the background node. + +To search the editor window for a specific node use `CTRL` + `F` to bring up the search bar. + +### 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 +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 + +- `TAB`: Add Node Popup +- `Right Click`: pan along the editor +- `Double Click on Node`: Dive into node's subgraph if it has one +- `U`: Go up and out of a subgraph +- `F`: Frame selected node(s) +- `Ctrl + F` to search for a node in the editor by name +- `Ctrl/Cmd + C` for Copying Nodes +- `Ctrl/Cmd+X` for Cutting Nodes +- `Ctrl/Cmd+V` for Pasting Nodes +- `+` : 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 + +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 +- `--mesh [FILENAME]` : Specify the filename of the OBJ or glTF mesh to be displayed in the graph editor +- `--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. +- `--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 + +- 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/MaterialX/documents/DeveloperGuide/MainPage.md b/MaterialX/documents/DeveloperGuide/MainPage.md old mode 100644 new mode 100755 index 1c6a031..20068e4 --- a/MaterialX/documents/DeveloperGuide/MainPage.md +++ b/MaterialX/documents/DeveloperGuide/MainPage.md @@ -1,110 +1,85 @@ -# MaterialX Overview - -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 - -- 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](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/documents/DeveloperGuide/Viewer.md). -- Select the `MATERIALX_BUILD_GRAPH_EDITOR` option to build the [MaterialX Graph Editor](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/documents/DeveloperGuide/GraphEditor.md). - -## Supported Platforms - -The MaterialX codebase requires a compiler with support for C++17, and can be built with any of the following: - -- Microsoft Visual Studio 2017 or newer -- GCC 8 or newer -- Clang 5 or newer - -The Python bindings for MaterialX are based on [PyBind11](https://github.com/pybind/pybind11), and support Python versions 3.9 and greater. - -On macOS, you'll need to [install Xcode](https://developer.apple.com/xcode/resources/), in order to get access to the Metal Tools as well as compiler toolchains. - -## Building MaterialX - -### Building MaterialX C++ - -The MaterialX C++ libraries are automatically included when building MaterialX through CMake. - -To enable OpenImageIO and OpenColorIO support in MaterialX builds, the following additional options may be used: - -- `MATERIALX_BUILD_OIIO`: Requests that MaterialXRender be built with OpenImageIO in addition to stb_image, extending the set of supported image formats. The minimum supported version of OpenImageIO is 2.2. -- `MATERIALX_BUILD_OCIO`: Requests that MaterialXGenShader be built with support for custom OpenColorIO color spaces and transforms. The minimum supported version of OpenColorIO is 2.4. - -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 - -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: - -- `MATERIALX_PYTHON_VERSION`: Python version to be used in building the MaterialX Python package (e.g. `3.9`) -- `MATERIALX_PYTHON_EXECUTABLE`: Python executable to be used in building the MaterialX Python package (e.g. `C:/Python39/python.exe`) - -Additional options for the generation of MaterialX Python include the following: - -- `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 - -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 - -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. - -## Editor Setup - -MaterialX should work in any editor that supports CMake, or that CMake can generate a project for. -Some common Editors are listed here to help developers get started. - -### CLion - -[CLion](https://www.jetbrains.com/clion/) is a cross-platform IDE that can be used to develop MaterialX. -Additionally, it includes CMake and is free for non-commercial Use. - -To get started with CLion, open the MaterialX repository directly, and it will load the CMake project for you. -If you want to enable features like Python, go to `Settings -> Build, Execution and Deployment -> CMake` and configure -the CMake Options, for example: - -``` --DMATERIALX_BUILD_PYTHON=ON --DMATERIALX_BUILD_VIEWER=ON --DMATERIALX_BUILD_GRAPH_EDITOR=ON -``` - -To build, either select `Build -> Build Project` or select a specific configuration to build. -To install, select `Build -> Install` - -## 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 - -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. - -### 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 - -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: - -- In *build* version upgrades, only additive changes and fixes to the MaterialX data libraries are allowed. Additive changes are allowed to introduce new nodes, node versions, and node inputs with backwards-compatible default values. Data library fixes are allowed to update a node implementation to improve its alignment with the specification, without making any changes to its name or interface. -- 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 - -- 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. -- The [MaterialX Unit Tests](https://github.com/materialx/MaterialX/tree/main/source/MaterialXTest) folder contains examples of useful patterns for MaterialX C++. -- The [MaterialX Viewer](https://github.com/materialx/MaterialX/blob/main/documents/DeveloperGuide/Viewer.md) is a complete, cross-platform C++ application based upon [MaterialX Shader Generation](https://github.com/materialx/MaterialX/blob/main/documents/DeveloperGuide/ShaderGeneration.md) +# MaterialX Overview + +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 + +- 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 + +The MaterialX codebase requires a compiler with support for C++17, and can be built with any of the following: + +- Microsoft Visual Studio 2017 or newer +- GCC 8 or newer +- Clang 5 or newer + +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 C++ + +The MaterialX C++ libraries are automatically included when building MaterialX through CMake. + +To enable OpenImageIO support in MaterialX builds, the following additional options may be used: + +- `MATERIALX_BUILD_OIIO`: Requests that MaterialXRender be built with OpenImageIO in addition to stb_image, extending the set of supported image formats. +- `MATERIALX_OIIO_DIR`: Path to the root folder of an OpenImageIO installation. If MATERIALX_BUILD_OIIO has been enabled, then this option may be used to select which installation is used. + +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 + +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: + +- `MATERIALX_PYTHON_VERSION`: Python version to be used in building the MaterialX Python package (e.g. `3.9`) +- `MATERIALX_PYTHON_EXECUTABLE`: Python executable to be used in building the MaterialX Python package (e.g. `C:/Python39/python.exe`) + +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 + +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 + +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 + +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 + +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. + +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 + +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 + +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: + +- In *build* version upgrades, only additive changes and fixes to the MaterialX data libraries are allowed. Additive changes are allowed to introduce new nodes, node versions, and node inputs with backwards-compatible default values. Data library fixes are allowed to update a node implementation to improve its alignment with the specification, without making any changes to its name or interface. +- 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 + +- 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. +- The [MaterialX Unit Tests](https://github.com/materialx/MaterialX/tree/main/source/MaterialXTest) folder contains examples of useful patterns for MaterialX C++. +- The [MaterialX Viewer](https://github.com/materialx/MaterialX/blob/main/documents/DeveloperGuide/Viewer.md) is a complete, cross-platform C++ application based upon [MaterialX Shader Generation](https://github.com/materialx/MaterialX/blob/main/documents/DeveloperGuide/ShaderGeneration.md) diff --git a/MaterialX/documents/DeveloperGuide/ShaderGeneration.md b/MaterialX/documents/DeveloperGuide/ShaderGeneration.md old mode 100644 new mode 100755 index 9bfd835..3296fca --- a/MaterialX/documents/DeveloperGuide/ShaderGeneration.md +++ b/MaterialX/documents/DeveloperGuide/ShaderGeneration.md @@ -1,356 +1,356 @@ -# 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](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](https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/documents/Images/shadergen.png) - -**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. - -Class inheritance and specialization is used to create support for new languages or to customize existing language support for a new target. To add a new shader generator for a target you add a new C++ class derived from the base class `ShaderGenerator`, or one of the existing derived shader generator classes (`GlslShaderGenerator`, `OslShaderGenerator`, etc.), and override the methods you need to customize. You might also need to derive a new `Syntax` class, which is used to handle syntactical differences between different shading languages. Then you need to make sure there are implementations defined for all the nodes you want to support, standard library nodes and nodes from other libraries, by either reusing existing implementations where applicable or adding in new ones. See **1.3 Node Implementations** on how that is done. - -Note that a shader generator doesn’t need to be defined at the time when node definitions are added. New shader generators can be added later, and node implementations for new targets can be added for existing nodes. - -## 1.3 Node Implementations -There are four different methods to define the implementation of a node: -1. Using an inline expression. -2. Using a function written in the target language. -3. Using a nodegraph that defines the operation performed by the node. -4. Using a C++ class that emits code dynamically during shader generation. - -In the following sub-sections each of these methods are explained. For all methods the implementation is tied to a specific `nodedef` with a well defined interface of typed inputs and outputs. - -### 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 -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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` -```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 -`` 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](https://materialx.org/Specification.html) for more information. - -```xml - - - - - - - - - - - - - - - - - -``` -```c++ -// File 'mx_image_color3.osl' contains: -void mx_image_color3(string file, string layer, color defaultvalue, - vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, - string framerange, int frameoffset, string frameendaction, - output color out) -{ - // Sample the texture - out = texture(file, texcoord.x, texcoord.y, - "interp", filtertype, - "subimage", layer, - "missingcolor", defaultvalue, - "wrap", uaddressmode); -} -``` -**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. - -This is useful for creating a compound for a set of nodes performing some common operation. It can then be referenced as a node inside other nodegraphs. It is also useful for creating compatibility graphs for unknown nodes. If a node is created by some third party, and its implementation is unknown or proprietary, a compatibility graph can be created using known nodes and be referenced as a stand-in implementation. Linking a nodegraph to a nodedef is done by simply setting a nodedef attribute on the nodegraph definition. See Figure 4 for an example. - -```xml - - - - - - - - - - - - - - - - - - - - - - - -``` -**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. - -In this case, a C++ class can be added to handle the implementation of the node. The class should be derived from the base class `ShaderNodeImpl`. It should specify what target it is for by overriding `getTarget()`. It then needs to be registered for a `ShaderGenerator` by calling `ShaderGenerator::registerImplementation()`. See Figure 5 for an example. - -When a `ShaderNodeImpl` class is used for a nodedef the corresponding `` element doesn’t need a file attribute, since no static source code is used. The `` element will then act only as a declaration that there exists an implementation for the nodedef for a particular target. - -Note that by using a `ShaderNodeImpl` class for your node's implementation it is no longer data driven, as in the other three methods above. So it's recommended to use this only when inline expressions or static source code functions are not enough to handle the implementation of a node. - -```c++ -/// Implementation of ’foo' node for OSL -class FooOsl : public ShaderNodeImpl -{ - public: - static ShaderNodeImplPtr create() { return std::make_shared(); } - - const string& getTarget() const override { return OslShaderGenerator::TARGET; } - - void emitFunctionDefinition(const ShaderNode& node, GenContext& context, - ShaderStage& stage) const override - { - // Emit function definition if needed for the node - } - - void emitFunctionCall(const ShaderNode& node, GenContext& context, - ShaderStage& stage) const override - { - // Emit function call, or inline shader code, for the node - } -}; -``` -```c++ -OslShaderGenerator::OslShaderGenerator() : - ShaderGenerator(std::make_shared()) -{ - ... - // Register foo implementation for nodedefs it should be used for - registerImplementation("IM_foo_color2_osl", FooOsl::create); - registerImplementation("IM_foo_color3_osl", FooOsl::create); - registerImplementation("IM_foo_color4_osl", FooOsl::create); - ... -} -``` -**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. - -Shader generation supports generating a shader starting from either an `output` element or a `shaderref` element in a material. The `output` can be an output port on a nodegraph or an output element inserted anywhere in a node network. A shader is generated by calling your shader generator class with either of these element types as input. The given element and all dependencies upstream will be translated into a single monolithic shader in the target shading language. - -```c++ -// Generate a shader starting from the given element, translating -// the element and all dependencies upstream into shader code. -ShaderPtr ShaderGenerator::generate(const string& name, - ElementPtr element, - GenContext& context) -``` - -The shader generation process can be divided into initialization and code generation. The initialization consists of a number of steps: -1. Create an optimized version of the graph as a tree with the given input element as root, and with only the used dependencies connected upstream. This involves removing unused paths in the graph, converting constant nodes to constant values, and adding in any default nodes for ports that are unconnected but have default connections specified. Removal of unused paths typically involves constant folding and pruning of conditional branches that will never be taken. Since the resulting shader in the end will be compiled by a shading language compiler, and receive a lot of additional optimizations, we don’t need to do too much work in this optimization step. However, a few graph level optimizations can make the resulting shader a lot smaller and save time and memory during shader compilation. It will also produce more readable source code which is good for debugging purposes. This optimization step is also a good place to do other custom optimizations needed by a particular target. For example simplification of the graph, which could involve substituting expensive nodes with approximate nodes, identification of common subgraphs that can be merged, etc. -2. The nodes are sorted in topological order. Since a node can be referenced by many other nodes in the graph we need an ordering of the nodes so that nodes that have a dependency on other nodes come after all dependent nodes. This step also makes sure there are no cyclic dependencies in the graph. -3. The stages for the shader are created. For a HW shader this is normally a vertex stage and a pixel stage, but other stages can be added as needed. At the minimum a single pixel stage is required, so even shaders that has no concept of multiple stages, like OSL, needs to have a single pixel stage created. -4. The shader stages interface of uniforms and varyings are established. This consists of the graph interface ports that are in use, as well as internal ports that have been published to the interface (an example of the latter is for a hardware shader generator where image texture filenames get converted to texture samplers which needs to be published in order to be bound by the target application). Each node in the graph is also called for a chance to create any uniforms or varyings needed by its implementation. -5. Information about scope is tracked for each node. This information is needed to handle branching by conditional nodes. For example, if a node is used only by a particular branch on a varying conditional we want to calculate this node only inside that scope, when that corresponding branch is taken. A node can be used in global scope, in a single conditional scope or by multiple conditional scopes. - -The output from the initialization step is a new graph representation constructed using the classes `ShaderNode`, `ShaderInput`, `ShaderOutput`, `ShaderGraph`, etc. This is a graph representation optimized for shader generation with quick access and traversal of nodes and ports, as well as caching of extra information needed by shader generation. - -After initialization the code generation steps are handled by the `ShaderGenerator` class and derived classes. This part is specific to the particular generator being used, but in general it consists of the following steps: -1. Typedefs are emitted as specified by the Syntax class. -2. Function definitions are emitted for all the atomic nodes that have shading -language functions for their implementations. For nodes using dynamic code generation their `ShaderNodeImpl` instances are called to generate the functions. For nodes that are implemented by graphs a function definition representing the graph computation is emitted. -3. The shader signature is emitted with all uniforms set to default values. The shader uniforms can later be accessed on the returned `Shader` instance in order for applications to be able to bind values to them. -4. The function calls for all nodes are emitted, in the right dependency order, propagating -output results from upstream nodes as inputs to downstream nodes. Inline expressions are -emitted instead of functions calls for nodes that use this. -5. The final shader output is produced and assigned to the shader output variable. - -Note that if a single monolithic shader for the whole graph is not appropriate for your system, the generator can be called on `output` elements at any point in your graph, and generate code for sub-parts. It is then up to the application to decide where to split the graph, and to assemble the shader code for sub-parts after all have been generated. - -## 1.5 Shader Stages - -Creation of multiple shader stages is supported. This is needed in order to generate separate code for multiple stages on hardware render targets. A `pixel` stage must always be created by all targets, even for shading languages like OSL that natively doesn't have a concept of stages. The stage is where the generated shader code is stored as well as all uniforms, inputs and outputs for the shader. This is handled by the `ShaderStage` class, and the data can be retrieved from it when generation is completed. - -One or more `ShaderStage` instances are created and stored on the `Shader` class. In addition to the `pixel` stage, hardware generators always specify a `vertex` stage. If additional stages are needed they can be added as well. When creating shader input variables you specify which stage the variable should be used in, see 1.7 for more information on shader variable creation. - -Node implementations using static source code (function or inline expressions) are always emitted to the `pixel` stage. Controlling the `vertex` stage, or other stages, is not supported using static source code. In order to do that you must use dynamic code generation with a custom `ShaderNodeImpl` sub-class for your node. You are then able to control how it affects all stages separately. Inside `emitFunctionDefinition` and `emitFunctionCall` you can add separate sections for each stage using begin/end shader stage macros. Figure 6 shows how the texcoord node for GLSL is emitting different code into the `vertex` and `pixel` stages. - -## 1.6 Shader Variables -When generating a shader from a node graph or shaderref the inputs and parameters on those elements will be published as shader uniforms on the resulting shader. A listing of the created uniforms can be read from the produced `Shader` and `ShaderStage` instances. The shader uniforms can then be presented to the user and have their values set by the application. - -### 1.6.1 Variable Creation -Adding new uniforms, input and outputs to a shader stage is done by first creating a `VariableBlock` to store them. There are some predefined identifiers for commonly used variable blocks. For uniforms there are e.g. one named `HW::PUBLIC_UNIFORMS` and another named `HW::PRIVATE_UNIFORMS`. Public is used for uniforms to be published to the user, as described above, and private is used for uniforms needed by node implementations but set by the application and not published. For hardware targets there are also specific variable blocks called `connector blocks` which are used to send data from one stage to another, connecting the stages. A connector block named `HW::VERTEX_DATA` is used for sending data from the `vertex` stage to the `pixel` stage. Variable block creation and handling can be customized as needed by each shader generator target. - -All variable blocks can be queried and accessed by the application from the `ShaderStage` instances after generation. - -Figure 6 shows how creation of shader inputs and connector variables are done for a node implementation that requires this. - -```c++ -// Implementation of 'texcoord' node for GLSL -class TexCoordGlsl : public ShaderNodeImpl -{ - public: - static ShaderNodeImplPtr create() - { - return std::make_shared(); - } - - void TexCoordNodeGlsl::createVariables(const ShaderNode& node, GenContext&, - Shader& shader) const - { - const ShaderOutput* output = node.getOutput(); - const ShaderInput* indexInput = node.getInput(INDEX); - const string index = indexInput ? indexInput->getValue()->getValueString() : "0"; - - ShaderStage& vs = shader.getStage(Stage::VERTEX); - ShaderStage& ps = shader.getStage(Stage::PIXEL); - - addStageInput(HW::VERTEX_INPUTS, output->getType(), "i_texcoord_" + index, vs); - addStageConnector(HW::VERTEX_DATA, output->getType(), "texcoord_" + index, vs, ps); - } - - void TexCoordNodeGlsl::emitFunctionCall(const ShaderNode& node, - GenContext& context, - ShaderStage& stage) const - { - const ShaderGenerator& shadergen = context.getShaderGenerator(); - - const ShaderInput* indexInput = node.getInput(INDEX); - const string index = indexInput ? indexInput->getValue()->getValueString() : "0"; - const string variable = "texcoord_" + index; - - DEFINE_SHADER_STAGE(stage, Stage::VERTEX) - { - VariableBlock& vertexData = stage.getOutputBlock(HW::VERTEX_DATA); - const string prefix = vertexData.getInstance() + "."; - ShaderPort* texcoord = vertexData[variable]; - if (!texcoord->isEmitted()) - { - shadergen.emitLine(prefix + texcoord->getVariable() + " = i_" + variable, stage); - texcoord->setEmitted(); - } - } - - DEFINE_SHADER_STAGE(stage, Stage::PIXEL) - { - VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA); - const string prefix = vertexData.getInstance() + "."; - ShaderPort* texcoord = vertexData[variable]; - shadergen.emitLineBegin(stage); - shadergen.emitOutput(node.getOutput(), true, false, context, stage); - shadergen.emitString(" = " + prefix + texcoord->getVariable(), stage); - shadergen.emitLineEnd(stage); - } - } -}; -``` -**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 - -Creating shader variables and binding values to them needs to be done in agreement with the shader generator side and application side. The application must know what a variable is for in order to bind meaningful data to it. One way of handling this is by using semantics. All shader variables created can be assigned a semantic if that is used by the target application. Shader generation does not impose a specific set of semantics to use, so for languages and applications that use this any semantics can be used. For languages that do not use semantics a variable naming convention needs to be used instead. - -Built-in shader generators and accompanying node implementations have a naming convention for shader variables. A custom shader generator that derives from and takes advantage of built-in features should preferably use the same convention. Uniform variables are prefixed with `u_` and vertex inputs with `i_` . For languages not using semantics, Figure 7 shows the naming used for variables (inputs and uniforms) with predefined binding rules: - -App data input variables - -| NAME | TYPE | BINDING | -| :--- | :--: | :--- | -| i_position | vec3 | Vertex position in object space. | -| i_normal | vec3 | Vertex normal in object space. | -| i_tangent | vec3 | Vertex tangent in object space. | -| i_bitangent | vec3 | Vertex bitangent in object space. | -| i_texcoord_N | vec2 | Vertex texture coord for N:th uv set. | -| i_color_N | vec4 | Vertex color for N:th color set. | - - -Uniform variables - -| NAME | TYPE | BINDING | -| :--- | :--: | :--- | -| u_worldMatrix | mat4 | World transform. | -| u_worldInverseMatrix | mat4 | World transform, inverted. | -| u_worldTransposeMatrix | mat4 | World transform, transposed. | -| u_worldInverseTransposeMatrix | mat4 | World transform, inverted, transposed. | -| u_viewMatrix | mat4 | View transform. | -| u_viewInverseMatrix | mat4 | View transform, inverted. | -| u_viewTransposeMatrix | mat4 | View transform, transposed. | -| u_viewInverseTransposeMatrix | mat4 | View transform, inverted, transposed. | -| u_projectionMatrix | mat4 | Projection transform. | -| u_projectionInverseMatrix | mat4 | Projection transform, inverted. | -| u_projectionTransposeMatrix | mat4 | Projection transform, transposed. | -| u_projectionInverseTransposeMatrix | mat4 | Projection transform, inverted, transposed. | -| u_worldViewMatrix | mat4 | World-view transform. | -| u_viewProjectionMatrix | mat4 | View-projection transform. | -| u_worldViewProjectionMatrix | mat4 | World-view-projection transform. | -| u_viewPosition | vec3 | World-space position of the viewer. | -| u_viewDirection | vec3 | World-space direction of the viewer. | -| u_frame | float | The current frame number as defined by the host application. | -| u_time | float | The current time in seconds. | -| u_geomprop_\ | \ | A named property of given \ where \ is the name of the variable on the geometry. | -| u_numActiveLightSources | int | The number of currently active light sources. Note that in shader this is clamped against the maximum allowed number of light sources. | -| 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. +# 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). + +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) + +**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. + +Class inheritance and specialization is used to create support for new languages or to customize existing language support for a new target. To add a new shader generator for a target you add a new C++ class derived from the base class `ShaderGenerator`, or one of the existing derived shader generator classes (`GlslShaderGenerator`, `OslShaderGenerator`, etc.), and override the methods you need to customize. You might also need to derive a new `Syntax` class, which is used to handle syntactical differences between different shading languages. Then you need to make sure there are implementations defined for all the nodes you want to support, standard library nodes and nodes from other libraries, by either reusing existing implementations where applicable or adding in new ones. See **1.3 Node Implementations** on how that is done. + +Note that a shader generator doesn’t need to be defined at the time when node definitions are added. New shader generators can be added later, and node implementations for new targets can be added for existing nodes. + +## 1.3 Node Implementations +There are four different methods to define the implementation of a node: +1. Using an inline expression. +2. Using a function written in the target language. +3. Using a nodegraph that defines the operation performed by the node. +4. Using a C++ class that emits code dynamically during shader generation. + +In the following sub-sections each of these methods are explained. For all methods the implementation is tied to a specific `nodedef` with a well defined interface of typed inputs and outputs. + +### 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 +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 + + + + + + + + + + +<... more types ...> + +// Implementation elements for node + + +<... more types ...> + +// Nodedef elements for node + + + + + + + + + + + + +<... 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 +`` 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. + +```xml +// Nodedef element + + + + + + + + + + + + + + +// Implementation element + +``` +```c++ +// File 'mx_image_color3.osl' contains: +void mx_image_color3(string file, string layer, color defaultvalue, + vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, + string framerange, int frameoffset, string frameendaction, + output color out) +{ + // Sample the texture + out = texture(file, texcoord.x, texcoord.y, + "interp", filtertype, + "subimage", layer, + "missingcolor", defaultvalue, + "wrap", uaddressmode); +} +``` +**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. + +This is useful for creating a compound for a set of nodes performing some common operation. It can then be referenced as a node inside other nodegraphs. It is also useful for creating compatibility graphs for unknown nodes. If a node is created by some third party, and its implementation is unknown or proprietary, a compatibility graph can be created using known nodes and be referenced as a stand-in implementation. Linking a nodegraph to a nodedef is done by simply setting a nodedef attribute on the nodegraph definition. See Figure 4 for an example. + +```xml + + + + + + + + + + + + + + + + + + + + + + + +``` +**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. + +In this case, a C++ class can be added to handle the implementation of the node. The class should be derived from the base class `ShaderNodeImpl`. It should specify what target it is for by overriding `getTarget()`. It then needs to be registered for a `ShaderGenerator` by calling `ShaderGenerator::registerImplementation()`. See Figure 5 for an example. + +When a `ShaderNodeImpl` class is used for a nodedef the corresponding `` element doesn’t need a file attribute, since no static source code is used. The `` element will then act only as a declaration that there exists an implementation for the nodedef for a particular target. + +Note that by using a `ShaderNodeImpl` class for your node's implementation it is no longer data driven, as in the other three methods above. So it's recommended to use this only when inline expressions or static source code functions are not enough to handle the implementation of a node. + +```c++ +/// Implementation of ’foo' node for OSL +class FooOsl : public ShaderNodeImpl +{ + public: + static ShaderNodeImplPtr create() { return std::make_shared(); } + + const string& getTarget() const override { return OslShaderGenerator::TARGET; } + + void emitFunctionDefinition(const ShaderNode& node, GenContext& context, + ShaderStage& stage) const override + { + // Emit function definition if needed for the node + } + + void emitFunctionCall(const ShaderNode& node, GenContext& context, + ShaderStage& stage) const override + { + // Emit function call, or inline shader code, for the node + } +}; +``` +```c++ +OslShaderGenerator::OslShaderGenerator() : + ShaderGenerator(std::make_shared()) +{ + ... + // Register foo implementation for nodedefs it should be used for + registerImplementation("IM_foo_color2_osl", FooOsl::create); + registerImplementation("IM_foo_color3_osl", FooOsl::create); + registerImplementation("IM_foo_color4_osl", FooOsl::create); + ... +} +``` +**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. + +Shader generation supports generating a shader starting from either an `output` element or a `shaderref` element in a material. The `output` can be an output port on a nodegraph or an output element inserted anywhere in a node network. A shader is generated by calling your shader generator class with either of these element types as input. The given element and all dependencies upstream will be translated into a single monolithic shader in the target shading language. + +```c++ +// Generate a shader starting from the given element, translating +// the element and all dependencies upstream into shader code. +ShaderPtr ShaderGenerator::generate(const string& name, + ElementPtr element, + GenContext& context) +``` + +The shader generation process can be divided into initialization and code generation. The initialization consists of a number of steps: +1. Create an optimized version of the graph as a tree with the given input element as root, and with only the used dependencies connected upstream. This involves removing unused paths in the graph, converting constant nodes to constant values, and adding in any default nodes for ports that are unconnected but have default connections specified. Removal of unused paths typically involves constant folding and pruning of conditional branches that will never be taken. Since the resulting shader in the end will be compiled by a shading language compiler, and receive a lot of additional optimizations, we don’t need to do too much work in this optimization step. However, a few graph level optimizations can make the resulting shader a lot smaller and save time and memory during shader compilation. It will also produce more readable source code which is good for debugging purposes. This optimization step is also a good place to do other custom optimizations needed by a particular target. For example simplification of the graph, which could involve substituting expensive nodes with approximate nodes, identification of common subgraphs that can be merged, etc. +2. The nodes are sorted in topological order. Since a node can be referenced by many other nodes in the graph we need an ordering of the nodes so that nodes that have a dependency on other nodes come after all dependent nodes. This step also makes sure there are no cyclic dependencies in the graph. +3. The stages for the shader are created. For a HW shader this is normally a vertex stage and a pixel stage, but other stages can be added as needed. At the minumum a single pixel stage is required, so even shaders that has no concept of multiple stages, like OSL, needs to have a single pixel stage created. +4. The shader stages interface of uniforms and varyings are established. This consists of the graph interface ports that are in use, as well as internal ports that have been published to the interface (an example of the latter is for a hardware shader generator where image texture filenames get converted to texture samplers which needs to be published in order to be bound by the target application). Each node in the graph is also called for a chance to create any uniforms or varyings needed by its implementation. +5. Information about scope is tracked for each node. This information is needed to handle branching by conditional nodes. For example, if a node is used only by a particular branch on a varying conditional we want to calculate this node only inside that scope, when that corresponding branch is taken. A node can be used in global scope, in a single conditional scope or by multiple conditional scopes. + +The output from the initialization step is a new graph representation constructed using the classes `ShaderNode`, `ShaderInput`, `ShaderOutput`, `ShaderGraph`, etc. This is a graph representation optimized for shader generation with quick access and traversal of nodes and ports, as well as caching of extra information needed by shader generation. + +After initialization the code generation steps are handled by the `ShaderGenerator` class and derived classes. This part is specific to the particular generator being used, but in general it consists of the following steps: +1. Typedefs are emitted as specified by the Syntax class. +2. Function definitions are emitted for all the atomic nodes that have shading +language functions for their implementations. For nodes using dynamic code generation their `ShaderNodeImpl` instances are called to generate the functions. For nodes that are implemented by graphs a function definition representing the graph computation is emitted. +3. The shader signature is emitted with all uniforms set to default values. The shader uniforms can later be accessed on the returned `Shader` instance in order for applications to be able to bind values to them. +4. The function calls for all nodes are emitted, in the right dependency order, propagating +output results from upstream nodes as inputs to downstream nodes. Inline expressions are +emitted instead of functions calls for nodes that use this. +5. The final shader output is produced and assigned to the shader output variable. + +Note that if a single monolithic shader for the whole graph is not appropriate for your system the generator can be called on `output` elements at any point in your graph, and generate code for sub-parts. It is then up to the application to decide where to split the graph, and to assemble the shader code for sub-parts after all have been generated. + +## 1.5 Shader Stages + +Creation of multiple shader stages is supported. This is needed in order to generate separate code for multiple stages on hardware render targets. A `pixel` stage must always be created by all targets, even for shading languages like OSL that natively doensn't have a concept of stages. The stage is where the generated shader code is stored as well as all uniforms, inputs and outputs for the shader. This is handled by the `ShaderStage` class, and the data can be retrieved from it when generation is completed. + +One or more `ShaderStage` instances are created and stored on the `Shader` class. In addition to the `pixel` stage, hardware generators always specify a `vertex` stage. If additional stages are needed they can be added as well. When creating shader input variables you specify which stage the variable should be used in, see 1.7 for more information on shader variable creation. + +Node implementations using static source code (function or inline expressions) are always emitted to the `pixel` stage. Controlling the `vertex` stage, or other stages, is not supported using static source code. In order to do that you must use dynamic code generation with a custom `ShaderNodeImpl` sub-class for your node. You are then able to control how it affects all stages separately. Inside `emitFunctionDefinition` and `emitFunctionCall` you can add separate sections for each stage using begin/end shader stage macros. Figure 6 shows how the texcoord node for GLSL is emitting different code into the `vertex` and `pixel` stages. + +## 1.6 Shader Variables +When generating a shader from a node graph or shaderref the inputs and parameters on those elements will be published as shader uniforms on the resulting shader. A listing of the created uniforms can be read from the produced `Shader` and `ShaderStage` instances. The shader uniforms can then be presented to the user and have their values set by the application. + +### 1.6.1 Variable Creation +Adding new uniforms, input and outputs to a shader stage is done by first creating a `VariableBlock` to store them. There are some predefined identifiers for commonly used variable blocks. For uniforms there are e.g. one named `HW::PUBLIC_UNIFORMS` and another named `HW::PRIVATE_UNIFORMS`. Public is used for uniforms to be published to the user, as described above, and private is used for uniforms needed by node implementations but set by the application and not published. For hardware targets there are also specific variable blocks called `connector blocks` which are used to send data from one stage to another, connecting the stages. A connector block named `HW::VERTEX_DATA` is used for sending data from the `vertex` stage to the `pixel` stage. Variable block creation and handling can be customized as needed by each shader generator target. + +All variable blocks can be queried and accessed by the application from the `ShaderStage` instances after generation. + +Figure 6 shows how creation of shader inputs and connector variables are done for a node implementation that requires this. + +```c++ +// Implementation of 'texcoord' node for GLSL +class TexCoordGlsl : public ShaderNodeImpl +{ + public: + static ShaderNodeImplPtr create() + { + return std::make_shared(); + } + + void TexCoordNodeGlsl::createVariables(const ShaderNode& node, GenContext&, + Shader& shader) const + { + const ShaderOutput* output = node.getOutput(); + const ShaderInput* indexInput = node.getInput(INDEX); + const string index = indexInput ? indexInput->getValue()->getValueString() : "0"; + + ShaderStage& vs = shader.getStage(Stage::VERTEX); + ShaderStage& ps = shader.getStage(Stage::PIXEL); + + addStageInput(HW::VERTEX_INPUTS, output->getType(), "i_texcoord_" + index, vs); + addStageConnector(HW::VERTEX_DATA, output->getType(), "texcoord_" + index, vs, ps); + } + + void TexCoordNodeGlsl::emitFunctionCall(const ShaderNode& node, + GenContext& context, + ShaderStage& stage) const + { + const ShaderGenerator& shadergen = context.getShaderGenerator(); + + const ShaderInput* indexInput = node.getInput(INDEX); + const string index = indexInput ? indexInput->getValue()->getValueString() : "0"; + const string variable = "texcoord_" + index; + + DEFINE_SHADER_STAGE(stage, Stage::VERTEX) + { + VariableBlock& vertexData = stage.getOutputBlock(HW::VERTEX_DATA); + const string prefix = vertexData.getInstance() + "."; + ShaderPort* texcoord = vertexData[variable]; + if (!texcoord->isEmitted()) + { + shadergen.emitLine(prefix + texcoord->getVariable() + " = i_" + variable, stage); + texcoord->setEmitted(); + } + } + + DEFINE_SHADER_STAGE(stage, Stage::PIXEL) + { + VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA); + const string prefix = vertexData.getInstance() + "."; + ShaderPort* texcoord = vertexData[variable]; + shadergen.emitLineBegin(stage); + shadergen.emitOutput(node.getOutput(), true, false, context, stage); + shadergen.emitString(" = " + prefix + texcoord->getVariable(), stage); + shadergen.emitLineEnd(stage); + } + } +}; +``` +**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 + +Creating shader variables and binding values to them needs to be done in agreement with the shader generator side and application side. The application must know what a variable is for in order to bind meaningful data to it. One way of handling this is by using semantics. All shader variables created can be assigned a semantic if that is used by the target application. Shader generation does not impose a specific set of semantics to use, so for languages and applications that use this any semantics can be used. For languages that do not use semantics a variable naming convention needs to be used instead. + +Built-in shader generators and accompanying node implementations have a naming convention for shader variables. A custom shader generator that derives from and takes advantage of built-in features should preferably use the same convention. Uniform variables are prefixed with `u_` and vertex inputs with `i_` . For languages not using semantics, Figure 7 shows the naming used for variables (inputs and uniforms) with predefined binding rules: + +App data input variables + +| NAME | TYPE | BINDING | +| :--- | :--: | :--- | +| i_position | vec3 | Vertex position in object space. | +| i_normal | vec3 | Vertex normal in object space. | +| i_tangent | vec3 | Vertex tangent in object space. | +| i_bitangent | vec3 | Vertex bitangent in object space. | +| i_texcoord_N | vec2 | Vertex texture coord for N:th uv set. | +| i_color_N | vec4 | Vertex color for N:th color set. | + + +Uniform variables + +| NAME | TYPE | BINDING | +| :--- | :--: | :--- | +| u_worldMatrix | mat4 | World transform. | +| u_worldInverseMatrix | mat4 | World transform, inverted. | +| u_worldTransposeMatrix | mat4 | World transform, transposed. | +| u_worldInverseTransposeMatrix | mat4 | World transform, inverted, transposed. | +| u_viewMatrix | mat4 | View transform. | +| u_viewInverseMatrix | mat4 | View transform, inverted. | +| u_viewTransposeMatrix | mat4 | View transform, transposed. | +| u_viewInverseTransposeMatrix | mat4 | View transform, inverted, transposed. | +| u_projectionMatrix | mat4 | Projection transform. | +| u_projectionInverseMatrix | mat4 | Projection transform, inverted. | +| u_projectionTransposeMatrix | mat4 | Projection transform, transposed. | +| u_projectionInverseTransposeMatrix | mat4 | Projection transform, inverted, transposed. | +| u_worldViewMatrix | mat4 | World-view transform. | +| u_viewProjectionMatrix | mat4 | View-projection transform. | +| u_worldViewProjectionMatrix | mat4 | World-view-projection transform. | +| u_viewPosition | vec3 | World-space position of the viewer. | +| u_viewDirection | vec3 | World-space direction of the viewer. | +| u_frame | float | The current frame number as defined by the host application. | +| u_time | float | The current time in seconds. | +| u_geomprop_\ | \ | A named property of given \ where \ is the name of the variable on the geometry. | +| u_numActiveLightSources | int | The number of currently active light sources. Note that in shader this is clamped against the maximum allowed number of light sources. | +| 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. diff --git a/MaterialX/documents/DeveloperGuide/Viewer.md b/MaterialX/documents/DeveloperGuide/Viewer.md old mode 100644 new mode 100755 index 17155b1..0fed2eb --- a/MaterialX/documents/DeveloperGuide/Viewer.md +++ b/MaterialX/documents/DeveloperGuide/Viewer.md @@ -1,114 +1,102 @@ -# MaterialX Viewer - -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 - -**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 - -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 - -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 - -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](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 - -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 - -By default, the MaterialX viewer loads and saves image files using `stb_image`, which supports common 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 - -- `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. -- `O`: Save the current OSL shader source to file. -- `M`: Save the current MDL shader source to file. -- `L`: Load GLSL shader source from file. Editing the source files before loading provides a way to debug and experiment with shader source code. -- `D`: Save each node graph in the current material as a DOT file. See www.graphviz.org for more details on this format. -- `F`: Capture the current frame and save to file. -- `W`: Create a wedge rendering and save to file. See `Advanced Settings` for additional controls. -- `T`: Translate the current material to a different shading model. See `Advanced Settings` for additional controls. -- `B`: Bake the current material to textures. See `Advanced Settings` for additional controls. -- `UP` : Select the previous geometry. -- `DOWN` : Select the next geometry. -- `RIGHT` : Switch to the next material. -- `LEFT` : Switch to the previous material. -- `+` : Zoom in with the camera. -- `-` : Zoom out with the camera. - -## 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 -- `--mesh [FILENAME]` : Specify the filename of the OBJ or glTF mesh to be displayed in the viewer -- `--meshRotation [VECTOR3]` : Specify the rotation of the displayed mesh as three comma-separated floats, representing rotations in degrees about the X, Y, and Z axes (defaults to 0,0,0) -- `--meshScale [FLOAT]` : Specify the uniform scale of the displayed mesh -- `--cameraPosition [VECTOR3]` : Specify the position of the camera as three comma-separated floats (defaults to 0,0,5) -- `--cameraTarget [VECTOR3]` : Specify the position of the camera target as three comma-separated floats (defaults to 0,0,0) -- `--cameraViewAngle [FLOAT]` : Specify the view angle of the camera, or zero for an orthographic projection (defaults to 45) -- `--cameraZoom [FLOAT]` : Specify the zoom factor for the camera, implemented as a mesh scale multiplier (defaults to 1) -- `--envRad [FILENAME]` : Specify the filename of the environment light to display, stored as HDR environment radiance in the latitude-longitude format -- `--envMethod [INTEGER]` : Specify the environment lighting method (0 = filtered importance sampling, 1 = prefiltered environment maps, defaults to 0) -- `--envSampleCount [INTEGER]` : Specify the environment sample count (defaults to 16) -- `--lightRotation [FLOAT]` : Specify the rotation in degrees of the lighting environment about the Y axis (defaults to 0) -- `--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. -- `--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. -- `--screenWidth [INTEGER]` : Specify the width of the screen image in pixels (defaults to 1280) -- `--screenHeight [INTEGER]` : Specify the height of the screen image in pixels (defaults to 960) -- `--screenColor [VECTOR3]` : Specify the background color of the viewer as three comma-separated floats (defaults to 0.3,0.3,0.32) -- `--captureFilename [FILENAME]` : Specify the filename to which the first rendered frame should be written -- `--refresh [FLOAT]` : Specify the refresh period for the viewer in milliseconds (defaults to 50, set to -1 to disable) -- `--remap [TOKEN1:TOKEN2]` : Specify the remapping from one token to another when MaterialX document is loaded -- `--skip [NAME]` : Specify to skip elements matching the given name attribute -- `--terminator [STRING]` : Specify to enforce the given terminator string for file prefixes -- `--help` : Display the complete list of command-line options +# MaterialX Viewer + +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 + +**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 + +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 + +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. + +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 + +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. + +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. + +### 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. + +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 + +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 + +- `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. +- `O`: Save the current OSL shader source to file. +- `M`: Save the current MDL shader source to file. +- `L`: Load GLSL shader source from file. Editing the source files before loading provides a way to debug and experiment with shader source code. +- `D`: Save each node graph in the current material as a DOT file. See www.graphviz.org for more details on this format. +- `F`: Capture the current frame and save to file. +- `W`: Create a wedge rendering and save to file. See `Advanced Settings` for additional controls. +- `T`: Translate the current material to a different shading model. See `Advanced Settings` for additional controls. +- `B`: Bake the current material to textures. See `Advanced Settings` for additional controls. +- `UP` : Select the previous geometry. +- `DOWN` : Select the next geometry. +- `RIGHT` : Switch to the next material. +- `LEFT` : Switch to the previous material. +- `+` : Zoom in with the camera. +- `-` : Zoom out with the camera. + +### 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 +- `--mesh [FILENAME]` : Specify the filename of the OBJ or glTF mesh to be displayed in the viewer +- `--meshRotation [VECTOR3]` : Specify the rotation of the displayed mesh as three comma-separated floats, representing rotations in degrees about the X, Y, and Z axes (defaults to 0,0,0) +- `--meshScale [FLOAT]` : Specify the uniform scale of the displayed mesh +- `--cameraPosition [VECTOR3]` : Specify the position of the camera as three comma-separated floats (defaults to 0,0,5) +- `--cameraTarget [VECTOR3]` : Specify the position of the camera target as three comma-separated floats (defaults to 0,0,0) +- `--cameraViewAngle [FLOAT]` : Specify the view angle of the camera, or zero for an orthographic projection (defaults to 45) +- `--cameraZoom [FLOAT]` : Specify the zoom factor for the camera, implemented as a mesh scale multiplier (defaults to 1) +- `--envRad [FILENAME]` : Specify the filename of the environment light to display, stored as HDR environment radiance in the latitude-longitude format +- `--envMethod [INTEGER]` : Specify the environment lighting method (0 = filtered importance sampling, 1 = prefiltered environment maps, defaults to 0) +- `--envSampleCount [INTEGER]` : Specify the environment sample count (defaults to 16) +- `--lightRotation [FLOAT]` : Specify the rotation in degrees of the lighting environment about the Y axis (defaults to 0) +- `--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. +- `--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. +- `--screenWidth [INTEGER]` : Specify the width of the screen image in pixels (defaults to 1280) +- `--screenHeight [INTEGER]` : Specify the height of the screen image in pixels (defaults to 960) +- `--screenColor [VECTOR3]` : Specify the background color of the viewer as three comma-separated floats (defaults to 0.3,0.3,0.32) +- `--captureFilename [FILENAME]` : Specify the filename to which the first rendered frame should be written +- `--refresh [FLOAT]` : Specify the refresh period for the viewer in milliseconds (defaults to 50, set to -1 to disable) +- `--remap [TOKEN1:TOKEN2]` : Specify the remapping from one token to another when MaterialX document is loaded +- `--skip [NAME]` : Specify to skip elements matching the given name attribute +- `--terminator [STRING]` : Specify to enforce the given terminator string for file prefixes +- `--help` : Display the complete list of command-line options diff --git a/MaterialX/documents/Doxyfile.in b/MaterialX/documents/Doxyfile.in old mode 100644 new mode 100755 index 890d2d7..007bb59 --- a/MaterialX/documents/Doxyfile.in +++ b/MaterialX/documents/Doxyfile.in @@ -1,28 +1,25 @@ -PROJECT_NAME = MaterialX -PROJECT_NUMBER = ${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION} -PROJECT_LOGO = MaterialXLogo_200x155.png - -USE_MDFILE_AS_MAINPAGE = MainPage.md -HTML_EXTRA_STYLESHEET = doxygen-awesome.css - -INPUT = ${DOXYGEN_INPUT_STR} -OUTPUT_DIRECTORY = ${DOXYGEN_OUTPUT_DIR} -IMAGE_PATH = ${DOXYGEN_OUTPUT_DIR} -HTML_OUTPUT = ${DOXYGEN_HTML_OUTPUT_DIR} -STRIP_FROM_PATH = ${PROJECT_SOURCE_DIR} - -JAVADOC_AUTOBRIEF = YES -HIDE_SCOPE_NAMES = YES -EXTRACT_LOCAL_CLASSES = NO -GENERATE_TODOLIST = NO -GENERATE_LATEX = NO - -GENERATE_TREEVIEW = YES -DISABLE_INDEX = NO -FULL_SIDEBAR = NO - -QUIET = YES -WARN_IF_UNDOCUMENTED = NO - -GENERATE_XML = YES -XML_OUTPUT = doxygen_xml +PROJECT_NAME = MaterialX +PROJECT_NUMBER = ${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION} +PROJECT_LOGO = MaterialXLogo_200x155.png + +USE_MDFILE_AS_MAINPAGE = MainPage.md +HTML_EXTRA_STYLESHEET = doxygen-awesome.css + +INPUT = ${DOXYGEN_INPUT_STR} +OUTPUT_DIRECTORY = ${DOXYGEN_OUTPUT_DIR} +IMAGE_PATH = ${DOXYGEN_OUTPUT_DIR} +HTML_OUTPUT = ${DOXYGEN_HTML_OUTPUT_DIR} +STRIP_FROM_PATH = ${CMAKE_SOURCE_DIR} + +JAVADOC_AUTOBRIEF = YES +HIDE_SCOPE_NAMES = YES +EXTRACT_LOCAL_CLASSES = NO +GENERATE_TODOLIST = NO +GENERATE_LATEX = NO + +GENERATE_TREEVIEW = YES +DISABLE_INDEX = NO +FULL_SIDEBAR = NO + +QUIET = YES +WARN_IF_UNDOCUMENTED = NO diff --git a/MaterialX/documents/DoxygenAwesome/LICENSE b/MaterialX/documents/DoxygenAwesome/LICENSE old mode 100644 new mode 100755 index 1d8b99a..f0e249c --- a/MaterialX/documents/DoxygenAwesome/LICENSE +++ b/MaterialX/documents/DoxygenAwesome/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2021 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2021 jothepro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MaterialX/documents/DoxygenAwesome/doxygen-awesome.css b/MaterialX/documents/DoxygenAwesome/doxygen-awesome.css old mode 100644 new mode 100755 index abd2893..9b869aa --- a/MaterialX/documents/DoxygenAwesome/doxygen-awesome.css +++ b/MaterialX/documents/DoxygenAwesome/doxygen-awesome.css @@ -1,2405 +1,2405 @@ -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -MIT License - -Copyright (c) 2021 - 2022 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -html { - /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ - --primary-color: #1779c4; - --primary-dark-color: #335c80; - --primary-light-color: #70b1e9; - - /* page base colors */ - --page-background-color: #ffffff; - --page-foreground-color: #2f4153; - --page-secondary-foreground-color: #6f7e8e; - - /* color for all separators on the website: hr, borders, ... */ - --separator-color: #dedede; - - /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */ - --border-radius-large: 8px; - --border-radius-small: 4px; - --border-radius-medium: 6px; - - /* default spacings. Most components reference these values for spacing, to provide uniform spacing on the page. */ - --spacing-small: 5px; - --spacing-medium: 10px; - --spacing-large: 16px; - - /* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */ - --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); - - --odd-color: rgba(0,0,0,.028); - - /* font-families. will affect all text on the website - * font-family: the normal font for text, headlines, menus - * font-family-monospace: used for preformatted text in memtitle, code, fragments - */ - --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; - --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; - - /* font sizes */ - --page-font-size: 15.6px; - --navigation-font-size: 14.4px; - --toc-font-size: 13.4px; - --code-font-size: 14px; /* affects code, fragment */ - --title-font-size: 22px; - - /* content text properties. These only affect the page content, not the navigation or any other ui elements */ - --content-line-height: 27px; - /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/ - --content-maxwidth: 1050px; - --table-line-height: 24px; - --toc-sticky-top: var(--spacing-medium); - --toc-width: 200px; - --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 85px); - - /* colors for various content boxes: @warning, @note, @deprecated @bug */ - --warning-color: #f8d1cc; - --warning-color-dark: #b61825; - --warning-color-darker: #75070f; - --note-color: #faf3d8; - --note-color-dark: #f3a600; - --note-color-darker: #5f4204; - --todo-color: #e4f3ff; - --todo-color-dark: #1879C4; - --todo-color-darker: #274a5c; - --deprecated-color: #ecf0f3; - --deprecated-color-dark: #5b6269; - --deprecated-color-darker: #43454a; - --bug-color: #e4dafd; - --bug-color-dark: #5b2bdd; - --bug-color-darker: #2a0d72; - --invariant-color: #d8f1e3; - --invariant-color-dark: #44b86f; - --invariant-color-darker: #265532; - - /* blockquote colors */ - --blockquote-background: #f8f9fa; - --blockquote-foreground: #636568; - - /* table colors */ - --tablehead-background: #f1f1f1; - --tablehead-foreground: var(--page-foreground-color); - - /* menu-display: block | none - * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible. - * `GENERATE_TREEVIEW` MUST be enabled! - */ - --menu-display: block; - - --menu-focus-foreground: var(--page-background-color); - --menu-focus-background: var(--primary-color); - --menu-selected-background: rgba(0,0,0,.05); - - - --header-background: var(--page-background-color); - --header-foreground: var(--page-foreground-color); - - /* searchbar colors */ - --searchbar-background: var(--side-nav-background); - --searchbar-foreground: var(--page-foreground-color); - - /* searchbar size - * (`searchbar-width` is only applied on screens >= 768px. - * on smaller screens the searchbar will always fill the entire screen width) */ - --searchbar-height: 33px; - --searchbar-width: 210px; - --searchbar-border-radius: var(--searchbar-height); - - /* code block colors */ - --code-background: #f5f5f5; - --code-foreground: var(--page-foreground-color); - - /* fragment colors */ - --fragment-background: #F8F9FA; - --fragment-foreground: #37474F; - --fragment-keyword: #bb6bb2; - --fragment-keywordtype: #8258b3; - --fragment-keywordflow: #d67c3b; - --fragment-token: #438a59; - --fragment-comment: #969696; - --fragment-link: #5383d6; - --fragment-preprocessor: #46aaa5; - --fragment-linenumber-color: #797979; - --fragment-linenumber-background: #f4f4f5; - --fragment-linenumber-border: #e3e5e7; - --fragment-lineheight: 20px; - - /* sidebar navigation (treeview) colors */ - --side-nav-background: #fbfbfb; - --side-nav-foreground: var(--page-foreground-color); - --side-nav-arrow-opacity: 0; - --side-nav-arrow-hover-opacity: 0.9; - - --toc-background: var(--side-nav-background); - --toc-foreground: var(--side-nav-foreground); - - /* height of an item in any tree / collapsable table */ - --tree-item-height: 30px; - - --memname-font-size: var(--code-font-size); - --memtitle-font-size: 18px; - - --webkit-scrollbar-size: 7px; - --webkit-scrollbar-padding: 4px; - --webkit-scrollbar-color: var(--separator-color); -} - -@media screen and (max-width: 767px) { - html { - --page-font-size: 16px; - --navigation-font-size: 16px; - --toc-font-size: 15px; - --code-font-size: 15px; /* affects code, fragment */ - --title-font-size: 22px; - } -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) { - color-scheme: dark; - - --primary-color: #1982d2; - --primary-dark-color: #86a9c4; - --primary-light-color: #4779ac; - - --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); - - --odd-color: rgba(100,100,100,.06); - - --menu-selected-background: rgba(0,0,0,.4); - - --page-background-color: #1C1D1F; - --page-foreground-color: #d2dbde; - --page-secondary-foreground-color: #859399; - --separator-color: #38393b; - --side-nav-background: #252628; - - --code-background: #2a2c2f; - - --tablehead-background: #2a2c2f; - - --blockquote-background: #222325; - --blockquote-foreground: #7e8c92; - - --warning-color: #2e1917; - --warning-color-dark: #ad2617; - --warning-color-darker: #f5b1aa; - --note-color: #3b2e04; - --note-color-dark: #f1b602; - --note-color-darker: #ceb670; - --todo-color: #163750; - --todo-color-dark: #1982D2; - --todo-color-darker: #dcf0fa; - --deprecated-color: #2e323b; - --deprecated-color-dark: #738396; - --deprecated-color-darker: #abb0bd; - --bug-color: #2a2536; - --bug-color-dark: #7661b3; - --bug-color-darker: #ae9ed6; - --invariant-color: #303a35; - --invariant-color-dark: #76ce96; - --invariant-color-darker: #cceed5; - - --fragment-background: #282c34; - --fragment-foreground: #dbe4eb; - --fragment-keyword: #cc99cd; - --fragment-keywordtype: #ab99cd; - --fragment-keywordflow: #e08000; - --fragment-token: #7ec699; - --fragment-comment: #999999; - --fragment-link: #98c0e3; - --fragment-preprocessor: #65cabe; - --fragment-linenumber-color: #cccccc; - --fragment-linenumber-background: #35393c; - --fragment-linenumber-border: #1f1f1f; - } -} - -/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */ -html.dark-mode { - color-scheme: dark; - - --primary-color: #1982d2; - --primary-dark-color: #86a9c4; - --primary-light-color: #4779ac; - - --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30); - - --odd-color: rgba(100,100,100,.06); - - --menu-selected-background: rgba(0,0,0,.4); - - --page-background-color: #1C1D1F; - --page-foreground-color: #d2dbde; - --page-secondary-foreground-color: #859399; - --separator-color: #38393b; - --side-nav-background: #252628; - - --code-background: #2a2c2f; - - --tablehead-background: #2a2c2f; - - --blockquote-background: #222325; - --blockquote-foreground: #7e8c92; - - --warning-color: #2e1917; - --warning-color-dark: #ad2617; - --warning-color-darker: #f5b1aa; - --note-color: #3b2e04; - --note-color-dark: #f1b602; - --note-color-darker: #ceb670; - --todo-color: #163750; - --todo-color-dark: #1982D2; - --todo-color-darker: #dcf0fa; - --deprecated-color: #2e323b; - --deprecated-color-dark: #738396; - --deprecated-color-darker: #abb0bd; - --bug-color: #2a2536; - --bug-color-dark: #7661b3; - --bug-color-darker: #ae9ed6; - --invariant-color: #303a35; - --invariant-color-dark: #76ce96; - --invariant-color-darker: #cceed5; - - --fragment-background: #282c34; - --fragment-foreground: #dbe4eb; - --fragment-keyword: #cc99cd; - --fragment-keywordtype: #ab99cd; - --fragment-keywordflow: #e08000; - --fragment-token: #7ec699; - --fragment-comment: #999999; - --fragment-link: #98c0e3; - --fragment-preprocessor: #65cabe; - --fragment-linenumber-color: #cccccc; - --fragment-linenumber-background: #35393c; - --fragment-linenumber-border: #1f1f1f; -} - -body { - color: var(--page-foreground-color); - background-color: var(--page-background-color); - font-size: var(--page-font-size); -} - -body, table, div, p, dl, #nav-tree .label, .title, -.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, -.SelectItem, #MSearchField, .navpath li.navelem a, -.navpath li.navelem a:hover, p.reference, p.definition { - font-family: var(--font-family); -} - -h1, h2, h3, h4, h5 { - margin-top: .9em; - font-weight: 600; - line-height: initial; -} - -p, div, table, dl, p.reference, p.definition { - font-size: var(--page-font-size); -} - -p.reference, p.definition { - color: var(--page-secondary-foreground-color); -} - -a:link, a:visited, a:hover, a:focus, a:active { - color: var(--primary-color) !important; - font-weight: 500; -} - -a.anchor { - scroll-margin-top: var(--spacing-large); - display: block; -} - -/* - Title and top navigation - */ - -#top { - background: var(--header-background); - border-bottom: 1px solid var(--separator-color); -} - -@media screen and (min-width: 768px) { - #top { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - align-items: center; - } -} - -#main-nav { - flex-grow: 5; - padding: var(--spacing-small) var(--spacing-medium); -} - -#titlearea { - width: auto; - padding: var(--spacing-medium) var(--spacing-large); - background: none; - color: var(--header-foreground); - border-bottom: none; -} - -@media screen and (max-width: 767px) { - #titlearea { - padding-bottom: var(--spacing-small); - } -} - -#titlearea table tbody tr { - height: auto !important; -} - -#projectname { - font-size: var(--title-font-size); - font-weight: 600; -} - -#projectnumber { - font-family: inherit; - font-size: 60%; -} - -#projectbrief { - font-family: inherit; - font-size: 80%; -} - -#projectlogo { - vertical-align: middle; -} - -#projectlogo img { - max-height: calc(var(--title-font-size) * 2); - margin-right: var(--spacing-small); -} - -.sm-dox, .tabs, .tabs2, .tabs3 { - background: none; - padding: 0; -} - -.tabs, .tabs2, .tabs3 { - border-bottom: 1px solid var(--separator-color); - margin-bottom: -1px; -} - -.main-menu-btn-icon, .main-menu-btn-icon:before, .main-menu-btn-icon:after { - background: var(--page-secondary-foreground-color); -} - -@media screen and (max-width: 767px) { - .sm-dox a span.sub-arrow { - background: var(--code-background); - } - - #main-menu a.has-submenu span.sub-arrow { - color: var(--page-secondary-foreground-color); - border-radius: var(--border-radius-medium); - } - - #main-menu a.has-submenu:hover span.sub-arrow { - color: var(--page-foreground-color); - } -} - -@media screen and (min-width: 768px) { - .sm-dox li, .tablist li { - display: var(--menu-display); - } - - .sm-dox a span.sub-arrow { - border-color: var(--header-foreground) transparent transparent transparent; - } - - .sm-dox a:hover span.sub-arrow { - border-color: var(--menu-focus-foreground) transparent transparent transparent; - } - - .sm-dox ul a span.sub-arrow { - border-color: transparent transparent transparent var(--page-foreground-color); - } - - .sm-dox ul a:hover span.sub-arrow { - border-color: transparent transparent transparent var(--menu-focus-foreground); - } -} - -.sm-dox ul { - background: var(--page-background-color); - box-shadow: var(--box-shadow); - border: 1px solid var(--separator-color); - border-radius: var(--border-radius-medium) !important; - padding: var(--spacing-small); - animation: ease-out 150ms slideInMenu; -} - -@keyframes slideInMenu { - from { - opacity: 0; - transform: translate(0px, -2px); - } - - to { - opacity: 1; - transform: translate(0px, 0px); - } -} - -.sm-dox ul a { - color: var(--page-foreground-color) !important; - background: var(--page-background-color); - font-size: var(--navigation-font-size); -} - -.sm-dox>li>ul:after { - border-bottom-color: var(--page-background-color) !important; -} - -.sm-dox>li>ul:before { - border-bottom-color: var(--separator-color) !important; -} - -.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus { - font-size: var(--navigation-font-size) !important; - color: var(--menu-focus-foreground) !important; - text-shadow: none; - background-color: var(--menu-focus-background); - border-radius: var(--border-radius-small) !important; -} - -.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a { - text-shadow: none; - background: transparent; - background-image: none !important; - color: var(--header-foreground) !important; - font-weight: normal; - font-size: var(--navigation-font-size); - border-radius: var(--border-radius-small) !important; -} - -.sm-dox a:focus { - outline: auto; -} - -.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover { - text-shadow: none; - font-weight: normal; - background: var(--menu-focus-background); - color: var(--menu-focus-foreground) !important; - border-radius: var(--border-radius-small) !important; - font-size: var(--navigation-font-size); -} - -.tablist li.current { - border-radius: var(--border-radius-small); - background: var(--menu-selected-background); -} - -.tablist li { - margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small); -} - -.tablist a { - padding: 0 var(--spacing-large); -} - - -/* - Search box - */ - -#MSearchBox { - height: var(--searchbar-height); - background: var(--searchbar-background); - border-radius: var(--searchbar-border-radius); - border: 1px solid var(--separator-color); - overflow: hidden; - width: var(--searchbar-width); - position: relative; - box-shadow: none; - display: block; - margin-top: 0; -} - -/* until Doxygen 1.9.4 */ -.left img#MSearchSelect { - left: 0; - user-select: none; - padding-left: 8px; -} - -/* Doxygen 1.9.5 */ -.left span#MSearchSelect { - left: 0; - user-select: none; - margin-left: 8px; - padding: 0; -} - -.left #MSearchSelect[src$=".png"] { - padding-left: 0 -} - -.SelectionMark { - user-select: none; -} - -.tabs .left #MSearchSelect { - padding-left: 0; -} - -.tabs #MSearchBox { - position: absolute; - right: var(--spacing-medium); -} - -@media screen and (max-width: 767px) { - .tabs #MSearchBox { - position: relative; - right: 0; - margin-left: var(--spacing-medium); - margin-top: 0; - } -} - -#MSearchSelectWindow, #MSearchResultsWindow { - z-index: 9999; -} - -#MSearchBox.MSearchBoxActive { - border-color: var(--primary-color); - box-shadow: inset 0 0 0 1px var(--primary-color); -} - -#main-menu > li:last-child { - margin-right: 0; -} - -@media screen and (max-width: 767px) { - #main-menu > li:last-child { - height: 50px; - } -} - -#MSearchField { - font-size: var(--navigation-font-size); - height: calc(var(--searchbar-height) - 2px); - background: transparent; - width: calc(var(--searchbar-width) - 64px); -} - -.MSearchBoxActive #MSearchField { - color: var(--searchbar-foreground); -} - -#MSearchSelect { - top: calc(calc(var(--searchbar-height) / 2) - 11px); -} - -#MSearchBox span.left, #MSearchBox span.right { - background: none; - background-image: none; -} - -#MSearchBox span.right { - padding-top: calc(calc(var(--searchbar-height) / 2) - 12px); - position: absolute; - right: var(--spacing-small); -} - -.tabs #MSearchBox span.right { - top: calc(calc(var(--searchbar-height) / 2) - 12px); -} - -@keyframes slideInSearchResults { - from { - opacity: 0; - transform: translate(0, 15px); - } - - to { - opacity: 1; - transform: translate(0, 20px); - } -} - -#MSearchResultsWindow { - left: auto !important; - right: var(--spacing-medium); - border-radius: var(--border-radius-large); - border: 1px solid var(--separator-color); - transform: translate(0, 20px); - box-shadow: var(--box-shadow); - animation: ease-out 280ms slideInSearchResults; - background: var(--page-background-color); -} - -iframe#MSearchResults { - margin: 4px; -} - -iframe { - color-scheme: normal; -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) iframe#MSearchResults { - filter: invert() hue-rotate(180deg); - } -} - -html.dark-mode iframe#MSearchResults { - filter: invert() hue-rotate(180deg); -} - -#MSearchResults .SRPage { - background-color: transparent; -} - -#MSearchResults .SRPage .SREntry { - font-size: 10pt; - padding: var(--spacing-small) var(--spacing-medium); -} - -#MSearchSelectWindow { - border: 1px solid var(--separator-color); - border-radius: var(--border-radius-medium); - box-shadow: var(--box-shadow); - background: var(--page-background-color); - padding-top: var(--spacing-small); - padding-bottom: var(--spacing-small); -} - -#MSearchSelectWindow a.SelectItem { - font-size: var(--navigation-font-size); - line-height: var(--content-line-height); - margin: 0 var(--spacing-small); - border-radius: var(--border-radius-small); - color: var(--page-foreground-color) !important; - font-weight: normal; -} - -#MSearchSelectWindow a.SelectItem:hover { - background: var(--menu-focus-background); - color: var(--menu-focus-foreground) !important; -} - -@media screen and (max-width: 767px) { - #MSearchBox { - margin-top: var(--spacing-medium); - margin-bottom: var(--spacing-medium); - width: calc(100vw - 30px); - } - - #main-menu > li:last-child { - float: none !important; - } - - #MSearchField { - width: calc(100vw - 110px); - } - - @keyframes slideInSearchResultsMobile { - from { - opacity: 0; - transform: translate(0, 15px); - } - - to { - opacity: 1; - transform: translate(0, 20px); - } - } - - #MSearchResultsWindow { - left: var(--spacing-medium) !important; - right: var(--spacing-medium); - overflow: auto; - transform: translate(0, 20px); - animation: ease-out 280ms slideInSearchResultsMobile; - width: auto !important; - } - - /* - * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2 - */ - label.main-menu-btn ~ #searchBoxPos1 { - top: 3px !important; - right: 6px !important; - left: 45px; - display: flex; - } - - label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox { - margin-top: 0; - margin-bottom: 0; - flex-grow: 2; - float: left; - } -} - -/* - Tree view - */ - -#side-nav { - padding: 0 !important; - background: var(--side-nav-background); -} - -@media screen and (max-width: 767px) { - #side-nav { - display: none; - } - - #doc-content { - margin-left: 0 !important; - } -} - -#nav-tree { - background: transparent; -} - -#nav-tree .label { - font-size: var(--navigation-font-size); -} - -#nav-tree .item { - height: var(--tree-item-height); - line-height: var(--tree-item-height); -} - -#nav-sync { - bottom: 12px; - right: 12px; - top: auto !important; - user-select: none; -} - -#nav-tree .selected { - text-shadow: none; - background-image: none; - background-color: transparent; - position: relative; -} - -#nav-tree .selected::after { - content: ""; - position: absolute; - top: 1px; - bottom: 1px; - left: 0; - width: 4px; - border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; - background: var(--primary-color); -} - - -#nav-tree a { - color: var(--side-nav-foreground) !important; - font-weight: normal; -} - -#nav-tree a:focus { - outline-style: auto; -} - -#nav-tree .arrow { - opacity: var(--side-nav-arrow-opacity); -} - -.arrow { - color: inherit; - cursor: pointer; - font-size: 45%; - vertical-align: middle; - margin-right: 2px; - font-family: serif; - height: auto; - text-align: right; -} - -#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow { - opacity: var(--side-nav-arrow-hover-opacity); -} - -#nav-tree .selected a { - color: var(--primary-color) !important; - font-weight: bolder; - font-weight: 600; -} - -.ui-resizable-e { - background: var(--separator-color); - width: 1px; -} - -/* - Contents - */ - -div.header { - border-bottom: 1px solid var(--separator-color); - background-color: var(--page-background-color); - background-image: none; -} - -@media screen and (min-width: 1000px) { - #doc-content > div > div.contents, - .PageDoc > div.contents { - display: flex; - flex-direction: row-reverse; - flex-wrap: nowrap; - align-items: flex-start; - } - - div.contents .textblock { - min-width: 200px; - flex-grow: 1; - } -} - -div.contents, div.header .title, div.header .summary { - max-width: var(--content-maxwidth); -} - -div.contents, div.header .title { - line-height: initial; - margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto; -} - -div.header .summary { - margin: var(--spacing-medium) auto 0 auto; -} - -div.headertitle { - padding: 0; -} - -div.header .title { - font-weight: 600; - font-size: 225%; - padding: var(--spacing-medium) var(--spacing-large); - word-break: break-word; -} - -div.header .summary { - width: auto; - display: block; - float: none; - padding: 0 var(--spacing-large); -} - -td.memSeparator { - border-color: var(--separator-color); -} - -span.mlabel { - background: var(--primary-color); - border: none; - padding: 4px 9px; - border-radius: 12px; - margin-right: var(--spacing-medium); -} - -span.mlabel:last-of-type { - margin-right: 2px; -} - -div.contents { - padding: 0 var(--spacing-large); -} - -div.contents p, div.contents li { - line-height: var(--content-line-height); -} - -div.contents div.dyncontent { - margin: var(--spacing-medium) 0; -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) div.contents div.dyncontent img, - html:not(.light-mode) div.contents center img, - html:not(.light-mode) div.contents > table img, - html:not(.light-mode) div.contents div.dyncontent iframe, - html:not(.light-mode) div.contents center iframe, - html:not(.light-mode) div.contents table iframe { - filter: hue-rotate(180deg) invert(); - } -} - -html.dark-mode div.contents div.dyncontent img, -html.dark-mode div.contents center img, -html.dark-mode div.contents > table img, -html.dark-mode div.contents div.dyncontent iframe, -html.dark-mode div.contents center iframe, -html.dark-mode div.contents table iframe { - filter: hue-rotate(180deg) invert(); -} - -h2.groupheader { - border-bottom: 0px; - color: var(--page-foreground-color); - box-shadow: - 100px 0 var(--page-background-color), - -100px 0 var(--page-background-color), - 100px 0.75px var(--separator-color), - -100px 0.75px var(--separator-color), - 500px 0 var(--page-background-color), - -500px 0 var(--page-background-color), - 500px 0.75px var(--separator-color), - -500px 0.75px var(--separator-color), - 900px 0 var(--page-background-color), - -900px 0 var(--page-background-color), - 900px 0.75px var(--separator-color), - -900px 0.75px var(--separator-color), - 1400px 0 var(--page-background-color), - -1400px 0 var(--page-background-color), - 1400px 0.75px var(--separator-color), - -1400px 0.75px var(--separator-color), - 1900px 0 var(--page-background-color), - -1900px 0 var(--page-background-color), - 1900px 0.75px var(--separator-color), - -1900px 0.75px var(--separator-color); -} - -blockquote { - margin: 0 var(--spacing-medium) 0 var(--spacing-medium); - padding: var(--spacing-small) var(--spacing-large); - background: var(--blockquote-background); - color: var(--blockquote-foreground); - border-left: 0; - overflow: visible; - border-radius: var(--border-radius-medium); - overflow: visible; - position: relative; -} - -blockquote::before, blockquote::after { - font-weight: bold; - font-family: serif; - font-size: 360%; - opacity: .15; - position: absolute; -} - -blockquote::before { - content: "“"; - left: -10px; - top: 4px; -} - -blockquote::after { - content: "”"; - right: -8px; - bottom: -25px; -} - -blockquote p { - margin: var(--spacing-small) 0 var(--spacing-medium) 0; -} -.paramname { - font-weight: 600; - color: var(--primary-dark-color); -} - -.paramname > code { - border: 0; -} - -table.params .paramname { - font-weight: 600; - font-family: var(--font-family-monospace); - font-size: var(--code-font-size); - padding-right: var(--spacing-small); - line-height: var(--table-line-height); -} - -h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { - text-shadow: 0 0 15px var(--primary-light-color); -} - -.alphachar a { - color: var(--page-foreground-color); -} - -/* - Table of Contents - */ - -div.contents .toc { - max-height: var(--toc-max-height); - min-width: var(--toc-width); - border: 0; - border-left: 1px solid var(--separator-color); - border-radius: 0; - background-color: transparent; - box-shadow: none; - position: sticky; - top: var(--toc-sticky-top); - padding: 0 var(--spacing-large); - margin: var(--spacing-small) 0 var(--spacing-large) var(--spacing-large); -} - -div.toc h3 { - color: var(--toc-foreground); - font-size: var(--navigation-font-size); - margin: var(--spacing-large) 0 var(--spacing-medium) 0; -} - -div.toc li { - padding: 0; - background: none; - line-height: var(--toc-font-size); - margin: var(--toc-font-size) 0 0 0; -} - -div.toc li::before { - display: none; -} - -div.toc ul { - margin-top: 0 -} - -div.toc li a { - font-size: var(--toc-font-size); - color: var(--page-foreground-color) !important; - text-decoration: none; -} - -div.toc li a:hover, div.toc li a.active { - color: var(--primary-color) !important; -} - -div.toc li a.aboveActive { - color: var(--page-secondary-foreground-color) !important; -} - - -@media screen and (max-width: 999px) { - div.contents .toc { - max-height: 45vh; - float: none; - width: auto; - margin: 0 0 var(--spacing-medium) 0; - position: relative; - top: 0; - position: relative; - border: 1px solid var(--separator-color); - border-radius: var(--border-radius-medium); - background-color: var(--toc-background); - box-shadow: var(--box-shadow); - } - - div.contents .toc.interactive { - max-height: calc(var(--navigation-font-size) + 2 * var(--spacing-large)); - overflow: hidden; - } - - div.contents .toc > h3 { - -webkit-tap-highlight-color: transparent; - cursor: pointer; - position: sticky; - top: 0; - background-color: var(--toc-background); - margin: 0; - padding: var(--spacing-large) 0; - display: block; - } - - div.contents .toc.interactive > h3::before { - content: ""; - width: 0; - height: 0; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - border-top: 5px solid var(--primary-color); - display: inline-block; - margin-right: var(--spacing-small); - margin-bottom: calc(var(--navigation-font-size) / 4); - transform: rotate(-90deg); - transition: transform 0.25s ease-out; - } - - div.contents .toc.interactive.open > h3::before { - transform: rotate(0deg); - } - - div.contents .toc.interactive.open { - max-height: 45vh; - overflow: auto; - transition: max-height 0.2s ease-in-out; - } - - div.contents .toc a, div.contents .toc a.active { - color: var(--primary-color) !important; - } - - div.contents .toc a:hover { - text-decoration: underline; - } -} - -/* - Code & Fragments - */ - -code, div.fragment, pre.fragment { - border-radius: var(--border-radius-small); - border: 1px solid var(--separator-color); - overflow: hidden; -} - -code { - display: inline; - background: var(--code-background); - color: var(--code-foreground); - padding: 2px 6px; -} - -div.fragment, pre.fragment { - margin: var(--spacing-medium) 0; - padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large); - background: var(--fragment-background); - color: var(--fragment-foreground); - overflow-x: auto; -} - -@media screen and (max-width: 767px) { - div.fragment, pre.fragment { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - border-right: 0; - } - - .contents > div.fragment, - .textblock > div.fragment, - .textblock > pre.fragment, - .contents > .doxygen-awesome-fragment-wrapper > div.fragment, - .textblock > .doxygen-awesome-fragment-wrapper > div.fragment, - .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-large)); - border-radius: 0; - border-left: 0; - } - - .textblock li > .fragment, - .textblock li > .doxygen-awesome-fragment-wrapper > .fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-large)); - } - - .memdoc li > .fragment, - .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); - } - - .textblock ul, .memdoc ul { - overflow: initial; - } - - .memdoc > div.fragment, - .memdoc > pre.fragment, - dl dd > div.fragment, - dl dd pre.fragment, - .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment, - .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment, - dl dd > .doxygen-awesome-fragment-wrapper > div.fragment, - dl dd .doxygen-awesome-fragment-wrapper > pre.fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); - border-radius: 0; - border-left: 0; - } -} - -code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span { - font-family: var(--font-family-monospace); - font-size: var(--code-font-size) !important; -} - -div.line:after { - margin-right: var(--spacing-medium); -} - -div.fragment .line, pre.fragment { - white-space: pre; - word-wrap: initial; - line-height: var(--fragment-lineheight); -} - -div.fragment span.keyword { - color: var(--fragment-keyword); -} - -div.fragment span.keywordtype { - color: var(--fragment-keywordtype); -} - -div.fragment span.keywordflow { - color: var(--fragment-keywordflow); -} - -div.fragment span.stringliteral { - color: var(--fragment-token) -} - -div.fragment span.comment { - color: var(--fragment-comment); -} - -div.fragment a.code { - color: var(--fragment-link) !important; -} - -div.fragment span.preprocessor { - color: var(--fragment-preprocessor); -} - -div.fragment span.lineno { - display: inline-block; - width: 27px; - border-right: none; - background: var(--fragment-linenumber-background); - color: var(--fragment-linenumber-color); -} - -div.fragment span.lineno a { - background: none; - color: var(--fragment-link) !important; -} - -div.fragment .line:first-child .lineno { - box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border); -} - -div.line { - border-radius: var(--border-radius-small); -} - -div.line.glow { - background-color: var(--primary-light-color); - box-shadow: none; -} - -/* - dl warning, attention, note, deprecated, bug, ... - */ - -dl.bug dt a, dl.deprecated dt a, dl.todo dt a { - font-weight: bold !important; -} - -dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.todo, dl.remark { - padding: var(--spacing-medium); - margin: var(--spacing-medium) 0; - color: var(--page-background-color); - overflow: hidden; - margin-left: 0; - border-radius: var(--border-radius-small); -} - -dl.section dd { - margin-bottom: 2px; -} - -dl.warning, dl.attention { - background: var(--warning-color); - border-left: 8px solid var(--warning-color-dark); - color: var(--warning-color-darker); -} - -dl.warning dt, dl.attention dt { - color: var(--warning-color-dark); -} - -dl.note, dl.remark { - background: var(--note-color); - border-left: 8px solid var(--note-color-dark); - color: var(--note-color-darker); -} - -dl.note dt, dl.remark dt { - color: var(--note-color-dark); -} - -dl.todo { - background: var(--todo-color); - border-left: 8px solid var(--todo-color-dark); - color: var(--todo-color-darker); -} - -dl.todo dt { - color: var(--todo-color-dark); -} - -dl.bug dt a { - color: var(--todo-color-dark) !important; -} - -dl.bug { - background: var(--bug-color); - border-left: 8px solid var(--bug-color-dark); - color: var(--bug-color-darker); -} - -dl.bug dt a { - color: var(--bug-color-dark) !important; -} - -dl.deprecated { - background: var(--deprecated-color); - border-left: 8px solid var(--deprecated-color-dark); - color: var(--deprecated-color-darker); -} - -dl.deprecated dt a { - color: var(--deprecated-color-dark) !important; -} - -dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { - margin-inline-start: 0px; -} - -dl.invariant, dl.pre { - background: var(--invariant-color); - border-left: 8px solid var(--invariant-color-dark); - color: var(--invariant-color-darker); -} - -dl.invariant dt, dl.pre dt { - color: var(--invariant-color-dark); -} - -/* - memitem - */ - -div.memdoc, div.memproto, h2.memtitle { - box-shadow: none; - background-image: none; - border: none; -} - -div.memdoc { - padding: 0 var(--spacing-medium); - background: var(--page-background-color); -} - -h2.memtitle, div.memitem { - border: 1px solid var(--separator-color); - box-shadow: var(--box-shadow); -} - -h2.memtitle { - box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow); -} - -div.memitem { - transition: none; -} - -div.memproto, h2.memtitle { - background: var(--fragment-background); -} - -h2.memtitle { - font-weight: 500; - font-size: var(--memtitle-font-size); - font-family: var(--font-family-monospace); - border-bottom: none; - border-top-left-radius: var(--border-radius-medium); - border-top-right-radius: var(--border-radius-medium); - word-break: break-all; - position: relative; -} - -h2.memtitle:after { - content: ""; - display: block; - background: var(--fragment-background); - height: var(--spacing-medium); - bottom: calc(0px - var(--spacing-medium)); - left: 0; - right: -14px; - position: absolute; - border-top-right-radius: var(--border-radius-medium); -} - -h2.memtitle > span.permalink { - font-size: inherit; -} - -h2.memtitle > span.permalink > a { - text-decoration: none; - padding-left: 3px; - margin-right: -4px; - user-select: none; - display: inline-block; - margin-top: -6px; -} - -h2.memtitle > span.permalink > a:hover { - color: var(--primary-dark-color) !important; -} - -a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { - border-color: var(--primary-light-color); -} - -div.memitem { - border-top-right-radius: var(--border-radius-medium); - border-bottom-right-radius: var(--border-radius-medium); - border-bottom-left-radius: var(--border-radius-medium); - overflow: hidden; - display: block !important; -} - -div.memdoc { - border-radius: 0; -} - -div.memproto { - border-radius: 0 var(--border-radius-small) 0 0; - overflow: auto; - border-bottom: 1px solid var(--separator-color); - padding: var(--spacing-medium); - margin-bottom: -1px; -} - -div.memtitle { - border-top-right-radius: var(--border-radius-medium); - border-top-left-radius: var(--border-radius-medium); -} - -div.memproto table.memname { - font-family: var(--font-family-monospace); - color: var(--page-foreground-color); - font-size: var(--memname-font-size); - text-shadow: none; -} - -div.memproto div.memtemplate { - font-family: var(--font-family-monospace); - color: var(--primary-dark-color); - font-size: var(--memname-font-size); - margin-left: 2px; - text-shadow: none; -} - -table.mlabels, table.mlabels > tbody { - display: block; -} - -td.mlabels-left { - width: auto; -} - -td.mlabels-right { - margin-top: 3px; - position: sticky; - left: 0; -} - -table.mlabels > tbody > tr:first-child { - display: flex; - justify-content: space-between; - flex-wrap: wrap; -} - -.memname, .memitem span.mlabels { - margin: 0 -} - -/* - reflist - */ - -dl.reflist { - box-shadow: var(--box-shadow); - border-radius: var(--border-radius-medium); - border: 1px solid var(--separator-color); - overflow: hidden; - padding: 0; -} - - -dl.reflist dt, dl.reflist dd { - box-shadow: none; - text-shadow: none; - background-image: none; - border: none; - padding: 12px; -} - - -dl.reflist dt { - font-weight: 500; - border-radius: 0; - background: var(--code-background); - border-bottom: 1px solid var(--separator-color); - color: var(--page-foreground-color) -} - - -dl.reflist dd { - background: none; -} - -/* - Table - */ - -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname), -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { - display: inline-block; - max-width: 100%; -} - -.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) { - margin-left: calc(0px - var(--spacing-large)); - margin-right: calc(0px - var(--spacing-large)); - max-width: calc(100% + 2 * var(--spacing-large)); -} - -table.fieldtable, -table.markdownTable tbody, -table.doxtable tbody { - border: none; - margin: var(--spacing-medium) 0; - box-shadow: 0 0 0 1px var(--separator-color); - border-radius: var(--border-radius-small); -} - -table.doxtable caption { - display: block; -} - -table.fieldtable { - border-collapse: collapse; - width: 100%; -} - -th.markdownTableHeadLeft, -th.markdownTableHeadRight, -th.markdownTableHeadCenter, -th.markdownTableHeadNone, -table.doxtable th { - background: var(--tablehead-background); - color: var(--tablehead-foreground); - font-weight: 600; - font-size: var(--page-font-size); -} - -th.markdownTableHeadLeft:first-child, -th.markdownTableHeadRight:first-child, -th.markdownTableHeadCenter:first-child, -th.markdownTableHeadNone:first-child, -table.doxtable tr th:first-child { - border-top-left-radius: var(--border-radius-small); -} - -th.markdownTableHeadLeft:last-child, -th.markdownTableHeadRight:last-child, -th.markdownTableHeadCenter:last-child, -th.markdownTableHeadNone:last-child, -table.doxtable tr th:last-child { - border-top-right-radius: var(--border-radius-small); -} - -table.markdownTable td, -table.markdownTable th, -table.fieldtable td, -table.fieldtable th, -table.doxtable td, -table.doxtable th { - border: 1px solid var(--separator-color); - padding: var(--spacing-small) var(--spacing-medium); -} - -table.markdownTable td:last-child, -table.markdownTable th:last-child, -table.fieldtable td:last-child, -table.fieldtable th:last-child, -table.doxtable td:last-child, -table.doxtable th:last-child { - border-right: none; -} - -table.markdownTable td:first-child, -table.markdownTable th:first-child, -table.fieldtable td:first-child, -table.fieldtable th:first-child, -table.doxtable td:first-child, -table.doxtable th:first-child { - border-left: none; -} - -table.markdownTable tr:first-child td, -table.markdownTable tr:first-child th, -table.fieldtable tr:first-child td, -table.fieldtable tr:first-child th, -table.doxtable tr:first-child td, -table.doxtable tr:first-child th { - border-top: none; -} - -table.markdownTable tr:last-child td, -table.markdownTable tr:last-child th, -table.fieldtable tr:last-child td, -table.fieldtable tr:last-child th, -table.doxtable tr:last-child td, -table.doxtable tr:last-child th { - border-bottom: none; -} - -table.markdownTable tr, table.doxtable tr { - border-bottom: 1px solid var(--separator-color); -} - -table.markdownTable tr:last-child, table.doxtable tr:last-child { - border-bottom: none; -} - -table.fieldtable th { - font-size: var(--page-font-size); - font-weight: 600; - background-image: none; - background-color: var(--tablehead-background); - color: var(--tablehead-foreground); -} - -table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fielddoc, .fieldtable th { - border-bottom: 1px solid var(--separator-color); - border-right: 1px solid var(--separator-color); -} - -table.fieldtable tr:last-child td:first-child { - border-bottom-left-radius: var(--border-radius-small); -} - -table.fieldtable tr:last-child td:last-child { - border-bottom-right-radius: var(--border-radius-small); -} - -.memberdecls td.glow, .fieldtable tr.glow { - background-color: var(--primary-light-color); - box-shadow: none; -} - -table.memberdecls { - display: block; - -webkit-tap-highlight-color: transparent; -} - -table.memberdecls tr[class^='memitem'] { - font-family: var(--font-family-monospace); - font-size: var(--code-font-size); -} - -table.memberdecls tr[class^='memitem'] .memTemplParams { - font-family: var(--font-family-monospace); - font-size: var(--code-font-size); - color: var(--primary-dark-color); - white-space: normal; -} - -table.memberdecls .memItemLeft, -table.memberdecls .memItemRight, -table.memberdecls .memTemplItemLeft, -table.memberdecls .memTemplItemRight, -table.memberdecls .memTemplParams { - transition: none; - padding-top: var(--spacing-small); - padding-bottom: var(--spacing-small); - border-top: 1px solid var(--separator-color); - border-bottom: 1px solid var(--separator-color); - background-color: var(--fragment-background); -} - -table.memberdecls .memTemplItemLeft, -table.memberdecls .memTemplItemRight { - padding-top: 2px; -} - -table.memberdecls .memTemplParams { - border-bottom: 0; - border-left: 1px solid var(--separator-color); - border-right: 1px solid var(--separator-color); - border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; - padding-bottom: var(--spacing-small); -} - -table.memberdecls .memTemplItemLeft { - border-radius: 0 0 0 var(--border-radius-small); - border-left: 1px solid var(--separator-color); - border-top: 0; -} - -table.memberdecls .memTemplItemRight { - border-radius: 0 0 var(--border-radius-small) 0; - border-right: 1px solid var(--separator-color); - padding-left: 0; - border-top: 0; -} - -table.memberdecls .memItemLeft { - border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); - border-left: 1px solid var(--separator-color); - padding-left: var(--spacing-medium); - padding-right: 0; -} - -table.memberdecls .memItemRight { - border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; - border-right: 1px solid var(--separator-color); - padding-right: var(--spacing-medium); - padding-left: 0; - -} - -table.memberdecls .mdescLeft, table.memberdecls .mdescRight { - background: none; - color: var(--page-foreground-color); - padding: var(--spacing-small) 0; -} - -table.memberdecls .memItemLeft, -table.memberdecls .memTemplItemLeft { - padding-right: var(--spacing-medium); -} - -table.memberdecls .memSeparator { - background: var(--page-background-color); - height: var(--spacing-large); - border: 0; - transition: none; -} - -table.memberdecls .groupheader { - margin-bottom: var(--spacing-large); -} - -table.memberdecls .inherit_header td { - padding: 0 0 var(--spacing-medium) 0; - text-indent: -12px; - color: var(--page-secondary-foreground-color); -} - -table.memberdecls img[src="closed.png"], -table.memberdecls img[src="open.png"], -div.dynheader img[src="open.png"], -div.dynheader img[src="closed.png"] { - width: 0; - height: 0; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - border-top: 5px solid var(--primary-color); - margin-top: 8px; - display: block; - float: left; - margin-left: -10px; - transition: transform 0.25s ease-out; -} - -table.memberdecls img { - margin-right: 10px; -} - -table.memberdecls img[src="closed.png"], -div.dynheader img[src="closed.png"] { - transform: rotate(-90deg); - -} - -.compoundTemplParams { - font-family: var(--font-family-monospace); - color: var(--primary-dark-color); - font-size: var(--code-font-size); -} - -@media screen and (max-width: 767px) { - - table.memberdecls .memItemLeft, - table.memberdecls .memItemRight, - table.memberdecls .mdescLeft, - table.memberdecls .mdescRight, - table.memberdecls .memTemplItemLeft, - table.memberdecls .memTemplItemRight, - table.memberdecls .memTemplParams { - display: block; - text-align: left; - padding-left: var(--spacing-large); - margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large)); - border-right: none; - border-left: none; - border-radius: 0; - white-space: normal; - } - - table.memberdecls .memItemLeft, - table.memberdecls .mdescLeft, - table.memberdecls .memTemplItemLeft { - border-bottom: 0; - padding-bottom: 0; - } - - table.memberdecls .memTemplItemLeft { - padding-top: 0; - } - - table.memberdecls .mdescLeft { - margin-bottom: calc(0px - var(--page-font-size)); - } - - table.memberdecls .memItemRight, - table.memberdecls .mdescRight, - table.memberdecls .memTemplItemRight { - border-top: 0; - padding-top: 0; - padding-right: var(--spacing-large); - overflow-x: auto; - } - - table.memberdecls tr[class^='memitem']:not(.inherit) { - display: block; - width: calc(100vw - 2 * var(--spacing-large)); - } - - table.memberdecls .mdescRight { - color: var(--page-foreground-color); - } - - table.memberdecls tr.inherit { - visibility: hidden; - } - - table.memberdecls tr[style="display: table-row;"] { - display: block !important; - visibility: visible; - width: calc(100vw - 2 * var(--spacing-large)); - animation: fade .5s; - } - - @keyframes fade { - 0% { - opacity: 0; - max-height: 0; - } - - 100% { - opacity: 1; - max-height: 200px; - } - } -} - - -/* - Horizontal Rule - */ - -hr { - margin-top: var(--spacing-large); - margin-bottom: var(--spacing-large); - height: 1px; - background-color: var(--separator-color); - border: 0; -} - -.contents hr { - box-shadow: 100px 0 0 var(--separator-color), - -100px 0 0 var(--separator-color), - 500px 0 0 var(--separator-color), - -500px 0 0 var(--separator-color), - 1500px 0 0 var(--separator-color), - -1500px 0 0 var(--separator-color), - 2000px 0 0 var(--separator-color), - -2000px 0 0 var(--separator-color); -} - -.contents img, .contents .center, .contents center, .contents div.image object { - max-width: 100%; - overflow: auto; -} - -@media screen and (max-width: 767px) { - .contents .dyncontent > .center, .contents > center { - margin-left: calc(0px - var(--spacing-large)); - margin-right: calc(0px - var(--spacing-large)); - max-width: calc(100% + 2 * var(--spacing-large)); - } -} - -/* - Directories - */ -div.directory { - border-top: 1px solid var(--separator-color); - border-bottom: 1px solid var(--separator-color); - width: auto; -} - -table.directory { - font-family: var(--font-family); - font-size: var(--page-font-size); - font-weight: normal; - width: 100%; -} - -table.directory td.entry, table.directory td.desc { - padding: calc(var(--spacing-small) / 2) var(--spacing-small); - line-height: var(--table-line-height); -} - -table.directory tr.even td:last-child { - border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; -} - -table.directory tr.even td:first-child { - border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); -} - -table.directory tr.even:last-child td:last-child { - border-radius: 0 var(--border-radius-small) 0 0; -} - -table.directory tr.even:last-child td:first-child { - border-radius: var(--border-radius-small) 0 0 0; -} - -table.directory td.desc { - min-width: 250px; -} - -table.directory tr.even { - background-color: var(--odd-color); -} - -table.directory tr.odd { - background-color: transparent; -} - -.icona { - width: auto; - height: auto; - margin: 0 var(--spacing-small); -} - -.icon { - background: var(--primary-color); - border-radius: var(--border-radius-small); - font-size: var(--page-font-size); - padding: calc(var(--page-font-size) / 5); - line-height: var(--page-font-size); - transform: scale(0.8); - height: auto; - width: var(--page-font-size); - user-select: none; -} - -.iconfopen, .icondoc, .iconfclosed { - background-position: center; - margin-bottom: 0; - height: var(--table-line-height); -} - -.icondoc { - filter: saturate(0.2); -} - -@media screen and (max-width: 767px) { - div.directory { - margin-left: calc(0px - var(--spacing-large)); - margin-right: calc(0px - var(--spacing-large)); - } -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed { - filter: hue-rotate(180deg) invert(); - } -} - -html.dark-mode .iconfopen, html.dark-mode .iconfclosed { - filter: hue-rotate(180deg) invert(); -} - -/* - Class list - */ - -.classindex dl.odd { - background: var(--odd-color); - border-radius: var(--border-radius-small); -} - -.classindex dl.even { - background-color: transparent; -} - -/* - Class Index Doxygen 1.8 -*/ - -table.classindex { - margin-left: 0; - margin-right: 0; - width: 100%; -} - -table.classindex table div.ah { - background-image: none; - background-color: initial; - border-color: var(--separator-color); - color: var(--page-foreground-color); - box-shadow: var(--box-shadow); - border-radius: var(--border-radius-large); - padding: var(--spacing-small); -} - -div.qindex { - background-color: var(--odd-color); - border-radius: var(--border-radius-small); - border: 1px solid var(--separator-color); - padding: var(--spacing-small) 0; -} - -/* - Footer and nav-path - */ - -#nav-path { - width: 100%; -} - -#nav-path ul { - background-image: none; - background: var(--page-background-color); - border: none; - border-top: 1px solid var(--separator-color); - border-bottom: 1px solid var(--separator-color); - border-bottom: 0; - box-shadow: 0 0.75px 0 var(--separator-color); - font-size: var(--navigation-font-size); -} - -img.footer { - width: 60px; -} - -.navpath li.footer { - color: var(--page-secondary-foreground-color); -} - -address.footer { - color: var(--page-secondary-foreground-color); - margin-bottom: var(--spacing-large); -} - -#nav-path li.navelem { - background-image: none; - display: flex; - align-items: center; -} - -.navpath li.navelem a { - text-shadow: none; - display: inline-block; - color: var(--primary-color) !important; -} - -.navpath li.navelem b { - color: var(--primary-dark-color); - font-weight: 500; -} - -li.navelem { - padding: 0; - margin-left: -8px; -} - -li.navelem:first-child { - margin-left: var(--spacing-large); -} - -li.navelem:first-child:before { - display: none; -} - -#nav-path li.navelem:after { - content: ''; - border: 5px solid var(--page-background-color); - border-bottom-color: transparent; - border-right-color: transparent; - border-top-color: transparent; - transform: translateY(-1px) scaleY(4.2); - z-index: 10; - margin-left: 6px; -} - -#nav-path li.navelem:before { - content: ''; - border: 5px solid var(--separator-color); - border-bottom-color: transparent; - border-right-color: transparent; - border-top-color: transparent; - transform: translateY(-1px) scaleY(3.2); - margin-right: var(--spacing-small); -} - -.navpath li.navelem a:hover { - color: var(--primary-color); -} - -/* - Scrollbars for Webkit -*/ - -#nav-tree::-webkit-scrollbar, -div.fragment::-webkit-scrollbar, -pre.fragment::-webkit-scrollbar, -div.memproto::-webkit-scrollbar, -.contents center::-webkit-scrollbar, -.contents .center::-webkit-scrollbar, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar, -div.contents .toc::-webkit-scrollbar { - background: transparent; - width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); - height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); -} - -#nav-tree::-webkit-scrollbar-thumb, -div.fragment::-webkit-scrollbar-thumb, -pre.fragment::-webkit-scrollbar-thumb, -div.memproto::-webkit-scrollbar-thumb, -.contents center::-webkit-scrollbar-thumb, -.contents .center::-webkit-scrollbar-thumb, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb, -div.contents .toc::-webkit-scrollbar-thumb { - background-color: transparent; - border: var(--webkit-scrollbar-padding) solid transparent; - border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); - background-clip: padding-box; -} - -#nav-tree:hover::-webkit-scrollbar-thumb, -div.fragment:hover::-webkit-scrollbar-thumb, -pre.fragment:hover::-webkit-scrollbar-thumb, -div.memproto:hover::-webkit-scrollbar-thumb, -.contents center:hover::-webkit-scrollbar-thumb, -.contents .center:hover::-webkit-scrollbar-thumb, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb, -div.contents .toc:hover::-webkit-scrollbar-thumb { - background-color: var(--webkit-scrollbar-color); -} - -#nav-tree::-webkit-scrollbar-track, -div.fragment::-webkit-scrollbar-track, -pre.fragment::-webkit-scrollbar-track, -div.memproto::-webkit-scrollbar-track, -.contents center::-webkit-scrollbar-track, -.contents .center::-webkit-scrollbar-track, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track, -div.contents .toc::-webkit-scrollbar-track { - background: transparent; -} - -#nav-tree::-webkit-scrollbar-corner { - background-color: var(--side-nav-background); -} - -#nav-tree, -div.fragment, -pre.fragment, -div.memproto, -.contents center, -.contents .center, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, -div.contents .toc { - overflow-x: auto; - overflow-x: overlay; -} - -#nav-tree { - overflow-x: auto; - overflow-y: auto; - overflow-y: overlay; -} - -/* - Scrollbars for Firefox -*/ - -#nav-tree, -div.fragment, -pre.fragment, -div.memproto, -.contents center, -.contents .center, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, -div.contents .toc { - scrollbar-width: thin; -} - -/* - Optional Dark mode toggle button -*/ - -doxygen-awesome-dark-mode-toggle { - display: inline-block; - margin: 0 0 0 var(--spacing-small); - padding: 0; - width: var(--searchbar-height); - height: var(--searchbar-height); - background: none; - border: none; - border-radius: var(--searchbar-height); - vertical-align: middle; - text-align: center; - line-height: var(--searchbar-height); - font-size: 22px; - display: flex; - align-items: center; - justify-content: center; - user-select: none; - cursor: pointer; -} - -doxygen-awesome-dark-mode-toggle > svg { - transition: transform .1s ease-in-out; -} - -doxygen-awesome-dark-mode-toggle:active > svg { - transform: scale(.5); -} - -doxygen-awesome-dark-mode-toggle:hover { - background-color: rgba(0,0,0,.03); -} - -html.dark-mode doxygen-awesome-dark-mode-toggle:hover { - background-color: rgba(0,0,0,.18); -} - -/* - Optional fragment copy button -*/ -.doxygen-awesome-fragment-wrapper { - position: relative; -} - -doxygen-awesome-fragment-copy-button { - opacity: 0; - background: var(--fragment-background); - width: 28px; - height: 28px; - position: absolute; - right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); - top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); - border: 1px solid var(--fragment-foreground); - cursor: pointer; - border-radius: var(--border-radius-small); - display: flex; - justify-content: center; - align-items: center; -} - -.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success { - opacity: .28; -} - -doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success { - opacity: 1 !important; -} - -doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg { - transform: scale(.91); -} - -doxygen-awesome-fragment-copy-button svg { - fill: var(--fragment-foreground); - width: 18px; - height: 18px; -} - -doxygen-awesome-fragment-copy-button.success svg { - fill: rgb(14, 168, 14); -} - -doxygen-awesome-fragment-copy-button.success { - border-color: rgb(14, 168, 14); -} - -@media screen and (max-width: 767px) { - .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button { - right: 0; - } -} - -/* - Optional paragraph link button -*/ - -a.anchorlink { - font-size: 90%; - margin-left: var(--spacing-small); - color: var(--page-foreground-color) !important; - text-decoration: none; - opacity: .15; - display: none; - transition: opacity .1s ease-in-out, color .1s ease-in-out; -} - -a.anchorlink svg { - fill: var(--page-foreground-color); -} - -h3 a.anchorlink svg, h4 a.anchorlink svg { - margin-bottom: -3px; - margin-top: -4px; -} - -a.anchorlink:hover { - opacity: .45; -} - -h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { - display: inline-block; -} +/** + +Doxygen Awesome +https://github.com/jothepro/doxygen-awesome-css + +MIT License + +Copyright (c) 2021 - 2022 jothepro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +html { + /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ + --primary-color: #1779c4; + --primary-dark-color: #335c80; + --primary-light-color: #70b1e9; + + /* page base colors */ + --page-background-color: #ffffff; + --page-foreground-color: #2f4153; + --page-secondary-foreground-color: #6f7e8e; + + /* color for all separators on the website: hr, borders, ... */ + --separator-color: #dedede; + + /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */ + --border-radius-large: 8px; + --border-radius-small: 4px; + --border-radius-medium: 6px; + + /* default spacings. Most components reference these values for spacing, to provide uniform spacing on the page. */ + --spacing-small: 5px; + --spacing-medium: 10px; + --spacing-large: 16px; + + /* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */ + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); + + --odd-color: rgba(0,0,0,.028); + + /* font-families. will affect all text on the website + * font-family: the normal font for text, headlines, menus + * font-family-monospace: used for preformatted text in memtitle, code, fragments + */ + --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; + --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; + + /* font sizes */ + --page-font-size: 15.6px; + --navigation-font-size: 14.4px; + --toc-font-size: 13.4px; + --code-font-size: 14px; /* affects code, fragment */ + --title-font-size: 22px; + + /* content text properties. These only affect the page content, not the navigation or any other ui elements */ + --content-line-height: 27px; + /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/ + --content-maxwidth: 1050px; + --table-line-height: 24px; + --toc-sticky-top: var(--spacing-medium); + --toc-width: 200px; + --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 85px); + + /* colors for various content boxes: @warning, @note, @deprecated @bug */ + --warning-color: #f8d1cc; + --warning-color-dark: #b61825; + --warning-color-darker: #75070f; + --note-color: #faf3d8; + --note-color-dark: #f3a600; + --note-color-darker: #5f4204; + --todo-color: #e4f3ff; + --todo-color-dark: #1879C4; + --todo-color-darker: #274a5c; + --deprecated-color: #ecf0f3; + --deprecated-color-dark: #5b6269; + --deprecated-color-darker: #43454a; + --bug-color: #e4dafd; + --bug-color-dark: #5b2bdd; + --bug-color-darker: #2a0d72; + --invariant-color: #d8f1e3; + --invariant-color-dark: #44b86f; + --invariant-color-darker: #265532; + + /* blockquote colors */ + --blockquote-background: #f8f9fa; + --blockquote-foreground: #636568; + + /* table colors */ + --tablehead-background: #f1f1f1; + --tablehead-foreground: var(--page-foreground-color); + + /* menu-display: block | none + * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible. + * `GENERATE_TREEVIEW` MUST be enabled! + */ + --menu-display: block; + + --menu-focus-foreground: var(--page-background-color); + --menu-focus-background: var(--primary-color); + --menu-selected-background: rgba(0,0,0,.05); + + + --header-background: var(--page-background-color); + --header-foreground: var(--page-foreground-color); + + /* searchbar colors */ + --searchbar-background: var(--side-nav-background); + --searchbar-foreground: var(--page-foreground-color); + + /* searchbar size + * (`searchbar-width` is only applied on screens >= 768px. + * on smaller screens the searchbar will always fill the entire screen width) */ + --searchbar-height: 33px; + --searchbar-width: 210px; + --searchbar-border-radius: var(--searchbar-height); + + /* code block colors */ + --code-background: #f5f5f5; + --code-foreground: var(--page-foreground-color); + + /* fragment colors */ + --fragment-background: #F8F9FA; + --fragment-foreground: #37474F; + --fragment-keyword: #bb6bb2; + --fragment-keywordtype: #8258b3; + --fragment-keywordflow: #d67c3b; + --fragment-token: #438a59; + --fragment-comment: #969696; + --fragment-link: #5383d6; + --fragment-preprocessor: #46aaa5; + --fragment-linenumber-color: #797979; + --fragment-linenumber-background: #f4f4f5; + --fragment-linenumber-border: #e3e5e7; + --fragment-lineheight: 20px; + + /* sidebar navigation (treeview) colors */ + --side-nav-background: #fbfbfb; + --side-nav-foreground: var(--page-foreground-color); + --side-nav-arrow-opacity: 0; + --side-nav-arrow-hover-opacity: 0.9; + + --toc-background: var(--side-nav-background); + --toc-foreground: var(--side-nav-foreground); + + /* height of an item in any tree / collapsable table */ + --tree-item-height: 30px; + + --memname-font-size: var(--code-font-size); + --memtitle-font-size: 18px; + + --webkit-scrollbar-size: 7px; + --webkit-scrollbar-padding: 4px; + --webkit-scrollbar-color: var(--separator-color); +} + +@media screen and (max-width: 767px) { + html { + --page-font-size: 16px; + --navigation-font-size: 16px; + --toc-font-size: 15px; + --code-font-size: 15px; /* affects code, fragment */ + --title-font-size: 22px; + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #2e1917; + --warning-color-dark: #ad2617; + --warning-color-darker: #f5b1aa; + --note-color: #3b2e04; + --note-color-dark: #f1b602; + --note-color-darker: #ceb670; + --todo-color: #163750; + --todo-color-dark: #1982D2; + --todo-color-darker: #dcf0fa; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2a2536; + --bug-color-dark: #7661b3; + --bug-color-darker: #ae9ed6; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; + } +} + +/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */ +html.dark-mode { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #2e1917; + --warning-color-dark: #ad2617; + --warning-color-darker: #f5b1aa; + --note-color: #3b2e04; + --note-color-dark: #f1b602; + --note-color-darker: #ceb670; + --todo-color: #163750; + --todo-color-dark: #1982D2; + --todo-color-darker: #dcf0fa; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2a2536; + --bug-color-dark: #7661b3; + --bug-color-darker: #ae9ed6; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; +} + +body { + color: var(--page-foreground-color); + background-color: var(--page-background-color); + font-size: var(--page-font-size); +} + +body, table, div, p, dl, #nav-tree .label, .title, +.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, +.SelectItem, #MSearchField, .navpath li.navelem a, +.navpath li.navelem a:hover, p.reference, p.definition { + font-family: var(--font-family); +} + +h1, h2, h3, h4, h5 { + margin-top: .9em; + font-weight: 600; + line-height: initial; +} + +p, div, table, dl, p.reference, p.definition { + font-size: var(--page-font-size); +} + +p.reference, p.definition { + color: var(--page-secondary-foreground-color); +} + +a:link, a:visited, a:hover, a:focus, a:active { + color: var(--primary-color) !important; + font-weight: 500; +} + +a.anchor { + scroll-margin-top: var(--spacing-large); + display: block; +} + +/* + Title and top navigation + */ + +#top { + background: var(--header-background); + border-bottom: 1px solid var(--separator-color); +} + +@media screen and (min-width: 768px) { + #top { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + } +} + +#main-nav { + flex-grow: 5; + padding: var(--spacing-small) var(--spacing-medium); +} + +#titlearea { + width: auto; + padding: var(--spacing-medium) var(--spacing-large); + background: none; + color: var(--header-foreground); + border-bottom: none; +} + +@media screen and (max-width: 767px) { + #titlearea { + padding-bottom: var(--spacing-small); + } +} + +#titlearea table tbody tr { + height: auto !important; +} + +#projectname { + font-size: var(--title-font-size); + font-weight: 600; +} + +#projectnumber { + font-family: inherit; + font-size: 60%; +} + +#projectbrief { + font-family: inherit; + font-size: 80%; +} + +#projectlogo { + vertical-align: middle; +} + +#projectlogo img { + max-height: calc(var(--title-font-size) * 2); + margin-right: var(--spacing-small); +} + +.sm-dox, .tabs, .tabs2, .tabs3 { + background: none; + padding: 0; +} + +.tabs, .tabs2, .tabs3 { + border-bottom: 1px solid var(--separator-color); + margin-bottom: -1px; +} + +.main-menu-btn-icon, .main-menu-btn-icon:before, .main-menu-btn-icon:after { + background: var(--page-secondary-foreground-color); +} + +@media screen and (max-width: 767px) { + .sm-dox a span.sub-arrow { + background: var(--code-background); + } + + #main-menu a.has-submenu span.sub-arrow { + color: var(--page-secondary-foreground-color); + border-radius: var(--border-radius-medium); + } + + #main-menu a.has-submenu:hover span.sub-arrow { + color: var(--page-foreground-color); + } +} + +@media screen and (min-width: 768px) { + .sm-dox li, .tablist li { + display: var(--menu-display); + } + + .sm-dox a span.sub-arrow { + border-color: var(--header-foreground) transparent transparent transparent; + } + + .sm-dox a:hover span.sub-arrow { + border-color: var(--menu-focus-foreground) transparent transparent transparent; + } + + .sm-dox ul a span.sub-arrow { + border-color: transparent transparent transparent var(--page-foreground-color); + } + + .sm-dox ul a:hover span.sub-arrow { + border-color: transparent transparent transparent var(--menu-focus-foreground); + } +} + +.sm-dox ul { + background: var(--page-background-color); + box-shadow: var(--box-shadow); + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium) !important; + padding: var(--spacing-small); + animation: ease-out 150ms slideInMenu; +} + +@keyframes slideInMenu { + from { + opacity: 0; + transform: translate(0px, -2px); + } + + to { + opacity: 1; + transform: translate(0px, 0px); + } +} + +.sm-dox ul a { + color: var(--page-foreground-color) !important; + background: var(--page-background-color); + font-size: var(--navigation-font-size); +} + +.sm-dox>li>ul:after { + border-bottom-color: var(--page-background-color) !important; +} + +.sm-dox>li>ul:before { + border-bottom-color: var(--separator-color) !important; +} + +.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus { + font-size: var(--navigation-font-size) !important; + color: var(--menu-focus-foreground) !important; + text-shadow: none; + background-color: var(--menu-focus-background); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a { + text-shadow: none; + background: transparent; + background-image: none !important; + color: var(--header-foreground) !important; + font-weight: normal; + font-size: var(--navigation-font-size); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a:focus { + outline: auto; +} + +.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover { + text-shadow: none; + font-weight: normal; + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; + border-radius: var(--border-radius-small) !important; + font-size: var(--navigation-font-size); +} + +.tablist li.current { + border-radius: var(--border-radius-small); + background: var(--menu-selected-background); +} + +.tablist li { + margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small); +} + +.tablist a { + padding: 0 var(--spacing-large); +} + + +/* + Search box + */ + +#MSearchBox { + height: var(--searchbar-height); + background: var(--searchbar-background); + border-radius: var(--searchbar-border-radius); + border: 1px solid var(--separator-color); + overflow: hidden; + width: var(--searchbar-width); + position: relative; + box-shadow: none; + display: block; + margin-top: 0; +} + +/* until Doxygen 1.9.4 */ +.left img#MSearchSelect { + left: 0; + user-select: none; + padding-left: 8px; +} + +/* Doxygen 1.9.5 */ +.left span#MSearchSelect { + left: 0; + user-select: none; + margin-left: 8px; + padding: 0; +} + +.left #MSearchSelect[src$=".png"] { + padding-left: 0 +} + +.SelectionMark { + user-select: none; +} + +.tabs .left #MSearchSelect { + padding-left: 0; +} + +.tabs #MSearchBox { + position: absolute; + right: var(--spacing-medium); +} + +@media screen and (max-width: 767px) { + .tabs #MSearchBox { + position: relative; + right: 0; + margin-left: var(--spacing-medium); + margin-top: 0; + } +} + +#MSearchSelectWindow, #MSearchResultsWindow { + z-index: 9999; +} + +#MSearchBox.MSearchBoxActive { + border-color: var(--primary-color); + box-shadow: inset 0 0 0 1px var(--primary-color); +} + +#main-menu > li:last-child { + margin-right: 0; +} + +@media screen and (max-width: 767px) { + #main-menu > li:last-child { + height: 50px; + } +} + +#MSearchField { + font-size: var(--navigation-font-size); + height: calc(var(--searchbar-height) - 2px); + background: transparent; + width: calc(var(--searchbar-width) - 64px); +} + +.MSearchBoxActive #MSearchField { + color: var(--searchbar-foreground); +} + +#MSearchSelect { + top: calc(calc(var(--searchbar-height) / 2) - 11px); +} + +#MSearchBox span.left, #MSearchBox span.right { + background: none; + background-image: none; +} + +#MSearchBox span.right { + padding-top: calc(calc(var(--searchbar-height) / 2) - 12px); + position: absolute; + right: var(--spacing-small); +} + +.tabs #MSearchBox span.right { + top: calc(calc(var(--searchbar-height) / 2) - 12px); +} + +@keyframes slideInSearchResults { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } +} + +#MSearchResultsWindow { + left: auto !important; + right: var(--spacing-medium); + border-radius: var(--border-radius-large); + border: 1px solid var(--separator-color); + transform: translate(0, 20px); + box-shadow: var(--box-shadow); + animation: ease-out 280ms slideInSearchResults; + background: var(--page-background-color); +} + +iframe#MSearchResults { + margin: 4px; +} + +iframe { + color-scheme: normal; +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) iframe#MSearchResults { + filter: invert() hue-rotate(180deg); + } +} + +html.dark-mode iframe#MSearchResults { + filter: invert() hue-rotate(180deg); +} + +#MSearchResults .SRPage { + background-color: transparent; +} + +#MSearchResults .SRPage .SREntry { + font-size: 10pt; + padding: var(--spacing-small) var(--spacing-medium); +} + +#MSearchSelectWindow { + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + box-shadow: var(--box-shadow); + background: var(--page-background-color); + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); +} + +#MSearchSelectWindow a.SelectItem { + font-size: var(--navigation-font-size); + line-height: var(--content-line-height); + margin: 0 var(--spacing-small); + border-radius: var(--border-radius-small); + color: var(--page-foreground-color) !important; + font-weight: normal; +} + +#MSearchSelectWindow a.SelectItem:hover { + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; +} + +@media screen and (max-width: 767px) { + #MSearchBox { + margin-top: var(--spacing-medium); + margin-bottom: var(--spacing-medium); + width: calc(100vw - 30px); + } + + #main-menu > li:last-child { + float: none !important; + } + + #MSearchField { + width: calc(100vw - 110px); + } + + @keyframes slideInSearchResultsMobile { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } + } + + #MSearchResultsWindow { + left: var(--spacing-medium) !important; + right: var(--spacing-medium); + overflow: auto; + transform: translate(0, 20px); + animation: ease-out 280ms slideInSearchResultsMobile; + width: auto !important; + } + + /* + * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2 + */ + label.main-menu-btn ~ #searchBoxPos1 { + top: 3px !important; + right: 6px !important; + left: 45px; + display: flex; + } + + label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox { + margin-top: 0; + margin-bottom: 0; + flex-grow: 2; + float: left; + } +} + +/* + Tree view + */ + +#side-nav { + padding: 0 !important; + background: var(--side-nav-background); +} + +@media screen and (max-width: 767px) { + #side-nav { + display: none; + } + + #doc-content { + margin-left: 0 !important; + } +} + +#nav-tree { + background: transparent; +} + +#nav-tree .label { + font-size: var(--navigation-font-size); +} + +#nav-tree .item { + height: var(--tree-item-height); + line-height: var(--tree-item-height); +} + +#nav-sync { + bottom: 12px; + right: 12px; + top: auto !important; + user-select: none; +} + +#nav-tree .selected { + text-shadow: none; + background-image: none; + background-color: transparent; + position: relative; +} + +#nav-tree .selected::after { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + width: 4px; + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + background: var(--primary-color); +} + + +#nav-tree a { + color: var(--side-nav-foreground) !important; + font-weight: normal; +} + +#nav-tree a:focus { + outline-style: auto; +} + +#nav-tree .arrow { + opacity: var(--side-nav-arrow-opacity); +} + +.arrow { + color: inherit; + cursor: pointer; + font-size: 45%; + vertical-align: middle; + margin-right: 2px; + font-family: serif; + height: auto; + text-align: right; +} + +#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow { + opacity: var(--side-nav-arrow-hover-opacity); +} + +#nav-tree .selected a { + color: var(--primary-color) !important; + font-weight: bolder; + font-weight: 600; +} + +.ui-resizable-e { + background: var(--separator-color); + width: 1px; +} + +/* + Contents + */ + +div.header { + border-bottom: 1px solid var(--separator-color); + background-color: var(--page-background-color); + background-image: none; +} + +@media screen and (min-width: 1000px) { + #doc-content > div > div.contents, + .PageDoc > div.contents { + display: flex; + flex-direction: row-reverse; + flex-wrap: nowrap; + align-items: flex-start; + } + + div.contents .textblock { + min-width: 200px; + flex-grow: 1; + } +} + +div.contents, div.header .title, div.header .summary { + max-width: var(--content-maxwidth); +} + +div.contents, div.header .title { + line-height: initial; + margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto; +} + +div.header .summary { + margin: var(--spacing-medium) auto 0 auto; +} + +div.headertitle { + padding: 0; +} + +div.header .title { + font-weight: 600; + font-size: 225%; + padding: var(--spacing-medium) var(--spacing-large); + word-break: break-word; +} + +div.header .summary { + width: auto; + display: block; + float: none; + padding: 0 var(--spacing-large); +} + +td.memSeparator { + border-color: var(--separator-color); +} + +span.mlabel { + background: var(--primary-color); + border: none; + padding: 4px 9px; + border-radius: 12px; + margin-right: var(--spacing-medium); +} + +span.mlabel:last-of-type { + margin-right: 2px; +} + +div.contents { + padding: 0 var(--spacing-large); +} + +div.contents p, div.contents li { + line-height: var(--content-line-height); +} + +div.contents div.dyncontent { + margin: var(--spacing-medium) 0; +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) div.contents div.dyncontent img, + html:not(.light-mode) div.contents center img, + html:not(.light-mode) div.contents > table img, + html:not(.light-mode) div.contents div.dyncontent iframe, + html:not(.light-mode) div.contents center iframe, + html:not(.light-mode) div.contents table iframe { + filter: hue-rotate(180deg) invert(); + } +} + +html.dark-mode div.contents div.dyncontent img, +html.dark-mode div.contents center img, +html.dark-mode div.contents > table img, +html.dark-mode div.contents div.dyncontent iframe, +html.dark-mode div.contents center iframe, +html.dark-mode div.contents table iframe { + filter: hue-rotate(180deg) invert(); +} + +h2.groupheader { + border-bottom: 0px; + color: var(--page-foreground-color); + box-shadow: + 100px 0 var(--page-background-color), + -100px 0 var(--page-background-color), + 100px 0.75px var(--separator-color), + -100px 0.75px var(--separator-color), + 500px 0 var(--page-background-color), + -500px 0 var(--page-background-color), + 500px 0.75px var(--separator-color), + -500px 0.75px var(--separator-color), + 900px 0 var(--page-background-color), + -900px 0 var(--page-background-color), + 900px 0.75px var(--separator-color), + -900px 0.75px var(--separator-color), + 1400px 0 var(--page-background-color), + -1400px 0 var(--page-background-color), + 1400px 0.75px var(--separator-color), + -1400px 0.75px var(--separator-color), + 1900px 0 var(--page-background-color), + -1900px 0 var(--page-background-color), + 1900px 0.75px var(--separator-color), + -1900px 0.75px var(--separator-color); +} + +blockquote { + margin: 0 var(--spacing-medium) 0 var(--spacing-medium); + padding: var(--spacing-small) var(--spacing-large); + background: var(--blockquote-background); + color: var(--blockquote-foreground); + border-left: 0; + overflow: visible; + border-radius: var(--border-radius-medium); + overflow: visible; + position: relative; +} + +blockquote::before, blockquote::after { + font-weight: bold; + font-family: serif; + font-size: 360%; + opacity: .15; + position: absolute; +} + +blockquote::before { + content: "“"; + left: -10px; + top: 4px; +} + +blockquote::after { + content: "”"; + right: -8px; + bottom: -25px; +} + +blockquote p { + margin: var(--spacing-small) 0 var(--spacing-medium) 0; +} +.paramname { + font-weight: 600; + color: var(--primary-dark-color); +} + +.paramname > code { + border: 0; +} + +table.params .paramname { + font-weight: 600; + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + padding-right: var(--spacing-small); + line-height: var(--table-line-height); +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px var(--primary-light-color); +} + +.alphachar a { + color: var(--page-foreground-color); +} + +/* + Table of Contents + */ + +div.contents .toc { + max-height: var(--toc-max-height); + min-width: var(--toc-width); + border: 0; + border-left: 1px solid var(--separator-color); + border-radius: 0; + background-color: transparent; + box-shadow: none; + position: sticky; + top: var(--toc-sticky-top); + padding: 0 var(--spacing-large); + margin: var(--spacing-small) 0 var(--spacing-large) var(--spacing-large); +} + +div.toc h3 { + color: var(--toc-foreground); + font-size: var(--navigation-font-size); + margin: var(--spacing-large) 0 var(--spacing-medium) 0; +} + +div.toc li { + padding: 0; + background: none; + line-height: var(--toc-font-size); + margin: var(--toc-font-size) 0 0 0; +} + +div.toc li::before { + display: none; +} + +div.toc ul { + margin-top: 0 +} + +div.toc li a { + font-size: var(--toc-font-size); + color: var(--page-foreground-color) !important; + text-decoration: none; +} + +div.toc li a:hover, div.toc li a.active { + color: var(--primary-color) !important; +} + +div.toc li a.aboveActive { + color: var(--page-secondary-foreground-color) !important; +} + + +@media screen and (max-width: 999px) { + div.contents .toc { + max-height: 45vh; + float: none; + width: auto; + margin: 0 0 var(--spacing-medium) 0; + position: relative; + top: 0; + position: relative; + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + background-color: var(--toc-background); + box-shadow: var(--box-shadow); + } + + div.contents .toc.interactive { + max-height: calc(var(--navigation-font-size) + 2 * var(--spacing-large)); + overflow: hidden; + } + + div.contents .toc > h3 { + -webkit-tap-highlight-color: transparent; + cursor: pointer; + position: sticky; + top: 0; + background-color: var(--toc-background); + margin: 0; + padding: var(--spacing-large) 0; + display: block; + } + + div.contents .toc.interactive > h3::before { + content: ""; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + display: inline-block; + margin-right: var(--spacing-small); + margin-bottom: calc(var(--navigation-font-size) / 4); + transform: rotate(-90deg); + transition: transform 0.25s ease-out; + } + + div.contents .toc.interactive.open > h3::before { + transform: rotate(0deg); + } + + div.contents .toc.interactive.open { + max-height: 45vh; + overflow: auto; + transition: max-height 0.2s ease-in-out; + } + + div.contents .toc a, div.contents .toc a.active { + color: var(--primary-color) !important; + } + + div.contents .toc a:hover { + text-decoration: underline; + } +} + +/* + Code & Fragments + */ + +code, div.fragment, pre.fragment { + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + overflow: hidden; +} + +code { + display: inline; + background: var(--code-background); + color: var(--code-foreground); + padding: 2px 6px; +} + +div.fragment, pre.fragment { + margin: var(--spacing-medium) 0; + padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large); + background: var(--fragment-background); + color: var(--fragment-foreground); + overflow-x: auto; +} + +@media screen and (max-width: 767px) { + div.fragment, pre.fragment { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: 0; + } + + .contents > div.fragment, + .textblock > div.fragment, + .textblock > pre.fragment, + .contents > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + border-radius: 0; + border-left: 0; + } + + .textblock li > .fragment, + .textblock li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + } + + .memdoc li > .fragment, + .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + } + + .textblock ul, .memdoc ul { + overflow: initial; + } + + .memdoc > div.fragment, + .memdoc > pre.fragment, + dl dd > div.fragment, + dl dd pre.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment, + dl dd > .doxygen-awesome-fragment-wrapper > div.fragment, + dl dd .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + border-radius: 0; + border-left: 0; + } +} + +code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size) !important; +} + +div.line:after { + margin-right: var(--spacing-medium); +} + +div.fragment .line, pre.fragment { + white-space: pre; + word-wrap: initial; + line-height: var(--fragment-lineheight); +} + +div.fragment span.keyword { + color: var(--fragment-keyword); +} + +div.fragment span.keywordtype { + color: var(--fragment-keywordtype); +} + +div.fragment span.keywordflow { + color: var(--fragment-keywordflow); +} + +div.fragment span.stringliteral { + color: var(--fragment-token) +} + +div.fragment span.comment { + color: var(--fragment-comment); +} + +div.fragment a.code { + color: var(--fragment-link) !important; +} + +div.fragment span.preprocessor { + color: var(--fragment-preprocessor); +} + +div.fragment span.lineno { + display: inline-block; + width: 27px; + border-right: none; + background: var(--fragment-linenumber-background); + color: var(--fragment-linenumber-color); +} + +div.fragment span.lineno a { + background: none; + color: var(--fragment-link) !important; +} + +div.fragment .line:first-child .lineno { + box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border); +} + +div.line { + border-radius: var(--border-radius-small); +} + +div.line.glow { + background-color: var(--primary-light-color); + box-shadow: none; +} + +/* + dl warning, attention, note, deprecated, bug, ... + */ + +dl.bug dt a, dl.deprecated dt a, dl.todo dt a { + font-weight: bold !important; +} + +dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.todo, dl.remark { + padding: var(--spacing-medium); + margin: var(--spacing-medium) 0; + color: var(--page-background-color); + overflow: hidden; + margin-left: 0; + border-radius: var(--border-radius-small); +} + +dl.section dd { + margin-bottom: 2px; +} + +dl.warning, dl.attention { + background: var(--warning-color); + border-left: 8px solid var(--warning-color-dark); + color: var(--warning-color-darker); +} + +dl.warning dt, dl.attention dt { + color: var(--warning-color-dark); +} + +dl.note, dl.remark { + background: var(--note-color); + border-left: 8px solid var(--note-color-dark); + color: var(--note-color-darker); +} + +dl.note dt, dl.remark dt { + color: var(--note-color-dark); +} + +dl.todo { + background: var(--todo-color); + border-left: 8px solid var(--todo-color-dark); + color: var(--todo-color-darker); +} + +dl.todo dt { + color: var(--todo-color-dark); +} + +dl.bug dt a { + color: var(--todo-color-dark) !important; +} + +dl.bug { + background: var(--bug-color); + border-left: 8px solid var(--bug-color-dark); + color: var(--bug-color-darker); +} + +dl.bug dt a { + color: var(--bug-color-dark) !important; +} + +dl.deprecated { + background: var(--deprecated-color); + border-left: 8px solid var(--deprecated-color-dark); + color: var(--deprecated-color-darker); +} + +dl.deprecated dt a { + color: var(--deprecated-color-dark) !important; +} + +dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { + margin-inline-start: 0px; +} + +dl.invariant, dl.pre { + background: var(--invariant-color); + border-left: 8px solid var(--invariant-color-dark); + color: var(--invariant-color-darker); +} + +dl.invariant dt, dl.pre dt { + color: var(--invariant-color-dark); +} + +/* + memitem + */ + +div.memdoc, div.memproto, h2.memtitle { + box-shadow: none; + background-image: none; + border: none; +} + +div.memdoc { + padding: 0 var(--spacing-medium); + background: var(--page-background-color); +} + +h2.memtitle, div.memitem { + border: 1px solid var(--separator-color); + box-shadow: var(--box-shadow); +} + +h2.memtitle { + box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow); +} + +div.memitem { + transition: none; +} + +div.memproto, h2.memtitle { + background: var(--fragment-background); +} + +h2.memtitle { + font-weight: 500; + font-size: var(--memtitle-font-size); + font-family: var(--font-family-monospace); + border-bottom: none; + border-top-left-radius: var(--border-radius-medium); + border-top-right-radius: var(--border-radius-medium); + word-break: break-all; + position: relative; +} + +h2.memtitle:after { + content: ""; + display: block; + background: var(--fragment-background); + height: var(--spacing-medium); + bottom: calc(0px - var(--spacing-medium)); + left: 0; + right: -14px; + position: absolute; + border-top-right-radius: var(--border-radius-medium); +} + +h2.memtitle > span.permalink { + font-size: inherit; +} + +h2.memtitle > span.permalink > a { + text-decoration: none; + padding-left: 3px; + margin-right: -4px; + user-select: none; + display: inline-block; + margin-top: -6px; +} + +h2.memtitle > span.permalink > a:hover { + color: var(--primary-dark-color) !important; +} + +a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { + border-color: var(--primary-light-color); +} + +div.memitem { + border-top-right-radius: var(--border-radius-medium); + border-bottom-right-radius: var(--border-radius-medium); + border-bottom-left-radius: var(--border-radius-medium); + overflow: hidden; + display: block !important; +} + +div.memdoc { + border-radius: 0; +} + +div.memproto { + border-radius: 0 var(--border-radius-small) 0 0; + overflow: auto; + border-bottom: 1px solid var(--separator-color); + padding: var(--spacing-medium); + margin-bottom: -1px; +} + +div.memtitle { + border-top-right-radius: var(--border-radius-medium); + border-top-left-radius: var(--border-radius-medium); +} + +div.memproto table.memname { + font-family: var(--font-family-monospace); + color: var(--page-foreground-color); + font-size: var(--memname-font-size); + text-shadow: none; +} + +div.memproto div.memtemplate { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--memname-font-size); + margin-left: 2px; + text-shadow: none; +} + +table.mlabels, table.mlabels > tbody { + display: block; +} + +td.mlabels-left { + width: auto; +} + +td.mlabels-right { + margin-top: 3px; + position: sticky; + left: 0; +} + +table.mlabels > tbody > tr:first-child { + display: flex; + justify-content: space-between; + flex-wrap: wrap; +} + +.memname, .memitem span.mlabels { + margin: 0 +} + +/* + reflist + */ + +dl.reflist { + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-medium); + border: 1px solid var(--separator-color); + overflow: hidden; + padding: 0; +} + + +dl.reflist dt, dl.reflist dd { + box-shadow: none; + text-shadow: none; + background-image: none; + border: none; + padding: 12px; +} + + +dl.reflist dt { + font-weight: 500; + border-radius: 0; + background: var(--code-background); + border-bottom: 1px solid var(--separator-color); + color: var(--page-foreground-color) +} + + +dl.reflist dd { + background: none; +} + +/* + Table + */ + +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname), +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: inline-block; + max-width: 100%; +} + +.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); +} + +table.fieldtable, +table.markdownTable tbody, +table.doxtable tbody { + border: none; + margin: var(--spacing-medium) 0; + box-shadow: 0 0 0 1px var(--separator-color); + border-radius: var(--border-radius-small); +} + +table.doxtable caption { + display: block; +} + +table.fieldtable { + border-collapse: collapse; + width: 100%; +} + +th.markdownTableHeadLeft, +th.markdownTableHeadRight, +th.markdownTableHeadCenter, +th.markdownTableHeadNone, +table.doxtable th { + background: var(--tablehead-background); + color: var(--tablehead-foreground); + font-weight: 600; + font-size: var(--page-font-size); +} + +th.markdownTableHeadLeft:first-child, +th.markdownTableHeadRight:first-child, +th.markdownTableHeadCenter:first-child, +th.markdownTableHeadNone:first-child, +table.doxtable tr th:first-child { + border-top-left-radius: var(--border-radius-small); +} + +th.markdownTableHeadLeft:last-child, +th.markdownTableHeadRight:last-child, +th.markdownTableHeadCenter:last-child, +th.markdownTableHeadNone:last-child, +table.doxtable tr th:last-child { + border-top-right-radius: var(--border-radius-small); +} + +table.markdownTable td, +table.markdownTable th, +table.fieldtable td, +table.fieldtable th, +table.doxtable td, +table.doxtable th { + border: 1px solid var(--separator-color); + padding: var(--spacing-small) var(--spacing-medium); +} + +table.markdownTable td:last-child, +table.markdownTable th:last-child, +table.fieldtable td:last-child, +table.fieldtable th:last-child, +table.doxtable td:last-child, +table.doxtable th:last-child { + border-right: none; +} + +table.markdownTable td:first-child, +table.markdownTable th:first-child, +table.fieldtable td:first-child, +table.fieldtable th:first-child, +table.doxtable td:first-child, +table.doxtable th:first-child { + border-left: none; +} + +table.markdownTable tr:first-child td, +table.markdownTable tr:first-child th, +table.fieldtable tr:first-child td, +table.fieldtable tr:first-child th, +table.doxtable tr:first-child td, +table.doxtable tr:first-child th { + border-top: none; +} + +table.markdownTable tr:last-child td, +table.markdownTable tr:last-child th, +table.fieldtable tr:last-child td, +table.fieldtable tr:last-child th, +table.doxtable tr:last-child td, +table.doxtable tr:last-child th { + border-bottom: none; +} + +table.markdownTable tr, table.doxtable tr { + border-bottom: 1px solid var(--separator-color); +} + +table.markdownTable tr:last-child, table.doxtable tr:last-child { + border-bottom: none; +} + +table.fieldtable th { + font-size: var(--page-font-size); + font-weight: 600; + background-image: none; + background-color: var(--tablehead-background); + color: var(--tablehead-foreground); +} + +table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fielddoc, .fieldtable th { + border-bottom: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); +} + +table.fieldtable tr:last-child td:first-child { + border-bottom-left-radius: var(--border-radius-small); +} + +table.fieldtable tr:last-child td:last-child { + border-bottom-right-radius: var(--border-radius-small); +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: var(--primary-light-color); + box-shadow: none; +} + +table.memberdecls { + display: block; + -webkit-tap-highlight-color: transparent; +} + +table.memberdecls tr[class^='memitem'] { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); +} + +table.memberdecls tr[class^='memitem'] .memTemplParams { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + color: var(--primary-dark-color); + white-space: normal; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memItemRight, +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight, +table.memberdecls .memTemplParams { + transition: none; + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + background-color: var(--fragment-background); +} + +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight { + padding-top: 2px; +} + +table.memberdecls .memTemplParams { + border-bottom: 0; + border-left: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + padding-bottom: var(--spacing-small); +} + +table.memberdecls .memTemplItemLeft { + border-radius: 0 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + border-top: 0; +} + +table.memberdecls .memTemplItemRight { + border-radius: 0 0 var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-left: 0; + border-top: 0; +} + +table.memberdecls .memItemLeft { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + padding-left: var(--spacing-medium); + padding-right: 0; +} + +table.memberdecls .memItemRight { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-right: var(--spacing-medium); + padding-left: 0; + +} + +table.memberdecls .mdescLeft, table.memberdecls .mdescRight { + background: none; + color: var(--page-foreground-color); + padding: var(--spacing-small) 0; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memTemplItemLeft { + padding-right: var(--spacing-medium); +} + +table.memberdecls .memSeparator { + background: var(--page-background-color); + height: var(--spacing-large); + border: 0; + transition: none; +} + +table.memberdecls .groupheader { + margin-bottom: var(--spacing-large); +} + +table.memberdecls .inherit_header td { + padding: 0 0 var(--spacing-medium) 0; + text-indent: -12px; + color: var(--page-secondary-foreground-color); +} + +table.memberdecls img[src="closed.png"], +table.memberdecls img[src="open.png"], +div.dynheader img[src="open.png"], +div.dynheader img[src="closed.png"] { + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + margin-top: 8px; + display: block; + float: left; + margin-left: -10px; + transition: transform 0.25s ease-out; +} + +table.memberdecls img { + margin-right: 10px; +} + +table.memberdecls img[src="closed.png"], +div.dynheader img[src="closed.png"] { + transform: rotate(-90deg); + +} + +.compoundTemplParams { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--code-font-size); +} + +@media screen and (max-width: 767px) { + + table.memberdecls .memItemLeft, + table.memberdecls .memItemRight, + table.memberdecls .mdescLeft, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemLeft, + table.memberdecls .memTemplItemRight, + table.memberdecls .memTemplParams { + display: block; + text-align: left; + padding-left: var(--spacing-large); + margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large)); + border-right: none; + border-left: none; + border-radius: 0; + white-space: normal; + } + + table.memberdecls .memItemLeft, + table.memberdecls .mdescLeft, + table.memberdecls .memTemplItemLeft { + border-bottom: 0; + padding-bottom: 0; + } + + table.memberdecls .memTemplItemLeft { + padding-top: 0; + } + + table.memberdecls .mdescLeft { + margin-bottom: calc(0px - var(--page-font-size)); + } + + table.memberdecls .memItemRight, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemRight { + border-top: 0; + padding-top: 0; + padding-right: var(--spacing-large); + overflow-x: auto; + } + + table.memberdecls tr[class^='memitem']:not(.inherit) { + display: block; + width: calc(100vw - 2 * var(--spacing-large)); + } + + table.memberdecls .mdescRight { + color: var(--page-foreground-color); + } + + table.memberdecls tr.inherit { + visibility: hidden; + } + + table.memberdecls tr[style="display: table-row;"] { + display: block !important; + visibility: visible; + width: calc(100vw - 2 * var(--spacing-large)); + animation: fade .5s; + } + + @keyframes fade { + 0% { + opacity: 0; + max-height: 0; + } + + 100% { + opacity: 1; + max-height: 200px; + } + } +} + + +/* + Horizontal Rule + */ + +hr { + margin-top: var(--spacing-large); + margin-bottom: var(--spacing-large); + height: 1px; + background-color: var(--separator-color); + border: 0; +} + +.contents hr { + box-shadow: 100px 0 0 var(--separator-color), + -100px 0 0 var(--separator-color), + 500px 0 0 var(--separator-color), + -500px 0 0 var(--separator-color), + 1500px 0 0 var(--separator-color), + -1500px 0 0 var(--separator-color), + 2000px 0 0 var(--separator-color), + -2000px 0 0 var(--separator-color); +} + +.contents img, .contents .center, .contents center, .contents div.image object { + max-width: 100%; + overflow: auto; +} + +@media screen and (max-width: 767px) { + .contents .dyncontent > .center, .contents > center { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); + } +} + +/* + Directories + */ +div.directory { + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + width: auto; +} + +table.directory { + font-family: var(--font-family); + font-size: var(--page-font-size); + font-weight: normal; + width: 100%; +} + +table.directory td.entry, table.directory td.desc { + padding: calc(var(--spacing-small) / 2) var(--spacing-small); + line-height: var(--table-line-height); +} + +table.directory tr.even td:last-child { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; +} + +table.directory tr.even td:first-child { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); +} + +table.directory tr.even:last-child td:last-child { + border-radius: 0 var(--border-radius-small) 0 0; +} + +table.directory tr.even:last-child td:first-child { + border-radius: var(--border-radius-small) 0 0 0; +} + +table.directory td.desc { + min-width: 250px; +} + +table.directory tr.even { + background-color: var(--odd-color); +} + +table.directory tr.odd { + background-color: transparent; +} + +.icona { + width: auto; + height: auto; + margin: 0 var(--spacing-small); +} + +.icon { + background: var(--primary-color); + border-radius: var(--border-radius-small); + font-size: var(--page-font-size); + padding: calc(var(--page-font-size) / 5); + line-height: var(--page-font-size); + transform: scale(0.8); + height: auto; + width: var(--page-font-size); + user-select: none; +} + +.iconfopen, .icondoc, .iconfclosed { + background-position: center; + margin-bottom: 0; + height: var(--table-line-height); +} + +.icondoc { + filter: saturate(0.2); +} + +@media screen and (max-width: 767px) { + div.directory { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed { + filter: hue-rotate(180deg) invert(); + } +} + +html.dark-mode .iconfopen, html.dark-mode .iconfclosed { + filter: hue-rotate(180deg) invert(); +} + +/* + Class list + */ + +.classindex dl.odd { + background: var(--odd-color); + border-radius: var(--border-radius-small); +} + +.classindex dl.even { + background-color: transparent; +} + +/* + Class Index Doxygen 1.8 +*/ + +table.classindex { + margin-left: 0; + margin-right: 0; + width: 100%; +} + +table.classindex table div.ah { + background-image: none; + background-color: initial; + border-color: var(--separator-color); + color: var(--page-foreground-color); + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-large); + padding: var(--spacing-small); +} + +div.qindex { + background-color: var(--odd-color); + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + padding: var(--spacing-small) 0; +} + +/* + Footer and nav-path + */ + +#nav-path { + width: 100%; +} + +#nav-path ul { + background-image: none; + background: var(--page-background-color); + border: none; + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + border-bottom: 0; + box-shadow: 0 0.75px 0 var(--separator-color); + font-size: var(--navigation-font-size); +} + +img.footer { + width: 60px; +} + +.navpath li.footer { + color: var(--page-secondary-foreground-color); +} + +address.footer { + color: var(--page-secondary-foreground-color); + margin-bottom: var(--spacing-large); +} + +#nav-path li.navelem { + background-image: none; + display: flex; + align-items: center; +} + +.navpath li.navelem a { + text-shadow: none; + display: inline-block; + color: var(--primary-color) !important; +} + +.navpath li.navelem b { + color: var(--primary-dark-color); + font-weight: 500; +} + +li.navelem { + padding: 0; + margin-left: -8px; +} + +li.navelem:first-child { + margin-left: var(--spacing-large); +} + +li.navelem:first-child:before { + display: none; +} + +#nav-path li.navelem:after { + content: ''; + border: 5px solid var(--page-background-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(4.2); + z-index: 10; + margin-left: 6px; +} + +#nav-path li.navelem:before { + content: ''; + border: 5px solid var(--separator-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(3.2); + margin-right: var(--spacing-small); +} + +.navpath li.navelem a:hover { + color: var(--primary-color); +} + +/* + Scrollbars for Webkit +*/ + +#nav-tree::-webkit-scrollbar, +div.fragment::-webkit-scrollbar, +pre.fragment::-webkit-scrollbar, +div.memproto::-webkit-scrollbar, +.contents center::-webkit-scrollbar, +.contents .center::-webkit-scrollbar, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar, +div.contents .toc::-webkit-scrollbar { + background: transparent; + width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); +} + +#nav-tree::-webkit-scrollbar-thumb, +div.fragment::-webkit-scrollbar-thumb, +pre.fragment::-webkit-scrollbar-thumb, +div.memproto::-webkit-scrollbar-thumb, +.contents center::-webkit-scrollbar-thumb, +.contents .center::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb, +div.contents .toc::-webkit-scrollbar-thumb { + background-color: transparent; + border: var(--webkit-scrollbar-padding) solid transparent; + border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + background-clip: padding-box; +} + +#nav-tree:hover::-webkit-scrollbar-thumb, +div.fragment:hover::-webkit-scrollbar-thumb, +pre.fragment:hover::-webkit-scrollbar-thumb, +div.memproto:hover::-webkit-scrollbar-thumb, +.contents center:hover::-webkit-scrollbar-thumb, +.contents .center:hover::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb, +div.contents .toc:hover::-webkit-scrollbar-thumb { + background-color: var(--webkit-scrollbar-color); +} + +#nav-tree::-webkit-scrollbar-track, +div.fragment::-webkit-scrollbar-track, +pre.fragment::-webkit-scrollbar-track, +div.memproto::-webkit-scrollbar-track, +.contents center::-webkit-scrollbar-track, +.contents .center::-webkit-scrollbar-track, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track, +div.contents .toc::-webkit-scrollbar-track { + background: transparent; +} + +#nav-tree::-webkit-scrollbar-corner { + background-color: var(--side-nav-background); +} + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc { + overflow-x: auto; + overflow-x: overlay; +} + +#nav-tree { + overflow-x: auto; + overflow-y: auto; + overflow-y: overlay; +} + +/* + Scrollbars for Firefox +*/ + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc { + scrollbar-width: thin; +} + +/* + Optional Dark mode toggle button +*/ + +doxygen-awesome-dark-mode-toggle { + display: inline-block; + margin: 0 0 0 var(--spacing-small); + padding: 0; + width: var(--searchbar-height); + height: var(--searchbar-height); + background: none; + border: none; + border-radius: var(--searchbar-height); + vertical-align: middle; + text-align: center; + line-height: var(--searchbar-height); + font-size: 22px; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + cursor: pointer; +} + +doxygen-awesome-dark-mode-toggle > svg { + transition: transform .1s ease-in-out; +} + +doxygen-awesome-dark-mode-toggle:active > svg { + transform: scale(.5); +} + +doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.03); +} + +html.dark-mode doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.18); +} + +/* + Optional fragment copy button +*/ +.doxygen-awesome-fragment-wrapper { + position: relative; +} + +doxygen-awesome-fragment-copy-button { + opacity: 0; + background: var(--fragment-background); + width: 28px; + height: 28px; + position: absolute; + right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + border: 1px solid var(--fragment-foreground); + cursor: pointer; + border-radius: var(--border-radius-small); + display: flex; + justify-content: center; + align-items: center; +} + +.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success { + opacity: .28; +} + +doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success { + opacity: 1 !important; +} + +doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg { + transform: scale(.91); +} + +doxygen-awesome-fragment-copy-button svg { + fill: var(--fragment-foreground); + width: 18px; + height: 18px; +} + +doxygen-awesome-fragment-copy-button.success svg { + fill: rgb(14, 168, 14); +} + +doxygen-awesome-fragment-copy-button.success { + border-color: rgb(14, 168, 14); +} + +@media screen and (max-width: 767px) { + .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button { + right: 0; + } +} + +/* + Optional paragraph link button +*/ + +a.anchorlink { + font-size: 90%; + margin-left: var(--spacing-small); + color: var(--page-foreground-color) !important; + text-decoration: none; + opacity: .15; + display: none; + transition: opacity .1s ease-in-out, color .1s ease-in-out; +} + +a.anchorlink svg { + fill: var(--page-foreground-color); +} + +h3 a.anchorlink svg, h4 a.anchorlink svg { + margin-bottom: -3px; + margin-top: -4px; +} + +a.anchorlink:hover { + opacity: .45; +} + +h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { + display: inline-block; +} diff --git a/MaterialX/documents/Images/MaterialXGraphEditor_Marble.png b/MaterialX/documents/Images/MaterialXGraphEditor_Marble.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Images/MaterialXLogo.png b/MaterialX/documents/Images/MaterialXLogo.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Images/MaterialXLogo_200x155.png b/MaterialX/documents/Images/MaterialXLogo_200x155.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Images/MaterialXView_Carpaint.png b/MaterialX/documents/Images/MaterialXView_Carpaint.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Images/MaterialXView_Copper.png b/MaterialX/documents/Images/MaterialXView_Copper.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Images/MaterialXView_Marble.png b/MaterialX/documents/Images/MaterialXView_Marble.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Images/MaterialXView_Plastic.png b/MaterialX/documents/Images/MaterialXView_Plastic.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Images/MaterialXView_TiledBrass.png b/MaterialX/documents/Images/MaterialXView_TiledBrass.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Images/MaterialXView_TiledWood.png b/MaterialX/documents/Images/MaterialXView_TiledWood.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Images/OpenChessSet_Arnold_01.png b/MaterialX/documents/Images/OpenChessSet_Arnold_01.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Images/OpenChessSet_Karma_01.png b/MaterialX/documents/Images/OpenChessSet_Karma_01.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Images/shadergen.png b/MaterialX/documents/Images/shadergen.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Specification/MaterialX.GeomExts.md b/MaterialX/documents/Specification/MaterialX.GeomExts.md old mode 100644 new mode 100755 index e0fb3a8..7d1fe92 --- a/MaterialX/documents/Specification/MaterialX.GeomExts.md +++ b/MaterialX/documents/Specification/MaterialX.GeomExts.md @@ -1,525 +1,517 @@ - - - -# MaterialX Geometry Extensions - -**Version 1.39** -Doug Smythe - Industrial Light & Magic -Jonathan Stone - Lucasfilm Advanced Development Group -October 21, 2022 - - -# Introduction - -The core [**MaterialX Specification**](./MaterialX.Specification.md) defines a number of element types and specific functional node definitions which can be used to describe the structure of shading networks and materials, including the definitions and functionality of custom shading operations. - -There are many formats that can be used to describe the associations between shading materials and renderable geometry as well as various data and metadata associated with geometry. For performance and other reasons it is often desirable to use native application mechanisms or something like Pixar's USD[^1] to describe these associations. However, there is significant value in being able to store a complete description of a CG object "look" within a single application-independent file format. This document describes extensions to the core MaterialX Specification that can be used to define collections of geometries, geometric properties and their values per geometry, and assignment of materials, variants, visibility and rendering properties to specific geometries in named looks, either directly or via geometry name expressions or named collections. - - -## Table of Contents - -**[Introduction](#introduction)** - -**[Geometry Representation](#geometry-representation)** - [Lights](#lights) - [Geometry Name Expressions](#geometry-name-expressions) - [Collections](#collections) - [Geometry Prefixes](#geometry-prefixes) - -**[Additional MaterialX Data Types](#additional-materialx-data-types)** - -**[Additional Filename Substitutions](#additional-filename-substitutions)** - -**[Geometry Info Elements](#geometry-info-elements)** - [GeomInfo Definition](#geominfo-definition) - [GeomProp Elements](#geomprop-elements) - [Geometry Token Elements](#geometry-token-elements) - [TokenDefault Elements](#tokendefault-elements) - [Reserved GeomProp Names](#reserved-geomprop-names) - -**[Look and Property Elements](#look-and-property-elements)** - [Property Definition](#property-definition) - [Look Definition](#look-definition) - [Assignment Elements](#assignment-elements) - [MaterialAssign Elements](#materialassign-elements) - [VariantAssign Elements](#variantassign-elements) - [Visibility Elements](#visibility-elements) - [PropertyAssign Elements](#propertyassign-elements) - [Look Examples](#look-examples) - -**[References](#references)** - -
- - -# Geometry Representation - -Geometry is referenced by but not specifically defined within MaterialX content. The file in which geometry is defined can optionally be declared using `geomfile` attributes within any element; that `geomfile` declaration will then apply to any geometry name referenced within the scope of that element, e.g. any `geom` attributes, including those defining the contents of collections (but not when referencing the contents of a collection via a `collection` attribute). If a geomfile is not defined for the scope of any particular `geom` attribute, it is presumed that the host application can resolve the location of the geometry definition. - -The geometry naming conventions used in the MaterialX specification are designed to be compatible with those used in Alembic ([http://www.alembic.io/](http://www.alembic.io/)) and USD ([http://graphics.pixar.com/usd](http://graphics.pixar.com/usd)). "Geometry" can be any particular geometric object that a host application may support, including but not limited to polygons, meshes, subdivision surfaces, NURBS, implicit surfaces, particle sets, volumes, lights, procedurally-defined objects, etc. The only requirements for MaterialX are that geometries are named using the convention specified below, can be assigned to a material and can be rendered. - -The naming of geometry should follow a syntax similar to UNIX full paths: - -``` - /string1/string2/string3/... -``` - -E.g. an initial "/" followed by one or more hierarchy level strings separated by "/"s, ending with a final string and no "/". The strings making up the path component for a level of hierarchy cannot contain spaces or "/"s or any of the characters reserved for geometry name expressions (see below). Individual implementations may have further restrictions on what characters may be used for hierarchy level names, so for ultimate compatibility it is recommended to use names comprised only of upper- or lower-case letters, digits 0-9, and underscores ("_"). - -Geometry names (e.g. the full path name) must be unique within the entire set of geometries referenced in a setup. Note that _there is no implied transformation hierarchy in the specified geometry paths_: the paths are simply the names of the geometry. However, the path-like nature of geometry names can be used to benefit in geometry name expression pattern matching and assignments. - -Note: if a geometry mesh is divided into partitions, the syntax for the parent mesh would be: - -``` - /path/to/geom/meshname -``` - -and for the child partitions, the syntax would be: - -``` - /path/to/geom/meshname/partitionname -``` - -Assignments to non-leaf locations apply hierarchically to all geometries below the specified location, unless they are the target of another assignment. By extension, an assignment to "/" applies to _all _geometries within the MaterialX setup, unless they are the target of another assignment. - - -## Lights - -Computer Graphics assets often include lights as part of the asset, such as the headlights of a car. MaterialX does not define "light" objects per se, but instead allows referencing externally-defined light objects in the same manner as geometry, via a UNIX-like path. MaterialX does not describe the position, view or shape of a light object: MaterialX presumes that these properties are stored within the external representation. - -Light object geometries can be turned off (muted) in looks by making the light geometry invisible, assignment of "light"-context shader materials can be done using a <materialassign> within a <look>, and illumination and shadowing assignments can be handled using <visibility> declarations for the light geometry. See the [**Look Definition**](#look-definition) section below for details. - - - -## Geometry Name Expressions - -Certain elements in MaterialX files support geometry specification via expressions. The syntax for geometry name expressions in MaterialX largely follows that of “glob” patterns for filenames in Unix environments, with a few extensions for the specific needs of geometry references. - -Within a single hierarchy level (e.g. between "/"s): - -* `*` matches 0 or more characters -* `?` matches exactly one character -* `[]` are used to match any individual character within the brackets, with "-" meaning match anything between the character preceding and the character following the "-" -* `{}` are used to match any of the comma-separated strings or expressions within the braces - -Additionally, a `/` will match only exactly a single `/` in a geometry name, e.g. as a boundary for a hierarchy level, while a `//` will match a single `/`, or two `/`s any number of hierarchy levels apart; `//` can be used to specify a match at any hierarchy depth. If a geometry name ends with `//*`, the final `*` will only match leaf geometries in the hierarchy. A geometry name of `//*` by itself will match all leaf geometries in an entire scene, while the name `//*//` will match all geometries at any level, including nested geometries, and the name `/a/b/c//*//` will match all geometries at any level below `/a/b/c`. It should be noted that for a mesh with partitions, it is the partitions and not the mesh which are treated as leaf geometry by MaterialX geometry names using `//*`. - - - -## Collections - -Collections are recipes for building a list of geometries (which can be any path within the geometry hierarchy), which can be used as a shorthand for assignments to a (potentially large) number of geometries at once. Collections can be built up from lists of specific geometries, geometries matching defined geometry name expressions, other collections, or any combination of those. - -A **<collection>** element contains lists of geometry expressions and/or collections to be included, and an optional list of geometry expressions to be excluded: - -```xml - -``` - -Either `includegeom` and/or `includecollection` must be specified. The `includegeom` and `includecollection` lists are applied first, followed by the `excludegeom` list. This can be used to build up the contents of a collection in pieces, or to add expression-matched geometry then remove specific unwanted matched geometries. The contents of a collection can itself be used to define a portion of another collection. The contents of each `includecollection` collection are effectively evaluated in whole before being added to the collection being built. - -If the containing file is capable of defining MaterialX-compliant collections (e.g. an Alembic or USD file), its collections can be referred to in any situation where a collection="name" reference is allowed. - - - -## Geometry Prefixes - -As a shorthand convenience, MaterialX allows the specification of a `geomprefix` attribute that will be prepended to data values of type "geomname" or "geomnamearray" (e.g. `geom` attributes in ``, ``, ``, and `` elements) specified within the scope of the element defining the `geomprefix`, similar to how MaterialX allows the specification of a `fileprefix` attribute which is prepended to input values of type "filename". For data values of type "geomnamearray", the `geomprefix` is prepended to each individual comma-separated geometry name. Since the values of the prefix and the geometry are string-concatenated, the value of a `geomprefix` should generally end with a "/". Geomprefix is commonly used to split off leading portions of geometry paths common to all geometry names, e.g. to define the "asset root" path. - -So the following MTLX file snippets are equivalent: - - -```xml - - - - - - - -``` - -
- - -# Additional MaterialX Data Types - -Systems supporting MaterialX Geometry Extensions support the following additional standard data types: - -**GeomName** and **GeomNameArray**: attributes of type "geomname" are just strings within quotes, but specifically mean the name of a single geometry using the conventions described in the [**Geometry Representation**](#geometry-representation) and [**Geometry Name Expressions**](#geometry-name-expressions) sections. A geomname is allowed to use a geometry name expression as long as it resolves to a single geometry. Attributes of type "geomnamearray" are strings within quotes containing a comma-separated list of one or more geomname values with or without expressions, and may resolve to any number of geometries. - -
- - -# Additional Filename Substitutions - -Filename input values for various nodes can include one or more special strings which will be replaced by the application with values derived from the current geometry, from the MaterialX state, or from the host application environment. Applications which support MaterialX Geometry Extensions also support the following filename substitution: - - -| Token | Description | -| ---- | ---- | -| <geometry token> | The value of a specified token declared in a <geominfo> element or as a uniform primvar value (generally of type string or integer) for the current geometry. | - - -Only applications fully supporting Geometry Extensions may allow using a <_geometry token_> as part of a larger filename string. All applications should allow the use of "<_geometry token_>" as the full filename string, in which case the string primvar value stored with the geometry is used as the filename unchanged; the string primvar value itself might be allowed to contain another token such as <UDIM> which the renderer may be able to parse and replace itself. - -
- - -# Geometry Info Elements - -Geometry Info ("geominfo") elements are used to define sets of named geometric properties with constant values, and to associate them with specific external geometries. - -The most common use for geominfo elements is to define the filenames (or portions of filenames) of texture map images mapped onto the geometry. Typically, there are several types of textures such as color, roughness, bump, opacity, etc. associated with each geometry: each texture name string would be a separate <token> within the <geominfo>. These images could contain texture data for multiple geometries, which would either be listed in the `geom` attribute of the <geominfo> element, or be assembled into a collection and the name of that collection would be specified in the `collection` attribute. - - -## GeomInfo Definition - -A **<geominfo>** element contains one or more geometry property and/or token definitions, and associates them and their values with all geometries listed in the `geom` or `collection` attribute of the <geominfo>: - -```xml - - ...geometry property and token value definitions... - -``` - -Note that no two <geominfo>s may define values for the same geometry property or token for the same geometry, whether the geometry is specified directly, matched via a geometry name expression, or contained within a specified collection. - -Attributes for GeomInfo elements: - -* `name` (string, required): the unique name of the GeomInfo element -* `geom` (geomnamearray, optional): the list of geometries and/or geometry name expressions that the GeomInfo is to apply to -* `collection` (string, optional): the name of a geometric collection - -Either a `geom` or a `collection` may be specified, but not both. - - - -### GeomProp Elements - -The core MaterialX Specification defines a Geometric Property, or "geomprop", as an intrinsic or user-defined surface coordinate property of geometries referenced in a specific space and/or index, and provides several nodes to retrieve the values of these properties within a shading network nodegraph, as well as a <geompropdef> element used to define the name and output type of custom geometric properties beyond the standard ones: `position`, `normal`, `tangent`, `bitangent`, `texcoord` and `geomcolor`. - -MaterialX Geometry Extensions expands upon this by allowing the use of <geomprop> elements to define specific uniform values of a geometric property with specific geometries, as opposed to relying on those values being defined externally. This could include application-specific metadata, attributes passed from a lighting package to a renderer, or other geometry-specific data. A geomprop may also specify a `unittype` and `unit` if appropriate to indicate that the geometric property's value is in that unit; see the [**Units** section of the main MaterialX Specification](./MaterialX.Specification.md#units), although typically the <geompropdef> would define the `unittype` and `unit`, and a geomprop would only provide an overriding `unit` if the unit for its value differed from the geompropdef's defined default unit. - -```xml - -``` - -GeomProp elements have the following attributes: - -* `name` (string, required): the name of the geometric property to define -* `type` (string, required): the data type of the given property -* `value` (any MaterialX type, required): the value to assign to the given property. -* `unittype` (attribute, string, optional): the type of unit for this property, e.g. "distance", which must be defined by a <unittypedef>. Default is to not specify a unittype. -* `unit` (attribute, string, optional): the specific unit for this property. Default is to not specify a unit. - -Only float and vectorN geometric properties may specify a `unittype` and a `unit`. - -For example, one could specify a unique surface ID value associated with a geometry: - -```xml - - - - -``` - -GeomProp values can be accessed from a nodegraph using a `` node: - -```xml - -``` - -A <geomprop> can also be used to define a default value for an intrinsic varying geometric property such as "geomcolor" for the geometry specified by the enclosing <geominfo>, which would be returned by the corresponding Geometric node (e.g. <geomcolor>) if the current geometry did not itself define values for that property. - -```xml - - - -``` - - - -### Geometry Token Elements - -Token elements may be used within <geominfo> elements to define constant (typically string or integer) named values associated with specific geometries. These geometry token values can be substituted into filenames within image nodes; see the [**Additional Filename Substitutions**](#additional-filename-substitutions) section above for details: - -```xml - -``` - -The "value" can be any MaterialX type, but since tokens are used in filename substitutions, string and integer values are recommended. - -Token elements have the following attributes: - -* `name` (string, required): the name of the geometry token to define -* `type` (string, required): the geometry token's type -* `value` (any MaterialX type, optional): the value to assign to that token name for this geometry. - -For example, one could specify a texture identifier value associated with a geometry: - -```xml - - - -``` - -and then reference that token's value in a filename: - -```xml - - - -``` - -The <txtid> in the file name would be replaced by whatever value the txtid token had for each geometry. - - -### TokenDefault Elements - -TokenDefault elements define the default value for a specified geometry token name; this default value will be used in a filename string substitution if an explicit token value is not defined for the current geometry. Since TokenDefault does not apply to any geometry in particular, it must be used outside of a <geominfo> element. - -```xml - -``` - - -### Reserved GeomProp Names - -Workflows involving textures with implicitly-computed filenames based on u,v coordinates (such as <UDIM> and <UVTILE>) can be made more efficient by explicitly listing the set of values that they resolve to for any given geometry. The MaterialX specification reserves two geomprop names for this purpose, `udimset` and `uvtileset`, each of which is a stringarray containing a comma-separated list of UDIM or UVTILE values: - -```xml - - - - - - - -``` - -
- - -# Look and Property Elements - -**Look** elements define the assignments of materials, visibility and other properties to geometries and geometry collections. In MaterialX, a number of geometries are associated with each stated material, visibility type or property in a look, as opposed to defining the particular material or properties for each geometry. - -**Property** elements define non-material properties that can be assigned to geometries or collections in Looks. There are a number of standard MaterialX property types that can be applied universally for any rendering target, as well as a mechanism to define target-specific properties for geometries or collections. - -A MaterialX document can contain multiple property and/or look elements. - - -## Property Definition - -A **<property>** element defines the name, type and value of a look-specific non-material property of geometry; <**propertyset**> elements are used to group a number of <property>s into a single named object. The connection between properties or propertysets and specific geometries or collections is done in a <look> element, so that these properties can be reused across different geometries, and enabled in some looks but not others. <Property> elements may only be used within <propertyset>s; they may not be used independently, although a dedicated <propertyassign> element may be used within a <look> to declare a property name, type, value and assignment all at once. - -```xml - - - - -``` - -The following properties are considered standard in MaterialX, and should be respected on all platforms that support these concepts: - - -| Property | Type | Default Value | -| --- | --- | --- | -| **`twosided`** | boolean | false | -| **`matte`** | boolean | false | - -where `twosided` means the geometry should be rendered even if the surface normal faces away from camera, and `matte` means the geometry should hold out, or "matte" out anything behind it (including in the alpha channel). - -In the example above, the "trace_maxdiffusedepth" property is target-specific, having been restricted to the context of Renderman RIS by setting its `target` attribute to “rmanris”. - - - -## Look Definition - -A **<look>** element contains one or more material, variant, visibility and/or propertyset assignment declarations: - -```xml - - ...materialassign, variantassign, visibilityassign, property/propertysetassign declarations... - -``` - -Looks can inherit the assignments from another look by including an `inherit` attribute. The look can then specify additional assignments that will apply on top of/in place of whatever came from the source look. This is useful for defining a base look and then one or more "variation" looks. It is permissible for an inherited-from look to itself inherit from another look, but a look can inherit from only one parent look. - -A number of looks can be grouped together into a **LookGroup**, e.g. to indicate which looks are defined for a particular asset: - -```xml - -``` - -where `lookgroupname` is the name of the lookgroup being defined, `look1`/`look2`/etc. are the names of <look> or <lookgroup> elements to be contained in the lookgroup (a lookgroup name would resolve to the set of looks recursively contained in that lookgroup), and `default` (if specified) specifies the name of one of the looks defined in `looks` to be the default look to use. A look can be contained in any number of lookgroups. - -<Look> and <lookgroup> elements also support other attributes such as `xpos`, `ypos` and `uicolor` as described in the Standard UI Attributes section above. - - -## Assignment Elements - -Various types of assignment elements are used within looks to assign materials, categorized visibility and properties to specific geometries, or variants to materials. - -For elements which make assignments to geometries, the pathed names within `geom` attributes or stored within collections do not need to resolve strictly to "leaf" path locations or actual renderable geometry names: assignments can also be made to intermediate "branch" geometry path locations, which will then apply to any geometry at a deeper level in the path hierarchy which does not have another "closer to the leaf" level assignment. E.g. an assignment to "/a/b/c" will effectively apply to "/a/b/c/d" and "/a/b/c/foo/bar" (and anything else whose full path name begins with "/a/b/c/") if no other assignment is made to "/a/b/c/d", "/a/b/c/foo", or "/a/b/c/foo/bar". If a look inherits from another look, the child look can replace assignments made to any specific path location (e.g. a child assignment to "/a/b/c" would take precedence over a parent look's assignment to "/a/b/c"), but an assignment by the parent look to a more "leaf"-level path location would take precedence over a child look assignment to a higher "branch"-level location. - - -### MaterialAssign Elements - -MaterialAssign elements are used within a <look> to connect a specified material to one or more geometries or collections (either a `geom` or a `collection` may be specified, but not both). - -```xml - - ...optional variantassign elements... - -``` - -Material assignments are generally assumed to be mutually-exclusive, that is, any individual geometry is assigned to only one material. Therefore, assign declarations should be processed in the order they appear in the file, and if any geometry appears in multiple <materialassign>s, the last <materialassign> wins. However, some applications allow multiple materials to be assigned to the same geometry as long as the shader node types don't overlap. If the `exclusive` attribute is set to false (default is true), then earlier material assigns will still take effect for all shader node types not defined in the materials of later assigns: for each shader node type, the shader within the last assigned material referencing a matching shader node type wins. If a particular application does not support multiple material assignments to the same geometry, the value of `exclusive` is ignored and only the last full material and its shaders are assigned to the geometry, and the parser should issue a warning. - - -### VariantAssign Elements - -VariantAssign elements are used within a <materialassign> or a <look> to apply the values defined in one variant of a variantset to one assigned material, or to all applicable materials in a look. - -```xml - - - - - - - ... - -``` - -VariantAssign elements have the following attributes: - -* `name` (string, required): the unique name of the VariantAssign element -* `variantset` (string, required): the name of the variantset to apply the variant from -* `variant` (string, required): the name of the variant within `variantset` to use - -In the above example, the input/token values defined within variant "var1" will be applied to all identically-named inputs/tokens found in either "material1" or "material2" unless restricted by a `node` or `nodedef` attribute defined in the <variantset>, while values defined within variant "var2" will only be applied to matching-named bindings in "material1". VariantAssigns are applied in the order specified within a scope, with those within a <materialassign> taking precedence over those which are direct children of the <look>. - - -### Visibility Elements - -Visibility elements are used within a <look> to define various types of generalized visibility between a "viewer" object and other geometries. A "viewer object" is simply a geometry that has the ability to "see" other geometries in some rendering context and thus may need to have the list of geometries that it "sees" in different contexts be specified; the most common examples are light sources and a primary rendering camera. - -```xml - -``` - -Visibility elements have the following attributes: - -* `name` (string, required): the unique name of the Visibility element -* `viewergeom` (geomnamearray, optional): the list of viewer geometry objects that the <visibility> assignment affects -* `viewercollection` (string, optional): the name of a collection containing viewer geometry objects that the <visibility> assignment affects -* `geom` (geomnamearray, optional): the list of geometries and/or geometry name expressions that the `viewergeom` object should (or shouldn't) "see" -* `collection` (string, optional): the name of a defined collection of geometries that the `viewergeom` object should (or shouldn't) "see" -* `vistype` (string, optional): the type of visibility being defined; see table below -* `visible` (boolean, optional): if false, the geom/collection objects will be invisible to this particular type of visibility; defaults to "true". - -The `viewergeom` attribute (and/or the contents of a collection referred to by the `viewercollection` attribute) typically refers to the name of a light (or list of lights) or other "geometry viewing" object(s). If `viewergeom`/`viewercollection` are omitted, the visibility applies to all applicable viewers (camera, light, geometry) within the given render context; `viewergeom`/`viewercollection` are not typically specified for `vistype` "camera". Either `geom` or `collection` must be defined but not both; similarly, one cannot define both a `viewergeom` and a `viewercollection`. - -The `vistype` attribute refers to a specific type of visibility. If a particular `vistype` is not assigned within a <look>, then all geometry is visible by default to all `viewergeom`s for that `vistype`; this means that to have only a certain subset of geometries be visible (either overall or to a particular `vistype`), it is necessary to first assign <visibility> with `visible="false"` to all geometry. Additional <visibility> assignments to the same `vistype` within a <look> are applied on top of the current visibility state. The following `vistype`s are predefined by MaterialX; applications are free to define additional `vistype`s: - - -| Vistype | Description | -| --- | --- | -| **`camera`** | camera or "primary" ray visibility | -| **`illumination`** | geom or collection is illuminated by the viewergeom light(s) | -| **`shadow`** | geom or collection casts shadows from the viewergeom light(s) | -| **`secondary`** | indirect/bounce ray visibility of geom or collection to viewergeom geometry | - - -If `vistype` is not specified, then the visibility assignment applies to _all_ visibility types, and in fact will take precedence over any specific `vistype` setting on the same geometry: geometry assigned a <`visibility>` with no `vistype` and `visible="false"` will not be visible to camera, shadows, secondary rays, or any other ray or render type. This mechanism can be used to cleanly hide geometry not needed in certain variations of an asset, e.g. different costume pieces or alternate damage shapes. - -If the <visibility> `geom` or `collection` refers to light geometry, then assigning `vistype="camera"` determines whether or not the light object itself is visible to the camera/viewer (e.g. "do you see the bulb"), while assigning `visible="false"` with no `vistype` will mute the light so it is neither visible to camera nor emitting any light. - -For the "secondary" vistype, `viewergeom` should be renderable geometry rather than a light, to declare that certain other geometry is or is not visible to indirect bounce illumination or raytraced reflections in that `viewergeom`. In this example, "/b" would not be seen in reflections nor contribute indirect bounce illumination to "/a", while geometry "/c" would not be visible to _any_ secondary rays: - -```xml - - -``` - - -### PropertyAssign Elements - -PropertyAssign and PropertySetAssign elements are used within a <look> to connect a specified property value or propertyset to one or more geometries or collections. - -```xml - - -``` - -Either a `geom` or a `collection` may be specified, but not both. Multiple property/propertyset assignments can be made to the same geometry or collection, as long as no conflicting assignment is made. If there are any conflicting assignments, it is up to the host application to determine how such conflicts are to be resolved, but host applications should apply property assignments in the order they are listed in the look, so it should generally be safe to assume that if two property/propertyset assignments set different values for the same property to the same geometry, the later assignment will win. - - -## Look Examples - -This example defines four collections, a light shader and material, and a propertyset, which are then used by two looks: - -```xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - -
- - -# References - -[^1]: - + + + +# MaterialX Geometry Extensions + +**Version 1.39** +Doug Smythe - Industrial Light & Magic +Jonathan Stone - Lucasfilm Advanced Development Group +October 21, 2022 + + +# Introduction + +The core [**MaterialX Specification**](./MaterialX.Specification.md) defines a number of element types and specific functional node definitions which can be used to describe the structure of shading networks and materials, including the definitions and functionality of custom shading operations. + +There are many formats that can be used to describe the associations between shading materials and renderable geometry as well as various data and metadata associated with geometry. For performance and other reasons it is often desirable to use native application mechanisms or something like Pixar's USD[^1] to describe these associations. However, there is significant value in being able to store a complete description of a CG object "look" within a single application-independent file format. This document describes extensions to the core MaterialX Specification that can be used to define collections of geometries, geometric properties and their values per geometry, and assignment of materials, variants, visibility and rendering properties to specific geometries in named looks, either directly or via geometry name expressions or named collections. + + +## Table of Contents + +**[Introduction](#introduction)** + +**[Geometry Representation](#geometry-representation)** + [Lights](#lights) + [Geometry Name Expressions](#geometry-name-expressions) + [Collections](#collections) + [Geometry Prefixes](#geometry-prefixes) + +**[Additional MaterialX Data Types](#additional-materialx-data-types)** + +**[Additional Filename Substitutions](#additional-filename-substitutions)** + +**[Geometry Info Elements](#geometry-info-elements)** + [GeomInfo Definition](#geominfo-definition) + [GeomProp Elements](#geomprop-elements) + [Geometry Token Elements](#geometry-token-elements) + [TokenDefault Elements](#tokendefault-elements) + [Reserved GeomProp Names](#reserved-geomprop-names) + +**[Look and Property Elements](#look-and-property-elements)** + [Property Definition](#property-definition) + [Look Definition](#look-definition) + [Assignment Elements](#assignment-elements) + [MaterialAssign Elements](#materialassign-elements) + [VariantAssign Elements](#variantassign-elements) + [Visibility Elements](#visibility-elements) + [PropertyAssign Elements](#propertyassign-elements) + [Look Examples](#look-examples) + +**[References](#references)** + + + +# Geometry Representation + +Geometry is referenced by but not specifically defined within MaterialX content. The file in which geometry is defined can optionally be declared using `geomfile` attributes within any element; that `geomfile` declaration will then apply to any geometry name referenced within the scope of that element, e.g. any `geom` attributes, including those defining the contents of collections (but not when referencing the contents of a collection via a `collection` attribute). If a geomfile is not defined for the scope of any particular `geom` attribute, it is presumed that the host application can resolve the location of the geometry definition. + +The geometry naming conventions used in the MaterialX specification are designed to be compatible with those used in Alembic ([http://www.alembic.io/](http://www.alembic.io/)) and USD ([http://graphics.pixar.com/usd](http://graphics.pixar.com/usd)). "Geometry" can be any particular geometric object that a host application may support, including but not limited to polygons, meshes, subdivision surfaces, NURBS, implicit surfaces, particle sets, volumes, lights, procedurally-defined objects, etc. The only requirements for MaterialX are that geometries are named using the convention specified below, can be assigned to a material and can be rendered. + +The naming of geometry should follow a syntax similar to UNIX full paths: + +``` + /string1/string2/string3/... +``` + +E.g. an initial "/" followed by one or more hierarchy level strings separated by "/"s, ending with a final string and no "/". The strings making up the path component for a level of hierarchy cannot contain spaces or "/"s or any of the characters reserved for geometry name expressions (see below). Individual implementations may have further restrictions on what characters may be used for hierarchy level names, so for ultimate compatibility it is recommended to use names comprised only of upper- or lower-case letters, digits 0-9, and underscores ("_"). + +Geometry names (e.g. the full path name) must be unique within the entire set of geometries referenced in a setup. Note that _there is no implied transformation hierarchy in the specified geometry paths_: the paths are simply the names of the geometry. However, the path-like nature of geometry names can be used to benefit in geometry name expression pattern matching and assignments. + +Note: if a geometry mesh is divided into partitions, the syntax for the parent mesh would be: + +``` + /path/to/geom/meshname +``` + +and for the child partitions, the syntax would be: + +``` + /path/to/geom/meshname/partitionname +``` + +Assignments to non-leaf locations apply hierarchically to all geometries below the specified location, unless they are the target of another assignment. By extension, an assignment to "/" applies to _all _geometries within the MaterialX setup, unless they are the target of another assignment. + + +## Lights + +Computer Graphics assets often include lights as part of the asset, such as the headlights of a car. MaterialX does not define "light" objects per se, but instead allows referencing externally-defined light objects in the same manner as geometry, via a UNIX-like path. MaterialX does not describe the position, view or shape of a light object: MaterialX presumes that these properties are stored within the external representation. + +Light object geometries can be turned off (muted) in looks by making the light geometry invisible, assignment of "light"-context shader materials can be done using a <materialassign> within a <look>, and illumination and shadowing assignments can be handled using <visibility> declarations for the light geometry. See the [**Look Definition**](#look-definition) section below for details. + + + +## Geometry Name Expressions + +Certain elements in MaterialX files support geometry specification via expressions. The syntax for geometry name expressions in MaterialX largely follows that of “glob” patterns for filenames in Unix environments, with a few extensions for the specific needs of geometry references. + +Within a single hierarchy level (e.g. between "/"s): + +* `*` matches 0 or more characters +* `?` matches exactly one character +* `[]` are used to match any individual character within the brackets, with "-" meaning match anything between the character preceding and the character following the "-" +* `{}` are used to match any of the comma-separated strings or expressions within the braces + +Additionally, a `/` will match only exactly a single `/` in a geometry name, e.g. as a boundary for a hierarchy level, while a `//` will match a single `/`, or two `/`s any number of hierarchy levels apart; `//` can be used to specify a match at any hierarchy depth. If a geometry name ends with `//*`, the final `*` will only match leaf geometries in the hierarchy. A geometry name of `//*` by itself will match all leaf geometries in an entire scene, while the name `//*//` will match all geometries at any level, including nested geometries, and the name `/a/b/c//*//` will match all geometries at any level below `/a/b/c`. It should be noted that for a mesh with partitions, it is the partitions and not the mesh which are treated as leaf geometry by MaterialX geometry names using `//*`. + + + +## Collections + +Collections are recipes for building a list of geometries (which can be any path within the geometry hierarchy), which can be used as a shorthand for assignments to a (potentially large) number of geometries at once. Collections can be built up from lists of specific geometries, geometries matching defined geometry name expressions, other collections, or any combination of those. + +A **<collection>** element contains lists of geometry expressions and/or collections to be included, and an optional list of geometry expressions to be excluded: + +```xml + +``` + +Either `includegeom` and/or `includecollection` must be specified. The `includegeom` and `includecollection` lists are applied first, followed by the `excludegeom` list. This can be used to build up the contents of a collection in pieces, or to add expression-matched geometry then remove specific unwanted matched geometries. The contents of a collection can itself be used to define a portion of another collection. The contents of each `includecollection` collection are effectively evaluated in whole before being added to the collection being built. + +If the containing file is capable of defining MaterialX-compliant collections (e.g. an Alembic or USD file), its collections can be referred to in any situation where a collection="name" reference is allowed. + + + +## Geometry Prefixes + +As a shorthand convenience, MaterialX allows the specification of a `geomprefix` attribute that will be prepended to data values of type "geomname" or "geomnamearray" (e.g. `geom` attributes in ``, ``, ``, and `` elements) specified within the scope of the element defining the `geomprefix`, similar to how MaterialX allows the specification of a `fileprefix` attribute which is prepended to input values of type "filename". For data values of type "geomnamearray", the `geomprefix` is prepended to each individual comma-separated geometry name. Since the values of the prefix and the geometry are string-concatenated, the value of a `geomprefix` should generally end with a "/". Geomprefix is commonly used to split off leading portions of geometry paths common to all geometry names, e.g. to define the "asset root" path. + +So the following MTLX file snippets are equivalent: + + +```xml + + + + + + + +``` + + + +# Additional MaterialX Data Types + +Systems supporting MaterialX Geometry Extensions support the following additional standard data types: + +**GeomName** and **GeomNameArray**: attributes of type "geomname" are just strings within quotes, but specifically mean the name of a single geometry using the conventions described in the [**Geometry Representation**](#geometry-representation) and [**Geometry Name Expressions**](#geometry-name-expressions) sections. A geomname is allowed to use a geometry name expression as long as it resolves to a single geometry. Attributes of type "geomnamearray" are strings within quotes containing a comma-separated list of one or more geomname values with or without expressions, and may resolve to any number of geometries. + + +# Additional Filename Substitutions + +Filename input values for various nodes can include one or more special strings which will be replaced by the application with values derived from the current geometry, from the MaterialX state, or from the host application environment. Applications which support MaterialX Geometry Extensions also support the following filename substitution: + + +| Token | Description | +| ---- | ---- | +| <geometry token> | The value of a specified token declared in a <geominfo> element or as a uniform primvar value (generally of type string or integer) for the current geometry. | + + +Only applications fully supporting Geometry Extensions may allow using a <_geometry token_> as part of a larger filename string. All applications should allow the use of "<_geometry token_>" as the full filename string, in which case the string primvar value stored with the geometry is used as the filename unchanged; the string primvar value itself might be allowed to contain another token such as <UDIM> which the renderer may be able to parse and replace itself. + + + +# Geometry Info Elements + +Geometry Info ("geominfo") elements are used to define sets of named geometric properties with constant values, and to associate them with specific external geometries. + +The most common use for geominfo elements is to define the filenames (or portions of filenames) of texture map images mapped onto the geometry. Typically, there are several types of textures such as color, roughness, bump, opacity, etc. associated with each geometry: each texture name string would be a separate <token> within the <geominfo>. These images could contain texture data for multiple geometries, which would either be listed in the `geom` attribute of the <geominfo> element, or be assembled into a collection and the name of that collection would be specified in the `collection` attribute. + + +## GeomInfo Definition + +A **<geominfo>** element contains one or more geometry property and/or token definitions, and associates them and their values with all geometries listed in the `geom` or `collection` attribute of the <geominfo>: + +```xml + + ...geometry property and token value definitions... + +``` + +Note that no two <geominfo>s may define values for the same geometry property or token for the same geometry, whether the geometry is specified directly, matched via a geometry name expression, or contained within a specified collection. + +Attributes for GeomInfo elements: + +* `name` (string, required): the unique name of the GeomInfo element +* `geom` (geomnamearray, optional): the list of geometries and/or geometry name expressions that the GeomInfo is to apply to +* `collection` (string, optional): the name of a geometric collection + +Either a `geom` or a `collection` may be specified, but not both. + + + +### GeomProp Elements + +The core MaterialX Specification defines a Geometric Property, or "geomprop", as an intrinsic or user-defined surface coordinate property of geometries referenced in a specific space and/or index, and provides several nodes to retrive the values of these properties within a shading network nodegraph, as well as a <geompropdef> element used to define the name and output type of custom geometric properties beyond the standard ones: `position`, `normal`, `tangent`, `bitangent`, `texcoord` and `geomcolor`. + +MaterialX Geometry Extensions expands upons this by allowing the use of <geomprop> elements to define specific uniform values of a geometric property with specific geometries, as opposed to relying on those values being defined externally. This could include application-specific metadata, attributes passed from a lighting package to a renderer, or other geometry-specific data. A geomprop may also specify a `unittype` and `unit` if appropriate to indicate that the geometric property's value is in that unit; see the [**Units** section of the main MaterialX Specification](./MaterialX.Specification.md#units), although typically the <geompropdef> would define the `unittype` and `unit`, and a geomprop would only provide an overriding `unit` if the unit for its value differed from the geompropdef's defined default unit. + +```xml + +``` + +GeomProp elements have the following attributes: + +* `name` (string, required): the name of the geometric property to define +* `type` (string, required): the data type of the given property +* `value` (any MaterialX type, required): the value to assign to the given property. +* `unittype` (attribute, string, optional): the type of unit for this property, e.g. "distance", which must be defined by a <unittypedef>. Default is to not specify a unittype. +* `unit` (attribute, string, optional): the specific unit for this property. Default is to not specify a unit. + +Only float and vectorN geometric properties may specify a `unittype` and a `unit`. + +For example, one could specify a unique surface ID value associated with a geometry: + +```xml + + + + +``` + +GeomProp values can be accessed from a nodegraph using a `` node: + +```xml + +``` + +A <geomprop> can also be used to define a default value for an intrinsic varying geometric property such as "geomcolor" for the geometry specified by the enclosing <geominfo>, which would be returned by the corresponding Geometric node (e.g. <geomcolor>) if the current geometry did not itself define values for that property. + +```xml + + + +``` + + + +### Geometry Token Elements + +Token elements may be used within <geominfo> elements to define constant (typically string or integer) named values associated with specific geometries. These geometry token values can be substituted into filenames within image nodes; see the [**Additional Filename Substitutions**](#additional-filename-substitutions) section above for details: + +```xml + +``` + +The "value" can be any MaterialX type, but since tokens are used in filename substitutions, string and integer values are recommended. + +Token elements have the following attributes: + +* `name` (string, required): the name of the geometry token to define +* `type` (string, required): the geometry token's type +* `value` (any MaterialX type, optional): the value to assign to that token name for this geometry. + +For example, one could specify a texture identifier value associated with a geometry: + +```xml + + + +``` + +and then reference that token's value in a filename: + +```xml + + + +``` + +The <txtid> in the file name would be replaced by whatever value the txtid token had for each geometry. + + +### TokenDefault Elements + +TokenDefault elements define the default value for a specified geometry token name; this default value will be used in a filename string substitution if an explicit token value is not defined for the current geometry. Since TokenDefault does not apply to any geometry in particular, it must be used outside of a <geominfo> element. + +```xml + +``` + + +### Reserved GeomProp Names + +Workflows involving textures with implicitly-computed filenames based on u,v coordinates (such as <UDIM> and <UVTILE>) can be made more efficient by explicitly listing the set of values that they resolve to for any given geometry. The MaterialX specification reserves two geomprop names for this purpose, `udimset` and `uvtileset`, each of which is a stringarray containing a comma-separated list of UDIM or UVTILE values: + +```xml + + + + + + + +``` + + + +# Look and Property Elements + +**Look** elements define the assignments of materials, visibility and other properties to geometries and geometry collections. In MaterialX, a number of geometries are associated with each stated material, visibility type or property in a look, as opposed to defining the particular material or properties for each geometry. + +**Property** elements define non-material properties that can be assigned to geometries or collections in Looks. There are a number of standard MaterialX property types that can be applied universally for any rendering target, as well as a mechanism to define target-specific properties for geometries or collections. + +A MaterialX document can contain multiple property and/or look elements. + + +## Property Definition + +A **<property>** element defines the name, type and value of a look-specific non-material property of geometry; <**propertyset**> elements are used to group a number of <property>s into a single named object. The connection between properties or propertysets and specific geometries or collections is done in a <look> element, so that these properties can be reused across different geometries, and enabled in some looks but not others. <Property> elements may only be used within <propertyset>s; they may not be used independently, although a dedicated <propertyassign> element may be used within a <look> to declare a property name, type, value and assignment all at once. + +```xml + + + + +``` + +The following properties are considered standard in MaterialX, and should be respected on all platforms that support these concepts: + + +| Property | Type | Default Value | +| --- | --- | --- | +| **`twosided`** | boolean | false | +| **`matte`** | boolean | false | + +where `twosided` means the geometry should be rendered even if the surface normal faces away from camera, and `matte` means the geometry should hold out, or "matte" out anything behind it (including in the alpha channel). + +In the example above, the "trace_maxdiffusedepth" property is target-specific, having been restricted to the context of Renderman RIS by setting its `target` attribute to “rmanris”. + + + +## Look Definition + +A **<look>** element contains one or more material, variant, visibility and/or propertyset assignment declarations: + +```xml + + ...materialassign, variantassign, visibilityassign, property/propertysetassign declarations... + +``` + +Looks can inherit the assignments from another look by including an `inherit` attribute. The look can then specify additional assignments that will apply on top of/in place of whatever came from the source look. This is useful for defining a base look and then one or more "variation" looks. It is permissible for an inherited-from look to itself inherit from another look, but a look can inherit from only one parent look. + +A number of looks can be grouped together into a **LookGroup**, e.g. to indicate which looks are defined for a particular asset: + +```xml + +``` + +where `lookgroupname` is the name of the lookgroup being defined, `look1`/`look2`/etc. are the names of <look> or <lookgroup> elements to be contained in the lookgroup (a lookgroup name would resolve to the set of looks recursively contained in that lookgroup), and `default` (if specified) specifies the name of one of the looks defined in `looks` to be the default look to use. A look can be contained in any number of lookgroups. + +<Look> and <lookgroup> elements also support other attributes such as `xpos`, `ypos` and `uicolor` as described in the Standard UI Attributes section above. + + +## Assignment Elements + +Various types of assignment elements are used within looks to assign materials, categorized visibility and properties to specific geometries, or variants to materials. + +For elements which make assignments to geometries, the pathed names within `geom` attributes or stored within collections do not need to resolve strictly to "leaf" path locations or actual renderable geometry names: assignments can also be made to intermediate "branch" geometry path locations, which will then apply to any geometry at a deeper level in the path hierarchy which does not have another "closer to the leaf" level assignment. E.g. an assignment to "/a/b/c" will effectively apply to "/a/b/c/d" and "/a/b/c/foo/bar" (and anything else whose full path name begins with "/a/b/c/") if no other assignment is made to "/a/b/c/d", "/a/b/c/foo", or "/a/b/c/foo/bar". If a look inherits from another look, the child look can replace assignments made to any specific path location (e.g. a child assignment to "/a/b/c" would take precedence over a parent look's assignment to "/a/b/c"), but an assignment by the parent look to a more "leaf"-level path location would take precedence over a child look assignment to a higher "branch"-level location. + + +### MaterialAssign Elements + +MaterialAssign elements are used within a <look> to connect a specified material to one or more geometries or collections (either a `geom` or a `collection` may be specified, but not both). + +```xml + + ...optional variantassign elements... + +``` + +Material assignments are generally assumed to be mutually-exclusive, that is, any individual geometry is assigned to only one material. Therefore, assign declarations should be processed in the order they appear in the file, and if any geometry appears in multiple <materialassign>s, the last <materialassign> wins. However, some applications allow multiple materials to be assigned to the same geometry as long as the shader node types don't overlap. If the `exclusive` attribute is set to false (default is true), then earlier material assigns will still take effect for all shader node types not defined in the materials of later assigns: for each shader node type, the shader within the last assigned material referencing a matching shader node type wins. If a particular application does not support multiple material assignments to the same geometry, the value of `exclusive` is ignored and only the last full material and its shaders are assigned to the geometry, and the parser should issue a warning. + + +### VariantAssign Elements + +VariantAssign elements are used within a <materialassign> or a <look> to apply the values defined in one variant of a variantset to one assigned material, or to all applicable materials in a look. + +```xml + + + + + + + ... + +``` + +VariantAssign elements have the following attributes: + +* `name` (string, required): the unique name of the VariantAssign element +* `variantset` (string, required): the name of the variantset to apply the variant from +* `variant` (string, required): the name of the variant within `variantset` to use + +In the above example, the input/token values defined within variant "var1" will be applied to and and all identically-named inputs/tokens found in either "material1" or "material2" unless restricted by a `node` or `nodedef` attribute defined in the <variantset>, while values defined within variant "var2" will only be applied to matching-named bindings in "material1". VariantAssigns are applied in the order specified within a scope, with those within a <materialassign> taking precedence over those which are direct children of the <look>. + + +### Visibility Elements + +Visibility elements are used within a <look> to define various types of generalized visibility between a "viewer" object and other geometries. A "viewer object" is simply a geometry that has the ability to "see" other geometries in some rendering context and thus may need to have the list of geometries that it "sees" in different contexts be specified; the most common examples are light sources and a primary rendering camera. + +```xml + +``` + +Visibility elements have the following attributes: + +* `name` (string, required): the unique name of the Visibility element +* `viewergeom` (geomnamearray, optional): the list of viewer geometry objects that the <visibility> assignment affects +* `viewercollection` (string, optional): the name of a collection containing viewer geometry objects that the <visibility> assignment affects +* `geom` (geomnamearray, optional): the list of geometries and/or geometry name expressions that the `viewergeom` object should (or shouldn't) "see" +* `collection` (string, optional): the name of a defined collection of geometries that the `viewergeom` object should (or shouldn't) "see" +* `vistype` (string, optional): the type of visibility being defined; see table below +* `visible` (boolean, optional): if false, the geom/collection objects will be invisible to this particular type of visibility; defaults to "true". + +The `viewergeom` attribute (and/or the contents of a collection referred to by the `viewercollection` attribute) typically refers to the name of a light (or list of lights) or other "geometry viewing" object(s). If `viewergeom`/`viewercollection` are omitted, the visibility applies to all applicable viewers (camera, light, geometry) within the given render context; `viewergeom`/`viewercollection` are not typically specified for `vistype` "camera". Either `geom` or `collection` must be defined but not both; similarly, one cannot define both a `viewergeom` and a `viewercollection`. + +The `vistype` attribute refers to a specific type of visibility. If a particular `vistype` is not assigned within a <look>, then all geometry is visible by default to all `viewergeom`s for that `vistype`; this means that to have only a certain subset of geometries be visible (either overall or to a particular `vistype`), it is necessary to first assign <visibility> with `visible="false"` to all geometry. Additional <visibility> assignments to the same `vistype` within a <look> are applied on top of the current visibility state. The following `vistype`s are predefined by MaterialX; applications are free to define additional `vistype`s: + + +| Vistype | Description | +| --- | --- | +| **`camera`** | camera or "primary" ray visibility | +| **`illumination`** | geom or collection is illuminated by the viewergeom light(s) | +| **`shadow`** | geom or collection casts shadows from the viewergeom light(s) | +| **`secondary`** | indirect/bounce ray visibility of geom or collection to viewergeom geometry | + + +If `vistype` is not specified, then the visibility assignment applies to _all_ visibility types, and in fact will take precedence over any specific `vistype` setting on the same geometry: geometry assigned a <`visibility>` with no `vistype` and `visible="false"` will not be visible to camera, shadows, secondary rays, or any other ray or render type. This mechanism can be used to cleanly hide geometry not needed in certain variations of an asset, e.g. different costume pieces or alternate damage shapes. + +If the <visibility> `geom` or `collection` refers to light geometry, then assigning `vistype="camera"` determines whether or not the light object itself is visible to the camera/viewer (e.g. "do you see the bulb"), while assigning `visible="false"` with no `vistype` will mute the light so it is neither visible to camera nor emitting any light. + +For the "secondary" vistype, `viewergeom` should be renderable geometry rather than a light, to declare that certain other geometry is or is not visible to indirect bounce illumination or raytraced reflections in that `viewergeom`. In this example, "/b" would not be seen in reflections nor contribute indirect bounce illumination to "/a", while geometry "/c" would not be visible to _any_ secondary rays: + +```xml + + +``` + + +### PropertyAssign Elements + +PropertyAssign and PropertySetAssign elements are used within a <look> to connect a specified property value or propertyset to one or more geometries or collections. + +```xml + + +``` + +Either a `geom` or a `collection` may be specified, but not both. Multiple property/propertyset assignments can be made to the same geometry or collection, as long as no conflicting assignment is made. If there are any conflicting assignments, it is up to the host application to determine how such conflicts are to be resolved, but host applications should apply property assignments in the order they are listed in the look, so it should generally be safe to assume that if two property/propertyset assignments set different values for the same property to the same geometry, the later assignment will win. + + +## Look Examples + +This example defines four collections, a light shader and material, and a propertyset, which are then used by two looks: + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + + +# References + +[^1]: + diff --git a/MaterialX/documents/Specification/MaterialX.NPRSpec.md b/MaterialX/documents/Specification/MaterialX.NPRSpec.md old mode 100644 new mode 100755 index 180f97c..0506f29 --- a/MaterialX/documents/Specification/MaterialX.NPRSpec.md +++ b/MaterialX/documents/Specification/MaterialX.NPRSpec.md @@ -1,74 +1,71 @@ - - - -# MaterialX NPR Shading Nodes - -**Version 1.39** -Doug Smythe - Industrial Light & Magic -Jonathan Stone - Lucasfilm Advanced Development Group -July 1, 2024 - -# Introduction - -The [MaterialX Standard Nodes](./MaterialX.StandardNodes.md) and [MaterialX Physically Based Shading Nodes](./MaterialX.PBRSpec.md) documents describe a number of standard pattern and shading nodes that may be used to construct nodegraph-based shaders for physically based rendering in a variety of applications. However, there are certain operations that are desirable in non-photorealistic shading styles but which cannot be implemented within certain rendering constructs. It is also helpful conceptually to separate nodes primarily useful for photorealistic and non-photorealistic shading styles into separate libraries. - -This document describes a number of MaterialX nodes primarily applicable to non-photorealistic, or NPR, rendering. Rendering applications whose architecture cannot support these operations are not required to support these nodes. - - -## Table of Contents - -**[MaterialX NPR Library](#materialx-npr-library)** - [NPR Application Nodes](#npr-application-nodes) - [NPR Utility Nodes](#npr-utility-nodes) - [NPR Shading Nodes](#npr-shading-nodes) - -**[References](#references)** - -
- - -# MaterialX NPR Library - - -## NPR Application Nodes - - - -* **`viewdirection`**: the current scene view direction (e.g. from the viewing/camera position to the current shading position). If `viewdirection` is used in a PBR shading context, it should be noted that this would be the same as the incident ray direction for primary ("camera") rays but **not** for secondary/reflection rays. This node must be of type vector3. - - * `space` (uniform string): the space in which to return the view vector direction, defaults to `world`. - - - -## NPR Utility Nodes - - - -* **`facingratio`**: returns the geometric facing ratio, computed as the dot product between the view direction and geometric normal. Output is a float between 0.0 and 1.0. - - * `viewdirection` (vector3): the viewing direction, defaults to the value of the "Vworld" (world space view direction) geometric property. - * `normal` (vector3): the surface normal vector, defaults to the value of the "Nworld" (world space view direction) geometric property. This vector is expected to be prenormalized to length 1.0. - * `faceforward` (boolean): description needed; default is false. - * `invert` (boolean): description needed; default is false. - - - -## NPR Shading Nodes - - - -* **`gooch_shade`**: Computes the single-pass shading portion of the Gooch[^Gooch1998] lighting model. Output type `surfaceshader`. - * `warm_color` (color3): the "warm" color for shading, defaults to (0.8, 0.8, 0.7) in the `lin_rec709` colorspace. - * `cool_color` (color3): the "cool" color for shading, defaults to (0.3, 0.3, 0.8) in the `lin_rec709` colorspace. - * `specular_intensity` (float): the intensity of the specular component. Defaults to 1.0. - * `shininess` (float): the specular power typically ranging from 1 to 256, defaults to 64. - * `light_direction` (vector3): the incoming predominant lighting direction in world space, defaults to (1.0, -0.5, -0.5). - -
- - -# References - -[^Gooch1998]: Gooch et al., **A Non-Photorealistic Lighting Model For Automatic Technical Illustration**, , 1998. + + + +# MaterialX NPR Shading Nodes + +**Version 1.39** +Doug Smythe - Industrial Light & Magic +Jonathan Stone - Lucasfilm Advanced Development Group +July 1, 2024 + +# Introduction + +The MaterialX Specification and MaterialX Physically Based Shading Nodes documents describe a number of standard pattern and shading nodes that may be used to construct nodegraph-based shaders for physically based rendering in a variety of applications. However, there are certain operations that are desirable in non-photorealistic shading styles but which cannot be implemented within certain rendering constructs. It is also helpful conceptually to separate nodes primarily useful for photorealistic and non-photorealistic shading styles into separate libraries. + +This document describes a number of MaterialX nodes primarily applicable to non-photorealistic, or NPR, rendering. Rendering applications whose architecture cannot support these operations are not required to support these nodes. + + +## Table of Contents + +**[MaterialX NPR Library](#materialx-npr-library)** + [NPR Application Nodes](#npr-application-nodes) + [NPR Utility Nodes](#npr-utility-nodes) + [NPR Shading Nodes](#npr-shading-nodes) + +**[References](#references)** + + +# MaterialX NPR Library + + +## NPR Application Nodes + + + +* **`viewdirection`**: the current scene view direction (e.g. from the viewing/camera position to the current shading position). If `viewdirection` is used in a PBR shading context, it should be noted that this would be the same as the incident ray direction for primary ("camera") rays but **not** for secondary/reflection rays. This node must be of type vector3. + + * `space` (uniform string): the space in which to return the view vector direction, defaults to `world`. + + + +## NPR Utility Nodes + + + +* **`facingratio`**: returns the geometric facing ratio, computed as the dot product between the view direction and geometric normal. Output is a float between 0.0 and 1.0. + + * `viewdirection` (vector3): the viewing direction, defaults to the value of the "Vworld" (world space view direction) geometric property. + * `normal` (vector3): the surface normal vector, defaults to the value of the "Nworld" (world space view direction) geometric property. This vector is expected to be prenormalized to length 1.0. + * `faceforward` (boolean): description needed; default is false. + * `invert` (boolean): description needed; default is false. + + + +## NPR Shading Nodes + + + +* **`gooch_shade`**: Computes the single-pass shading portion of the Gooch[^Gooch1998] lighting model. Output type `surfaceshader`. + * `warm_color` (color3): the "warm" color for shading, defaults to (0.8, 0.8, 0.7) in the `lin_rec709` colorspace. + * `cool_color` (color3): the "cool" color for shading, defaults to (0.3, 0.3, 0.8) in the `lin_rec709` colorspace. + * `specular_intensity` (float): the intensity of the specular component. Defaults to 1.0. + * `shininess` (float): the specular power typically ranging from 1 to 256, defaults to 64. + * `light_direction` (vector3): the incoming predominant lighting direction in world space, defaults to (1.0, -0.5, -0.5). + + + +# References + +[^Gooch1998]: Gooch et al., **A Non-Photorealistic Lighting Model For Automatic Technical Illustration**, , 1998. diff --git a/MaterialX/documents/Specification/MaterialX.PBRSpec.md b/MaterialX/documents/Specification/MaterialX.PBRSpec.md old mode 100644 new mode 100755 index 6f19a10..afed6e7 --- a/MaterialX/documents/Specification/MaterialX.PBRSpec.md +++ b/MaterialX/documents/Specification/MaterialX.PBRSpec.md @@ -1,709 +1,451 @@ - - - -# MaterialX Physically Based Shading Nodes - -**Version 1.39** -Niklas Harrysson - Lumiere Software -Doug Smythe - Industrial Light & Magic -Jonathan Stone - Lucasfilm Advanced Development Group -December 22, 2025 - -# Introduction - -The [MaterialX Specification](./MaterialX.Specification.md) describes a number of standard nodes that may be used to construct node graphs for the processing of images, procedurally-generated values, coordinates and other data. With the addition of user-defined custom nodes, it is possible to describe complete rendering shaders using node graphs. Up to this point, there has been no standardization of the specific shader-semantic nodes used in these node graph shaders, although with the widespread shift toward physically-based shading, it appears that the industry is settling upon a number of specific BSDF and other functions with standardized parameters and functionality. - -This document describes a number of shader-semantic nodes implementing widely-used surface scattering, emission and volume distribution functions and utility nodes useful in constructing complex layered rendering shaders using node graphs. These nodes in combination with other nodes may be used with the [MaterialX Shader Generation](../DeveloperGuide/ShaderGeneration.md) system. - - -## Table of Contents - -**[Physical Material Model](#physical-material-model)** - [Scope](#scope) - [Physically Plausible Materials](#physically-plausible-materials) - [Quantities and Units](#quantities-and-units) - [Color Management](#color-management) - [Surfaces](#surfaces) -  [Layering](#layering) -  [Bump and Normal Mapping](#bump-and-normal-mapping) -  [Surface Thickness](#surface-thickness) - [Volumes](#volumes) - [Lights](#lights) - -**[MaterialX PBS Library](#materialx-pbs-library)** - [Data Types](#data-types) - [BSDF Nodes](#bsdf-nodes) - [EDF Nodes](#edf-nodes) - [VDF Nodes](#vdf-nodes) - [PBR Shader Nodes](#pbr-shader-nodes) - [Utility Nodes](#utility-nodes) - -**[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)** - -
- - -# Physical Material Model - -This section describes the material model used in the MaterialX Physically Based Shading (PBS) library and the rules we must follow to be physically plausible. - - -## Scope - -A material describes the properties of a surface or medium that involves how it reacts to light. To be efficient, a material model is split into different parts, where each part handles a specific type of light interaction: light being scattered at the surface, light being emitted from a surface, light being scattered inside a medium, etc. The goal of our material model definition is to describe light-material interactions typical for physically plausible rendering systems, including those in feature film production, real-time preview, and game engines. - -Our model has support for surface materials, which includes scattering and emission of light from the surface of objects, and volume materials, which includes scattering and emission of light within a participating medium. For lighting, we support local lights and distant light from environments. Geometric modification is supported in the form of bump and normal mapping as well as displacement mapping. - - -## Physically Plausible Materials - -The initial requirements for a physically-plausible material are that it 1) should be energy conserving and 2) support reciprocity. The energy conserving says that the sum of reflected and transmitted light leaving a surface must be less than or equal to the amount of light reaching it. The reciprocity requirement says that if the direction of the traveling light is reversed, the response from the material remains unchanged. That is, the response is identical if the incoming and outgoing directions are swapped. All materials implemented for ShaderGen should respect these requirements and only in rare cases deviate from it when it makes sense for the purpose of artistic freedom. - - -## Quantities and Units - -Radiometric quantities are used by the material model for interactions with the renderer. The fundamental radiometric quantity is **radiance** (measured in _Wm−2sr−1_) and gives the intensity of light arriving at, or leaving from, a given point in a given direction. If incident radiance is integrated over all directions we get **irradiance** (measured in _Wm−2_), and if we integrate this over surface area we get **power** (measured in _W_). Input parameters for materials and lights specified in photometric units can be suitably converted to their radiometric counterparts before being submitted to the renderer. - -The interpretation of the data types returned by surface and volume shaders are unspecified, and left to the renderer and the shader generator for that renderer to decide. For an OpenGL-type renderer they will be tuples of floats containing radiance calculated directly by the shader node, but for an OSL-type renderer they may be closure primitives that are used by the renderer in the light transport simulation. - -In general, a color given as input to the renderer is considered to represent a linear RGB color space. However, there is nothing stopping a renderer from interpreting the color type differently, for instance to hold spectral values. In that case, the shader generator for that renderer needs to handle this in the implementation of the nodes involving the color type. - - -## Color Management - -MaterialX supports the use of [color management systems](./MaterialX.Specification.md#color-spaces-and-color-management-systems) to associate colors with specific color spaces. A MaterialX document typically specifies the working color space that is to be used for the document as well as the color space in which input values and textures are given. If these color spaces are different from the working color space, it is the application's and shader generator's responsibility to transform them. - -The ShaderGen module has an interface that can be used to integrate support for different color management systems. A simplified implementation with some popular and commonly used color transformations is supplied and enabled by default. An integration with the relevant portions of OpenColorIO ([http://opencolorio.org](http://opencolorio.org)) is planned for the future. - - -## Surfaces - -In our surface shading model the scattering and emission of light is controlled by distribution functions. Incident light can be reflected off, transmitted through, or absorbed by a surface. This is represented by a Bidirectional Scattering Distribution Function (BSDF). Light can also be emitted from a surface, for instance from a light source or glowing material. This is represented by an Emission Distribution Function (EDF). The PBS library introduces the [data types](#data-types) `BSDF` and `EDF` to represent the distribution functions, and there are nodes for constructing, combining and manipulating them. - -![Physically Based Shading Diagram](media/PBSdiagram.png "Physically Based Shading Diagram") - -Another important property is the **index of refraction** (IOR), which describes how light is propagated through a medium. It controls how much a light ray is bent when crossing the interface between two media of different refractive indices. It also determines the amount of light that is reflected and transmitted when reaching the interface, as described by the Fresnel equations. - -A surface shader is represented with the data type `surfaceshader`. In the PBS library there is a [<surface>](#node-surface) node that constructs a surface shader from a BSDF and an EDF. Since there are nodes to combine and modify them, you can easily build surface shaders from different combinations of distribution functions. Inputs on the distribution function nodes can be connected, and nodes from the standard library can be combined into complex calculations, giving flexibility for the artist to author material variations over the surfaces. - -It is common for shading models to differentiate between closed surfaces and thin-walled surfaces. A closed surface represents a closed watertight interface with a solid interior. A typical example is a solid glass object. A thin-walled surface on the other hand has an infinitely thin volume, as with a sheet of paper or a soap bubble. For a closed surface there can be no backside visible if the material is opaque. In the case of a transparent closed surface a backside hit is treated as light exiting the closed interface. For a thin-walled surface both the front and back side are visible and it can either have the same material on both sides or different materials on each side. If the material is transparent in this case the thin wall makes the light transmit without refraction or scattering. By default the [<surface>](#node-surface) node constructs a surface shader for a closed surface, but there is a boolean switch to make it thin-walled. - -In order to assign different shaders to each side of a thin-walled object the [<surfacematerial>](./MaterialX.Specification.md#node-surfacematerial) node in the standard library has an input to connect an extra backside surface shader. If any of the sides of a <surfacematerial> has a thin-walled shader connected, both sides are considered to be thin-walled. Hence the thin-walled property takes precedence to avoid ambiguity between the sides. If only one side has a shader connected this is used for both sides. If both sides are connected but none of the shaders are thin-walled the front shader is used. The thin-walled property also takes precedence in the case of mixing surface shaders. If any of the shaders involved in the mix is thin-walled, both shaders are considered to be thin-walled. - -Note that in order to have surface shaders set for both sides the geometry has to be set as double-sided. Geometry sidedness is a property not handled by MaterialX and needs to be set elsewhere. - - -### Layering - -In order to simplify authoring of complex materials, our model supports the notion of layering. Typical examples include: adding a layer of clear coat over a car paint material, or putting a layer of dirt or rust over a metal surface. Layering can be done in a number of different ways: - - - -* Horizontal Layering: A simple way of layering is using per-shading-point linear mixing of different BSDFs where a mix factor is given per BSDF controlling its contribution. Since the weight is calculated per shading point it can be used as a mask to hide contributions on different parts of a surface. The weight can also be calculated dependent on view angle to simulate approximate Fresnel behavior. This type of layering can be done both on a BSDF level and on a surface shader level. The latter is useful for mixing complete shaders which internally contain many BSDFs, e.g. to put dirt over a car paint, grease over a rusty metal or adding decals to a plastic surface. We refer to this type of layering as **horizontal layering** and the [<mix>](#node-mix) node in the PBS library can be used to achieve this (see below). -* Vertical Layering: A more physically correct form of layering is also supported where a top BSDF layer is placed over another base BSDF layer, and the light not reflected by the top layer is assumed to be transmitted to the base layer; for example, adding a dielectric coating layer over a substrate. The refraction index and roughness of the coating will then affect the attenuation of light reaching the substrate. The substrate can be a transmissive BSDF to transmit the light further, or a reflective BSDF to reflect the light back up through the coating. The substrate can in turn be a reflective BSDF to simulate multiple specular lobes. We refer to this type of layering as **vertical layering** and it can be achieved using the [<layer>](#node-layer) node in the PBS library. See [<dielectric_bsdf>](#node-dielectric-bsdf) and [<sheen_bsdf>](#node-sheen-bsdf) below. -* Shader Input Blending: Calculating and blending many BSDFs or separate surface shaders can be expensive. In some situations good results can be achieved by blending the texture/value inputs instead, before any illumination calculations. Typically one would use this with an über-shader that can simulate many different materials, and by masking or blending its inputs over the surface you get the appearance of having multiple layers, but with less expensive texture or value blending. Examples of this are given in the main [MaterialX Specification "Pre-Shader Compositing Example"](./MaterialX.Specification.md#example-pre-shader-compositing-material). - - -### Bump and Normal Mapping - -The surface normal used for shading calculations is supplied as input to each BSDF that requires it. The normal can be perturbed by bump or normal mapping, before it is given to the BSDF. As a result, one can supply different normals for different BSDFs for the same shading point. When layering BSDFs, each layer can use different bump and normal maps. - - -## Volumes - -In our volume shader model the scattering of light in a participating medium is controlled by a volume distribution function (VDF), with coefficients controlling the rate of absorption and scattering. The VDF represents what physicists call a _phase function, _describing how the light is distributed from its current direction when it is scattered in the medium. This is analogous to how a BSDF describes scattering at a surface, but with one important difference: a VDF is normalized, summing to 1.0 if all directions are considered. Additionally, the amount of absorption and scattering is controlled by coefficients that gives the rate (probability) per distance traveled in world space. The **absorption coefficient** sets the rate of absorption for light traveling through the medium, and the **scattering coefficient** sets the rate of which the light is scattered from its current direction. The unit for these are _m−1_. - -Light can also be emitted from a volume. This is represented by an EDF analog to emission from surfaces, but in this context the emission is given as radiance per distance traveled through the medium. The unit for this is _Wm−3sr−1_. The emission distribution is oriented along the current direction. - -The [<volume>](#node-volume) node in the PBS library constructs a volume shader from individual VDF and EDF components. There are also nodes to construct various VDFs, as well as nodes to combine them to build more complex ones. - -VDFs can also be used to describe the interior of a surface. A typical example would be to model how light is absorbed or scattered when transmitted through colored glass or turbid water. This is done by layering a BSDF for the surface transmission over the VDF using a [<layer>](#node-layer) node. - - -## Lights - -Light sources can be divided into environment lights and local lights. Environment lights represent contributions coming from infinitely far away. All other lights are local lights and have a position and extent in space. - -Local lights are specified as light shaders assigned to a locator, modeling an explicit light source, or in the form of emissive geometry using an emissive surface shader. The [<light>](#node-light) node in the PBS library constructs a light shader from an EDF. There are also nodes to construct various EDFs as well as nodes to combine them to build more complex ones. Emissive properties of surface shaders are also modelled using EDFs; see the [**EDF Nodes**](#edf-nodes) section below for more information. - -Light contributions coming from far away are handled by environment lights. These are typically photographically-captured or procedurally-generated images that surround the whole scene. This category of lights also includes sources like the sun, where the long distance traveled makes the light essentially directional and without falloff. For all shading points, an environment is seen as being infinitely far away. - -
- - -# MaterialX PBS Library - -MaterialX includes a library of types and nodes for creating physically plausible materials and lights as described above. This section outlines the content of that library. - - -## Data Types - -* `BSDF`: Data type representing a Bidirectional Scattering Distribution Function. -* `EDF`: Data type representing an Emission Distribution Function. -* `VDF`: Data type representing a Volume Distribution Function. - -The PBS nodes also make use of the following standard MaterialX types: - -* `surfaceshader`: Data type representing a surface shader. -* `lightshader`: Data type representing a light shader. -* `volumeshader`: Data type representing a volume shader. -* `displacementshader`: Data type representing a displacement shader. - - -## BSDF Nodes - - - -### `oren_nayar_diffuse_bsdf` -Constructs a diffuse reflection BSDF based on the Oren-Nayar reflectance model. - -A `roughness` of 0.0 gives Lambertian reflectance. - -An `energy_compensation` boolean selects between the Qualitative Oren-Nayar[^Oren1994] and Energy-Preserving Oren-Nayar[^Portsmouth2025] models of diffuse reflectance. - -|Port |Description |Type |Default |Accepted Values| -|---------------------|---------------------------------------|-------|----------------|---------------| -|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] | -|`color` |Diffuse reflectivity or albedo |color3 |0.18, 0.18, 0.18| | -|`roughness` |Surface roughness |float |0.0 |[0, 1] | -|`normal` |Normal vector of the surface |vector3|Nworld | | -|`energy_compensation`|Enable energy compensation for the BSDF|boolean|false | | -|`out` |Output: the computed BSDF |BSDF | | | - - - -### `burley_diffuse_bsdf` -Constructs a diffuse reflection BSDF based on the corresponding component of the Disney Principled model[^Burley2012]. - -|Port |Description |Type |Default |Accepted Values| -|-----------|-------------------------------|--------|----------------|---------------| -|`weight` |Weight of the BSDF contribution|float |1.0 |[0, 1] | -|`color` |Diffuse reflectivity or albedo |color3 |0.18, 0.18, 0.18| | -|`roughness`|Surface roughness |float |0.0 |[0, 1] | -|`normal` |Normal vector of the surface |vector3 |Nworld | | -|`out` |Output: the computed BSDF |BSDF | | | - - - -### `dielectric_bsdf` -Constructs a reflection and/or transmission BSDF based on a microfacet reflectance model and a Fresnel curve for dielectrics[^Walter2007]. If reflection scattering is enabled the node may be layered vertically over a base BSDF for the surface beneath the dielectric layer. By chaining multiple <dielectric_bsdf> nodes you can describe a surface with multiple specular lobes. If transmission scattering is enabled the node may be layered over a VDF describing the surface interior to handle absorption and scattering inside the medium, useful for colored glass, turbid water, etc. - -Implementations are expected to preserve energy as the roughness of the surface increases, with multiple scattering compensation[^Turquin2019] being a popular implementation strategy. - -The `tint` input colors the reflected and transmitted light but should be left at white (1,1,1) for physically correct results. Setting the `ior` input to zero disables the Fresnel curve, allowing reflectivity to be controlled purely by weight and tint. - -The `scatter_mode` controls whether the surface reflects light (`R`), transmits light (`T`), or both (`RT`). In `RT` mode, reflection and transmission occur both when entering and leaving a surface, with their respective intensities controlled by the Fresnel curve. Depending on the IOR and incident angle, total internal reflection may occur even when transmission modes are selected. - -Thin-film iridescence effects[^Belcour2017] may be enabled by setting `thinfilm_thickness` to a non-zero value. - -|Port |Description |Type |Default |Accepted Values| -|--------------------|---------------------------------------------------------------|-------|-------------|---------------| -|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] | -|`tint` |Color weight to tint the reflected and transmitted light |color3 |1.0, 1.0, 1.0| | -|`ior` |Index of refraction of the surface |float |1.5 | | -|`roughness` |Surface roughness along the tangent and bitangent |vector2|0.05, 0.05 |[0, 1] | -|`thinfilm_thickness`|Thickness of the iridescent thin-film layer in nanometers |float |0.0 | | -|`thinfilm_ior` |Index of refraction of the thin-film layer |float |1.5 | | -|`normal` |Normal vector of the surface |vector3|Nworld | | -|`tangent` |Tangent vector of the surface |vector3|Tworld | | -|`distribution` |Microfacet distribution type |string |ggx |ggx | -|`scatter_mode` |Surface Scatter mode, specifying reflection and/or transmission|string |R |R, T, RT | -|`out` |Output: the computed BSDF |BSDF | | | - - - -### `conductor_bsdf` -Constructs a reflection BSDF based on a microfacet reflectance model[^Burley2012]. Uses a Fresnel curve with complex refraction index for conductors/metals. If an artistic parametrization[^Gulbrandsen2014] is needed the [<artistic_ior>](#node-artistic-ior) utility node can be connected to handle this. - -Implementations are expected to preserve energy as the roughness of the surface increases, with multiple scattering compensation[^Turquin2019] being a popular implementation strategy. - -The default values for `ior` and `extinction` represent approximate values for gold. - -Thin-film iridescence effects[^Belcour2017] may be enabled by setting `thinfilm_thickness` to a non-zero value. - -|Port |Description |Type |Default |Accepted Values| -|--------------------|---------------------------------------------------------|-------|----------------------|---------------| -|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] | -|`ior` |Index of refraction |color3 |0.183, 0.421, 1.373 | | -|`extinction` |Extinction coefficient |color3 |3.424, 2.346, 1.770 | | -|`roughness` |Surface roughness |vector2|0.05, 0.05 |[0, 1] | -|`thinfilm_thickness`|Thickness of the iridescent thin-film layer in nanometers|float |0.0 | | -|`thinfilm_ior` |Index of refraction of the thin-film layer |float |1.5 | | -|`normal` |Normal vector of the surface |vector3|Nworld | | -|`tangent` |Tangent vector of the surface |vector3|Tworld | | -|`distribution` |Microfacet distribution type |string |ggx |ggx | -|`out` |Output: the computed BSDF |BSDF | | | - - - -### `generalized_schlick_bsdf` -Constructs a reflection and/or transmission BSDF based on a microfacet model and a generalized Schlick Fresnel curve[^Hoffman2023]. If reflection scattering is enabled the node may be layered vertically over a base BSDF for the surface beneath the dielectric layer. By chaining multiple <generalized_schlick_bsdf> nodes you can describe a surface with multiple specular lobes. If transmission scattering is enabled the node may be layered over a VDF describing the surface interior to handle absorption and scattering inside the medium, useful for colored glass, turbid water, etc. - -Implementations are expected to preserve energy as the roughness of the surface increases, with multiple scattering compensation[^Turquin2019] being a popular implementation strategy. - -The `color82` input provides a multiplier on reflectivity at 82 degrees, useful for capturing the characteristic "dip" in the reflectance curve of metallic surfaces. Setting it to (1,1,1) effectively disables this feature for backward compatibility. - -The `scatter_mode` behavior matches that of `dielectric_bsdf`: in `RT` mode, reflection and transmission occur both when entering and leaving a surface, with intensities controlled by the Fresnel curve. Total internal reflection may occur depending on the incident angle. - -Thin-film iridescence effects[^Belcour2017] may be enabled by setting `thinfilm_thickness` to a non-zero value. - -|Port |Description |Type |Default |Accepted Values| -|--------------------|---------------------------------------------------------------|-------|-------------|---------------| -|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] | -|`color0` |Reflectivity per color component at facing angles |color3 |1.0, 1.0, 1.0| | -|`color82` |Reflectivity multiplier at 82 degrees |color3 |1.0, 1.0, 1.0| | -|`color90` |Reflectivity per color component at grazing angles |color3 |1.0, 1.0, 1.0| | -|`exponent` |Exponent for Schlick blending between color0 and color90 |float |5.0 | | -|`roughness` |Surface roughness along the tangent and bitangent |vector2|0.05, 0.05 |[0, 1] | -|`thinfilm_thickness`|Thickness of the iridescent thin-film layer in nanometers |float |0.0 | | -|`thinfilm_ior` |Index of refraction of the thin-film layer |float |1.5 | | -|`normal` |Normal vector of the surface |vector3|Nworld | | -|`tangent` |Tangent vector of the surface |vector3|Tworld | | -|`distribution` |Microfacet distribution type |string |ggx |ggx | -|`scatter_mode` |Surface Scatter mode, specifying reflection and/or transmission|string |R |R, T, RT | -|`out` |Output: the computed BSDF |BSDF | | | - - - -### `translucent_bsdf` -Constructs a translucent (diffuse transmission) BSDF based on the Lambert reflectance model. - -|Port |Description |Type |Default |Accepted Values| -|---------|-------------------------------|-------|-------------|---------------| -|`weight` |Weight of the BSDF contribution|float |1.0 |[0, 1] | -|`color` |Diffuse transmittance |color3 |1.0, 1.0, 1.0| | -|`normal` |Normal vector of the surface |vector3|Nworld | | -|`out` |Output: the computed BSDF |BSDF | | | - - - -### `subsurface_bsdf` -Constructs a subsurface scattering BSDF for subsurface scattering within a homogeneous medium. The parameterization is chosen to match random walk Monte Carlo methods as well as approximate empirical methods[^Christensen2015]. Note that this category of subsurface scattering can be defined more rigorously as a BSDF vertically layered over an [](#node-anisotropic-vdf), and we expect these two descriptions of the scattering-surface distribution function to be unified in future versions of MaterialX. - -The `radius` input sets the average distance (mean free path) that light propagates below the surface before scattering back out, and can be set independently for each color channel. - -The `anisotropy` input controls the scattering direction: negative values produce backwards scattering, positive values produce forward scattering, and zero produces uniform scattering. - -|Port |Description |Type |Default |Accepted Values| -|------------|------------------------------------------|-------|----------------|---------------| -|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] | -|`color` |Diffuse reflectivity (albedo) |color3 |0.18, 0.18, 0.18| | -|`radius` |Mean free path per color channel |color3 |1.0, 1.0, 1.0 | | -|`anisotropy`|Anisotropy factor for scattering direction|float |0.0 |[-1, 1] | -|`normal` |Normal vector of the surface |vector3|Nworld | | -|`out` |Output: the computed BSDF |BSDF | | | - - - -### `sheen_bsdf` -Constructs a microfacet BSDF for the back-scattering properties of cloth-like materials. This node may be layered vertically over a base BSDF using a [<layer>](#node-layer) node. All energy that is not reflected will be transmitted to the base layer. A `mode` option selects between two available sheen models, Conty-Kulla[^Conty2017] and Zeltner[^Zeltner2022]. - -|Port |Description |Type |Default |Accepted Values | -|-----------|--------------------------------------------------------|-------|-------------|--------------------| -|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] | -|`color` |Sheen reflectivity |color3 |1.0, 1.0, 1.0| | -|`roughness`|Surface roughness |float |0.3 | | -|`normal` |Normal vector of the surface |vector3|Nworld | | -|`mode` |Selects between `conty_kulla` and `zeltner` sheen models|string |conty_kulla |conty_kulla, zeltner| -|`out` |Output: the computed BSDF |BSDF | | | - - - -### `chiang_hair_bsdf` -Constructs a hair BSDF based on the Chiang hair shading model[^Chiang2016]. This node does not support vertical layering. - -The roughness inputs control longitudinal (ν) and azimuthal (s) roughness for each lobe, with (0,0) specifying pure specular scattering. The default `ior` of 1.55 represents the index of refraction for keratin. The `cuticle_angle` is in radians, with 0.5 representing no tilt, and values above 0.5 tilting the scales toward the root of the fiber. - -|Port |Description |Type |Default |Accepted Values| -|------------------------|--------------------------------------------------------|-------|-------------|---------------| -|`tint_R` |Color multiplier for the first R-lobe |color3 |1.0, 1.0, 1.0| | -|`tint_TT` |Color multiplier for the first TT-lobe |color3 |1.0, 1.0, 1.0| | -|`tint_TRT` |Color multiplier for the first TRT-lobe |color3 |1.0, 1.0, 1.0| | -|`ior` |Index of refraction |float |1.55 | | -|`roughness_R` |Longitudinal and azimuthal roughness for R-lobe |vector2|0.1, 0.1 |[0, ∞) | -|`roughness_TT` |Longitudinal and azimuthal roughness for TT-lobe |vector2|0.05, 0.05 |[0, ∞) | -|`roughness_TRT` |Longitudinal and azimuthal roughness for TRT-lobe |vector2|0.2, 0.2 |[0, ∞) | -|`cuticle_angle` |Cuticle angle in radians |float |0.5 |[0, 1] | -|`absorption_coefficient`|Absorption coefficient normalized to hair fiber diameter|vector3|0.0, 0.0, 0.0| | -|`normal` |Normal vector of the surface |vector3|Nworld | | -|`curve_direction` |Direction of the hair geometry |vector3|Tworld | | -|`out` |Output: the computed BSDF |BSDF | | | - - -## EDF Nodes - - - -### `uniform_edf` -Constructs an EDF emitting light uniformly in all directions. - -|Port |Description |Type |Default | -|--------|----------------------------------------------|-------|-------------| -|`color` |Radiant emittance of light leaving the surface|color3 |1.0, 1.0, 1.0| -|`out` |Output: the computed EDF |EDF | | - - - -### `conical_edf` -Constructs an EDF emitting light inside a cone around the normal direction. - -Light intensity begins to fall off at the `inner_angle` and reaches zero at the `outer_angle` (both specified in degrees). If the `outer_angle` is smaller than the `inner_angle`, no falloff occurs within the cone. - -|Port |Description |Type |Default | -|-------------|--------------------------------------------------|-------|-------------| -|`color` |Radiant emittance of light leaving the surface |color3 |1.0, 1.0, 1.0| -|`normal` |Normal vector of the surface |vector3|Nworld | -|`inner_angle`|Angle of inner cone where intensity falloff starts|float |60.0 | -|`outer_angle`|Angle of outer cone where intensity goes to zero |float |0.0 | -|`out` |Output: the computed EDF |EDF | | - - - -### `measured_edf` -Constructs an EDF emitting light according to a measured IES light profile. - -|Port |Description |Type |Default | -|--------|--------------------------------------------------|--------|-------------| -|`color` |Radiant emittance of light leaving the surface |color3 |1.0, 1.0, 1.0| -|`normal`|Normal vector of the surface |vector3 |Nworld | -|`file` |Path to a file containing IES light profile data |filename|__empty__ | -|`out` |Output: the computed EDF |EDF | | - - - -### `generalized_schlick_edf` -Adds a directionally varying factor to an EDF. Scales the emission distribution of the base EDF according to a generalized Schlick Fresnel curve. - -|Port |Description |Type |Default | -|----------|-------------------------------------------------------------|------|-------------| -|`color0` |Scale factor for emittance at facing angles |color3|1.0, 1.0, 1.0| -|`color90` |Scale factor for emittance at grazing angles |color3|1.0, 1.0, 1.0| -|`exponent`|Exponent for the Schlick blending between color0 and color90 |float |5.0 | -|`base` |The base EDF to be modified |EDF |__zero__ | -|`out` |Output: the computed EDF |EDF | | - - -## VDF Nodes - - - -### `absorption_vdf` -Constructs a VDF for pure light absorption. - -The `absorption` input represents the absorption rate per distance traveled in the medium, stated in _m−1_, with independent control for each wavelength. - -|Port |Description |Type |Default | -|------------|------------------------------|-------|-------------| -|`absorption`|Absorption rate for the medium|vector3|0.0, 0.0, 0.0| -|`out` |Output: the computed VDF |VDF | | - - - -### `anisotropic_vdf` -Constructs a VDF scattering light for a participating medium, based on the Henyey-Greenstein phase function[^Pharr2023]. Forward, backward and uniform scattering is supported and controlled by the anisotropy input. - -The `absorption` input represents the absorption rate per distance traveled in the medium, stated in _m−1_, with independent control for each wavelength. - -The `anisotropy` input controls the scattering direction: negative values produce backwards scattering, positive values produce forward scattering, and 0.0 produces uniform scattering. Both absorption and scattering rates are specified per wavelength. - -|Port |Description |Type |Default |Accepted Values| -|------------|------------------------------------------|-------|-------------|---------------| -|`absorption`|Absorption rate for the medium |vector3|0.0, 0.0, 0.0| | -|`scattering`|Scattering rate for the medium |vector3|0.0, 0.0, 0.0| | -|`anisotropy`|Anisotropy factor for scattering direction|float |0.0 |[-1, 1] | -|`out` |Output: the computed VDF |VDF | | | - - -## PBR Shader Nodes - - - -### `surface` -Constructs a surface shader describing light scattering and emission for surfaces. By default the node will construct a shader for a closed surface, representing an interface to a solid volume. In this mode refraction and scattering is enabled for any transmissive BSDFs connected to this surface. By setting thin_walled to "true" the node will instead construct a thin-walled surface, representing a surface with an infinitely thin volume. In thin-walled mode refraction and scattering will be disabled. Thin-walled mode must be enabled to construct a double-sided material with different surface shaders on the front and back side of geometry (using [<surfacematerial>](./MaterialX.Specification.md#node-surfacematerial) in the standard library). - -If the `edf` input is left unconnected, no emission will occur from the surface. - -|Port |Description |Type |Default | -|-------------|----------------------------------------------|-------------|--------| -|`bsdf` |Bidirectional scattering distribution function|BSDF |__zero__| -|`edf` |Emission distribution function for the surface|EDF |__zero__| -|`opacity` |Cutout opacity for the surface |float |1.0 | -|`thin_walled`|Set to true to make the surface thin-walled |boolean |false | -|`out` |Output: the computed surface shader |surfaceshader| | - - - -### `volume` -Constructs a volume shader describing a participating medium. - -If the `edf` input is left unconnected, no emission will occur from the medium. - -|Port |Description |Type |Default | -|------|---------------------------------------------|------------|--------| -|`vdf` |Volume distribution function for the medium |VDF |__zero__| -|`edf` |Emission distribution function for the medium|EDF |__zero__| -|`out` |Output: the computed volume shader |volumeshader| | - - - -### `light` -Constructs a light shader describing an explicit light source. The light shader will emit light according to the connected EDF. If the shader is attached to geometry both sides will be considered for light emission and the EDF controls if light is emitted from both sides or not. - -|Port |Description |Type |Default | -|-----------|---------------------------------------------------|------------|--------| -|`edf` |Emission distribution function for the light source|EDF |__zero__| -|`intensity`|Intensity multiplier for the EDF's emittance |float |1.0 | -|`exposure` |Exposure control for the EDF's emittance |float |0.0 | -|`out` |Output: the computed light shader |lightshader | | - -Note that the standard library includes definitions for [**`displacement`**](./MaterialX.Specification.md#node-displacement) and [**`surface_unlit`**](./MaterialX.Specification.md#node-surfaceunlit) shader nodes. - - -## Utility Nodes - - - -### `mix` -Mix two same-type distribution functions according to a weight. Performs horizontal layering by linear interpolation between the two inputs, using the function "bg∗(1−mix) + fg∗mix". - -|Port |Description |Type |Default |Accepted Values| -|------|-------------------------------------------|--------------------|--------|---------------| -|`bg` |The first distribution function |BSDF, EDF, or VDF |__zero__| | -|`fg` |The second distribution function |Same as `bg` |__zero__| | -|`mix` |The mixing weight |float |0.0 |[0, 1] | -|`out` |Output: the mixed distribution function |Same as `bg` | | | - - - -### `layer` -Vertically layer a layerable BSDF such as [<dielectric_bsdf>](#node-dielectric-bsdf), [<generalized_schlick_bsdf>](#node-generalized-schlick-bsdf) or [<sheen_bsdf>](#node-sheen-bsdf) over a BSDF or VDF. The implementation is target specific, but a standard way of handling this is by albedo scaling, using the function "base*(1-reflectance(top)) + top", where the reflectance function calculates the directional albedo of a given BSDF. - -|Port |Description |Type |Default | -|------|--------------------------------|-----------|--------| -|`top` |The top BSDF |BSDF |__zero__| -|`base`|The base BSDF or VDF |BSDF or VDF|__zero__| -|`out` |Output: the layered distribution|BSDF | | - - - -### `add` -Additively blend two distribution functions of the same type. - -|Port |Description |Type |Default | -|------|-------------------------------------------|-----------------|--------| -|`in1` |The first distribution function |BSDF, EDF, or VDF|__zero__| -|`in2` |The second distribution function |Same as `in1` |__zero__| -|`out` |Output: the added distribution functions |Same as `in1` | | - - - -### `multiply` -Multiply the contribution of a distribution function by a scaling weight. The weight is either a float to attenuate the channels uniformly, or a color which can attenuate the channels separately. To be energy conserving the scaling weight should be no more than 1.0 in any channel. - -|Port |Description |Type |Default | -|------|-----------------------------------------|--------------------|--------| -|`in1` |The distribution function to scale |BSDF, EDF, or VDF |__zero__| -|`in2` |The scaling weight |float or color3 |1.0 | -|`out` |Output: the scaled distribution function |Same as `in1` | | - - - -### `roughness_anisotropy` -Calculates anisotropic surface roughness from a scalar roughness and anisotropy parameterization. An anisotropy value above 0.0 stretches the roughness in the direction of the surface's "tangent" vector. An anisotropy value of 0.0 gives isotropic roughness. The roughness value is squared to achieve a more linear roughness look over the input range [0,1]. - -|Port |Description |Type |Default |Accepted Values| -|------------|----------------------------------|--------|--------|---------------| -|`roughness` |Roughness value |float |0.0 |[0, 1] | -|`anisotropy`|Amount of anisotropy |float |0.0 |[0, 1] | -|`out` |Output: the computed roughness |vector2 |0.0, 0.0| | - - - -### `roughness_dual` -Calculates anisotropic surface roughness from a dual surface roughness parameterization. The roughness is squared to achieve a more linear roughness look over the input range [0,1]. - -|Port |Description |Type |Default |Accepted Values| -|-----------|----------------------------------------|--------|--------|---------------| -|`roughness`|Roughness in x and y directions |vector2 |0.0, 0.0|[0, 1] | -|`out` |Output: the computed roughness |vector2 |0.0, 0.0| | - - - -### `glossiness_anisotropy` -Calculates anisotropic surface roughness from a scalar glossiness and anisotropy parameterization. This node gives the same result as roughness anisotropy except that the glossiness value is an inverted roughness value. To be used as a convenience for shading models using the glossiness parameterization. - -|Port |Description |Type |Default|Accepted Values| -|------------|----------------------------------|--------|-------|---------------| -|`glossiness`|Glossiness value |float |0.0 |[0, 1] | -|`anisotropy`|Amount of anisotropy |float |0.0 |[0, 1] | -|`out` |Output: the computed roughness |vector2 | | | - - - -### `blackbody` -Returns the radiant emittance of a blackbody radiator with the given temperature. - -|Port |Description |Type |Default| -|-------------|-----------------------------|------|-------| -|`temperature`|Temperature in Kelvin |float |5000.0 | -|`out` |Output: the radiant emittance|color3| | - - - -### `artistic_ior` -Converts the artistic parameterization reflectivity and edge_color to complex IOR values. To be used with the [<conductor_bsdf>](#node-conductor-bsdf) node. - -|Port |Description |Type |Default | -|--------------|-----------------------------------------------------|------|-------------------| -|`reflectivity`|Reflectivity per color component at facing angles |color3|0.947, 0.776, 0.371| -|`edge_color` |Reflectivity per color component at grazing angles |color3|1.0, 0.982, 0.753 | -|`ior` |Output: Computed index of refraction |color3| | -|`extinction` |Output: Computed extinction coefficient |color3| | - - - -### `chiang_hair_roughness` -Converts the artistic parameterization hair roughness to roughness for R, TT and TRT lobes, as described in [^Chiang2016]. - -|Port |Description |Type |Default|Accepted Values| -|----------------|--------------------------------------------------------|--------|-------|---------------| -|`longitudinal` |Longitudinal roughness |float |0.1 |[0, 1] | -|`azimuthal` |Azimuthal roughness |float |0.2 |[0, 1] | -|`scale_TT` |Roughness scale for TT lobe[^Marschner2003] |float |0.5 | | -|`scale_TRT` |Roughness scale for TRT lobe[^Marschner2003] |float |2.0 | | -|`roughness_R` |Output: Roughness for R lobe |vector2 | | | -|`roughness_TT` |Output: Roughness for TT lobe |vector2 | | | -|`roughness_TRT` |Output: Roughness for TRT lobe |vector2 | | | - - - -### `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. - -|Port |Description |Type |Default |Accepted Values| -|-----------------------|----------------------------------------------------|-------|----------------------------|---------------| -|`melanin_concentration`|Amount of melanin affected to the output |float |0.25 |[0, 1] | -|`melanin_redness` |Amount of redness affected to the output |float |0.5 |[0, 1] | -|`eumelanin_color` |Eumelanin color |color3 |0.657704, 0.498077, 0.254107| | -|`pheomelanin_color` |Pheomelanin color |color3 |0.829444, 0.67032, 0.349938 | | -|`absorption` |Output: the computed absorption coefficient |vector3| | | - - - -### `chiang_hair_absorption_from_color` -Converts the hair scattering color to absorption coefficient using the mapping method described in [^Chiang2016]. - -|Port |Description |Type |Default |Accepted Values| -|---------------------|------------------------------------------------|-------|-------------|---------------| -|`color` |Scattering color |color3 |1.0, 1.0, 1.0| | -|`azimuthal_roughness`|Azimuthal roughness |float |0.2 |[0, 1] | -|`absorption` |Output: the computed absorption coefficient |vector3| | | - -
- - -# Shading Model Examples - -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]. - -A MaterialX definition and nodegraph implementation of Autodesk Standard Surface can be found here: -[https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/standard_surface.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/standard_surface.mtlx) - - -## UsdPreviewSurface - -This is a shading model proposed by Pixar for USD[^Pixar2019]. It is meant to model a physically based surface that strikes a balance between expressiveness and reliable interchange between current day DCC’s and game engines and other real-time rendering clients. - -A MaterialX definition and nodegraph implementation of UsdPreviewSurface can be found here: -[https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/usd_preview_surface.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/usd_preview_surface.mtlx) - - -## Khronos glTF PBR - -This is a shading model using the PBR material extensions in Khronos glTF specification. - -A MaterialX definition and nodegraph implementation of glTF PBR can be found here: -[https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/gltf_pbr.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/gltf_pbr.mtlx) - - -## OpenPBR Surface - -This is an open surface shading model that was designed as a collaboration between Adobe, Autodesk, and other companies in the industry, and is currently maintained as a subproject of MaterialX within the Academy Software Foundation[^Andersson2024]. - -A MaterialX definition and nodegraph implementation of OpenPBR Surface can be found here: -[https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/open_pbr_surface.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/open_pbr_surface.mtlx) - -
- - -# Shading Translation Graphs - -The MaterialX PBS Library includes a number of nodegraphs that can be used to approximately translate the input parameters for one shading model into values to drive the inputs of a different shading model, to produce the same visual results to the degree the differences between the shading models allow. Currently, the library includes translation graphs for: - -* Autodesk Standard Surface to UsdPreviewSurface -* Autodesk Standard Surface to glTF - -
- - -# References - -[^Andersson2024]: Andersson et al., **OpenPBR Surface Specification**, , 2024. - -[^Belcour2017]: Laurent Belcour, Pascal Barla, **A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence**, , 2017 - -[^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 - -[^Pixar2019]: Pixar Animation Studios, **UsdPreviewSurface Specification**, , 2019. - -[^Portsmouth2025]: Portsmouth et al., **EON: A practical energy-preserving rough diffuse BRDF**, , 2025. - -[^Turquin2019]: Emmanuel Turquin, **Practical multiple scattering compensation for microfacet models**, , 2019. - -[^Walter2007]: Bruce Walter et al., **Microfacet Models for Refraction through Rough Surfaces**, , 2007 - -[^Zeltner2022]: Tizian Zeltner et al., **Practical Multiple-Scattering Sheen Using Linearly Transformed Cosines**, , 2022 + + + +# MaterialX Physically Based Shading Nodes + +**Version 1.39** +Niklas Harrysson - Lumiere Software +Doug Smythe - Industrial Light & Magic +Jonathan Stone - Lucasfilm Advanced Development Group +June 29, 2024 + +# Introduction + +The [MaterialX Specification](./MaterialX.Specification.md) describes a number of standard nodes that may be used to construct node graphs for the processing of images, procedurally-generated values, coordinates and other data. With the addition of user-defined custom nodes, it is possible to describe complete rendering shaders using node graphs. Up to this point, there has been no standardization of the specific shader-semantic nodes used in these node graph shaders, although with the widespread shift toward physically-based shading, it appears that the industry is settling upon a number of specific BSDF and other functions with standardized parameters and functionality. + +This document describes a number of shader-semantic nodes implementing widely-used surface scattering, emission and volume distribution functions and utility nodes useful in constructing complex layered rendering shaders using node graphs. These nodes in combination with other nodes may be used with the [MaterialX Shader Generation](../DeveloperGuide/ShaderGeneration.md) system. + + +## Table of Contents + +**[Physical Material Model](#physical-material-model)** + [Scope](#scope) + [Physically Plausible Materials](#physically-plausible-materials) + [Quantities and Units](#quantities-and-units) + [Color Management](#color-management) + [Surfaces](#surfaces) +  [Layering](#layering) +  [Bump and Normal Mapping](#bump-and-normal-mapping) +  [Surface Thickness](#surface-thickness) + [Volumes](#volumes) + [Lights](#lights) + +**[MaterialX PBS Library](#materialx-pbs-library)** + [Data Types](#data-types) + [BSDF Nodes](#bsdf-nodes) + [EDF Nodes](#edf-nodes) + [VDF Nodes](#vdf-nodes) + [PBR Shader Nodes](#pbr-shader-nodes) + [Utility Nodes](#utility-nodes) + +**[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)** + + + +# Physical Material Model + +This section describes the material model used in the MaterialX Physically Based Shading (PBS) library and the rules we must follow to be physically plausible. + + +## Scope + +A material describes the properties of a surface or medium that involves how it reacts to light. To be efficient, a material model is split into different parts, where each part handles a specific type of light interaction: light being scattered at the surface, light being emitted from a surface, light being scattered inside a medium, etc. The goal of our material model definition is to describe light-material interactions typical for physically plausible rendering systems, including those in feature film production, real-time preview, and game engines. + +Our model has support for surface materials, which includes scattering and emission of light from the surface of objects, and volume materials, which includes scattering and emission of light within a participating medium. For lighting, we support local lights and distant light from environments. Geometric modification is supported in the form of bump and normal mapping as well as displacement mapping. + + +## Physically Plausible Materials + +The initial requirements for a physically-plausible material are that it 1) should be energy conserving and 2) support reciprocity. The energy conserving says that the sum of reflected and transmitted light leaving a surface must be less than or equal to the amount of light reaching it. The reciprocity requirement says that if the direction of the traveling light is reversed, the response from the material remains unchanged. That is, the response is identical if the incoming and outgoing directions are swapped. All materials implemented for ShaderGen should respect these requirements and only in rare cases deviate from it when it makes sense for the purpose of artistic freedom. + + +## Quantities and Units + +Radiometric quantities are used by the material model for interactions with the renderer. The fundamental radiometric quantity is **radiance** (measured in _Wm−2sr−1_) and gives the intensity of light arriving at, or leaving from, a given point in a given direction. If incident radiance is integrated over all directions we get **irradiance** (measured in _Wm−2_), and if we integrate this over surface area we get **power** (measured in _W_). Input parameters for materials and lights specified in photometric units can be suitably converted to their radiometric counterparts before being submitted to the renderer. + +The interpretation of the data types returned by surface and volume shaders are unspecified, and left to the renderer and the shader generator for that renderer to decide. For an OpenGL-type renderer they will be tuples of floats containing radiance calculated directly by the shader node, but for an OSL-type renderer they may be closure primitives that are used by the renderer in the light transport simulation. + +In general, a color given as input to the renderer is considered to represent a linear RGB color space. However, there is nothing stopping a renderer from interpreting the color type differently, for instance to hold spectral values. In that case, the shader generator for that renderer needs to handle this in the implementation of the nodes involving the color type. + + +## Color Management + +MaterialX supports the use of [color management systems](./MaterialX.Specification.md#color-spaces-and-color-management-systems) to associate colors with specific color spaces. A MaterialX document typically specifies the working color space that is to be used for the document as well as the color space in which input values and textures are given. If these color spaces are different from the working color space, it is the application's and shader generator's responsibility to transform them. + +The ShaderGen module has an interface that can be used to integrate support for different color management systems. A simplified implementation with some popular and commonly used color transformations is supplied and enabled by default. A full integration of OpenColorIO ([http://opencolorio.org](http://opencolorio.org)) is planned for the future. + + +## Surfaces + +In our surface shading model the scattering and emission of light is controlled by distribution functions. Incident light can be reflected off, transmitted through, or absorbed by a surface. This is represented by a Bidirectional Scattering Distribution Function (BSDF). Light can also be emitted from a surface, for instance from a light source or glowing material. This is represented by an Emission Distribution Function (EDF). The PBS library introduces the [data types](#data-types) `BSDF` and `EDF` to represent the distribution functions, and there are nodes for constructing, combining and manipulating them. + +![Physically Based Shading Diagram](media/PBSdiagram.png "Physically Based Shading Diagram") + +Another important property is the **index of refraction** (IOR), which describes how light is propagated through a medium. It controls how much a light ray is bent when crossing the interface between two media of different refractive indices. It also determines the amount of light that is reflected and transmitted when reaching the interface, as described by the Fresnel equations. + +A surface shader is represented with the data type `surfaceshader`. In the PBS library there is a [<surface>](#node-surface) node that constructs a surface shader from a BSDF and an EDF. Since there are nodes to combine and modify them, you can easily build surface shaders from different combinations of distribution functions. Inputs on the distribution function nodes can be connected, and nodes from the standard library can be combined into complex calculations, giving flexibility for the artist to author material variations over the surfaces. + +It is common for shading models to differentiate between closed surfaces and thin-walled surfaces. A closed surface represents a closed watertight interface with a solid interior. A typical example is a solid glass object. A thin-walled surface on the other hand has an infinitely thin volume, as with a sheet of paper or a soap bubble. For a closed surface there can be no backside visible if the material is opaque. In the case of a transparent closed surface a backside hit is treated as light exiting the closed interface. For a thin-walled surface both the front and back side are visible and it can either have the same material on both sides or different materials on each side. If the material is transparent in this case the thin wall makes the light transmit without refraction or scattering. By default the [<surface>](#node-surface) node constructs a surface shader for a closed surface, but there is a boolean switch to make it thin-walled. + +In order to assign different shaders to each side of a thin-walled object the [<surfacematerial>](./MaterialX.Specification.md#node-surfacematerial) node in the standard library has an input to connect an extra backside surface shader. If any of the sides of a <surfacematerial> has a thin-walled shader connected, both sides are considered to be thin-walled. Hence the thin-walled property takes precedence to avoid ambiguity between the sides. If only one side has a shader connected this is used for both sides. If both sides are connected but none of the shaders are thin-walled the front shader is used. The thin-walled property also takes precedence in the case of mixing surface shaders. If any of the shaders involved in the mix is thin-walled, both shaders are considered to be thin-walled. + +Note that in order to have surface shaders set for both sides the geometry has to be set as double-sided. Geometry sidedness is a property not handled by MaterialX and needs to be set elsewhere. + + +### Layering + +In order to simplify authoring of complex materials, our model supports the notion of layering. Typical examples include: adding a layer of clear coat over a car paint material, or putting a layer of dirt or rust over a metal surface. Layering can be done in a number of different ways: + + + +* Horizontal Layering: A simple way of layering is using per-shading-point linear mixing of different BSDFs where a mix factor is given per BSDF controlling its contribution. Since the weight is calculated per shading point it can be used as a mask to hide contributions on different parts of a surface. The weight can also be calculated dependent on view angle to simulate approximate Fresnel behavior. This type of layering can be done both on a BSDF level and on a surface shader level. The latter is useful for mixing complete shaders which internally contain many BSDFs, e.g. to put dirt over a car paint, grease over a rusty metal or adding decals to a plastic surface. We refer to this type of layering as **horizontal layering** and the [<mix>](#node-mix) node in the PBS library can be used to achieve this (see below). +* Vertical Layering: A more physically correct form of layering is also supported where a top BSDF layer is placed over another base BSDF layer, and the light not reflected by the top layer is assumed to be transmitted to the base layer; for example, adding a dielectric coating layer over a substrate. The refraction index and roughness of the coating will then affect the attenuation of light reaching the substrate. The substrate can be a transmissive BSDF to transmit the light further, or a reflective BSDF to reflect the light back up through the coating. The substrate can in turn be a reflective BSDF to simulate multiple specular lobes. We refer to this type of layering as **vertical layering** and it can be achieved using the [<layer>](#node-layer) node in the PBS library. See [<dielectric_bsdf>](#node-dielectric-bsdf) and [<sheen_bsdf>](#node-sheen-bsdf) below. +* Shader Input Blending: Calculating and blending many BSDFs or separate surface shaders can be expensive. In some situations good results can be achieved by blending the texture/value inputs instead, before any illumination calculations. Typically one would use this with an über-shader that can simulate many different materials, and by masking or blending its inputs over the surface you get the appearance of having multiple layers, but with less expensive texture or value blending. Examples of this are given in the main [MaterialX Specification "Pre-Shader Compositing Example"](./MaterialX.Specification.md#example-pre-shader-compositing-material). + + +### Bump and Normal Mapping + +The surface normal used for shading calculations is supplied as input to each BSDF that requires it. The normal can be perturbed by bump or normal mapping, before it is given to the BSDF. As a result, one can supply different normals for different BSDFs for the same shading point. When layering BSDFs, each layer can use different bump and normal maps. + + +## Volumes + +In our volume shader model the scattering of light in a participating medium is controlled by a volume distribution function (VDF), with coefficients controlling the rate of absorption and scattering. The VDF represents what physicists call a _phase function, _describing how the light is distributed from its current direction when it is scattered in the medium. This is analogous to how a BSDF describes scattering at a surface, but with one important difference: a VDF is normalized, summing to 1.0 if all directions are considered. Additionally, the amount of absorption and scattering is controlled by coefficients that gives the rate (probability) per distance traveled in world space. The **absorption coefficient** sets the rate of absorption for light traveling through the medium, and the **scattering coefficient** sets the rate of which the light is scattered from its current direction. The unit for these are _m−1_. + +Light can also be emitted from a volume. This is represented by an EDF analog to emission from surfaces, but in this context the emission is given as radiance per distance traveled through the medium. The unit for this is _Wm−3sr−1_. The emission distribution is oriented along the current direction. + +The [<volume>](#node-volume) node in the PBS library constructs a volume shader from individual VDF and EDF components. There are also nodes to construct various VDFs, as well as nodes to combine them to build more complex ones. + +VDFs can also be used to describe the interior of a surface. A typical example would be to model how light is absorbed or scattered when transmitted through colored glass or turbid water. This is done by layering a BSDF for the surface transmission over the VDF using a [<layer>](#node-layer) node. + + +## Lights + +Light sources can be divided into environment lights and local lights. Environment lights represent contributions coming from infinitely far away. All other lights are local lights and have a position and extent in space. + +Local lights are specified as light shaders assigned to a locator, modeling an explicit light source, or in the form of emissive geometry using an emissive surface shader. The [<light>](#node-light) node in the PBS library constructs a light shader from an EDF. There are also nodes to construct various EDFs as well as nodes to combine them to build more complex ones. Emissive properties of surface shaders are also modelled using EDFs; see the [**EDF Nodes**](#edf-nodes) section below for more information. + +Light contributions coming from far away are handled by environment lights. These are typically photographically-captured or procedurally-generated images that surround the whole scene. This category of lights also includes sources like the sun, where the long distance traveled makes the light essentially directional and without falloff. For all shading points, an environment is seen as being infinitely far away. + + + +# MaterialX PBS Library + +MaterialX includes a library of types and nodes for creating physically plausible materials and lights as described above. This section outlines the content of that library. + + +## Data Types + +* `BSDF`: Data type representing a Bidirectional Scattering Distribution Function. +* `EDF`: Data type representing an Emission Distribution Function. +* `VDF`: Data type representing a Volume Distribution Function. + +The PBS nodes also make use of the following standard MaterialX types: + +* `surfaceshader`: Data type representing a surface shader. +* `lightshader`: Data type representing a light shader. +* `volumeshader`: Data type representing a volume shader. +* `displacementshader`: Data type representing a displacement shader. + + +## BSDF Nodes + + + +* **`oren_nayar_diffuse_bsdf`**: Constructs a diffuse reflection BSDF based on the Oren-Nayar reflectance model. A `roughness` of 0.0 gives Lambertian reflectance. An `energy_compensation` boolean selects between classic Oren-Nayar behavior[^Oren1994] and the energy-compensated Oren-Nayar in OpenPBR[^Andersson2024]. + * `weight` (float): Weight for this BSDF’s contribution, range [0.0, 1.0]. Defaults to 1.0. + * `color` (color3): Diffuse reflectivity (albedo). Defaults to (0.18, 0.18, 0.18). + * `roughness `(float): Surface roughness, range [0.0, 1.0]. Defaults to 0.0. + * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. + * `energy_compensation` (uniform boolean): Set to `true` to enable energy compensation. Defaults to `false`. + + + +* **`burley_diffuse_bsdf`**: Constructs a diffuse reflection BSDF based on the corresponding component of the Disney Principled model[^Burley2012]. + * `weight` (float): Weight for this BSDF’s contribution, range [0.0, 1.0]. Defaults to 1.0. + * `color` (color3): Diffuse reflectivity (albedo). Defaults to (0.18, 0.18, 0.18). + * `roughness` (float): Surface roughness, range [0.0, 1.0]. Defaults to 0.0. + * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. + + + +* **`dielectric_bsdf`**: Constructs a reflection and/or transmission BSDF based on a microfacet reflectance model and a Fresnel curve for dielectrics[^Walter2007]. If reflection scattering is enabled the node may be layered vertically over a base BSDF for the surface beneath the dielectric layer. By chaining multiple <dielectric_bsdf> nodes you can describe a surface with multiple specular lobes. If transmission scattering is enabled the node may be layered over a VDF describing the surface interior to handle absorption and scattering inside the medium, useful for colored glass, turbid water, etc. + * `weight` (float): Weight for this BSDF’s contribution, range [0.0, 1.0]. Defaults to 1.0. + * `tint` (color3): Color weight to tint the reflected and transmitted light. Defaults to (1.0, 1.0, 1.0). Note that changing the tint gives non-physical results and should only be done when needed for artistic purposes. + * `ior` (float): Index of refraction of the surface. Defaults to 1.5. If set to 0.0 the Fresnel curve is disabled and reflectivity is controlled only by weight and tint. + * `roughness` (vector2): Surface roughness. Defaults to (0.05, 0.05). + * `thinfilm_thickness` (float): The thickness of an iridescent thin film layer[^Belcour2017] applied over the base bsdf, expressed in nanometers. Defaults to 0.0, for no thin film. + * `thinfilm_ior` (float): The index of refraction of the thin film layer. Defaults to 1.5. + * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. + * `tangent` (vector3): Tangent vector of the surface. Defaults to world space tangent. + * `distribution` (uniform string): Microfacet distribution type. Defaults to `ggx`. + * `scatter_mode` (uniform string): Scattering mode, specifying whether the BSDF supports reflection `R`, transmission `T` or both reflection and transmission `RT`. With `RT`, reflection and transmission occur both when entering and leaving a surface, with their respective intensities controlled by the Fresnel curve. Depending on the IOR and incident angle, it is possible for total internal reflection to occur, generating no transmission even if `T` or `RT` is selected. Defaults to `R`. + + + +* **`conductor_bsdf`**: Constructs a reflection BSDF based on a microfacet reflectance model[^Burley2012]. Uses a Fresnel curve with complex refraction index for conductors/metals. If an artistic parametrization[^Gulbrandsen2014] is needed the [<artistic_ior>](#node-artistic-ior) utility node can be connected to handle this. + * `weight` (float): Weight for this BSDF’s contribution, range [0.0, 1.0]. Defaults to 1.0. + * `ior `(color3): Index of refraction. Defaults to (0.18, 0.42, 1.37) (approximate IOR for gold). + * `extinction` (color3): Extinction coefficient. Defaults to (3.42, 2.35, 1.77) (approximate extinction coefficients for gold). + * `roughness` (vector2): Surface roughness. Defaults to (0.05, 0.05). + * `thinfilm_thickness` (float): The thickness of an iridescent thin film layer[^Belcour2017] applied over the base bsdf, expressed in nanometers. Defaults to 0.0, for no thin film. + * `thinfilm_ior` (float): The index of refraction of the thin film layer. Defaults to 1.5. + * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. + * `tangent` (vector3): Tangent vector of the surface. Defaults to world space tangent. + * `distribution` (uniform string): Microfacet distribution type. Defaults to `ggx`. + + + +* **`generalized_schlick_bsdf`**: Constructs a reflection and/or transmission BSDF based on a microfacet model and a generalized Schlick Fresnel curve[^Hoffman2023]. If reflection scattering is enabled the node may be layered vertically over a base BSDF for the surface beneath the dielectric layer. By chaining multiple <generalized_schlick_bsdf> nodes you can describe a surface with multiple specular lobes. If transmission scattering is enabled the node may be layered over a VDF describing the surface interior to handle absorption and scattering inside the medium, useful for colored glass, turbid water, etc. + * `weight` (float): Weight for this BSDF’s contribution, range [0.0, 1.0]. Defaults to 1.0. + * `color0` (color3): Reflectivity per color component at facing angles. Defaults to (1.0, 1.0, 1.0). + * `color82` (color3): A multiplier on the reflectivity per color component at 82 degrees, useful for capturing the "dip" in the reflectance curve of metallic surfaces. Defaults to (1.0, 1.0, 1.0), which effectively disables "color82" for backward compatibility. + * `color90` (color3): Reflectivity per color component at grazing angles. Defaults to (1.0, 1.0, 1.0). + * `exponent` (float): Exponent for the Schlick blending between `color0` and `color90`. Defaults to 5.0. + * `roughness` (vector2): Surface roughness. Defaults to (0.05, 0.05). + * `thinfilm_thickness` (float): The thickness of an iridescent thin film layer[^Belcour2017] applied over the base bsdf, expressed in nanometers. Defaults to 0.0, for no thin film. + * `thinfilm_ior` (float): The index of refraction of the thin film layer. Defaults to 1.5. + * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. + * `tangent` (vector3): Tangent vector of the surface. Defaults to world space tangent. + * `distribution` (uniform string): Microfacet distribution type. Defaults to `ggx`. + * `scatter_mode` (uniform string): Scattering mode, specifying whether the BSDF supports reflection `R`, transmission `T` or both reflection and transmission `RT`. With `RT`, reflection and transmission occur both when entering and leaving a surface, with their respective intensities controlled by the Fresnel curve. Depending on the IOR and incident angle, it is possible for total internal reflection to occur, generating no transmission even if `T` or `RT` is selected. Defaults to `R`. + + + +* **`translucent_bsdf`**: Constructs a translucent (diffuse transmission) BSDF based on the Lambert reflectance model. + * `weight` (float): Weight for this BSDF’s contribution, range [0.0, 1.0]. Defaults to 1.0. + * `color` (color3): Diffuse transmittance. Defaults to (1.0, 1.0, 1.0). + * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. + + + +* **`subsurface_bsdf`**: Constructs a subsurface scattering BSDF for subsurface scattering within a homogeneous medium. The parameterization is chosen to match random walk Monte Carlo methods as well as approximate empirical methods[^Christensen2015]. Note that this category of subsurface scattering can be defined more rigorously as a BSDF vertically layered over an [](#node-anisotropic-vdf), and we expect these two descriptions of the scattering-surface distribution function to be unified in future versions of MaterialX. + * `weight` (float): Weight for this BSDF’s contribution, range [0.0, 1.0]. Defaults to 1.0. + * `color` (color3): Diffuse reflectivity (albedo). Defaults to (0.18, 0.18, 0.18). + * `radius` (color3): Sets the average distance that light might propagate below the surface before scattering back out. This is also known as the mean free path of the material. The radius can be set for each color component separately. Defaults to (1, 1, 1). + * `anisotropy` (float): Anisotropy factor, controlling the scattering direction, range [-1.0, 1.0]. Negative values give backwards scattering, positive values give forward scattering, and a value of zero gives uniform scattering. Defaults to 0.0. + * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. + + + +* **`sheen_bsdf`**: Constructs a microfacet BSDF for the back-scattering properties of cloth-like materials. This node may be layered vertically over a base BSDF using a [<layer>](#node-layer) node. All energy that is not reflected will be transmitted to the base layer. A `mode` option selects between two available sheen models, Conty-Kulla[^Conty2017] and Zeltner[^Zeltner2022]. + * `weight` (float): Weight for this BSDF’s contribution, range [0.0, 1.0]. Defaults to 1.0. + * `color` (color3): Sheen reflectivity. Defaults to (1.0, 1.0, 1.0). + * `roughness` (float): Surface roughness, range [0.0, 1.0]. Defaults to 0.3. + * `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`. + + +## EDF Nodes + + + +* **`uniform_edf`**: Constructs an EDF emitting light uniformly in all directions. + * `color` (color3): Radiant emittance of light leaving the surface. Defaults to (1, 1, 1). + + + +* **`conical_edf`**: Constructs an EDF emitting light inside a cone around the normal direction. + * `color` (color3): Radiant emittance of light leaving the surface. Defaults to (1, 1, 1). + * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. + * `inner_angle` (uniform float): Angle of inner cone where intensity falloff starts (given in degrees). Defaults to 60. + * `outer_angle` (uniform float): Angle of outer cone where intensity goes to zero (given in degrees). If set to a smaller value than inner angle no falloff will occur within the cone. Defaults to 0. + + + +* **`measured_edf`**: Constructs an EDF emitting light according to a measured IES light profile. + * `color` (color3): Radiant emittance of light leaving the surface. Defaults to (1, 1, 1). + * `normal` (vector3): Normal vector of the surface. Defaults to world space normal. + * `file` (uniform filename): Path to a file containing IES light profile data. Defaults to "". + + + +* **`generalized_schlick_edf`**: Adds a directionally varying factor to an EDF. Scales the emission distribution of the base EDF according to a generalized Schlick Fresnel curve. + * `color0` (color3): Scale factor for emittance at facing angles. Defaults to (1, 1, 1). + * `color90` (color3): Scale factor for emittance at grazing angles. Defaults to (1, 1, 1). + * `exponent` (float): Exponent for the Schlick blending between `color0` and `color90`. Defaults to 5.0. + * `base` (EDF): The base EDF to be modified. Defaults to "". + + +## VDF Nodes + + + +* **`absorption_vdf`**: Constructs a VDF for pure light absorption. + * `absorption` (color3): Absorption rate for the medium (rate per distance traveled in the medium, given in _m−1_). Set for each color component/wavelength separately. Defaults to (0, 0, 0). + + + +* **`anisotropic_vdf`**: Constructs a VDF scattering light for a participating medium, based on the Henyey-Greenstein phase function[^Pharr2023]. Forward, backward and uniform scattering is supported and controlled by the anisotropy input. + * `absorption` (color3): Absorption rate for the medium (rate per distance traveled in the medium, given in _m−1_). Set for each color component/wavelength separately. Defaults to (0, 0, 0). + * `scattering` (color3): Scattering rate for the medium (rate per distance traveled in the medium, given in _m−1_). Set for each color component/wavelength separately. Defaults to (0, 0, 0). + * `anisotropy` (float): Anisotropy factor, controlling the scattering direction, range [-1.0, 1.0]. Negative values give backwards scattering, positive values give forward scattering, and a value of 0.0 (the default) gives uniform scattering. + + +## PBR Shader Nodes + + + +* **`surface`**: Constructs a surface shader describing light scattering and emission for surfaces. By default the node will construct a shader for a closed surface, representing an interface to a solid volume. In this mode refraction and scattering is enabled for any transmissive BSDFs connected to this surface. By setting thin_walled to "true" the node will instead construct a thin-walled surface, representing a surface with an infinitely thin volume. In thin-walled mode refraction and scattering will be disabled. Thin-walled mode must be enabled to construct a double-sided material with different surface shaders on the front and back side of geometry (using [<surfacematerial>](./MaterialX.Specification.md#node-surfacematerial) in the standard library). Output type "surfaceshader". + * `bsdf` (BSDF): Bidirectional scattering distribution function for the surface. Defaults to "". + * `edf` (EDF): Emission distribution function for the surface. If unconnected, then no emission will occur. + * `opacity` (float): Cutout opacity for the surface. Defaults to 1.0. + * `thin_walled` (boolean): Set to `true` to make the surface thin-walled. Defaults to `false`. + + + +* **`volume`**: Constructs a volume shader describing a participating medium. Output type "volumeshader". + * `vdf` (VDF): Volume distribution function for the medium. Defaults to "". + * `edf` (EDF): Emission distribution function for the medium. If unconnected, then no emission will occur. + + + +* **`light`**: Constructs a light shader describing an explicit light source. The light shader will emit light according to the connected EDF. If the shader is attached to geometry both sides will be considered for light emission and the EDF controls if light is emitted from both sides or not. Output type "lightshader". + * `edf` (EDF): Emission distribution function for the light source. Defaults to no emission. + * `intensity` (color3): Intensity multiplier for the EDF’s emittance. Defaults to (1.0, 1.0, 1.0). + * `exposure` (float): Exposure control for the EDF’s emittance. Defaults to 0.0. + +Note that the standard library includes definitions for [**`displacement`**](./MaterialX.Specification.md#node-displacement) and [**`surface_unlit`**](./MaterialX.Specification.md#node-surfaceunlit) shader nodes. + + + +## Utility Nodes + + + +* **`mix`**: Mix two same-type distribution functions according to a weight. Performs horizontal layering by linear interpolation between the two inputs, using the function "bg∗(1−mix) + fg∗mix". + * `bg` (BSDF or EDF or VDF): The first distribution function. Defaults to "". + * `fg` (same type as `bg`): The second distribution function. Defaults to "". + * `mix` (float): The mixing weight, range [0.0, 1.0]. Defaults to 0. + + + +* **`layer`**: Vertically layer a layerable BSDF such as [<dielectric_bsdf>](#node-dielectric-bsdf), [<generalized_schlick_bsdf>](#node-generalized-schlick-bsdf) or [<sheen_bsdf>](#node-sheen-bsdf) over a BSDF or VDF. The implementation is target specific, but a standard way of handling this is by albedo scaling, using the function "base*(1-reflectance(top)) + top", where the reflectance function calculates the directional albedo of a given BSDF. + * `top` (BSDF): The top BSDF. Defaults to "". + * `base` (BSDF or VDF): The base BSDF or VDF. Defaults to "". + + + +* **`add`**: Additively blend two distribution functions of the same type. + * `in1` (BSDF or EDF or VDF): The first distribution function. Defaults to "". + * `in2` (same type as `in1`): The second distribution function. Defaults to "". + + + +* **`multiply`**: Multiply the contribution of a distribution function by a scaling weight. The weight is either a float to attenuate the channels uniformly, or a color which can attenuate the channels separately. To be energy conserving the scaling weight should be no more than 1.0 in any channel. + * `in1` (BSDF or EDF or VDF): The distribution function to scale. Defaults to "". + * `in2` (float or color3): The scaling weight. Defaults to 1.0. + + + +* **`roughness_anisotropy`**: Calculates anisotropic surface roughness from a scalar roughness and anisotropy parameterization. An anisotropy value above 0.0 stretches the roughness in the direction of the surface's "tangent" vector. An anisotropy value of 0.0 gives isotropic roughness. The roughness value is squared to achieve a more linear roughness look over the input range [0,1]. Output type `vector2`. + * `roughness` (float): Roughness value, range [0.0, 1.0]. Defaults to 0.0. + * `anisotropy` (float): Amount of anisotropy, range [0.0, 1.0]. Defaults to 0.0. + + + +* **`roughness_dual`**: Calculates anisotropic surface roughness from a dual surface roughness parameterization. The roughness is squared to achieve a more linear roughness look over the input range [0,1]. Output type `vector2`. + * `roughness` (vector2): Roughness in x and y directions, range [0.0, 1.0]. Defaults to (0.0, 0.0). + + + +* **`glossiness_anisotropy`**: Calculates anisotropic surface roughness from a scalar glossiness and anisotropy parameterization. This node gives the same result as roughness anisotropy except that the glossiness value is an inverted roughness value. To be used as a convenience for shading models using the glossiness parameterization. Output type `vector2`. + * `glossiness` (float): Roughness value, range [0.0, 1.0]. Defaults to 0.0. + * `anisotropy` (float): Amount of anisotropy, range [0.0, 1.0]. Defaults to 0.0. + + + +* **`blackbody`**: Returns the radiant emittance of a blackbody radiator with the given temperature. Output type `color3`. + * `temperature` (float): Temperature in Kelvin. Defaults to 5000. + + + +* **`artistic_ior`**: Converts the artistic parameterization reflectivity and edge_color to complex IOR values. To be used with the [<conductor_bsdf>](#node-conductor-bsdf) node. + * `reflectivity` (color3): Reflectivity per color component at facing angles. Defaults to (0.947, 0.776, 0.371). + * `edge_color` (color3): Reflectivity per color component at grazing angles. Defaults to (1.0, 0.982, 0.753). + * `ior` (**output**, vector3): Computed index of refraction. + * `extinction` (**output**, vector3): Computed extinction coefficient. + + + +# Shading Model Examples + +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. + + +## 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]. + +A MaterialX definition and nodegraph implementation of Autodesk Standard Surface can be found here: +[https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/standard_surface.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/standard_surface.mtlx) + + +## UsdPreviewSurface + +This is a shading model proposed by Pixar for USD[^Pixar2019]. It is meant to model a physically based surface that strikes a balance between expressiveness and reliable interchange between current day DCC’s and game engines and other real-time rendering clients. + +A MaterialX definition and nodegraph implementation of UsdPreviewSurface can be found here: +[https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/usd_preview_surface.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/usd_preview_surface.mtlx) + + +## Khronos glTF PBR + +This is a shading model using the PBR material extensions in Khronos glTF specification. + +A MaterialX definition and nodegraph implementation of glTF PBR can be found here: +[https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/gltf_pbr.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/gltf_pbr.mtlx) + + +## OpenPBR Surface + +This is an open surface shading model that was designed as a collaboration between Adobe, Autodesk, and other companies in the industry, and is currently maintained as a subproject of MaterialX within the Academy Software Foundation[^Andersson2024]. + +A MaterialX definition and nodegraph implementation of OpenPBR Surface can be found here: +[https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/open_pbr_surface.mtlx](https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/bxdf/open_pbr_surface.mtlx) + + + +# Shading Translation Graphs + +The MaterialX PBS Library includes a number of nodegraphs that can be used to approximately translate the input parameters for one shading model into values to drive the inputs of a different shading model, to produce the same visual results to the degree the differences between the shading models allow. Currently, the library includes translation graphs for: + +* Autodesk Standard Surface to UsdPreviewSurface +* Autodesk Standard Surface to glTF + + +# References + +[^Andersson2024]: Andersson et al., **OpenPBR Surface Specification**, , 2024. + +[^Belcour2017]: Laurent Belcour, Pascal Barla, **A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence**, , 2017 + +[^Burley2012]: Brent Burley, **Physically-Based Shading at Disney**, , 2012 + +[^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 + +[^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 + +[^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 + +[^Pixar2019]: Pixar Animation Studios, **UsdPreviewSurface Specification**, , 2019. + +[^Walter2007]: Bruce Walter et al., **Microfacet Models for Refraction through Rough Surfaces**, , 2007 + +[^Zeltner2022]: Tizian Zeltner et al., **Practical Multiple-Scattering Sheen Using Linearly Transformed Cosines**, , 2022 diff --git a/MaterialX/documents/Specification/MaterialX.Proposals.md b/MaterialX/documents/Specification/MaterialX.Proposals.md old mode 100644 new mode 100755 index 4548bda..56e159a --- a/MaterialX/documents/Specification/MaterialX.Proposals.md +++ b/MaterialX/documents/Specification/MaterialX.Proposals.md @@ -1,337 +1,331 @@ - - - -# 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 - -(Summary for README.md: **New Support for Shader AOVs** - -Previously, MaterialX used custom types with a structure of output variables to define shader AOVs. But this approach was not very flexible and in fact had not been implemented. In v1.39, nodegraph-based shader implementations can include new [<aovoutput> elements](./MaterialX.Specification.md#aov-output-elements) to define AOVs which renderers can use to output additional channels of information in addition to the final shading result, while file-based <implementation>s can similarly define AOVs using [<aov> elements](./MaterialX.Specification.md#implementation-aov-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 - - - -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 - -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 - + + + +# MaterialX: Proposed Additions and Changes + +**Proposals for Version 1.39** +July 26, 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. + + + +### 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. + + + +### 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/MaterialX/documents/Specification/MaterialX.Specification.md b/MaterialX/documents/Specification/MaterialX.Specification.md old mode 100644 new mode 100755 index 2904920..c8e1f88 --- a/MaterialX/documents/Specification/MaterialX.Specification.md +++ b/MaterialX/documents/Specification/MaterialX.Specification.md @@ -1,1582 +1,2722 @@ - - - -# MaterialX: An Open Standard for Network-Based CG Object Looks - -**Version 1.39** -Doug Smythe - Industrial Light & Magic -Jonathan Stone - Lucasfilm Advanced Development Group -March 15, 2025 - - -# Introduction - -Computer graphics production studios commonly use workflows involving multiple software tools for different parts of the production pipeline. There is also a significant amount of sharing and outsourcing of work across facilities, requiring companies to hand off fully look-developed models to other divisions or studios which may use different software packages and rendering systems. In addition, studio rendering pipelines that previously used monolithic shaders built by expert programmers or technical directors with fixed, predetermined texture-to-shader connections and hard-coded texture color-correction options are now using more flexible node-based shader networks built up by connecting images and procedurals to shader inputs through a graph of image processing and blending operators. - -At least four distinct interrelated data relationships are required to specify the complete "look" of a CG object: - -1. _Image processing networks_ of sources, operators, connections and input values, outputting a number of spatially-varying data streams. -2. _Geometry-specific information_ such as associated texture filenames or IDs for various map types. -3. Associations between spatially-varying data streams and/or uniform values and the inputs of surface, volume, or other shaders, defining a number of _materials_. -4. Associations between materials and specific geometries to create a number of _looks_. - -**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 Standard Nodes**](./MaterialX.StandardNodes.md), [**MaterialX Physically Based Shading Nodes**](./MaterialX.PBRSpec.md) and [**MaterialX NPR Shading Nodes**](./MaterialX.NPRSpec.md) describe the standard mathematical, pattern and shading nodes of MaterialX, while companion documents [**MaterialX Geometry Extensions**](./MaterialX.GeomExts.md) and [**MaterialX Supplemental Notes**](./MaterialX.Supplement.md) describe additional element types and other information about the library, while [**MaterialX: Proposed Additions and Changes**](./MaterialX.Proposals.md) describes forward-looking proposed functionality for MaterialX. - - - -## Table of Contents - -**[Introduction](#introduction)** - -**[MaterialX Overview](#materialx-overview)** - [Definitions](#definitions) - [MaterialX Names](#materialx-names) - [MaterialX Data Types](#materialx-data-types) - [Custom Data Types](#custom-data-types) - [MTLX File Format Definition](#mtlx-file-format-definition) - [Color Spaces and Color Management Systems](#color-spaces-and-color-management-systems) - [Units](#units) - [MaterialX Namespaces](#materialx-namespaces) - [Geometric Properties](#geometric-properties) - [Geometric Spaces](#geometric-spaces) - [File Prefixes](#file-prefixes) - [Filename Substitutions](#filename-substitutions) - -**[Nodes](#nodes)** - [Inputs](#inputs) - [Node Graph Elements](#node-graph-elements) - [Output Elements](#output-elements) - [Standard Nodes](#standard-nodes) - [Standard Node Inputs](#standard-node-inputs) - [Standard UI Attributes](#standard-ui-attributes) - [Backdrop Elements](#backdrop-elements) - [Node Graph Examples](#node-graph-examples) - -**[Customization, Targeting and Shading](#customization-targeting-and-shading)** - [Target Definition](#target-definition) - [Custom Attributes and Inputs](#custom-attributes-and-inputs) - - [Custom Nodes](#custom-nodes) -  [Custom Node Declaration NodeDef Elements](#custom-node-declaration-nodedef-elements) -   [NodeDef Parameter Interface](#nodedef-parameter-interface) -   [NodeDef Input Elements](#nodedef-input-elements) -   [NodeDef Token Elements](#nodedef-token-elements) -   [NodeDef Output Elements](#nodedef-output-elements) -  [Custom Node Definition Using Implementation Elements](#custom-node-definition-using-implementation-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) -   [Compound Nodegraphs](#compound-nodegraphs) -   [Example Custom Node Defined by a Nodegraph](#example-custom-node-defined-by-a-nodegraph) -  [Custom Node Use](#custom-node-use) - [Shader Nodes](#shader-nodes) - [Material Nodes](#material-nodes) -  [Example Pre-Shader Compositing Material](#example-pre-shader-compositing-material) - [Material Variants](#material-variants) - -**[References](#references)** - -
- - -# MaterialX Overview - -The diagram below gives a high-level overview of a typical MaterialX look definition. A directed acyclic graph of pattern generation and processing nodes is connected to inputs of a surface Shader which defines a layered BSDF response. One or more shaders can be connected to form a Material, which is ultimately associated with specific scene geometry via a MaterialAssign, a number of which comprise a Look. The assignments of Materials to geometries can be defined within a MaterialX document in applications supporting MaterialX Geometry Extensions, or using an alternative mechanism such as USD[^1] or a native application's toolset. Each of the pattern nodes and even the Shaders may in turn be implemented using a graph of nodes: these NodeGraphs are given a parameter interface using NodeDefs, and these implementations may be reused with different input values just like any other Standard node defined by MaterialX. - -![MaterialX Overview Diagram](media/MaterialX_1.39_Overview_v5.png "MaterialX Overview Diagram") - -MaterialX also allows the specification of additional information not shown in this diagram, such as geometry-specific properties, material variations, arbitrary custom inputs and attributes for nodes, rendering-target-specific versions of shaders, nodes and implementations, external compiled or generated shader implementations, and much more. - - - -## Definitions - -Because the same word can be used to mean slightly different things in different contexts, and because each studio and package has its own vocabulary, it's important to define exactly what we mean by any particular term in this proposal and use each term consistently. - -An **Element** is a named object within a MaterialX document, which may possess any number of child elements and attributes. An **Attribute** is a named property of a MaterialX element. - -A **Node** is a function that generates or operates upon spatially-varying data. This specification provides a set of standard nodes with precise definitions, and also supports the creation of custom nodes for application-specific uses. The interface for a node’s incoming data is declared through **Inputs**, which may be spatially-varying or uniform, and **Tokens**, which are string values that can be substituted into filenames declared in node inputs. The interface for a node's outgoing data is declared through one or more **Outputs**; a node's Inputs, Tokens and Outputs are collectively referred to as the node's **Ports**. - -A **Pattern** is a node that generates or processes simple scalar, vector, and color data, and has access to local properties of any geometry that has been bound. - -A **Shader** is a node that can generate or process arbitrary lighting or BSDF data, and has access to global properties of the scene in which it is evaluated. - -A **Material** is a node which internally or externally references one or more shaders with specific data streams or uniform values bound to their inputs. - -A **Node Graph** is a directed acyclic graph of nodes, which may be used to define arbitrarily complex generation or processing networks. Common uses of Node Graphs are to describe a network of pattern nodes flowing into shader inputs, or to define a complex or layered node in terms of simpler nodes. - -A **Stream** refers to a flow of spatially-varying data from one node to another. A Stream most commonly consists of color, vector, or scalar data, but can transport data of any standard or custom type. - -A **Layer** is a named 1-, 2-, 3- or 4-channel color "plane" within an image file. Image file formats that do not support multiple or named layers within a file should be treated as if the (single) layer was named "rgba". - -A **Channel** is a single float value within a color or vector value, e.g. each layer of an image might have a red Channel, a green Channel, a blue Channel and an alpha Channel. - -A **Geometry** is any renderable object, while a **Partition** refers to a specific named renderable subset of a piece of geometry, such as a face set. - -A **Collection** is a recipe for building a list of geometries, which can be used as a shorthand for assigning e.g. a Material to a number of geometries in a Look. - -A **Target** is a software environment that interprets MaterialX content to generate images, with common examples being digital content creation tools and 3D renderers. - - - -## MaterialX Names - -All elements in MaterialX (nodes, materials, shaders, etc.) are required to have a `name` attribute of type "string". The `name` attribute of a MaterialX element is its unique identifier, and no two elements within the same scope (i.e. elements with the same parent) may share a name. - -Element names are restricted to upper- and lower-case letters, numbers, and underscores (“_”) from the ASCII character set; all other characters and symbols are disallowed. MaterialX names are case-sensitive and are not allowed to begin with a digit. - - - -## MaterialX Data Types - -All values, input and output ports, and streams in MaterialX are strongly typed, and are explicitly associated with a specific data type. The following standard data types are defined by MaterialX: - -**Base Types**: - -``` - integer, boolean, float, - color3, color4, - vector2, vector3, vector4, - matrix33, matrix44, string, filename -``` - -**Array Types**: - -``` - integerarray, floatarray, - color3array, color4array, - vector2array, vector3array, vector4array, - stringarray -``` - - -The following examples show the appropriate syntax for MaterialX attributes in MTLX files: - -**Integer**, **Float**: just a value inside quotes: - -``` - integervalue = "1" - floatvalue = "1.0" -``` - -**Boolean**: the lower-case word "true" or "false" inside quotes: - -``` - booleanvalue = "true" -``` - -**Color** types: MaterialX supports two different color types: - -* color3 (red, green, blue) -* color4 (red, green, blue, alpha) - -Color channel values should be separated by commas (with or without whitespace), within quotes: - -``` - color3value = "0.1,0.2,0.3" - color4value = "0.1,0.2,0.3,1.0" -``` - -Note: all color3 values and the RGB components of a color4 value are presumed to be specified in the "working color space" defined in the enclosing <materialx> element, although any element within a document may provide a `colorspace` attribute that explicitly states the space in which color values within its scope should be interpreted; implementations are expected to translate those color values into the working color space before performing computations with those values. See the [Color Spaces and Color Management Systems](#color-spaces-and-color-management-systems) section below. - -**Vector** types: similar to colors, MaterialX supports three different vector types: - -* vector2 (x, y) -* vector3 (x, y, z) -* vector4 (x, y, z, w) - -Coordinate values should be separated by commas (with or without whitespace), within quotes: - -``` - vector2value = "0.234,0.885" - vector3value = "-0.13,12.883,91.7" - vector4value = "-0.13,12.883,91.7,1.0" -``` - -While colorN and vectorN types both describe vectors of floating-point values, they differ in a number of significant ways. First, the final channel of a color4 value is interpreted as an alpha channel by compositing operators, and is only meaningful within the [0, 1] range, while the fourth channel of a vector4 value _could be_ (but is not necessarily) interpreted as the "w" value of a homogeneous 3D vector. Additionally, values of type color3 and color4 are always associated with a particular color space and are affected by color transformations, while values of type vector3 and vector4 are not. More detailed rules for colorN and vectorN operations may be found in the [Standard Operator Nodes](./MaterialX.StandardNodes.md#standard-operator-nodes) section of the specification. - -**Matrix** types: MaterialX supports two matrix types that may be used to represent geometric and color transforms. The `matrix33` and `matrix44` types, respectively, represent 3x3 and 4x4 matrices and are written as nine or sixteen float values separated by commas, in row-major order: - -``` - matrix33value = "1,0,0, 0,1,0, 0,0,1" - matrix44value = "1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1" -``` - -**String**: literal text within quotes. See the [MTLX File Format Definition](#mtlx-file-format-definition) section for details on representing special characters within string data. - -``` - stringvalue = "some text" -``` - -**Filename**: attributes of type "filename" are just strings within quotes, but specifically mean a Uniform Resource Identifier ([https://en.wikipedia.org/wiki/Uniform_Resource_Identifier](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier)) optionally containing one or more Filename Substitution strings (see below) that represents a reference to an external asset, such as a file on disk or a query into a content management system. - -``` - filevalue = "diffuse/color01.tif" - filevalue = "/s/myshow/assets/myasset/v102.1/wetdrips/drips.{frame}.tif" - filevalue = "https://github.com/organization/project/tree/master/src/node.osl" - filevalue = "cmsscheme:myassetdiffuse..tif?ver=current" -``` - -**IntegerArray**, **FloatArray**, **Color3Array**, **Color4Array**, **Vector2Array**, **Vector3Array**, **Vector4Array**, **StringArray**: any number of values (including zero) of the same base type, separated by commas (with or without whitespace), within quotes; arrays of color3’s, color4’s, vector2's, vector3's or vector4's are simply a 1D list of channel values in order, e.g. "r0, g0, b0, r1, g1, b1, r2, g2, b2". Individual string values within stringarrays may not contain commas or semicolons, and any leading and trailing whitespace characters in them is ignored. MaterialX does not support multi-dimensional or nested arrays. Array-typed inputs to nodes must be static uniform values of a length specified by another uniform input value of the node, or implicitly by the node's implementation requirements. Nodes cannot output an Array type. - -``` - integerarrayvalue = "1,2,3,4,5" - floatarrayvalue = "1.0, 2.2, 3.3, 4.4, 5.5" - color3arrayvalue = ".1,.2,.3, .2,.3,.4, .3,.4,.5" - color4arrayvalue = ".1,.2,.3,1, .2,.3,.4,.98, .3,.4,.5,.9" - vector2arrayvalue = "0,.1, .4,.5, .9,1.0" - vector3arrayvalue = "-0.2,0.11,0.74, 5.1,-0.31,4.62" - vector4arrayvalue = "-0.2,0.11,0.74,1, 5.1,-0.31,4.62,1" - stringarrayvalue = "hello, there, world" -``` - - - -## 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. 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: - -* "`color`": the type is interpreted to represent or contain a color, and thus should be color-managed as described in the [Color Spaces and Color Management Systems](#color-spaces-and-color-management-systems) section. -* "`shader`": the type is interpreted as a shader output type; nodes or nodegraphs which output a type with a "shader" semantic can be used to define a shader-type node, which can be connected to inputs of "material"-type nodes. -* "`material`": the type is interpreted as a material output type; nodes or nodegraphs which output a type with a "material" semantic can be referenced by a <materialassign> in a <look>. - -Types not defined with a specific semantic are assumed to have semantic="default". - -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. 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. -* `hint` (string, optional): A hint to help those creating code generators understand how the type might be defined. The following hints for typedefs are currently defined: - * "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. - - - -## MTLX File Format Definition - -An MTLX file (with file extension ".mtlx") has the following general form: - -```xml - - - - -``` - -That is, a standard XML declaration line followed by a root <materialx> element, which contains any number of MaterialX elements and sub-elements. The default character encoding for MTLX files is UTF-8, and this encoding is expected for the in-memory representation of string values in MaterialX implementations. - -Standard XML XIncludes are supported ([http://en/wikipedia.org/wiki/XInclude](http://en/wikipedia.org/wiki/Xinclude)), as well as standard XML comments and the XML character entities `"`, `&`, `'`, `<` and `>`: - -```xml - - - -``` - -To support stringarray types, MaterialX supports a non-standard XML convention where a comma (and any following whitespace) is a separator for strings within a stringarray, a comma or semicolon preceded by a backslash is interpreted as a regular comma or semicolon rather than as a separator, and two backslashes are interpreted as a single backslash. - -Each XIncluded document must itself be a valid MTLX file, containing an XML header and its own root `` element, the children of which are added to the root element of the including document. Hierarchical root-level attributes such as `colorspace` and `namespace` are distributed to the included children to maintain correct semantics within the including MaterialX document. - -Attributes for a <materialx> element: - -* `version` (string, required): a string containing the version number of the MaterialX specification that this document conforms to, specified as a major and minor number separated by a dot. The MaterialX library automatically upgrades older-versioned documents to the current MaterialX version at load time. -* `colorspace` (string, optional): the name of the "working color space" for this element and all of its descendants. This is the default color space for all image inputs and color values, and the color space in which all color computations will be performed. The default is "none", for no color management. -* `namespace` (string, optional): defines the namespace for all elements defined within this <materialx> scope. Please see the [MaterialX Namespaces](#materialx-namespaces) section below for details. - - - -## Color Spaces and Color Management Systems - -MaterialX supports the use of color management systems to associate RGB colors and images with specific color spaces. MaterialX documents typically specify the working color space of the application that created them, and any input color or image described in the document can specify the name of its color space if different from the working color space. This allows applications using MaterialX to transform color values within input colors and images from their original color space into a desired working color space upon ingest. MaterialX does not specify _how_ or _when_ color values should be transformed: that is up to the host application, which can use any appropriate method including code generation, conversion when loading images into memory, maintaining cached or pre-converted image textures, etc. It is generally presumed that the working color space of a MaterialX document will be linear (as opposed to log, a display-referred space such as sRGB, or some other non-linear encoding), although this is not a firm requirement. - -By default, MaterialX supports the following color spaces as defined in ACES 1.2 ([http://www.oscars.org/science-technology/sci-tech-projects/aces)](http://www.oscars.org/science-technology/sci-tech-projects/aces), and applications rendering MaterialX documents are expected to transform input colors and images from these spaces to the color space of their renderer. One straightforward option for providing this support is to leverage MaterialX code generators, which support these transforms automatically, but applications may use any appropriate means to handle the transforms on their own. - -* `srgb_texture` -* `lin_rec709` -* `g22_rec709` -* `g18_rec709` -* `acescg` -* `lin_ap1 (alias for "acescg")` -* `g22_ap1` -* `g18_ap1` -* `lin_srgb` -* `adobergb` -* `lin_adobergb` -* `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 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. 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 - - - - -``` - -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. - - - -## Units - -MaterialX allows floating-point and vector values to be defined in terms of a specific unit and unit type, and can automatically convert values from their specified unit into a scene unit of the same type specified by the application. This allows images and the quantities they represent such as displacement amount to be specified at an absolute real-world size, and then be converted automatically to the expected scene units of the application. - -Unit types are defined using a <unittypedef> element, and a set of units of that type is defined using a <unitdef> element with one or more child <unit> elements. The following unittypes and units are pre-defined by MaterialX: - -```xml - - - - - - - - - - - - - - - - - - -``` - -The <unittypedef> defines the name of a unittype, while the <unitdef> defines any number of units for a unittype along with the multiplicative conversion `scale` values relative to the other units. Additional unit definitions for any unit type may be done by providing another <unitdef> with the same `unittype` attribute value. - -Any input or other floating-point value may specify a `unit` and/or `unittype` attribute subject to guidelines clarified throughout this document. Units and unittypes may also be provided for floatarray, vectorN and vectorNarray quantities, with all components of the vector or all values in the array using the same unit, and for "filename"-type input, in which case the `unit` and/or `unittype` attribute applies to the float or vectorN values read from those files. It is not expected that all inputs will have defined units or unittypes; in fact, it is expected that the vast majority of inputs will have neither. Units and unittypes should only be specified where specific units are important and it is reasonably expected that unit conversion may need to take place. - -Please refer to the [Inputs](#inputs), [Custom Node Declaration NodeDef Elements](#custom-node-declaration-nodedef-elements), [Geometric Properties](#geometric-properties) and [Geometric Nodes](./MaterialX.StandardNodes.md#geometric-nodes) sections below and in the MaterialX Standard Nodes and MaterialX Geometry Extensions documents for additional specific requirements for the use of units. - - - -## MaterialX Namespaces - -MaterialX supports the specification of “namespaces”, which qualify the MaterialX names of all elements within their scope. Namespaces are specified via a `namespace` attribute in a <materialx> element, and other MaterialX files which <xi:include> this .mtlx file can refer to its content without worrying about element or object naming conflicts, similar to the way namespaces are used in various programming languages. It is permissible for multiple <materialx> elements to specify the same namespace; the elements from each will simply be merged into the same namespace. <materialx> elements which do not specify a namespace will define elements into the (unnamed) global namespace. MaterialX namespaces are most commonly used to define families of custom nodes (nodedefs), material libraries, or commonly-used network shaders or nodegraphs. - -References to elements in a different namespace are qualified using the syntax "_namespace_:_elementname_", where _namespace_ is the namespace at the scope of the referenced element and _elementname_ is the name of the referenced element. References to elements in the same namespace, or to elements in the global namespace, should not be qualified. - -#### Namespace Examples - -Mtllib.mtlx contains the following (assuming that "..." contains any necessary material input connections and other element definitions): - -```xml - - - ... - - ... - - - ... - - -``` - -Then another MaterialX file could reference these materials like this: - -```xml - - ... - - - - -``` - -Similarly, if a .mtlx file defining the "site_ops" namespace defined a custom color3-typed node "mynoise" with a single float input "f", it could be used in a node graph like this: - -```xml - - - -``` - -A `namespace` attribute may also be added to individual <nodedef>s or <nodegraph>s, in which case the `name` and `node` of a <nodedef>, or just the `name` of a <nodegraph> will be assigned to the specified `namespace`. In a <nodegraph>, the `nodedef` must include a namespace reference if the <nodedef> to which it refers is defined in a specific namespace, even if it's the same namespace as the <nodegraph>: this is because the `namespace` only applies to the content that is created by or contained within an element, not to anything external referenced by that element. - -```xml - - - - - - - - - - -``` - - - -## Geometric Properties - -Geometric Properties, or "geomprops", are intrinsic or user-defined surface coordinate properties of geometries referenced in a specific space and/or index, and are functionally equivalent to USD's concept of "primvars". A number of geometric properties are predefined in MaterialX: `position`, `normal`, `tangent`, `bitangent`, `texcoord` and `geomcolor`, the values of which can be accessed in nodegraphs using elements of those same names; see the [Geometric Nodes](./MaterialX.StandardNodes.md#geometric-nodes) section of the MaterialX Standard Nodes document for details. The value of a varying geometric property can also be used as the default value for a node input using a `defaultgeomprop` attribute. - -The following geometric properties are pre-defined by MaterialX: - -| GeomProp Name | Type | Description | -| ---- | ---- | ---- | -| Pobject | vector3 | Object space position | -| Nobject | vector3 | Object space surface normal | -| Tobject | vector3 | Object space tangent vector (index 0) | -| Bobject | vector3 | Object space bitangent vector (index 0) | -| Pworld | vector3 | World space position | -| Nworld | vector3 | World space surface normal | -| Tworld | vector3 | World space tangent vector (index 0) | -| Bworld | vector3 | World space bitangent vector (index 0) | -| UV0 | vector2 | Index "0" UV texture coordinate | - -One may also define custom geometric properties using a <geompropdef> element: - -```xml - -``` - -e.g. - -```xml - - -``` - -The `type` of the geomprop may be any non-array MaterialX type, although `string`- or `filename`-type geomprops must be declared with uniform="true". The "geomprop", "space" and "index" attributes are optional; if "geomprop" is specified, it must be one of the standard geometric properties noted above, and if it is not specified, the new geomprop is a blind geometric property, e.g. one that can be referenced but which MaterialX knows no details about. The "space" and "index" attributes may only be specified if a "geomprop" attribute is specified and the standard geomproperty supports it. "Geomprop", "space" and "index" attributes may not be specified for `uniform="true"` geomprops. - -Once defined, a custom geomprop name may be used any place that a standard geomprop can: - -```xml - -``` - -A geompropdef may also specify a `unittype` and a `unit` to indicate that the geometric property is defined in terms of a specific unit. If a geomprop with a defined unit is accessed in a nodegraph using <geompropvalue>, the geometric property value will be converted from the unit specified by the geompropdef to the application-specified scene unit. - -```xml - -``` - - -## Geometric Spaces - -Various operator nodes may need to specify which 3D space a position or vector is in. The following values are supported by the `space` inputs of Geometric nodes and when transforming from one space to another: - -* "model": The local coordinate space of the geometry, before any local deformations or global transforms have been applied. -* "object": The local coordinate space of the geometry, after local deformations have been applied, but before any global transforms. -* "world": The global coordinate space of the geometry, after local deformations and global transforms have been applied. - - - -## File Prefixes - -As a shorthand convenience, MaterialX allows the specification of a `fileprefix` attribute which will be prepended to input values of type "filename" (e.g. `file` inputs in `` nodes, or any shader input of type "filename") specified within the scope of the element defining the `fileprefix`. Note that `fileprefix` values are only prepended to input with a `type` attribute that explicitly states its data type as “filename”. Since the values of the prefix and the filename are string-concatenated, the value of a `fileprefix` should generally end with a "/". Fileprefixes are frequently used to split off common path components for asset directories, e.g. to define an asset's "texture root" directory. - -So the following snippets are equivalent: - -```xml - - - - - - - - - - - - - - - - - -``` - -Note in the second example that `` "in2" redefined `fileprefix` for itself, and that any other nodes in the same nodegraph would use the fileprefix value ("textures/color/") defined in the parent/enclosing scope. - -Note: Application implementations have access to both the raw input values and attributes (e.g. the "file" name and the current "fileprefix") and to fully-resolved filenames at the scope of any given element. - - - -## Filename Substitutions - -Filename input values for various nodes can include one or more special strings, which will be replaced as described in the following table. Substitution strings within <>'s come from the current geometry, strings within []'s come from the MaterialX state, and strings within {}'s come from the host application environment. - -| Token | Description | -| ---- | ---- | -| <UDIM> | A special geometry token that will be replaced with the computed four digit Mari-style "udim" value at render or evaluation time based on the current point’s uv value, using the formula UDIM = 1001 + U + V*10, where U is the integer portion of the u coordinate, and V is the integer portion of the v coordinate. | -| <UVTILE> | A special geometry token that will be replaced with the computed Mudbox-style "uU_vV" string, where U is 1+ the integer portion of the u coordinate, and V is 1+ the integer portion of the v coordinate. | -| [interface token] | The value of a specified token declared in the containing nodegraph's <nodedef> interface; the value for the token may be set in the shader node in a material referencing the node or within a <variant>; it is an error if the same token is defined in more than one of those places for the current geometry. | -| {hostattr} | The host application may define other variables which can be resolved within filenames. | -| {frame} | A special string that will be replaced by the current frame number, as defined by the host environment. | -| {0Nframe} | A special string that will be replaced by the current frame number padded with zeros to be N digits total (replace N with a number): e.g. {04frame} will be replaced by a 4-digit zero-padded frame number such as "0010". | - - -Note: Implementations are expected to retain substitution strings within filenames upon export rather than "baking them out" into fully-evaluated filenames. Applications using USD for geometry and assignments may additionally use a <_geometry token_> (a.k.a. "<_primvarname_>") as the entire filename string to access an entire string primvar value unchanged (though that string value may contain the USD-supported <UDIM> token). - -
- - -# Nodes - -Nodes are individual data generation or processing "blocks". Node functionality can range from simple operations such as returning a constant color value or adding two input values, to more complex image processing operations, 3D spatial data operations, or even complete shader BxDFs. Nodes are connected together into a network or "node graph", and pass typed data streams between them. - -Individual node elements have the form: - -```xml - - - ...additional input or token elements... - -``` - -where _nodecategory_ is the general "category" of the node (e.g. "image", "add" or "mix"), `name` (string, required) defines the name of this instance of the node, which must be unique within the scope it appears in, and `type` (string, required) specifies the MaterialX type (typically float, colorN, or vectorN) of the output of that node. If the application uses a different name for this instance of the node in the user interface, a `uiname` attribute may be added to the <_nodecategory_> element to indicate the name of the node as it appears to the user. - -Node elements may optionally specify a `version` string attribute in "_major_[._minor_]" format, requesting that a specific version of that node's definition be used instead of the default version. Normally, the types of a node's inputs and outputs are sufficient to disambiguate which signature of the applicable version of a node is intended, but if necessary, a node instantiation may also declare a specific nodedef name to precisely define exactly which node signature is desired. Please refer to the [Custom Node Declaration NodeDef Elements](#custom-node-declaration-nodedef-elements) section below for further details. - -MaterialX defines a number of [Standard Nodes](#standard-nodes) which all implementations should support as described to the degree their architecture and capabilities allow. One can define new nodes by declaring their parameter interfaces and providing portable nodegraph or target-specific shading language implementations. Please see the [Custom Nodes](#custom-nodes) section for notes and implementation details. - - - -## 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](./MaterialX.StandardNodes.md#node-constant) (possibly through one or more no-op [<dot> nodes](./MaterialX.StandardNodes.md#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. - -```xml - - - -``` - -Unless specified otherwise, all inputs default to a value of 0 in all channels for integer, float, color and vector types, "" for string and filename types, "false" for boolean types, the identity matrix for matrix types, and for array types, an appropriate-length array consisting of the default value for the array's base type. - -Standard MaterialX nodes have exactly one output, while custom nodes may have any number of outputs; please see the [Custom Nodes](#custom-nodes) section for details. - - - -## Node Graph Elements - -A graph containing any number of nodes and output declarations forms a Node Graph, which may be enclosed within a <nodegraph> element to group them together into a single functional unit. Please see the [Custom Node Definition Using Node Graphs](#custom-node-definition-using-node-graphs) section below for details on how nodegraphs can be used to describe the functionality of new nodes. - -```xml - - ...node element(s)... - ...output element(s)... - -``` - - - -## Output Elements - -Output data streams are defined using **<output>** elements, and may be used to declare which output streams are connectable to other MaterialX elements. Within a node graph, an <output> element declares an output stream that may be connected to a shader input or to the input of a referencing node in another graph when the nodegraph is the implementation of a custom node. See the [Custom Node Definition Using Node Graphs](#custom-node-definition-using-node-graphs) section for details on the use of node graphs as node implementations. - -```xml - - -``` - -Attributes for Output elements: - -* `name` (string, required): the name of the output -* `type` (string, required): the MaterialX type of the output -* `nodename` (string, optional): the name of a node at the same scope within the document, whose result value will be output. This attribute is required for <output> elements within a node graph, but is not allowed in <output> elements within a <nodedef>. -* `output` (string, optional): if the node specified by `nodename` has multiple outputs, the name of the specific output to connect this <output> to. -* `uniform` (boolean, optional): If set to "true", then the output of this node is treated as a uniform value, and this output may be connected to a uniform input of the same (or compatible) type. It is up to the application creating the nodegraph to ensure that the value actually is uniform. Default is "false". - -MaterialX also supports the following additional attributes for Output elements in applications which process node graphs in 2D space and save or cache outputs as images for efficiency, such as texture baking or image caching. These attributes do **not** affect values from this <output> connected to other nodes, e.g. they would remain in the working colorspace and retain full resolution and bitdepth precision. - -* `colorspace` (string, optional): the name of the color space for the output image. Applications that support color space management are expected to perform the required transformations of output colors into this space. -* `width` (integer, optional): the expected width in pixels of the output image. -* `height` (integer, optional): the expected height in pixels of the output image. -* `bitdepth` (integer, optional): the expected per-channel bit depth of the output image, which may be used to capture expected color quantization effects. Common values for `bitdepth` are 8, 16, 32, and 64. It is up to the application to determine what the internal representation of any declared bit depth is (e.g. scaling factor, signed or unsigned, etc.). - - - -## Standard Nodes - -A core part of MaterialX is its set of Standard Nodes, divided into five categories: Source nodes, Operator nodes, Standard Shader nodes, Physically-Based Shading nodes, and NPR (non-photorealistic) Shading nodes. - -[**Source nodes**](./MaterialX.StandardNodes.md#standard-source-nodes) use external data and/or procedural functions to form an output; they do not have any required inputs. Standard Source Nodes are grouped into the following classifications: [Texture Nodes](./MaterialX.StandardNodes.md#texture-nodes), [Procedural Nodes](./MaterialX.StandardNodes.md#procedural-nodes), [Noise Nodes](./MaterialX.StandardNodes.md#noise-nodes), [Shape Nodes](./MaterialX.StandardNodes.md#shape-nodes), [Geometric Nodes](./MaterialX.StandardNodes.md#geometric-nodes) and [Application Nodes](./MaterialX.StandardNodes.md#application-nodes). - -[**Operator nodes**](./MaterialX.StandardNodes.md#standard-operator-nodes) process one or more input streams to form an output. Standard Operator Nodes are grouped into the following classifications: [Math Nodes](./MaterialX.StandardNodes.md#math-nodes), [Logical Operator Nodes](./MaterialX.StandardNodes.md#logical-operator-nodes), [Adjustment Nodes](./MaterialX.StandardNodes.md#adjustment-nodes), [Compositing Nodes](./MaterialX.StandardNodes.md#compositing-nodes), [Conditional Nodes](./MaterialX.StandardNodes.md#conditional-nodes), [Channel Nodes](./MaterialX.StandardNodes.md#channel-nodes) and [Convolution Nodes](./MaterialX.StandardNodes.md#convolution-nodes). - -[**Standard Shader nodes**](./MaterialX.StandardNodes.md#standard-shader-nodes) comprise non-shading shaders such as for displacement, and shaders which do not respond to external illumination. - -[**Physically-Based Shading nodes**](./MaterialX.PBRSpec.md) are shader-semantic nodes implementing a number of widely-used [BSDF/BSSRDF](./MaterialX.PBRSpec.md#bsdf-nodes), [emission](./MaterialX.PBRSpec.md#edf-nodes) and [volume](./MaterialX.PBRSpec.md#vdf-nodes) distribution functions and [utility nodes](./MaterialX.PBRSpec.md#utility-nodes) useful in constructing complex layered rendering shaders using node graphs, as well as a set of complete [PBR Shader Nodes](./MaterialX.PBRSpec.md#pbr-shader-nodes) implementing open standard shading models. - -[**NPR Shading nodes**](./MaterialX.NPRSpec.md) are operations that are desirable in non-photorealistic shading styles but which cannot be implemented within certain rendering constructs. These include [NPR Application Nodes](./MaterialX.NPRSpec.md#npr-application-nodes), [NPR Utility Nodes](./MaterialX.NPRSpec.md#npr-utility-nodes) and [NPR Shading Nodes](./MaterialX.NPRSpec.md#npr-shading-nodes). - - - -## Standard Node Inputs - -All standard nodes which define a `defaultinput` or `default` value support the following input: - - - -* `disable` (uniform boolean): if set to true, the node will pass its default input or value to its output, effectively disabling the node; default is false. Applications may choose to implement the `disable` input by skipping over the disabled node during traversal and instead passing through a connection to the defaultinput node or outputting the node's default value, rather than using an actual `disable` input in the node implementation. - - -## Standard UI Attributes - -All elements support the following additional UI-related attributes: - - - -* `doc` (string attribute): a description of the function or purpose of this element; may include standard HTML formatting strings such as <b>, <ul>, <p>, etc. but no complex formatting such as CSS or external references (e.g. no hyperlinks or images). May be used for functional documentation, or for UI pop-up "tool tip" strings. - - -All node types (sources, operators, shader nodes and material nodes) as well as <look> elements support the following UI-related attributes: - - - -* `xpos` (float attribute): X-position of the upper-left corner of the node when drawn in a UI. - - - -* `ypos` (float attribute): Y-position of the upper-left corner of the node when drawn in a UI. - - - -* `width` (float attribute): the relative width of the node when drawn in a UI; default is 1.0. - - - -* `height` (float attribute): the relative height of the node when drawn in a UI; default is 1.0. - - - -* `uicolor` (color3 attribute): the display-referred color of the node as drawn in the UI, normalized to 0.0-1.0 range; default is to not specify a particular color so the application's default node color would be used. `uicolor` values are expressed as color3 values in "none" colorspace, and thus are not affected by the current `colorspace`. - -All positioning and sizing attribute values are specified relative to an application's default size for drawing a node including any minimal-length connection edges and arrows. So a node drawn at position (xpos, ypos) will "look good" if connected to nodes drawn at position (xpos+width, ypos) and at position (xpos, ypos+height), and a node specifying `width="2"` would be drawn twice as wide (including outside whitespace for a minimal connecting arrow) as a node with the default width. It is not necessary that nodes be placed exactly on integer grid boundaries; this merely states the scale of nodes. It is also not assumed that the pixel scaling factors for X and Y are the same: the actual UI unit "grid" does not have to be square. If xpos and ypos are not both specified, placement of the node when drawn in a UI is undefined, and it is up to the application to figure out placement (which could mean "all piled up in the center in a tangled mess"). - -MaterialX defines xpos values to be increasing left to right, ypos values to be increasing top to bottom, and the general flow is generally downward. E.g. node inputs are on the top and outputs on the bottom, and a node at (10, 10) could connect naturally to a node at (10, 11). Content creation applications using left-to-right flow can simply exchange X and Y coordinates in their internal representations when reading or writing MaterialX data, and applications that internally use Y coordinates increasing upward rather than downward can invert the Y coordinates between MTLX files and their internal representations. - -The <input> and <token> elements within <nodedef>s and node instantiations (but not within <implementation>s or <nodegraph> parameter interfaces) support the following UI-related attributes: - - - -* `uivisible` (boolean attribute): whether or not the input is visible in the UI. If `uivisible` is specified on an input/token in a <nodedef> that defines the default visibility of that input/token, while a `uivisible` specified on a input/token in a node instantiation affects just the visibility of the input/token within that particular instantiation. Default is "true". - - - -* `uiadvanced` (boolean attribute): whether or not the input is considered to be an "advanced" parameter which an application may choose to hide in a more "basic" mode. Should normally be declared only within a <nodedef>. Default is "false", meaning the input should be displayed if `uivisible` is true, while "true" means the input would be displayed if `uivisible` is true and the application UI is set to show "advanced" parameters. - - - -## Backdrop Elements - -Backdrop elements are used to contain, group, and document nodes within a node graph, and they have no impact on the functionality of the graph. The following attributes are supported by <backdrop> elements: - -* `contains` (stringarray attribute): a comma-separated list of node names that the backdrop "contains"; default is to contain no nodes. -* `minimized` (boolean attribute): whether or not this backdrop is collapsed to a single node-sized box in the application's UI or not; default is false. - -Backdrop elements also support the standard `width`, `height`, `xpos`, `ypos` and `doc` attributes. - - - - -## Node Graph Examples - -The following examples demonstrate how a MaterialX Document might encode graphs of nodes. - - -#### Nodegraph Example 1 - -A simple merge of two single-layer images with a separate mask image, followed by a simple color operation. - -![Nodegraph Example 1](media/nodegraph1.png "Nodegraph Example 1") - -```xml - - - - - - - - - - - - - - - - - - - - - - -``` - - -#### Nodegraph Example 2 - -A more complex nodegraph using geometry properties to define two diffuse albedo colors and two masks, then color-correcting one albedo less red and more blue and increasing the contrast of the other, blending the two through an area mask, and adding a small amount of scaled 2D Perlin noise within a second mask. The graph outputs the area mask layer separately from the composited diffuse albedo color. - -![Nodegraph Example 2](media/nodegraph2.png "Nodegraph Example 2") - -```xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - -
- - -# Customization, Targeting and Shading - -While the Standard Nodes are considered universal across all MaterialX applications, there are many circumstances in which one would like to extend this with new custom functionality, or define functionality or underlying implementations specific to different applications or renderers. This includes the definition of nodes for shading and materials. - - -## Target Definition - -MaterialX supports the definition of nodes, attributes and inputs that are specific to particular rendering "targets". This allows a single implementation to restrict certain values or nodes to only the targets for which they are valid, or to allow separate definitions of the same node functionality for different renderers. - -Targets are declared using a <targetdef> element: - -```xml - - - -``` - -A target may inherit from another target, so that any reference to a parent target will automatically include any definitions specific to the inherited child target that do not have a definition for the parent target itself: - -```xml - - - -``` - -In the above example, any renderer that requests nodes/inputs/attributes for the "osl" target will also see any node/input/attribute that is defined with `target="oslpattern"`. A renderer may also declare that it will accept implementations for multiple targets, e.g. Vray might declare it will accept either "vrayosl", "mdl" or "vrayglsl", with "vrayosl" preferred. - -A targetdef element may also specify additional custom attributes for that target, such as configuration or code generation options. - - -## Custom Attributes and Inputs - -#### Custom Attributes - -While the MaterialX specification describes the attributes and elements that are meaningful to MaterialX-compliant applications, it is permissible to add custom attributes and inputs to standard MaterialX elements. These custom attributes and child elements are ignored by applications that do not understand them, although applications should preserve and re-output them with their values and connections even if they do not understand their meaning. - -If an application requires additional information related to any MaterialX element, it may define and utilize additional attributes with non-standard names. Custom attributes are defined using <attributedef> elements: - - -```xml - -``` - -where _name_ is a unique name for the attributedef, _attrname_ is the name of the custom attribute to define, _type_ is the type of the attribute (typically string, stringarray, integer or boolean, although any MaterialX type is allowed), _defaultvalue_ is the default value for the attribute, _target_ is an optional list of targets to which this attribute applies, and _elements_ is an optional list of element names or elementname/inputname in which the attribute may be used. It is also permissible to provide enum and enumvalues attributes for an attributedef, to define specific labels and values that the custom attribute is allowed to take, using the same syntax and limitations as enum/enumvalues on nodedef inputs and tokens (see below). By default, a custom attribute is not emitted as metadata in generated shaders, but can be exported if the `exportable` attribute is set to "true". Examples: - -```xml - - - -``` - -The first example above defines a 3ds Max-specific name attribute for surface materials, which may be given a value in addition to its MaterialX-compliant name in order to preserve the original package-specific name; it is assumed here that `maxmtlname` is the attribute name used by that particular implementation for this purpose. The second example defines a "mystudio"-specific boolean attribute "vflip", which could be used in the "file" input of <image> nodes. - -Once defined, custom attributes may be used in exactly the same manner as standard attributes: - -```xml - - - - - - ... - -``` - - -#### Custom Inputs - -If an application requires additional custom inputs within a standard MaterialX node, it may define a target application-specific <nodedef> for that node inheriting the base input definitions from the standard node's <nodedef>, then add inputs specific to that target application. - -```xml - - - -``` - -In the above example, a Maya-specific version of the color4-type <image> node has been declared, inheriting from the standard declaration then adding a maya-specific "preFilter" input. - -When using a node, the definition appropriate for the current target will automatically be used, and other targets will ignore any inputs that are not part of the nodedef for that target. However, one may specify a documentational `target` attribute on an input to hint what target it is intended for if desired. In this example, the "preFilter" input has indicated that it is specific to the "maya" target. - -```xml - - - - -``` - - -## Custom Nodes - -Specific applications will commonly support sources and operators that do not map directly to standard MaterialX nodes. Individual implementations may provide their own custom nodes, with <nodedef> elements to declare their parameter interfaces, and <implementation> and/or <nodegraph> elements to define their behaviors. - - -### Custom Node Declaration NodeDef Elements - -Each custom node must be explicitly declared with a <nodedef> element, with child <input>, <token> and <output> elements specifying the expected names and types of the node’s ports. - -Attributes for <nodedef> elements: - -* `name` (string, required): a unique name for this <nodedef> -* `node` (string, required): the name of the custom node being defined -* `inherit` (string, optional): the `name` of a <nodedef> to inherit node definitions from; the output types of this nodedef and the inherited one must match, and the input/output definitions of this nodedef will be applied on top of those in the inherited-from one. -* `nodegroup` (string, optional): an optional group to which this node declaration belongs. Standard MaterialX nodes have `nodegroup` values matching the titles of the section headings in which they are described, e.g. "texture2d", "procedural", "geometric", "application", "math", "adjustment", "compositing", "conditional", "channel", "convolution", or "organization". -* `version` (string, optional): a version string for this nodedef, allowing usage of a node to reference a specific version of a node. Version strings should be of the format "_major_[._minor_]", i.e. one or two integer numbers separated by a dot (the minor version is assumed to be "0" if not provided). If there are multiple nodedefs for the same `node` and `target` with the same combination of input and output types, they must each specify a `version`. -* `isdefaultversion` (boolean, optional): If true, then this nodedef should be used for node instances which do not request a specific version. Specifying `isdefaultversion` "true" is only required if there are multiple nodedefs for a node declaring a `version`, and it is not permissible for multiple nodedefs for the same `node` and `target` with the same combination of input and output types to set `isdefaultversion` "true". Defaults to "false". -* `target` (stringarray, optional): the set of targets to which this nodedef is restricted. By default, a nodedef is considered universal, not restricted to any specific targets, but it is possible that certain targets may have different parameter names or usage for the same node. -* `uiname` (string, optional): an alternative "node" value for this nodedef to be displayed in the UI. If `uiname` is not provided, then `node` is the presumed UI node value for the nodedef. This is most useful when the <nodedef> defines a namespace, so the user doesn't need to see a full namespaced path for the node. -* `internalgeomprops` (stringarray, optional): a list of MaterialX geometric properties (e.g. "position", "normal", "texcoord", etc. or any name defined by a <geompropdef> element) that the node expects to be able to access internally. This metadata hint allows code generators to ensure this data is available and can be used for error checking. `Internalgeomprops` is most useful for nodes whose implementation is defined by external code; it is not necessary for nodegraph-defined nodes, as the list of geometric properties accessed can be determined by examining the nodegraph. - -Custom nodes are allowed to overload a single `node` name by providing multiple <nodedef> elements with different combinations of input and output types. This overloading is permitted both for custom `node` names and for the standard MaterialX node set. Within the scope of a single MaterialX document and its included content, no two <nodedef> elements with an identical combination of input and output types for the same target and version may be provided for a single `node` name. It is recommended that all <nodedef> variations for a `node` use exactly the same set of input names differing only in their types, with no variation adding or removing any inputs. It is also recommended that newer versions of nodes be fully backward-compatible with earlier versions (including default values of input) so that a change in default version of a node does not break functionality; if this is not possible, using a different `node` name is recommended. - -The `inherit` attribute may be provided to allow one <nodedef> to inherit from another: this is most useful for defining additional inputs in a target- or version-specific <nodedef>, inheriting from a generic, canonical definition of a node or shader. NodeDefs which inherit from another nodedef may not re-declare <output>s from the parent nodedef, only add additional new <output>s. - -NodeDefs must define one or more child <output> elements within the <nodedef> to state the name and type of each output; for nodes defined using a nodegraph, the names and types of the outputs must agree with the <output> elements in the nodegraph. The output name for a single-output <nodedef> is less important, as any connection made to the output of a single-output node will succeed regardless of the actual `name` referenced, although by convention, the name "out" is preferred for single-output nodes. See the [**NodeDef Output Elements**](#nodedef-output-elements) section below for details. - - -#### NodeDef Parameter Interface - -The parameter interface of a custom node is specified via a set of child <input> and <token> elements of the <nodedef>, while documentation of the folder structure of a node may be defined using a number of <uifolder> elements, each of which may provide a doc attribute to provide documentation for that folder layer. A <uifolder> element may not contain any other elements; in particular, the <input>s and <token>s of the nodedef interface must be direct children of the <nodedef>. Nested folders may be indicated using a full path for the folder, with a "/" separator between folder levels. - -```xml - - - - - ...input and token definitions... - -``` - - -#### NodeDef Input Elements - -**Input** elements are used within a <nodedef> to declare the spatially-varying and uniform inputs for a node: - -```xml - -``` - -Attributes for NodeDef Input elements: - -* `name` (string, required): the name of the shader input -* `type` (string, required): the MaterialX type of the shader input -* `value` (same type as `type`, optional): a default value for this input, to be used if the input remains unconnected and is not otherwise assigned a value -* `uniform` (boolean, optional): if set to "true", then this input can only take uniform values and may only be connected to the outputs of <constant> nodes or any other node whose output is explicitly declared to be "uniform" (optionally through a number of <dot> nodes), but not to the outputs of other (non-"uniform") nodes. `uniform` must be set to true for string and filename-type inputs. -* `defaultgeomprop` (string, optional): for vector2 or vector3 inputs, the name of an intrinsic geometric property that provides the default value for this input, must be one of "position", "normal", "tangent", "bitangent" or "texcoord" or vector3-type custom geometric property for vector3 inputs, or "texcoord" or vector2-type custom geometric property for vector2 inputs. For standard geometric properties, this is effectively the same as declaring a default connection of the input to a Geometric Node with default input values. May not be specified on uniform inputs. -* `enum` (stringarray, optional): a comma-separated non-exclusive list of string value descriptors that the input couldmayis allowed to take: for string- and stringarray-type inputs, these are the actual values (or values per array index for stringarrays); for other types, these are the "enum" labels e.g. as shown in the application user interface for each of the actual underlying values specified by `enumvalues`. The enum list can be thought of as a list of commonly used values or UI labels for the input rather than a strict list, and MaterialX itself does not enforce that a specified input enum value is actually in this list, with the exception that if the input is a "string" (or "stringarray") type and an enum list is provided, then the value(s) must in fact be one of the enum stringarray values. -* `enumvalues` (typearray, optional): for non-string/stringarray types, a comma-separated list of values of the same base type as the <input>, representing the values that would be used if the corresponding `enum` string was chosen in the UI. MaterialX itself does not enforce that a specified input value is actually in this list. Note that implementations are allowed to redefine `enumvalues` (but not `enum`) for specific targets: see the [Custom Node Definition Using Implementation Elements](#custom-node-definition-using-implementation-elements) section below. -* `colorspace` (string, optional): for color3- or color4-type inputs, the colorspace of the default value for this input. -* `unittype` (string, optional): the type of unit for this input, e.g. "distance", which must be defined by a <unittypedef>. Default is to not specify a unittype. Only float-, vectorN- and filename-type inputs may specify a `unittype`. -* `unit` (string, optional): the specific unit for this input. Nodedef inputs do not typically specify a unit; if it does, that would indicate that the implementation of that node expects values to be specified in that unit, and that any invocation of that node using a different unit should be converted to the nodedef-specified unit for that input rather than to the application's scene unit. The most common instance of this is for angular values, where a nodedef might specify that it expects values to be given in degrees. -* `uiname` (string, optional): an alternative name for this input as it appears in the UI. If `uiname` is not provided, then `name` is the presumed UI name for the input. -* `uifolder` (attribute, string, optional): the pathed name of the folder in which this input appears in the UI, using a "/" character as a separator for nested UI folders. -* `uimin` (integer or float or colorN or vectorN, optional): for inputs of type integer, float, colorN or vectorN, the minimum value that the UI allows for this particular value. MaterialX itself does not enforce this as an actual minimum value. -* `uimax` (integer or float or colorN or vectorN, optional): for inputs of type integer, float, colorN or vectorN, the maximum value that the UI allows for this particular value. MaterialX itself does not enforce this as an actual maximum value. -* `uisoftmin` (integer or float or colorN or vectorN, optional): for inputs of type integer, float, colorN or vectorN, a suggested minimum UI slider value for this input, should be >= `uimin`. MaterialX itself does not enforce this as an actual minimum value. -* `uisoftmax` (integer or float or colorN or vectorN, optional): for inputs of type integer, float, colorN or vectorN, a suggested maximum UI slider value for this inputs, should be <= `uimax`. MaterialX itself does not enforce this as an actual maximum value. -* `uistep` (integer or float or colorN or vectorN, optional): for inputs of type integer, float, colorN or vectorN, the increment size that the UI would increment or decrement a component of the input value. -* `hint` (string): A hint to help code generators understand how the input may be used. The following hints for nodedef inputs are currently defined: - * "transparency": the input is indicating a level of shading transparency. - * "opacity": the input is indicating a level of shading opacity (inverse of transparency). - * "anisotropy": the presence of this hint on an input indicates that anisotropic reflections _may_ (but not necessarily) be taking place; if no input on a shading node(def) defines an "anisotropic" hint, then some implementations may use this as an optimization to allow only isotropic reflections. - -It is permissible to define a `value` or a `defaultgeomprop` for an input but not both. If neither `value` or `defaultgeomprop` are defined, then the input becomes required, and any invocation of the custom node without providing a value or connection for this input would be in error. - - -#### NodeDef Token Elements - -**Token** elements are used within a <nodedef> to declare uniform "interface token" string-substitution values to be referenced and substituted within filenames used in a node's nodegraph implementation: - -```xml - -``` - -Attributes for NodeDef Token elements: - -* `name` (string, required): the name of the token -* `type` (string, required): the MaterialX type of the token; when the token's value is substituted into a filename, the token value will be cast to a string, so string or integer types are recommended for tokens, although any MaterialX type is permitted. -* `value` (same type as `type`, optional): a default value for this token, to be used if the node is invoked without a value defined for this token. If a default value is not defined, then the token becomes required, so any invocation of the custom node without a value assigned to that token would be in error. -* `enum` (stringarray, optional): a comma-separated non-exclusive list of string value descriptors that the token could take: for string-type tokens, these are the actual values; for other types, these are the "enum" labels e.g. as shown in the application user interface for each of the actual underlying values specified by enumvalues. The enum list can be thought of as a list of commonly used values or UI labels for the input rather than a strict list, and MaterialX itself does not enforce that a specified token enum value is actually in this list, with the exception that if the input is a "string" (or "stringarray") type and an enum list is provided, then the value(s) must in fact be one of the enum stringarray values. -* `enumvalues` (typearray, optional): for non-string types, a comma-separated list of values of the same base type as the <token>, representing the values that would be used if the corresponding enum string was chosen in the UI. MaterialX itself does not enforce that a specified token value is actually in this list. Note that implementations are allowed to redefine enumvalues (but not enum) for specific targets: see the [Custom Node Definition Using Implementation Elements](#custom-node-definition-using-implementation-elements) section below. -* `uiname` (string, optional): an alternative name for this token as it appears in the UI. If `uiname` is not provided, then `name` is the presumed UI name for the token. -* `uifolder` (string, optional): the pathed name of the folder in which this token appears in the UI, using a "/" character as a separator for nested UI folders. - -Please see the [Example Pre-Shader Compositing Material](#example-pre-shader-compositing-material) in the [Material Nodes](#material-nodes) section below for an example of how Tokens are used. - - -#### NodeDef Output Elements - -**Output** elements are used within a <nodedef> to declare an output for node definitions, including the output's name, type, and default value or "defaultinput" connection: - -```xml - -``` - -Attributes for NodeDef Output elements: - -* `name` (string, required): the name of the output. For nodes with a single output, the name "out" is preferred. -* `type` (string, required): the MaterialX type of the output. -* `defaultinput` (string, optional): the name of an <input> element within the <nodedef>, which must be the same type as `type`, that will be passed through unmodified by applications that don’t have an implementation for this node. -* `default` (same type as `type`, optional): a constant value which will be output by applications that don’t have an implementation for this node, or if a `defaultinput` input is specified but that input is not connected. - -The <output> elements for NodeDefs are similar to those for NodeGraph outputs, except that they may define default output values for the node but may not define a connection to another node (except for the `defaultinput` pass-through connection declaration) or any output file-related attributes such as width, height, colorspace or bitdepth. - - - -### Custom Node Definition Using Implementation Elements - -Once the parameter interface of a custom node has been declared through a <nodedef>, MaterialX provides two methods for precisely defining its functionality: via an <implementation> element that references external source code, or via a <nodegraph> element that composes the required functionality from existing nodes. Providing a definition for a custom node is optional in MaterialX, but is recommended for maximum clarity and portability. - -**Implementation** elements are used to associate external function source code with a specific nodedef. Implementation elements support the following attributes: - -* `name` (string, required): a unique name for this <implementation> -* `nodedef` (string, required): the name of the <nodedef> for which this <implementation> applies -* `nodegraph` (string, optional): the name of the <nodegraph> which is the implementation for the specified nodedef; see the [Custom Node Definition Using Node Graphs](#custom-node-definition-using-node-graphs) section below. -* `implname` (string, optional): an alternative name for this node for the specified target; this allows one to say that for this particular target, the node/shader is called something else but is functionally equivalent to the node described by the nodedef. Note that node graphs in MaterialX documents should always use the node names defined in the nodedefs, never implementation-specific names. -* `file` (filename, optional): the URI of an external file containing the source code for the entry point of this particular node template. This file may contain source code for other templates of the same custom node, and/or for other custom nodes. -* `sourcecode` (string, optional): a string containing the actual source code for the node. -* `function` (string, optional): the name of a function within the given source code that contains the implementation of this node. If this attribute is not given it is assumed the source code is an inline expression for a shader code generator like ShaderGen. Please refer to appropriate language specifications and developer guides (such as the ShaderGeneration.md file in the GitHub documents/DeveloperGuide directory) for valid syntax for using inline code. -* `target` (stringarray, optional): the set of targets to which this implementation is restricted. By default, an implementation is considered applicable to all targets that the referenced nodedef applies to. If the referenced <nodedef> also specifies a target, then this `target` must be a subset of the nodedef's target list. -* `format` (string, optional): the format used by the given source code, typically "shader" if the source code is a complete shader that can be compiled and executed as is by a target renderer, or "fragment" if the source code is a code fragment that requires processing of a code generator before it can be compiled and executed. Default is "shader". - -An <implementation> may define a `file` or `sourcecode` attribute, or neither, but not both. If an <implementation> element specifies a `target` with no `file` or `sourcecode`, then it is interpreted purely as documentation that a private definition exists for the given target. Because the definition in an <implementation> may be restricted to specific targets, a <nodedef> that is defined with such restrictions may not be available in all applications; for this reason, a <nodedef> that is defined through an <implementation> is expected to provide a value for `default` and/or `defaultinput` when possible, specifying the expected behavior when no definition for the given node can be found. It should be noted that specifying `target` is intended to help applications differentiate between different implementations of nodes and implies compatibility for specific situations, but does not necessarily guarantee compatibility: they are intended to be hints about the particular implementation, and it is up to the host application to determine which <implementation>, if any, is appropriate for any particular use. - -Because the names used for node inputs (such as "normal" or "default") may conflict with the reserved words in various shading languages, or may simply be different for specific targets, <implementation> elements may contain a number of <input> elements to remap the `name`s of <input>s as specified in the <nodedef> to different `implname`s to indicate what the input name is actually called in the implementation's code. Only the inputs that need to be remapped to new `implname`s need to be listed; for each, it is recommended that the `type` of that input be listed for clarity, but if specified, it must match the type specified in the <nodedef>: <implementation>s are not allowed to change the type or any other attribute defined in the <nodedef>. In this example, the <implementation> declares that the "default" input defined in the "ND_image_color3" nodedef is actually called "default_value" in the "mx_image_color" function: - -```xml - - - -``` - -For uniform inputs and tokens whose nodedef description includes an enum list of allowable values, individual implementations may associate different target-specific resolved values for them potentially of a different type; these may be described by providing an `enumvalues` attribute on the uniform input or token within an <implementation> and if appropriate, an `impltype` to declare the target-specific type of these enumvalues. Note that if the type of an enum input in the nodedef is an array type, then the `impltype` (if specified) must also be an array type, while `enumvalues` is a list of values of the base (non-array) type. The following <implementation> states that for the "mystudio" target, the uaddressmode and vaddressmode inputs of the "image" node are actually called "extrapolate_u" and "extrapolate_v", are integers rather than strings, and take different values (e.g. "clamp" is 2): - -```xml - - - - - -``` - - -#### Example Custom Nodes Defined by External File Implementations - -```xml - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - -This example defines two templates for a custom operator node called "mariBlend" (one operating on color3 values, and one operating on floats), and one template for a custom source node called "mariCustomNoise". Implementations of these functions have been defined in both OSL and GLSL. There is also in this example an alternate implementation of the "mariCustomNoise" function specifically for VRay, as if the author had determined that the generic OSL version was not appropriate for that renderer. - -Here is an example of a two-output node definition and external implementation declaration. - -```xml - - - - - - - -``` - - - -### Custom Node Definition Using Node Graphs - -Alternatively, a custom node's implementation may be described using a Node Graph. A <nodegraph> element wraps a graph of standard or custom nodes, taking the inputs and producing the output(s) described in the specified <nodedef>. - -A **<nodegraph>** element consists of at least one node element and at least one <output> element contained within a <nodegraph> element. Nodegraph elements may be one of two types: a **functional nodegraph**, which is the implementation of a node defined by a separate <nodedef>, or a **compound nodegraph**, which is a set of nodes grouped together into a nodegraph container. A functional nodegraph must either itself specify a `nodedef` attribute or be referenced by an <implementation> element with a "nodegraph" attribute, while a compound nodegraph may do neither but may optionally specify one or more <input> and/or <token> elements. - - -#### Functional Nodegraphs - -A **functional nodegraph** is a nodegraph-based implementation for a specified <nodedef>, with the <nodedef> declaring the set of inputs that the nodegraph accepts: a functional nodegraph may not itself specify any direct child input elements. - -```xml - - ...node element(s)... - ...output element(s)... - -``` - -or - -```xml - - ...node element(s)... - ...output element(s)... - - -``` - -The type(s) of the <output>(s) of the <nodedef> and the type(s) of the nodegraph <output>(s) must agree, and if there are multiple outputs, then the `name`s of the <output>s in the <nodegraph> and <nodedef> must also agree. The inputs and tokens of the <nodedef> can be referenced within <input> and <token> elements of nodes within the nodegraph implementation using `interfacename` attributes in place of `value` or `nodename` attributes, e.g. a nodedef input "i2" and interface token "diffmap" could be referenced as follows: - -```xml - - -``` - -Note that a uniform <input> of a node within the nodegraph may use `interfacename` to reference a uniform input in the nodedef, but it may not reference a non-uniform nodedef input. - - -#### Compound Nodegraphs - -A **compound <nodegraph>** element may specify one or more child <input> and/or <token> elements. In this case, the <nodegraph> functions as a collapsible "wrapper" for the contained nodes. - -```xml - - [...input and/or token element(s)...] - ...node and/or (compound) nodegraph element(s)... - ...output element(s)... - -``` - -A compound nodegraph provides a set of named input and output connection ports which may be referenced by its contained nodes using `interfacename` attributes, and interface token names whose values may be substituted into filenames used within the nodegraph; nodes within this <nodegraph> adopt the context of that nodegraph. The <input>s and <token>s of a compound nodegraph may also be connected to other nodes outside the <nodegraph> at the same scope as the <nodegraph> itself using `nodename` attributes; inputs of nodes within a compound nodegraph may only be connected to the outputs of other nodes within the same compound nodegraph, or to the input connection ports using interfacename. This is in contrast to a <backdrop> node whose contained nodes connect directly to nodes outside the backdrop at the same level of context without going through an intermediate named <input>. A <nodegraph> element of this form may specify the same float `width` and `height` and boolean `minimized` attributes as <backdrop> nodes. Inputs of other nodes, or the inputs of a compound nodegraph, can connect to an output of a (different) compound nodegraph using a `nodegraph` attribute (and for multiple-output compound nodegraphs, an `output` attribute as well) on a node's <input>. - -It is permissible to define multiple nodegraph- and/or file-based implementations for a custom node for the same combination of input and output types, as long as the specified `version`/`target`/`format` combinations are unique, e.g. one implementation for target "oslpattern" and another for "glsl", or one "osl" target with `format="shader"` and another with `format="fragment"`. It is allowable for there to be both a <nodegraph> and an <implementation> for the same nodedef target/version, with the <implementation> generally prevailing in order to allow for optimized native-code node implementations, although ultimately it would be up to the host application to determine which implementation to actually use. - - -#### Example Custom Node Defined by a Nodegraph - -```xml - - - - - - - - - - - - - - - - - -``` - -The inputs of the nodegraph are declared by the <nodedef>, and the nodes within the nodegraph reference those inputs using `interfacename` attributes. The "fg" and "bg" inputs provide default values which are used if an input is left unconnected when the custom node is used, and the "amount" input defines a default value which will be used if invocations of the node do not explicitly provide a value for "amount". - - -### Custom Node Use - -Once defined with a <nodedef>, using a custom node within a node graph follows the same syntax as any other standard node: the name of the element is the name of the custom node, and the MaterialX type of the node's output is required; the custom node's child elements define connections of inputs to other node outputs as well as any input values for the custom node. - -```xml - - - - - - - - - - -``` - -When invoking nodes with multiple outputs, the `type` of the node should be declared as "multioutput", and other node inputs connecting to an output of the node must include an `output` attribute to specify which output of the node to connect to: - -```xml - - - - - - - - - - - - -``` - - - -## Shader Nodes - -Custom nodes that output data types with a "shader" semantic are referred to in MaterialX as "Shader Nodes". Shaders, along with their inputs, are declared using the same <nodedef>, <implementation> and <nodegraph> elements described above: - -```xml - - ...input declarations... - - -``` - -The attributes for <nodedef> elements as they pertain to the declaration of shaders are: - -* `name` (string, required): a user-chosen name for this shader node definition element. -* `node` (string, required): the name of the shader node being defined, which typically matches the name of an associated shader function such as “blinn_phong”, “disney_principled”, “volumecloud_vol”. Just as for custom nodes, this shading program may be defined precisely through an <implementation> or <nodegraph>, or left to the application to locate by name using any shader definition method that it chooses. - -The child <output> element within the <nodedef> defines the "data type" of the output for this shader, which must have been defined with a "shader" semantic; see the [Custom Data Types](#custom-data-types) section above and discussion below for details. - -NodeDef elements defining shader nodes do not typically include `default` or `defaultinput` attributes, though they are permitted using the syntax described in the [Custom Data Types](#custom-data-types) section if the output type of the shader node is not a blind data type. - -As mentioned in the [Custom Data Types](#custom-data-types) section earlier, the standard MaterialX distribution includes the following standard data types for shaders: - -```xml - - - - -``` - -These types all declare that they have "shader" semantic, but define different contexts in which a rendering target should interpret the output of the shader node. For a shading language based on deferred lighting computations (e.g. OSL), a shader-semantic data type is equivalent to a radiance closure. For a shading language based on in-line lighting computations (e.g. GLSL), a shader-semantic data type is equivalent to the final output values of the shader. - -Instantiation of shader nodes to give them specific values is done the same way as instantiating any other node type: - -```xml - - - - - -``` - -Instantiated shader nodes can also inherit from other shader nodes of the same class: - -```xml - - - -``` - -Declarations of shader node source implementations are accomplished using either <implementation> elements for external source file declarations, or functional nodegraphs for nodegraph-based definitions. - -As with non-shader custom nodes, **Input** elements are used within a <nodedef> to declare the input ports for a shader node. - -An input with a shader-semantic type may be given a value of "" to indicate no shader node is connected to this input; this is typically the default for shader-semantic inputs of operator nodes. It is up to applications to decide what to do with unconnected shader-semantic inputs. - -Please refer to [**Standard Shader Nodes**](./MaterialX.StandardNodes.md#standard-shader-nodes), [**Physically-Based Shading Nodes**](./MaterialX.PBRSpec.md) and [**NPR Shading Nodes**](./MaterialX.NPRSpec.md) for descriptions of Shader Nodes defined by MaterialX. - - - -## Material Nodes - -Custom nodes that output data types with a "material" semantic are referred to in MaterialX as "Material Nodes". Material nodes typically have one or more "shader" semantic inputs which establish what shaders the material references; previous versions of MaterialX used <shaderref> elements to establish these shader-to-material connections. Material Nodes are declared using the same <nodedef> elements as described above: - -```xml - - - ...additional shader or input declarations... - - -``` - -The attributes for <nodedef> elements as they pertain to the declaration of materials are: - -* `name` (string, required): a user-chosen name for this material node definition element. -* `node` (string, required): the name of the material node class being defined. - -The standard MaterialX distribution includes a single material type definition used as the output type for all material nodes: - -```xml - -``` - -as well as definitions for three standard material nodes, all outputting type "material": - - - -* **`surfacematerial`**: a surface shading material. - * `surfaceshader` (surfaceshader): the name of the surfaceshader node. - * `backsurfaceshader` (surfaceshader): the name of the surfaceshader node to be used for the back surface of an object, if the geometry is two-sided. Default is "", meaning the `surfaceshader` shader will be used for both sides of a surface if the geometry is two-sided. - * `displacementshader` (displacementshader): the name of the displacementshader node to use; default is "" for no displacement. - - - -* **`volumematerial`**: a volume shading material. - * `volumeshader` (volumeshader): the name of the volumeshader node. - - - -* **`lightmaterial`**: a light shader material. - * `lightshader` (lightshader): the name of the lightshader node. - -Material nodes supporting multiple shaders of the same type for different rendering targets can be defined: - -```xml - - - - - - - - -``` - -Creating materials with specific values bound to shader inputs involves instantiating a Shader Node for each desired shader type and setting values on those shader nodes, and connecting the shader node(s) to the inputs of a Material Node: - -```xml - - - - - - - - - - - -``` - -Alternatively, and perhaps more usefully, a complete network of multiple shader nodes of different types or for different targets along with a material node to collect them all can be packaged within a nodegraph, and the various inputs of the shader nodes and any other nodes connected to their inputs can be connected to a single material nodedef interface to provide parameter values for the entire multi-shader network. Because nodedef inputs can be referenced by more than one node, a single unified interface could be created for several shaders for different targets, and the networks for those targets could contain input value conversion nodes as needed to handle differences in parametrization or shading methodologies. - - -#### Example Pre-Shader Compositing Material - -A material to blend between three different surface layers using mask textures. This example also demonstrates the use of the "target" attribute of a shader implementation element to define multiple renderer-specific shaders of the same type referenced within a single material, and the use of interface tokens to define texture filenames. - -```xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - - -## Material Variants - -A Variant is a container for any number of uniform values for material inputs and interface tokens. One or more mutually-exclusive variants are defined as part of a <variantset>; variants may not be defined outside of a <variantset>. - -```xml - - - - - - - ...additional declarations for this variantset... - -``` - -<Input> elements within a <variant> may only define a `value`, not a connection to a node or <output>. - -Example uses for variants include defining a number of allowable colors and texture tokens for different costume variations, and defining values for progressively increasing levels of damage to a model. - -Variants and variantsets are not intrinsically associated with any particular material; they merely state a number of values for a number of named inputs/tokens. However, variantsets may state that they are associated with specific shader-semantic nodes and/or <nodedef> declarations by providing stringarray-type `node` and/or `nodedef` attributes: - -```xml - - ... -``` - -Variants and variantsets can be defined in any MaterialX implementation, but because variants are applied to materials within a <look>, they can only be applied in applications supporting MaterialX Geometry Extensions; please see the [**VariantAssign Elements**](./MaterialX.GeomExts.md#variantassign-elements) section in that document for information on using material variants. - -
- - -# References - -[^1]: - + + + +# MaterialX: An Open Standard for Network-Based CG Object Looks + +**Version 1.39** +Doug Smythe - Industrial Light & Magic +Jonathan Stone - Lucasfilm Advanced Development Group +July 26, 2024 + + +# Introduction + +Computer graphics production studios commonly use workflows involving multiple software tools for different parts of the production pipeline. There is also a significant amount of sharing and outsourcing of work across facilities, requiring companies to hand off fully look-developed models to other divisions or studios which may use different software packages and rendering systems. In addition, studio rendering pipelines that previously used monolithic shaders built by expert programmers or technical directors with fixed, predetermined texture-to-shader connections and hard-coded texture color-correction options are now using more flexible node-based shader networks built up by connecting images and procedurals to shader inputs through a graph of image processing and blending operators. + +At least four distinct interrelated data relationships are required to specify the complete "look" of a CG object: + +1. _Image processing networks_ of sources, operators, connections and input values, outputting a number of spatially-varying data streams. +2. _Geometry-specific information_ such as associated texture filenames or IDs for various map types. +3. Associations between spatially-varying data streams and/or uniform values and the inputs of surface, volume, or other shaders, defining a number of _materials_. +4. Associations between materials and specific geometries to create a number of _looks_. + +**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, while [**MaterialX: Proposed Additions and Changes**](./MaterialX.Proposals.md) describes forward-looking proposed funnctionality for MaterialX. + + + +## Table of Contents + +**[Introduction](#introduction)** + +**[MaterialX Overview](#materialx-overview)** + [Definitions](#definitions) + [MaterialX Names](#materialx-names) + [MaterialX Data Types](#materialx-data-types) + [Custom Data Types](#custom-data-types) + [MTLX File Format Definition](#mtlx-file-format-definition) + [Color Spaces and Color Management Systems](#color-spaces-and-color-management-systems) + [Units](#units) + [MaterialX Namespaces](#materialx-namespaces) + [Geometric Properties](#geometric-properties) + [File Prefixes](#file-prefixes) + [Filename Substitutions](#filename-substitutions) + +**[Nodes](#nodes)** + [Inputs](#inputs) + [Node Graph Elements](#node-graph-elements) + [Output Elements](#output-elements) + + [Standard Source Nodes](#standard-source-nodes) +  [Texture Nodes](#texture-nodes) +  [Procedural Nodes](#procedural-nodes) +  [Noise Nodes](#noise-nodes) +  [Shape Nodes](#shape-nodes) +  [Geometric Nodes](#geometric-nodes) +  [Application Nodes](#application-nodes) + + [Standard Operator Nodes](#standard-operator-nodes) +  [Math Nodes](#math-nodes) +  [Logical Operator Nodes](#logical-operator-nodes) +  [Adjustment Nodes](#adjustment-nodes) +  [Compositing Nodes](#compositing-nodes) +  [Conditional Nodes](#conditional-nodes) +  [Channel Nodes](#channel-nodes) +  [Convolution Nodes](#convolution-nodes) + + [Standard Node Inputs](#standard-node-inputs) + [Standard UI Attributes](#standard-ui-attributes) + [Backdrop Elements](#backdrop-elements) + [Node Graph Examples](#node-graph-examples) + +**[Customization, Targeting and Shading](#customization-targeting-and-shading)** + [Target Definition](#target-definition) + [Custom Attributes and Inputs](#custom-attributes-and-inputs) + + [Custom Nodes](#custom-nodes) +  [Custom Node Declaration NodeDef Elements](#custom-node-declaration-nodedef-elements) +   [NodeDef Parameter Interface](#nodedef-parameter-interface) +   [NodeDef Input Elements](#nodedef-input-elements) +   [NodeDef Token Elements](#nodedef-token-elements) +   [NodeDef Output Elements](#nodedef-output-elements) +  [Custom Node Definition Using Implementation Elements](#custom-node-definition-using-implementation-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) +   [Compound Nodegraphs](#compound-nodegraphs) +   [Example Custom Node Defined by a Nodegraph](#example-custom-node-defined-by-a-nodegraph) +  [Custom Node Use](#custom-node-use) + [Shader Nodes](#shader-nodes) +  [Standard Library Shader Nodes](#standard-library-shader-nodes) + [Material Nodes](#material-nodes) +  [Example Pre-Shader Compositing Material](#example-pre-shader-compositing-material) + [Material Variants](#material-variants) + +**[References](#references)** + + +# MaterialX Overview + +The diagram below gives a high-level overview of a typical MaterialX look definition. A directed acyclic graph of pattern generation and processing nodes is connected to inputs of a surface Shader which defines a layered BSDF response. One or more shaders can be connected to form a Material, which is ultimately associated with specific scene geometry via a MaterialAssign, a number of which comprise a Look. The assignments of Materials to geometries can be defined within a MaterialX document in applications supporting MaterialX Geometry Extensions, or using an alternative mechanism such as USD[^1] or a native application's toolset. Each of the pattern nodes and even the Shaders may in turn be implemented using a graph of nodes: these NodeGraphs are given a parameter interface using NodeDefs, and these implementations may be reused with different input values just like any other Standard node defined by MaterialX. + +![MaterialX Overview Diagram](media/MaterialX_1.39_Overview_v5.png "MaterialX Overview Diagram") + +MaterialX also allows the specification of additional information not shown in this diagram, such as geometry-specific properties, material variations, arbitrary custom inputs and attributes for nodes, rendering-target-specific versions of shaders, nodes and implementations, external compiled or generated shader implementations, and much more. + + + +## Definitions + +Because the same word can be used to mean slightly different things in different contexts, and because each studio and package has its own vocabulary, it's important to define exactly what we mean by any particular term in this proposal and use each term consistently. + +An **Element** is a named object within a MaterialX document, which may possess any number of child elements and attributes. An **Attribute** is a named property of a MaterialX element. + +A **Node** is a function that generates or operates upon spatially-varying data. This specification provides a set of standard nodes with precise definitions, and also supports the creation of custom nodes for application-specific uses. The interface for a node’s incoming data is declared through **Inputs**, which may be spatially-varying or uniform, and **Tokens**, which are string values that can be substituted into filenames declared in node inputs. + +A **Pattern** is a node that generates or processes simple scalar, vector, and color data, and has access to local properties of any geometry that has been bound. + +A **Shader** is a node that can generate or process arbitrary lighting or BSDF data, and has access to global properties of the scene in which it is evaluated. + +A **Material** is a node which internally or externally references one or more shaders with specific data streams or uniform values bound to their inputs. + +A **Node Graph** is a directed acyclic graph of nodes, which may be used to define arbitrarily complex generation or processing networks. Common uses of Node Graphs are to describe a network of pattern nodes flowing into shader inputs, or to define a complex or layered node in terms of simpler nodes. + +A **Stream** refers to a flow of spatially-varying data from one node to another. A Stream most commonly consists of color, vector, or scalar data, but can transport data of any standard or custom type. + +A **Layer** is a named 1-, 2-, 3- or 4-channel color "plane" within an image file. Image file formats that do not support multiple or named layers within a file should be treated as if the (single) layer was named "rgba". + +A **Channel** is a single float value within a color or vector value, e.g. each layer of an image might have a red Channel, a green Channel, a blue Channel and an alpha Channel. + +A **Geometry** is any renderable object, while a **Partition** refers to a specific named renderable subset of a piece of geometry, such as a face set. + +A **Collection** is a recipe for building a list of geometries, which can be used as a shorthand for assigning e.g. a Material to a number of geometries in a Look. + +A **Target** is a software environment that interprets MaterialX content to generate images, with common examples being digital content creation tools and 3D renderers. + + + +## MaterialX Names + +All elements in MaterialX (nodes, materials, shaders, etc.) are required to have a `name` attribute of type "string". The `name` attribute of a MaterialX element is its unique identifier, and no two elements within the same scope (i.e. elements with the same parent) may share a name. + +Element names are restricted to upper- and lower-case letters, numbers, and underscores (“_”) from the ASCII character set; all other characters and symbols are disallowed. MaterialX names are case-sensitive and are not allowed to begin with a digit. + + + +## MaterialX Data Types + +All values, input and output ports, and streams in MaterialX are strongly typed, and are explicitly associated with a specific data type. The following standard data types are defined by MaterialX: + +**Base Types**: + +``` + integer, boolean, float, + color3, color4, + vector2, vector3, vector4, + matrix33, matrix44, string, filename +``` + +**Array Types**: + +``` + integerarray, floatarray, + color3array, color4array, + vector2array, vector3array, vector4array, + stringarray +``` + + +The following examples show the appropriate syntax for MaterialX attributes in MTLX files: + +**Integer**, **Float**: just a value inside quotes: + +``` + integervalue = "1" + floatvalue = "1.0" +``` + +**Boolean**: the lower-case word "true" or "false" inside quotes: + +``` + booleanvalue = "true" +``` + +**Color** types: MaterialX supports two different color types: + +* color3 (red, green, blue) +* color4 (red, green, blue, alpha) + +Color channel values should be separated by commas (with or without whitespace), within quotes: + +``` + color3value = "0.1,0.2,0.3" + color4value = "0.1,0.2,0.3,1.0" +``` + +Note: all color3 values and the RGB components of a color4 value are presumed to be specified in the "working color space" defined in the enclosing <materialx> element, although any element within a document may provide a `colorspace` attribute that explicitly states the space in which color values within its scope should be interpreted; implementations are expected to translate those color values into the working color space before performing computations with those values. See the [Color Spaces and Color Management Systems](#color-spaces-and-color-management-systems) section below. + +**Vector** types: similar to colors, MaterialX supports three different vector types: + +* vector2 (x, y) +* vector3 (x, y, z) +* vector4 (x, y, z, w) + +Coordinate values should be separated by commas (with or without whitespace), within quotes: + +``` + vector2value = "0.234,0.885" + vector3value = "-0.13,12.883,91.7" + vector4value = "-0.13,12.883,91.7,1.0" +``` + +While colorN and vectorN types both describe vectors of floating-point values, they differ in a number of significant ways. First, the final channel of a color4 value is interpreted as an alpha channel by compositing operators, and is only meaningful within the [0, 1] range, while the fourth channel of a vector4 value _could be_ (but is not necessarily) interpreted as the "w" value of a homogeneous 3D vector. Additionally, values of type color3 and color4 are always associated with a particular color space and are affected by color transformations, while values of type vector3 and vector4 are not. More detailed rules for colorN and vectorN operations may be found in the [Standard Operator Nodes](#standard-operator-nodes) section of the specification. + +**Matrix** types: MaterialX supports two matrix types that may be used to represent geometric and color transforms. The `matrix33` and `matrix44` types, respectively, represent 3x3 and 4x4 matrices and are written as nine or sixteen float values separated by commas, in row-major order: + +``` + matrix33value = "1,0,0, 0,1,0, 0,0,1" + matrix44value = "1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1" +``` + +**String**: literal text within quotes. See the [MTLX File Format Definition](#mtlx-file-format-definition) section for details on representing special characters within string data. + +``` + stringvalue = "some text" +``` + +**Filename**: attributes of type "filename" are just strings within quotes, but specifically mean a Uniform Resource Identifier ([https://en.wikipedia.org/wiki/Uniform_Resource_Identifier](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier)) optionally containing one or more Filename Substitution strings (see below) that represents a reference to an external asset, such as a file on disk or a query into a content management system. + +``` + filevalue = "diffuse/color01.tif" + filevalue = "/s/myshow/assets/myasset/v102.1/wetdrips/drips.{frame}.tif" + filevalue = "https://github.com/organization/project/tree/master/src/node.osl" + filevalue = "cmsscheme:myassetdiffuse..tif?ver=current" +``` + +**IntegerArray**, **FloatArray**, **Color3Array**, **Color4Array**, **Vector2Array**, **Vector3Array**, **Vector4Array**, **StringArray**: any number of values (including zero) of the same base type, separated by commas (with or without whitespace), within quotes; arrays of color3’s, color4’s, vector2's, vector3's or vector4's are simply a 1D list of channel values in order, e.g. "r0, g0, b0, r1, g1, b1, r2, g2, b2". Individual string values within stringarrays may not contain commas or semicolons, and any leading and trailing whitespace characters in them is ignored. MaterialX does not support multi-dimensional or nested arrays. Array-typed inputs to nodes must be static uniform values of a length specified by another uniform input value of the node, or implicitly by the node's implementation requirements. Nodes cannot output an Array type. + +``` + integerarrayvalue = "1,2,3,4,5" + floatarrayvalue = "1.0, 2.2, 3.3, 4.4, 5.5" + color3arrayvalue = ".1,.2,.3, .2,.3,.4, .3,.4,.5" + color4arrayvalue = ".1,.2,.3,1, .2,.3,.4,.98, .3,.4,.5,.9" + vector2arrayvalue = "0,.1, .4,.5, .9,1.0" + vector3arrayvalue = "-0.2,0.11,0.74, 5.1,-0.31,4.62" + vector4arrayvalue = "-0.2,0.11,0.74,1, 5.1,-0.31,4.62,1" + stringarrayvalue = "hello, there, world" +``` + + + +## 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. 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: + +* "`color`": the type is interpreted to represent or contain a color, and thus should be color-managed as described in the [Color Spaces and Color Management Systems](#color-spaces-and-color-management-systems) section. +* "`shader`": the type is interpreted as a shader output type; nodes or nodegraphs which output a type with a "shader" semantic can be used to define a shader-type node, which can be connected to inputs of "material"-type nodes. +* "`material`": the type is interpreted as a material output type; nodes or nodegraphs which output a type with a "material" semantic can be referenced by a <materialassign> in a <look>. + +Types not defined with a specific semantic are assumed to have semantic="default". + +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. 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. +* `hint` (string, optional): A hint to help those creating code generators understand how the type might be defined. The following hints for typedefs are currently defined: + * "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. + + + +## MTLX File Format Definition + +An MTLX file (with file extension ".mtlx") has the following general form: + +```xml + + + + +``` + +That is, a standard XML declaration line followed by a root <materialx> element, which contains any number of MaterialX elements and sub-elements. The default character encoding for MTLX files is UTF-8, and this encoding is expected for the in-memory representation of string values in MaterialX implementations. + +Standard XML XIncludes are supported ([http://en/wikipedia.org/wiki/XInclude](http://en/wikipedia.org/wiki/Xinclude)), as well as standard XML comments and the XML character entities `"`, `&`, `'`, `<` and `>`: + +```xml + + + +``` + +To support stringarray types, MaterialX supports a non-standard XML convention where a comma (and any following whitespace) is a separator for strings within a stringarray, a comma or semicolon preceded by a backslash is interpreted as a regular comma or semicolon rather than as a separator, and two backslashes are interpreted as a single backslash. + +Each XIncluded document must itself be a valid MTLX file, containing an XML header and its own root `` element, the children of which are added to the root element of the including document. Hierarchical root-level attributes such as `colorspace` and `namespace` are distributed to the included children to maintain correct semantics within the including MaterialX document. + +Attributes for a <materialx> element: + +* `version` (string, required): a string containing the version number of the MaterialX specification that this document conforms to, specified as a major and minor number separated by a dot. The MaterialX library automatically upgrades older-versioned documents to the current MaterialX version at load time. +* `colorspace` (string, optional): the name of the "working color space" for this element and all of its descendants. This is the default color space for all image inputs and color values, and the color space in which all color computations will be performed. The default is "none", for no color management. +* `namespace` (string, optional): defines the namespace for all elements defined within this <materialx> scope. Please see the [MaterialX Namespaces](#materialx-namespaces) section below for details. + + + +## Color Spaces and Color Management Systems + +MaterialX supports the use of color management systems to associate RGB colors and images with specific color spaces. MaterialX documents typically specify the working color space of the application that created them, and any input color or image described in the document can specify the name of its color space if different from the working color space. This allows applications using MaterialX to transform color values within input colors and images from their original color space into a desired working color space upon ingest. MaterialX does not specify _how_ or _when_ color values should be transformed: that is up to the host application, which can use any appropriate method including code generation, conversion when loading images into memory, maintaining cached or pre-converted image textures, etc. It is generally presumed that the working color space of a MaterialX document will be linear (as opposed to log, a display-referred space such as sRGB, or some other non-linear encoding), although this is not a firm requirement. + +By default, MaterialX supports the following color spaces as defined in ACES 1.2 ([http://www.oscars.org/science-technology/sci-tech-projects/aces)](http://www.oscars.org/science-technology/sci-tech-projects/aces), and applications rendering MaterialX documents are expected to transform input colors and images from these spaces to the color space of their renderer. One straightforward option for providing this support is to leverage MaterialX code generators, which support these transforms automatically, but applications may use any appropriate means to handle the transforms on their own. + +* `srgb_texture` +* `lin_rec709` +* `g22_rec709` +* `g18_rec709` +* `acescg` +* `lin_ap1 (alias for "acescg")` +* `g22_ap1` +* `g18_ap1` +* `lin_srgb` +* `adobergb` +* `lin_adobergb` +* `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 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. + +```xml + + + + +``` + +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. + + + +## Units + +MaterialX allows floating-point and vector values to be defined in terms of a specific unit and unit type, and can automatically convert values from their specified unit into a scene unit of the same type specified by the application. This allows images and the quantities they represent such as displacement amount to be specified at an absolute real-world size, and then be converted automatically to the expected scene units of the application. + +Unit types are defined using a <unittypedef> element, and a set of units of that type is defined using a <unitdef> element with one or more child <unit> elements. The following unittypes and units are pre-defined by MaterialX: + +```xml + + + + + + + + + + + + + + + + + + +``` + +The <unittypedef> defines the name of a unittype, while the <unitdef> defines any number of units for a unittype along with the multiplicative conversion `scale` values relative to the other units. Additional unit definitions for any unit type may be done by providing another <unitdef> with the same `unittype` attribute value. + +Any input or other floating-point value may specify a `unit` and/or `unittype` attribute subject to guidelines clarified throughout this document. Units and unittypes may also be provided for floatarray, vectorN and vectorNarray quantities, with all components of the vector or all values in the array using the same unit, and for "filename"-type input, in which case the `unit` and/or `unittype` attribute applies to the float or vectorN values read from those files. It is not expected that all inputs will have defined units or unittypes; in fact, it is expected that the vast majority of inputs will have neither. Units and unittypes should only be specified where specific units are important and it is reasonably expected that unit conversion may need to take place. + +Please refer to the [Inputs](#inputs), [Custom Node Declaration NodeDef Elements](#custom-node-declaration-nodedef-elements), [Geometric Properties](#geometric-properties) and [Geometric Nodes](#geometric-nodes) sections below and in the MaterialX Geometry Extensions document for additional specific requirements for the use of units. + + + +## MaterialX Namespaces + +MaterialX supports the specification of “namespaces”, which qualify the MaterialX names of all elements within their scope. Namespaces are specified via a `namespace` attribute in a <materialx> element, and other MaterialX files which <xi:include> this .mtlx file can refer to its content without worrying about element or object naming conflicts, similar to the way namespaces are used in various programming languages. It is permissible for multiple <materialx> elements to specify the same namespace; the elements from each will simply be merged into the same namespace. <materialx> elements which do not specify a namespace will define elements into the (unnamed) global namespace. MaterialX namespaces are most commonly used to define families of custom nodes (nodedefs), material libraries, or commonly-used network shaders or nodegraphs. + +References to elements in a different namespace are qualified using the syntax "_namespace_:_elementname_", where _namespace_ is the namespace at the scope of the referenced element and _elementname_ is the name of the referenced element. References to elements in the same namespace, or to elements in the global namespace, should not be qualified. + +#### Namespace Examples + +Mtllib.mtlx contains the following (assuming that "..." contains any necessary material input connections and other element definitions): + +```xml + + + ... + + ... + + + ... + + +``` + +Then another MaterialX file could reference these materials like this: + +```xml + + ... + + + + +``` + +Similarly, if a .mtlx file defining the "site_ops" namespace defined a custom color3-typed node "mynoise" with a single float input "f", it could be used in a node graph like this: + +```xml + + + +``` + +A `namespace` attribute may also be added to individual <nodedef>s or <nodegraph>s, in which case the `name` and `node` of a <nodedef>, or just the `name` of a <nodegraph> will be assigned to the specified `namespace`. In a <nodegraph>, the `nodedef` must include a namespace reference if the <nodedef> to which it refers is defined in a specific namespace, even if it's the same namespace as the <nodegraph>: this is because the `namespace` only applies to the content that is created by or contained within an element, not to anything external referenced by that element. + +```xml + + + + + + + + + + +``` + + + +## Geometric Properties + +Geometric Properties, or "geomprops", are intrinsic or user-defined surface coordinate properties of geometries referenced in a specific space and/or index, and are functionally equivalent to USD's concept of "primvars". A number of geometric properties are predefined in MaterialX: `position`, `normal`, `tangent`, `bitangent`, `texcoord` and `geomcolor`, the values of which can be accessed in nodegraphs using elements of those same names; see the [Geometric Nodes](#geometric-nodes) section below for details. The value of a varying geometric property can also be used as the default value for a node input using a `defaultgeomprop` attribute. + +The following geometric properties are pre-defined by MaterialX: + +| GeomProp Name | Type | Description | +| ---- | ---- | ---- | +| Pobject | vector3 | Object space position | +| Nobject | vector3 | Object space surface normal | +| Tobject | vector3 | Object space tangent vector (index 0) | +| Bobject | vector3 | Object space bitangent vector (index 0) | +| Pworld | vector3 | World space position | +| Nworld | vector3 | World space surface normal | +| Tworld | vector3 | World space tangent vector (index 0) | +| Bworld | vector3 | World space bitangent vector (index 0) | +| UV0 | vector2 | Index "0" UV texture coordinate | + +One may also define custom geometric properties using a <geompropdef> element: + +```xml + +``` + +e.g. + +```xml + + +``` + +The `type` of the geomprop may be any non-array MaterialX type, although `string`- or `filename`-type geomprops must be declared with uniform="true". The "geomprop", "space" and "index" attributes are optional; if "geomprop" is specified, it must be one of the standard geometric properties noted above, and if it is not specified, the new geomprop is a blind geometric property, e.g. one that can be referenced but which MaterialX knows no details about. The "space" and "index" attributes may only be specified if a "geomprop" attribute is specified and the standard geomproperty supports it. "Geomprop", "space" and "index" attributes may not be specified for `uniform="true"` geomprops. + +Once defined, a custom geomprop name may be used any place that a standard geomprop can: + +```xml + +``` + +A geompropdef may also specify a `unittype` and a `unit` to indicate that the geometric property is defined in terms of a specific unit. If a geomprop with a defined unit is accessed in a nodegraph using <geompropvalue>, the geometric property value will be converted from the unit specified by the geompropdef to the application-specified scene unit. + +```xml + +``` + + + +## File Prefixes + +As a shorthand convenience, MaterialX allows the specification of a `fileprefix` attribute which will be prepended to input values of type "filename" (e.g. `file` inputs in `` nodes, or any shader input of type "filename") specified within the scope of the element defining the `fileprefix`. Note that `fileprefix` values are only prepended to input with a `type` attribute that explicitly states its data type as “filename”. Since the values of the prefix and the filename are string-concatenated, the value of a `fileprefix` should generally end with a "/". Fileprefixes are frequently used to split off common path components for asset directories, e.g. to define an asset's "texture root" directory. + +So the following snippets are equivalent: + +```xml + + + + + + + + + + + + + + + + + +``` + +Note in the second example that `` "in2" redefined `fileprefix` for itself, and that any other nodes in the same nodegraph would use the fileprefix value ("textures/color/") defined in the parent/enclosing scope. + +Note: Application implementations have access to both the raw input values and attributes (e.g. the "file" name and the current "fileprefix") and to fully-resolved filenames at the scope of any given element. + + + +## Filename Substitutions + +Filename input values for various nodes can include one or more special strings, which will be replaced as described in the following table. Substitution strings within <>'s come from the current geometry, strings within []'s come from the MaterialX state, and strings within {}'s come from the host application environment. + +| Token | Description | +| ---- | ---- | +| <UDIM> | A special geometry token that will be replaced with the computed four digit Mari-style "udim" value at render or evaluation time based on the current point’s uv value, using the formula UDIM = 1001 + U + V*10, where U is the integer portion of the u coordinate, and V is the integer portion of the v coordinate. | +| <UVTILE> | A special geometry token that will be replaced with the computed Mudbox-style "uU_vV" string, where U is 1+ the integer portion of the u coordinate, and V is 1+ the integer portion of the v coordinate. | +| [interface token] | The value of a specified token declared in the containing nodegraph's <nodedef> interface; the value for the token may be set in the shader node in a material referencing the node or within a <variant>; it is an error if the same token is defined in more than one of those places for the current geometry. | +| {hostattr} | The host application may define other variables which can be resolved within filenames. | +| {frame} | A special string that will be replaced by the current frame number, as defined by the host environment. | +| {0Nframe} | A special string that will be replaced by the current frame number padded with zeros to be N digits total (replace N with a number): e.g. {04frame} will be replaced by a 4-digit zero-padded frame number such as "0010". | + + +Note: Implementations are expected to retain substitution strings within filenames upon export rather than "baking them out" into fully-evaluated filenames. Applications using USD for geometry and assignments may additionally use a <_geometry token_> (a.k.a. "<_primvarname_>") as the entire filename string to access an entire string primvar value unchanged (though that string value may contain the USD-supported <UDIM> token). + + + +# Nodes + +Nodes are individual data generation or processing "blocks". Node functionality can range from simple operations such as returning a constant color value or adding two input values, to more complex image processing operations, 3D spatial data operations, or even complete shader BxDFs. Nodes are connected together into a network or "node graph", and pass typed data streams between them. + +Individual node elements have the form: + +```xml + + + ...additional input or token elements... + +``` + +where _nodecategory_ is the general "category" of the node (e.g. "image", "add" or "mix"), `name` (string, required) defines the name of this instance of the node, which must be unique within the scope it appears in, and `type` (string, required) specifies the MaterialX type (typically float, colorN, or vectorN) of the output of that node. If the application uses a different name for this instance of the node in the user interface, a `uiname` attribute may be added to the <_nodecategory_> element to indicate the name of the node as it appears to the user. + +Node elements may optionally specify a `version` string attribute in "_major_[._minor_]" format, requesting that a specific version of that node's definition be used instead of the default version. Normally, the types of a node's inputs and outputs are sufficient to disambiguate which signature of the applicable version of a node is intended, but if necessary, a node instantiation may also declare a specific nodedef name to precisely define exactly which node signature is desired. Please refer to the [Custom Node Declaration NodeDef Elements](#custom-node-declaration-nodedef-elements) section below for further details. + +MaterialX defines a number of Standard Nodes which all implementations should support as described to the degree their architecture and capabilities allow. These standard nodes are grouped into [Standard Source Nodes](#standard-source-nodes) and [Standard Operator Nodes](#standard-operator-nodes); these groups are further divided into additional subcategories of nodes. In the descriptions below, a node with an "(NG)" annotation indicates a node that is implemented using a nodegraph in the MaterialX distribution, while unannotated nodes are implemented natively in the various renderer shading languages. One can define new nodes by declaring their parameter interfaces and providing portable nodegraph or target-specific shading language implementations. Please see the [Custom Nodes](#custom-nodes) section for notes and implementation details. + + + +## 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). + +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. + +```xml + + + +``` + +Unless specified otherwise, all inputs default to a value of 0 in all channels for integer, float, color and vector types, "" for string and filename types, "false" for boolean types, the identity matrix for matrix types, and for array types, an appropriate-length array consisting of the default value for the array's base type. + +Standard MaterialX nodes have exactly one output, while custom nodes may have any number of outputs; please see the [Custom Nodes](#custom-nodes) section for details. + + + +## Node Graph Elements + +A graph containing any number of nodes and output declarations forms a Node Graph, which may be enclosed within a <nodegraph> element to group them together into a single functional unit. Please see the [Custom Node Definition Using Node Graphs](#custom-node-definition-using-node-graphs) section below for details on how nodegraphs can be used to describe the functionality of new nodes. + +```xml + + ...node element(s)... + ...output element(s)... + +``` + + + +## Output Elements + +Output data streams are defined using **<output>** elements, and may be used to declare which output streams are connectable to other MaterialX elements. Within a node graph, an <output> element declares an output stream that may be connected to a shader input or to the input of a referencing node in another graph when the nodegraph is the implementation of a custom node. See the [Custom Node Definition Using Node Graphs](#custom-node-definition-using-node-graphs) section for details on the use of node graphs as node implementations. + +```xml + + +``` + +Attributes for Output elements: + +* `name` (string, required): the name of the output +* `type` (string, required): the MaterialX type of the output +* `nodename` (string, optional): the name of a node at the same scope within the document, whose result value will be output. This attribute is required for <output> elements within a node graph, but is not allowed in <output> elements within a <nodedef>. +* `output` (string, optional): if the node specified by `nodename` has multiple outputs, the name of the specific output to connect this <output> to. +* `uniform` (boolean, optional): If set to "true", then the output of this node is treated as a uniform value, and this output may be connected to a uniform input of the same (or compatible) type. It is up to the application creating the nodegraph to ensure that the value actually is uniform. Default is "false". + +MaterialX also supports the following additional attributes for Output elements in applications which process node graphs in 2D space and save or cache outputs as images for efficiency, such as texture baking or image caching. These attributes do **not** affect values from this <output> connected to other nodes, e.g. they would remain in the working colorspace and retain full resolution and bitdepth precision. + +* `colorspace` (string, optional): the name of the color space for the output image. Applications that support color space management are expected to perform the required transformations of output colors into this space. +* `width` (integer, optional): the expected width in pixels of the output image. +* `height` (integer, optional): the expected height in pixels of the output image. +* `bitdepth` (integer, optional): the expected per-channel bit depth of the output image, which may be used to capture expected color quantization effects. Common values for `bitdepth` are 8, 16, 32, and 64. It is up to the application to determine what the internal representation of any declared bit depth is (e.g. scaling factor, signed or unsigned, etc.). + + + +## Standard Source Nodes + +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) and [Application Nodes](#application-nodes). + + +### Texture Nodes + +Texture nodes are used to read filtered image data from image or texture map files for processing within a node graph. + +```xml + + + + + + + + +``` + +Standard Texture nodes: + + + +* **`image`**: samples data from a single image, or from a layer within a multi-layer image. When used in the context of rendering a geometry, the image is mapped onto the geometry based on geometry UV coordinates, with the lower-left corner of an image mapping to the (0,0) UV coordinate (or to the fractional (0,0) UV coordinate for tiled images). +The type of the <image> node determines the number of channels output, which may be less than the number of channels in the image file, outputting the first N channels from the image file. So a `float` <image> would return the Red channel of an RGB image, and a `color3` <image> would return the RGB channels of an RGBA image. If the type of the <image> node has more channels than the referenced image file, then the output will contain zero values in all channels beyond the N channels of the image file. + * `file` (uniform filename): the URI of an image file. The filename can include one or more substitutions to change the file name (including frame number) that is accessed, as described in the [Filename Substitutions](#filename-substitutions) section above. + * `layer` (uniform string): the name of the layer to extract from a multi-layer input file. If no value for `layer` is provided and the input file has multiple layers, then the "default" layer will be used, or "rgba" if there is no "default" layer. Note: the number of channels defined by the `type` of the `` must match the number of channels in the named layer. + * `default` (float or colorN or vectorN): a default value to use if the `file` reference can not be resolved (e.g. if a <_geometry token_>, [_interface token_] or {_hostattr_} is included in the filename but no substitution value or default is defined, or if the resolved `file` URI cannot be read), or if the specified `layer` does not exist in the file. The `default` value must be the same type as the `` element itself. If `default` is not defined, the default color value will be 0.0 in all channels. + * `texcoord` (vector2): the name of a vector2-type node specifying the 2D texture coordinate at which the image data is read. Default is to use the current u,v coordinate. + * `uaddressmode` (uniform string): determines how U coordinates outside the 0-1 range are processed before sampling the image; see below. Default is "periodic". + * `vaddressmode` (uniform string): determines how V coordinates outside the 0-1 range are processed before sampling the image; see below. Default is "periodic". + * `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. + + + +* **`tiledimage`** (NG): samples data from a single image, with provisions for tiling and offsetting the image across uv space. + * `file` (uniform filename): the URI of an image file. The filename can include one or more substitutions to change the file name (including frame number) that is accessed, as described in the [Filename Substitutions](#filename-substitutions) section. + * `default` (float or colorN or vectorN): a default value to use if the `file` reference can not be resolved (e.g. if a <geomtoken>, [interfacetoken] or {hostattr} is included in the filename but no substitution value or default is defined, or if the resolved file URI cannot be read), or if the specified `layer` does not exist in the file. The `default` value must be the same type as the `` element itself. If `default` is not defined, the default color value will be 0.0 in all channels. + * `texcoord` (vector2): the name of a vector2-type node specifying the 2D texture coordinate at which the image data is read. Default is to use the current u,v coordinate. + * `uvtiling` (vector2): the tiling rate for the given image along the U and V axes. Mathematically equivalent to multiplying the incoming texture coordinates by the given vector value. Default value is (1.0, 1.0). + * `uvoffset` (vector2): the offset for the given image along the U and V axes. Mathematically equivalent to subtracting the given vector value from the incoming texture coordinates. Default value is (0.0, 0.0). + * `realworldimagesize` (vector2): the real-world size represented by the `file` image, with unittype "distance". A `unit` attribute may be provided to indicate the units that `realworldimagesize` is expressed in. + * `realworldtilesize` (vector2): the real-world size of a single square 0-1 UV tile, with unittype "distance". A `unit` attribute may be provided to indicate the units that `realworldtilesize` is expressed in. + * `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. + + + +* **`triplanarprojection`** (NG): samples data from three images (or layers within multi-layer images), 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. + * `filex` (uniform filename): the URI of an image file to be projected in the direction from the +X axis back toward the origin. + * `filey` (uniform filename): the URI of an image file to be projected in the direction from the +Y axis back toward the origin with the +X axis to the right. + * `filez` (uniform filename): the URI of an image file to be projected in the direction from the +Z axis back toward the origin. + * `layerx` (uniform string): the name of the layer to extract from a multi-layer input file for the x-axis projection. If no value for `layerx` is provided and the input file has multiple layers, then the "default" layer will be used, or "rgba" if there is no "default" layer. Note: the number of channels defined by the `type` of the `` must match the number of channels in the named layer. + * `layery` (uniform string): the name of the layer to extract from a multi-layer input file for the y-axis projection. + * `layerz` (uniform string): the name of the layer to extract from a multi-layer input file for the z-axis projection. + * `default` (float or colorN or vectorN): a default value to use if any `fileX` reference can not be resolved (e.g. if a <geomtoken>, [interfacetoken] or {hostattr} is included in the filename but no substitution value or default is defined, or if the resolved file URI cannot be read) The `default` value must be the same type as the `` element itself. If `default` is not defined, the default color value will be 0.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. + * `upaxis` (integer enum): which axis is considered to be "up", either 0 for X, 1 for Y, or 2 for Z. Default is Y (1). + * `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. + + + + +The following values are supported by `uaddressmode` and `vaddressmode` inputs of [image](#node-image) nodes: + +* “constant”: Texture coordinates outside the 0-1 range return the value of the node's `default` input. +* “clamp”: Texture coordinates are clamped to the 0-1 range before sampling the image. +* “periodic”: Texture coordinates outside the 0-1 range "wrap around", effectively being processed by a modulo 1 operation before sampling the image. +* "mirror": Texture coordinates outside the 0-1 range will be mirrored back into the 0-1 range, e.g. u=-0.01 will return the u=0.01 texture coordinate value, and u=1.01 will return the u=0.99 texture coordinate value. + + +Texture nodes using `file*` inputs also support the following inputs to handle boundary conditions for image file frame ranges for all `file*` inputs: + +* `framerange` (uniform string): a string "_minframe_-_maxframe_", e.g. "10-99", to specify the range of frames that the image file is allowed to have, usually the range of image files on disk. Default is unbounded. +* `frameoffset` (integer): a number that is added to the current frame number to get the image file frame number. E.g. if `frameoffset` is 25, then processing frame 100 will result in reading frame 125 from the imagefile sequence. Default is no frame offset. +* `frameendaction` (uniform string): what to do when the resolved image frame number is outside the `framerange` range: + * "constant": Return the value of the node's `default` input (default action) + * "clamp": Hold the minframe image for all frames before _minframe_ and hold the maxframe image for all frames after _maxframe_ + * "periodic": Frame numbers "wrap around", so after the _maxframe_ it will start again at _minframe_ (and similar before _minframe_ wrapping back around to _maxframe_) + * "mirror": Frame numbers "mirror" or "ping-pong" at the endpoints of framerange, so a read of the frame after _maxframe_ will return the image from frame _maxframe_-1, and a read of the frame before _minframe_ will return the image from frame _minframe_+1. + +Arbitrary frame number expressions and speed changes are not supported. + + + +### Procedural Nodes + +Procedural nodes are used to generate value data programmatically. + +```xml + + + + + + + +``` + +Standard Procedural nodes: + + + +* **`constant`**: a constant value. + * `value` (any non-shader-semantic type): the value to output + + + +* **`ramplr`**: a left-to-right linear value ramp. + * `valuel` (float or colorN or vectorN): the value at the left (U=0) edge + * `valuer` (float or colorN or vectorN): the value at the right (U=1) edge + * `texcoord` (vector2): the name of a vector2-type node specifying the 2D texture coordinate at which the ramp interpolation is evaluated. Default is to use the first set of texture coordinates. + + + +* **`ramptb`**: a top-to-bottom linear value ramp. + * `valuet` (float or colorN or vectorN): the value at the top (V=1) edge + * `valueb` (float or colorN or vectorN): the value at the bottom (V=0) edge + * `texcoord` (vector2): the name of a vector2-type node specifying the 2D texture coordinate at which the ramp interpolation is evaluated. Default is to use the first set of texture coordinates. + + + +* **`ramp4`** (NG): a 4-corner bilinear value ramp. + * `valuetl` (float or colorN or vectorN): the value at the top-left (U0V1) corner + * `valuetr` (float or colorN or vectorN): the value at the top-right (U1V1) corner + * `valuebl` (float or colorN or vectorN): the value at the bottom-left (U0V0) corner + * `valuebr` (float or colorN or vectorN): the value at the bottom-right (U1V0) corner + * `texcoord` (vector2, optional): the name of a vector2-type node specifying the 2D texture coordinate at which the ramp interpolation is evaluated. Default is to use the first set of texture coordinates. + + + +* **`splitlr`**: a left-right split matte, split at a specified U value. + * `valuel` (float or colorN or vectorN): the value at the left (U=0) edge + * `valuer` (float or colorN or vectorN): the value at the right (U=1) edge + * `center` (float): a value representing the U-coordinate of the split; all pixels to the left of "center" will be `valuel`, all pixels to the right of "center" will be `valuer`. Default is 0.5. + * `texcoord` (vector2): the name of a vector2-type node specifying the 2D texture coordinate at which the split position is evaluated. Default is to use the first set of texture coordinates. + + + +* **`splittb`**: a top-bottom split matte, split at a specified V value. + * `valuet` (float or colorN or vectorN): the value at the top (V=1) edge + * `valueb` (float or colorN or vectorN): the value at the bottom (V=0) edge + * `center` (float): a value representing the V-coordinate of the split; all pixels above "center" will be `valuet`, all pixels below "center" will be `valueb`. Default is 0.5. + * `texcoord` (vector2): the name of a vector2-type node specifying the 2D texture coordinate at which the split position is evaluated. Default is to use the first set of texture coordinates. + + + +* **`randomfloat`**: Produces a stable randomized float value between 'min' and 'max', based on an 'input' signal and 'seed' value. Uses a 2d cellnoise function to produce the output. + * `in` (float or integer): Initial randomization seed, default is 0. + * `min` (float): The minimum output value, default is 0.0. + * `max` (float): The maximum output value, default is 1.0. + * `seed` (integer): Additional randomization seed, default is 0. + + + +* **`randomcolor`**: Produces a randomized RGB color within a randomized hue, saturation and brightness range, based on an 'input' signal and 'seed' value. Output type color3. + * `in` (float or integer): Initial randomization seed, default is 0. + * `huelow` (float): The minimum hue value, default is 0.0. + * `huehigh` (float): The maximum hue value, default is 1.0. + * `saturationlow` (float): The minimum saturation value, default is 0.0. + * `saturationhigh` (float): The maximum saturation value, default is 1.0. + * `brightnesslow` (float): The minimum brightness value, default is 0.0. + * `brightnesshigh` (float): The maximum brightness value, default is 1.0. + * `seed` (integer): Additional randomization seed, default is 0. + + +To scale or offset `rampX` or `splitX` input coordinates, use a <texcoord> or similar Geometric node processed by vector2 <multiply>, <rotate> and/or <add> nodes, and connect to the node's `texcoord` input. + + + +### Noise Nodes + +Noise nodes are used to generate value data using one of several procedural noise functions. + +```xml + + + + +``` + +Standard Noise nodes: + + + +* **`noise2d`**: 2D Perlin noise in 1, 2, 3 or 4 channels. + * `amplitude` (float or vectorN): the center-to-peak amplitude of the noise (peak-to-peak amplitude is 2x this value). Default is 1.0. + * `pivot` (float): the center value of the output noise; effectively, this value is added to the result after the Perlin noise is multiplied by `amplitude`. Default is 0.0. + * `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. + + + +* **`noise3d`**: 3D Perlin noise in 1, 2, 3 or 4 channels. + * `amplitude` (float or vectorN): the center-to-peak amplitude of the noise (peak-to-peak amplitude is 2x this value). Default is 1.0. + * `pivot` (float): the center value of the output noise; effectively, this value is added to the result after the Perlin noise is multiplied by `amplitude`. Default is 0.0. + * `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. + + + +* **`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. + * `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. Default is 2.0. VectorN-output types can provide either a float (isotropic) or vectorN (anisotropic) values for `lacunarity` and `diminish`. + * `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 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. + + + +* **`cellnoise2d`**: 2D 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 texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. + * `texcoord` (vector2): the 2D position at which the noise is evaluated. Default is to use the first set of texture coordinates. + + + +* **`cellnoise3d`**: 3D 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 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. + + + +* **`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. + + + +* **`unifiednoise2d`** (NG): a single node supporting 2D Perlin, Cell, Worley or Fractal noise in a unified interface. + * `type` (integer): The type of noise function to use. One of 0 (Perlin), 1 (Cell), 2 (Worley), or 3 (Fractal); default is Perlin. + * `texcoord` (vector2): the input 2d space. Default is the first texture coordinates. + * `freq` (vector2): Adjusts the noise frequency, with higher values producing smaller noise shapes. Default is (1,1). + * `offset` (vector2): Shift the noise in 2d space. Default is (0,0). + * `jitter` (float): Adjust uniformity of Worley noise; for other noise types jitters the results. + * `outmin` (float): The lowest values fit to the noise. Default is 0.0. + * `outmax` (float): The highest values fit to the noise. Default is 1.0. + * `clampoutput` (boolean): Clamp the output to the min and max output values. + * `octaves` (integer): The number of octaves of Fractal noise to be generated. Default is 3. + * `lacunarity` (float): The exponential scale between successive octaves of Fractal noise. Default is 2.0. + * `diminish` (float): The rate at which noise amplitude is diminished for each octave of Fractal noise. Default is 0.5. + + + +* **`unifiednoise3d`** (NG): a single node supporting 3D Perlin, Cell, Worley or Fractal noise in a unified interface. + * `type` (integer): The type of noise function to use. One of 0 (Perlin), 1 (Cell), 2 (Worley), or 3 (Fractal); default is Perlin. + * `position` (vector3): the input 3d space. Default is position in object-space. + * `freq` (vector3): Adjusts the noise frequency, with higher values producing smaller noise shapes. Default is (1,1,1). + * `offset` (vector3): Shift the noise in 3d space. Default is (0,0,0). + * `jitter` (float): Adjust uniformity of Worley noise; for other noise types jitters the results. + * `outmin` (float): The lowest values fit to the noise. Default is 0.0. + * `outmax` (float): The highest values fit to the noise. Default is 1.0. + * `clampoutput` (boolean): Clamp the output to the min and max output values. + * `octaves` (integer): The number of octaves of Fractal noise to be generated. Default is 3. + * `lacunarity` (float): The exponential scale between successive octaves of Fractal noise. Default is 2.0. + * `diminish` (float): The rate at which noise amplitude is diminished for each octave of Fractal noise. Default is 0.5. + + +To scale or offset the noise pattern generated by a 3D noise node such as `noise3d`, `fractal3d` or `cellnoise3d`, use a <position> or other [Geometric Node](#geometric-nodes) (see below) connected to vector3 <multiply> and/or <add> nodes, in turn connected to the noise node's `position` input. To scale or offset the noise pattern generated by a 2D noise node such as `noise2d` or `cellnoise2d`, use a <texcoord> or similar Geometric node processed by vector2 <multiply>, <rotate> and/or <add> nodes, and connect to the node's `texcoord` input. + + + +### Shape Nodes + +Shape nodes are used to generate shapes or patterns in UV space. + +```xml + + + + + +``` + +Standard Shape nodes: + + + +* **`checkerboard`** (NG): a 2D checkerboard pattern. Output type color3. + * `color1` (color3): The first color used in the checkerboard pattern. + * `color2` (color3): The second color used in the checkerboard pattern. + * `uvtiling` (vector2): The tiling of the checkerboard pattern along each axis, with higher values producing smaller squares. Default is (8, 8). + * `uvoffset` (vector2): The offset of the checkerboard pattern along each axis. Default is (0, 0). + * `texcoord` (vector2): The input 2d space. Default is the first texture coordinates. + + + +* **`line`** (NG): Returns 1 if texcoord is at less than radius distance from a line segment defined by point1 and point2; otherwise returns 0. Output type float. + * `texcoord` (vector2): The input 2d space. Default is the first texture coordinates. + * `center` (vector2): An offset value added to both the point1 and point2 coordinates, default is (0, 0). + * `radius` (float): The radius or "half thickness" of the line, default is 0.1. + * `point1` (vector2): The UV coordinate of the first endpoint, default is (0.25, 0.25). + * `point2` (vector2): The UV coordinate of the second endpoint, default is (0.75, 0.75). + + + +* **`circle`** (NG): Returns 1 if texcoord is inside a circle defined by center and radius; otherwise returns 0. Output type float. + * `texcoord` (vector2): The input 2d space. Default is the first texture coordinates. + * `center` (vector2): The center coordinate of the circle, default is (0, 0). + * `radius` (float): The radius of the circle, default is 0.5. + + + +* **`cloverleaf`** (NG): Returns 1 if texcoord is inside a cloverleaf shape described by four semicircles on the edges of a square defined by center and radius; otherwise returns 0. Output type float. + * `texcoord` (vector2): The input 2d space. Default is the first texture coordinates. + * `center` (vector2): 2x the coordinate of the center of the cloverleaf pattern, default is (0, 0); a value of (1,1) will center the cloverleaf in the 0-1 UV space. + * `radius` (float): The radius of the complete cloverleaf pattern, default is 0.5 resulting in a cloverleaf pattern filling the 0-1 UV boundary. + + + +* **`hexagon`** (NG): Returns 1 if texcoord is inside a hexagon shape inscribed by a circle defined by center and radius; otherwise returns 0. Output type float. + * `texcoord` (vector2): The input 2d space. Default is the first texture coordinates. + * `center` (vector2): The center coordinate of the hexagon, default is (0, 0). + * `radius` (float): The inner (edge center to opposite edge center) radius of the hexagon, default is 0.5. + + + +* **`grid`** (NG): Creates a grid pattern of (1, 1, 1) white lines on a (0, 0, 0) black background with the given tiling, offset, and line thickness. Pattern can be regular or staggered. Output type color3. + * `texcoord` (vector2): The input 2d space. Default is the first texture coordinates. + * `uvtiling` (vector2): Tiling factor, with higher values producing a denser grid. Default is (1, 1). + * `uvoffset` (vector2): UV Offset, default is (0, 0). + * `thickness` (float): The thickness of the grid lines, default is 0.05. + * `staggered` (boolean): If true, every other row will be offset 50% to produce a "brick wall" pattern. Default is false. + + + +* **`crosshatch`** (NG): Creates a crosshatch pattern with the given tiling, offset, and line thickness. Pattern can be regular or staggered. Output type color3. + * `texcoord` (vector2): The input 2d space. Default is the first texture coordinates. + * `uvtiling` (vector2): Tiling factor, with higher values producing a denser grid. Default is (1, 1). + * `uvoffset` (vector2): UV Offset, default is (0, 0). + * `thickness` (float): The thickness of the grid lines, default is 0.05. + * `staggered` (boolean): If true, every other row will be offset 50% to produce an "alternating diamond" pattern. Default is false. + + + +* **`tiledcircles`** (NG): Creates a black and white pattern of circles with a defined tiling and size (diameter). Pattern can be regular or staggered. Output type color3. + * `texcoord` (vector2): The input 2d space. Default is the first texture coordinates. + * `uvtiling` (vector2): Tiling factor, with higher values producing a denser grid. Default is (1, 1). + * `uvoffset` (vector2): UV Offset, default is (0, 0). + * `size` (float): The diameter of the circles in the tiled pattern, default is 0.5; if `size` is 1.0, the edges of adjacent circles in the tiling will exactly touch. + * `staggered` (boolean): If true, every other row will be offset 50%, and the spacing of the tiling will be adjusted in the V direction to center the circles on the vertices of an equilateral triangle grid. Default is false. + + + +* **`tiledcloverleafs`** (NG): Creates a black and white pattern of cloverleafs with a defined tiling and size (diameter of the circles circumscribing the shape). Pattern can be regular or staggered. Output type color3. + * `texcoord` (vector2): The input 2d space. Default is the first texture coordinates. + * `uvtiling` (vector2): Tiling factor, with higher values producing a denser grid. Default is (1, 1). + * `uvoffset` (vector2): UV Offset, default is (0, 0). + * `size` (float): The outer diameter of the cloverleafs in the tiled pattern, default is 0.5; if `size` is 1.0, the edges of adjacent cloverleafs in the tiling will exactly touch. + * `staggered` (boolean): If true, an additional pattern of cloverleafs will be generated in between the originals offset by 50% in both U and V. Default is false. + + + +* **`tiledhexagons`** (NG): Creates a black and white pattern of hexagons with a defined tiling and size (diameter of the circles circumscribing the shape). Pattern can be regular or staggered. Output type color3. + * `texcoord` (vector2): The input 2d space. Default is the first texture coordinates. + * `uvtiling` (vector2): Tiling factor, with higher values producing a denser grid. Default is (1, 1). + * `uvoffset` (vector2): UV Offset, default is (0, 0). + * `size` (float): The inner diameter of the hexagons in the tiled pattern, default is 0.5; if `size` is 1.0, the edges of adjacent hexagons in the U-direcction tiling will exactly touch. + * `staggered` (boolean): If true, every other row will be offset 50%, and the spacing of the tiling will be adjusted in the V direction to center the hexagons on the vertices of an equilateral triangle grid. Default is false. + + + + +### Geometric Nodes + +Geometric nodes are used to reference local geometric properties from within a node graph: + +```xml + + + + +``` + +Standard Geometric nodes: + + + +* **`position`**: the coordinates associated with the currently-processed data, as defined in a specific coordinate space. This node must be of type vector3. + * `space` (uniform string): the name of the coordinate space in which the position is defined. Default is "object", see below for details. + + + +* **`normal`**: the geometric normal associated with the currently-processed data, as defined in a specific coordinate space. This node must be of type vector3. + * `space` (uniform string): the name of the coordinate space in which the normal vector is defined. Default is "object", see below for details. + + + +* **`tangent`**: the geometric tangent vector associated with the currently-processed data, as defined in a specific coordinate space. This node must be of type vector3. + * `space` (uniform string): the name of the coordinate space in which the tangent vector is defined. Default is "object", see below for details. + * `index` (uniform integer): the index of the texture coordinates against which the tangent is computed. The default index is 0. + + + +* **`bitangent`**: the geometric bitangent vector associated with the currently-processed data, as defined in a specific coordinate space. This node must be of type vector3. + * `space` (uniform string): the name of the coordinate space in which the bitangent vector is defined. Default is "object", see below for details. + * `index` (uniform integer): the index of the texture coordinates against which the tangent is computed. The default index is 0. + + + +* **`bump`**: offset the surface normal by a scalar value. This node must be of type type vector3, and is generally connected to a shader node's "normal" input. + * `height` (float): Amount to offset the surface normal. + * `scale` (float): Scalar to adjust the height amount. + * `normal` (vector3): Surface normal; defaults to the current world-space normal. + * `tangent` (vector3): Surface tangent vector, defaults to the current world-space tangent vector. + + + +* **`texcoord`**: the 2D or 3D texture coordinates associated with the currently-processed data. This node must be of type vector2 or vector3. + * `index` (uniform integer): the index of the texture coordinates to be referenced. The default index is 0. + + + +* **`geomcolor`**: the color associated with the current geometry at the current `position`, generally bound via per-vertex color values. Can be of type float, color3 or color4, and must match the type of the "color" bound to the geometry. + * `index` (uniform integer): the index of the color to be referenced, default is 0. + + + +* **`geompropvalue`**: the value of the specified varying 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. + + + +* **`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). + + + + +The following values are supported by the `space` inputs of Geometric nodes and when transforming from one space to another: + + +* "model": The local coordinate space of the geometry, before any local deformations or global transforms have been applied. +* "object": The local coordinate space of the geometry, after local deformations have been applied, but before any global transforms. +* "world": The global coordinate space of the geometry, after local deformations and global transforms have been applied. +* "tangent": A coordinate space defined by the tangent, bitangent and normal vectors of the geometry. + +Applications may also reference other renderer-specific named spaces, at the expense of portability. + + + +### Application Nodes + +Application nodes are used to reference application-defined properties within a node graph, and have no inputs: + +```xml + +

- ---- - - -**MaterialX v1.39** provides the following enhancements over v1.38: - - -**MaterialX Geometry Extensions** - -The parts of the main MaterialX Specification document dealing with various Geometry-related features has now been split into a separate [**MaterialX Geometry Extensions**](./MaterialX.GeomExts.md) document, describing Collections, Geometry Name Expressions, geometry-related data types, Geometry Info elements and the GeomProp and Token elements used within them, and Look, Property, Visibility and assignment elements. - -With this split, applications can claim to be MaterialX Compatible if they support all the things described in the main Specification, e.g. the elements for nodegraph shading networks and materials as well as the standard set of nodes, while using an application's native mechanisms or something like USD to describe the assignment of these materials to geometry. Applications may additionally support the MaterialX Geometry Extensions and thus use a single unified representation for complete CG object looks. - - -**Array Types Now Uniform and Static Length** - -Many shading languages do not support dynamic array types with a variable length, so MaterialX now only supports arrays with a fixed maximum length, and all array-type node inputs must be uniform; nodes are no longer permitted to output an array type. Array-type inputs may be accompanied by a uniform integer input declaring the number of array elements actually used in the array (the <curveadjust> node has been updated in this way). Because of this change, the unimplemented <arrayappend> node has been removed. - - -**Connectable Uniform Inputs and New Tokenvalue Node** - -A uniform node input is now explicitly allowed to be connected to the output of a <constant> node. This makes it possible to define a uniform value and use it in multiple places in a nodegraph. - -Similarly, <token>s in materials and other node instances may now be connected to the output of a new <tokenvalue> node: this is essentially a <constant> node but which connects to <token>s rather than <input>s. - - -**Standardized Color Space Names** - -The [standard colorspace names](./MaterialX.Specification.md#color-spaces-and-color-management-systems) in MaterialX have now been defined explicitly in the Specification, and are aligned to their definitions in the ACES 1.2 OCIO config file. With this change, there is no need for a definition of "cms" or "cmsconfig" in MaterialX documents, so those two attributes have been deprecated. Additionally, two new colorspaces, "srgb_displayp3" and "lin_displayp3" have been added as standard colorspaces. - - -**Disambiguated Nodedef and Nodegraph References** - -Normally, the set of provided inputs to a node and their types in conjunction with the output type of the node itself is sufficient to disambiguate exactly which nodedef signature should be applied. In the rare situations where this is not sufficient, it is now permissible for any node instantiation to specify the name of a nodedef to completely disambiguate the intended node signature. - -Additionally, a <nodegraph> could previously declare itself to be an implementation of a particular <nodedef> by providing a "nodedef" attribute, which is still the preferred method for making this association. Now, it is also permissible for an [<implementation> element](39/MaterialX.Specification.md#custom-node-definition-using-implementation-elements) to provide a "nodegraph" attribute to declare that nodegraph to be the implementation for the nodedef specified in the <implementation>. This allows a single nodegraph to be the implementation of multiple nodedefs, e.g. two different node names with the same underlying implementation, or if the only difference between two versions of a nodedef is the default values. - - -**Generalized Swizzle Operator Removed** - -The standard <swizzle> node using a string of channel names and allowing arbitrary channel reordering is very inefficient (and in some shading languages virtually impossible) to implement as previously specified, and as such has been removed. Nodegraphs should instead use combinations of <extract> (which is now a standard node), <separateN> and <combineN> nodes to perform arbitrary channel reordering. Additionally, the previous "channels" attribute for inputs which allowed arbitrary channel reordering and used string "swizzle" channel naming has been removed. - - -**New Unlit Surface Shader and Standard Materials** - -A new <surface_unlit> node for unlit surfaces has been added to the standard library. - -Additionally, the standard <surfacematerial> material now supports both single- or double-sided surfaces with the addition of a separate `backsurface` input. - - -**Inheritance and Hints for Typedefs** - -Typedefs may now inherit from other types, including built-in types, and may provide hints about their values such as floating-point precision. These new "inherit" and "hint" attributes are themselves merely metadata hints about the types; applications and code generators are still expected to provide their own precise definitions for all custom types. - - -**New and Updated Standard Library Nodes** - -In 1.39, we are removing the distinction between "standard nodes" and "supplemental nodes", and descriptions of both can now be found in the main Specification document. Nodes that are implemented in the standard distribution using nodegraphs are annotated with "(NG)" in the Spec to differentiate them from nodes implemented in each rendering target's native shading language. - -Additionally, the following new operator nodes have been added to the standard library: - -* [Procedural nodes](./MaterialX.Specification.md#procedural-nodes): **tokenvalue**, **checkerboard**, **fractal2d**, **cellnoise1d**, **unifiednoise2d**, **unifiednoise3d** -* [Geometric nodes](./MaterialX.Specification.md#geometric-nodes): **bump**, **geompropvalueuniform** -* [Math nodes](./MaterialX.Specification.md#math-nodes): boolean **and**, **or**, **not**; **distance**, **transformcolor**, **creatematrix** and **triplanarblend**, as well as integer-output variants of **floor** and **ceil** -* [Adjustment nodes](./MaterialX.Specification.md#adjustment-nodes): **curveinversecubic**, **curveuniformlinear**, **curveuniformcubic** and **colorcorrect** -* [Conditional nodes](./MaterialX.Specification.md#conditional-nodes): boolean-output variants of **ifgreater**, **ifgreatereq** and **ifequal**; new **ifelse** node -* [Channel nodes](./MaterialX.Specification.md#channel-nodes): **extractrowvector** and **separatecolor4** - - -**New Physically Based Shading Nodes** - -The following new standard physically based shading nodes have been added: - -* [EDF nodes](./MaterialX.PBRSpec.md#edf-nodes): **generalized_schlick_edf** -* [Shader nodes](./MaterialX.PBRSpec.md#shader-nodes): **environment** (latlong environment light source) - - -**Other Changes** - -* 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. -* The <noise2d/3d>, <fractal2d/3d>, <cellnoise2d/3d> and <worleynoise2d/3d> nodes now support a "period" input. -* The <worleynoise2d> and <worleynoise3d> nodes now support a number of different distance metrics. -* The <time> node no longer has a "frames per second" input: the application is now always expected to generate the "current time in seconds" using an appropriate method. The "fps" input was removed because variable-rate real-time applications have no static "fps", and it's generally not good to bake a situation-dependent value like fps into a shading network. -* A standard "tangent" space is now defined in addition to "model", "object" and "world" spaces, and the <heighttonormal> node now accepts a uniform "space" input to define the space of the output normal vector. -* The <switch> node now supports 10 inputs instead of just 5. -* The <surface> and <displacement> nodes are now part of the main Specification rather than being Physically Based Shading nodes. -* <Token> elements are now explicitly allowed to be children of compound nodegraphs, and token values may now have defined enum/enumvalues. -* Inputs in <nodedef>s may now supply "hints" to code generators as to their intended interpretation, e.g. "transparency" or "opacity". -* <Attributedef> elements may now define enum/enumvalues to list acceptable values or labels/mapped values for an attribute. -* If a string input specifies an "enum" list, the list is now considered a "strict" list of allowable values; no values are allowed outside that list. To make the input non-strict, one must omit the "enum" attribute from the input. - - -Suggestions for v1.39: - -* Add a boolean “bound” output to the various geometry property nodes, so materials can be flexible if a given attribute doesn’t exist. Especially ones like <texcoord> that don’t let users specify names. - + + +**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. MaterialX addresses the need for a common, open standard to represent the data values and relationships required to describe the look of a computer graphics model, including shading networks, patterns and texturing, complex nested materials and geometric assignments. To further encourage interchangeable CG look setups, MaterialX also defines a large set of standard shading and processing nodes with a precise mechanism for functional extensibility. + +The documents in this folder comprise the complete MaterialX Specification, version 1.39. + +* [**MaterialX Specification**](./MaterialX.Specification.md) - the main Specification, describing definitions, core functionality and the standard node library +* [**MaterialX Physically Based Shading Nodes**](./MaterialX.PBRSpec.md) - describes BSDF and other shading function nodes useful in constructing complex layered rendering shaders using node graphs +* [**MaterialX NPR Shading Nodes**](./MaterialX.NPRSpec.md) - specifies shading nodes that are designed for use in non-photorealistic and stylized rendering +* [**MaterialX Geometry Extensions**](./MaterialX.GeomExts.md) - additional MaterialX elements to define geometry-related information such as collections, properties and material assignments +* [**MaterialX Supplemental Notes**](./MaterialX.Supplement.md) - describes recommended naming and structuring conventions for libraries of custom node definitions +* [**MaterialX: Proposed Additions and Changes**](./MaterialX.Proposals.md) - describes proposed future updates to various components of the Specification + +

+ +--- + + +**MaterialX v1.39** provides the following enhancements over v1.38: + + +**MaterialX Geometry Extensions** + +The parts of the main MaterialX Specification document dealing with various Geometry-related features has now been split into a separate [**MaterialX Geometry Extensions**](./MaterialX.GeomExts.md) document, describing Collections, Geometry Name Expressions, geometry-related data types, Geometry Info elements and the GeomProp and Token elements used within them, and Look, Property, Visibility and assignment elements. + +With this split, applications can claim to be MaterialX Compatible if they support all the things described in the main Specification, e.g. the elements for nodegraph shading networks and materials as well as the standard set of nodes, while using an application's native mechanisms or something like USD to describe the assignment of these materials to geometry. Applications may additionally support the MaterialX Geometry Extensions and thus use a single unified representation for complete CG objecct looks. + + +**New Support for Shader AOVs** + +Previously, MaterialX used custom types with a structure of output variables to define shader AOVs. But this approach was not very flexible and in fact had not been implemented. In v1.39, nodegraph-based shader implementations can include new [<aovoutput> elements](./MaterialX.Specification.md#aov-output-elements) to define AOVs which renderers can use to output additional channels of information in addition to the final shading result, while file-based <implementation>s can similarly define AOVs using [<aov> elements](./MaterialX.Specification.md#implementation-aov-elements). + + +**Array Types Now Uniform and Static Length** + +Many shading languages do not support dynamic array types with a variable length, so MaterialX now only supports arrays with a fixed maximum length, and all array-type node inputs must be uniform; nodes are no longer permitted to output an array type. Array-type inputs may be accompanied by a uniform integer input declaring the number of array elements actually used in the array (the <curveadjust> node has been updated in this way). Because of this change, the unimplemented <arrayappend> node has been removed. + + +**Connectable Uniform Inputs and New Tokenvalue Node** + +A uniform node input is now explicitly allowed to be connected to the output of a <constant> node. This makes it possible to define a uniform value and use it in multiple places in a nodegraph. + +Similarly, <token>s in materials and other node instances may now be connected to the output of a new <tokenvalue> node: this is essentially a <constant> node but which connects to <token>s rather than <input>s. + + +**Standardized Color Space Names** + +The [standard colorspace names](./MaterialX.Specification.md#color-spaces-and-color-management-systems) in MaterialX have now been defined explicitly in the Specification, and are aligned to their definitions in the ACES 1.2 OCIO config file. With this change, there is no need for a definition of "cms" or "cmsconfig" in MaterialX documents, so those two attributes have been deprecated. Additionally, two new colorspaces, "srgb_displayp3" and "lin_displayp3" have been added as standard colorspaces. + + +**Disambiguated Nodedef and Nodegraph References** + +Normally, the set of provided inputs to a node and their types in conjunction with the output type of the node itself is sufficient to disambiguate exactly which nodedef signature should be applied. In the rare situations where this is not sufficient, it is now permissible for any node instantiation to specify the name of a nodedef to completely disambiguate the intended node signature. + +Additionally, a <nodegraph> could previously declare itself to be an implementation of a particular <nodedef> by providing a "nodedef" attribute, which is still the preferred method for making this association. Now, it is also permissible for an [<implementation> element](39/MaterialX.Specification.md#custom-node-definition-using-implementation-elements) to provide a "nodegraph" attribute to declare that nodegraph to be the implementation for the nodedef specified in the <implementation>. This allows a single nodegraph to be the implementation of multiple nodedefs, e.g. two different node names with the same underlying implementation, or if the only difference between two versions of a nodedef is the default values. + + +**Generalized Swizzle Operator Removed** + +The standard <swizzle> node using a string of channel names and allowing arbitrary channel reordering is very inefficient (and in some shading languages virtually impossible) to implement as previously specified, and as such has been removed. Nodegraphs should instead use combinations of <extract> (which is now a standard node), <separateN> and <combineN> nodes to perform arbitrary channel reordering. Additionally, the previous "channels" attribute for inputs which allowed arbitrary channel reordering and used string "swizzle" channel naming has been removed. + + +**New Unlit Surface Shader and Standard Materials** + +A new <surface_unlit> node for unlit surfaces has been added to the standard library. + +Additionally, the standard <surfacematerial> material now supports both single- or double-sided surfaces with the addition of a separate `backsurface` input. + + +**Inheritance and Hints for Typedefs** + +Typedefs may now inherit from other types, including built-in types, and may provide hints about their values such as floating-point precision. These new "inherit" and "hint" attributes are themselves merely metadata hints about the types; applications and code generators are still expected to provide their own precise definitions for all custom types. + + +**New and Updated Standard Library Nodes** + +In 1.39, we are removing the distinction between "standard nodes" and "supplemental nodes", and descriptions of both can now be found in the main Specification document. Nodes that are implemented in the standard distribution using nodegraphs are annotated with "(NG)" in the Spec to differentiate them from nodes implemented in each rendering target's native shading language. + +Additionally, the following new operator nodes have been added to the standard library: + +* [Procedural nodes](./MaterialX.Specification.md#procedural-nodes): **tokenvalue**, **checkerboard**, **fractal2d**, **cellnoise1d**, **unifiednoise2d**, **unifiednoise3d** +* [Geometric nodes](./MaterialX.Specification.md#geometric-nodes): **bump**, **geompropvalueuniform** +* [Math nodes](./MaterialX.Specification.md#math-nodes): boolean **and**, **or**, **not**; **distance**, **transformcolor**, **creatematrix** and **triplanarblend**, as well as integer-output variants of **floor** and **ceil** +* [Adjustment nodes](./MaterialX.Specification.md#adjustment-nodes): **curveinversecubic**, **curveuniformlinear**, **curveuniformcubic** and **colorcorrect** +* [Conditional nodes](./MaterialX.Specification.md#conditional-nodes): boolean-output variants of **ifgreater**, **ifgreatereq** and **ifequal**; new **ifelse** node +* [Channel nodes](./MaterialX.Specification.md#channel-nodes): **extractrowvector** and **separatecolor4** + + +**New Physically Based Shading Nodes** + +The following new standard physically based shading nodes have been added: + +* [EDF nodes](./MaterialX.PBRSpec.md#edf-nodes): **generalized_schlick_edf** +* [Shader nodes](./MaterialX.PBRSpec.md#shader-nodes): **environment** (latlong environment light source) + + +**Other Changes** + +* 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. +* The <noise2d/3d>, <fractal2d/3d>, <cellnoise2d/3d> and <worleynoise2d/3d> nodes now support a "period" input. +* The <worleynoise2d> and <worleynoise3d> nodes now support a number of different distance metrics. +* The <time> node no longer has a "frames per second" input: the application is now always expected to generate the "current time in seconds" using an appropriate method. The "fps" input was removed because variable-rate real-time applications have no static "fps", and it's generally not good to bake a situation-dependent value like fps into a shading network. +* A standard "tangent" space is now defined in addition to "model", "object" and "world" spaces, and the <heighttonormal> node now accepts a uniform "space" input to define the space of the output normal vector. +* The <switch> node now supports 10 inputs instead of just 5. +* The <surface> and <displacement> nodes are now part of the main Specification rather than being Physically Based Shading nodes. +* <Token> elements are now explicitly allowed to be children of compound nodegraphs, and token values may now have defined enum/enumvalues. +* Inputs in <nodedef>s may now supply "hints" to code generators as to their intended interpretation, e.g. "transparency" or "opacity". +* <Attributedef> elements may now define enum/enumvalues to list acceptable values or labels/mapped values for an attribute. +* If a string input specifies an "enum" list, the list is now considered a "strict" list of allowable values; no values are allowed outside that list. To make the input non-strict, one must omit the "enum" atribute from the input. + + +Suggestions for v1.39: + +* Add a boolean “bound” output to the various geometry property nodes, so materials can be flexible if a given attribute doesn’t exist. Especially ones like <texcoord> that don’t let users specify names. + diff --git a/MaterialX/documents/Specification/media/MaterialX_1.39_Overview_v5.png b/MaterialX/documents/Specification/media/MaterialX_1.39_Overview_v5.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Specification/media/PBSdiagram.png b/MaterialX/documents/Specification/media/PBSdiagram.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Specification/media/nodegraph1.png b/MaterialX/documents/Specification/media/nodegraph1.png old mode 100644 new mode 100755 diff --git a/MaterialX/documents/Specification/media/nodegraph2.png b/MaterialX/documents/Specification/media/nodegraph2.png old mode 100644 new mode 100755 diff --git a/MaterialX/javascript/.gitignore b/MaterialX/javascript/.gitignore old mode 100644 new mode 100755 index 751285d..e0e20ef --- a/MaterialX/javascript/.gitignore +++ b/MaterialX/javascript/.gitignore @@ -1,4 +1,4 @@ -build -**/_build -**/dist -**/node_modules +build +**/_build +**/dist +**/node_modules diff --git a/MaterialX/javascript/MaterialXTest/.babelrc b/MaterialX/javascript/MaterialXTest/.babelrc old mode 100644 new mode 100755 index e9c21ad..bc304d3 --- a/MaterialX/javascript/MaterialXTest/.babelrc +++ b/MaterialX/javascript/MaterialXTest/.babelrc @@ -1,10 +1,10 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "exclude": ["transform-regenerator"] - } - ] - ] -} +{ + "presets": [ + [ + "@babel/preset-env", + { + "exclude": ["transform-regenerator"] + } + ] + ] +} diff --git a/MaterialX/javascript/MaterialXTest/browser/karma.conf.js b/MaterialX/javascript/MaterialXTest/browser/karma.conf.js old mode 100644 new mode 100755 index eab858d..1f65584 --- a/MaterialX/javascript/MaterialXTest/browser/karma.conf.js +++ b/MaterialX/javascript/MaterialXTest/browser/karma.conf.js @@ -1,47 +1,37 @@ -module.exports = function (config) -{ - config.set({ - basePath: '../', // base is the javascript folder - files: [ - { pattern: '_build/JsMaterialXGenShader.js', watched: false, included: true, served: true }, - { pattern: '_build/JsMaterialXGenShader.wasm', watched: false, included: false, served: true }, - { pattern: '_build/JsMaterialXGenShader.data', watched: false, included: false, served: true, nocache: true }, - { pattern: 'browser/*.spec.js', watched: true, included: true, served: true }, - ], - mime: { - 'application/wasm': ['wasm'], - 'application/octet-stream; charset=UTF-8': ['data'], - }, - proxies: { - '/JsMaterialXGenShader.data': '/base/_build/JsMaterialXGenShader.data', - }, - reporters: ['mocha'], - client: { - mocha: { - reporter: 'html' - } - }, - browsers: ['Chrome'], - port: 8080, - autoWatch: true, - concurrency: Infinity, - // logLevel: config.LOG_DEBUG, - frameworks: ['mocha', 'chai'], - plugins: [ - 'karma-chai', - 'karma-chrome-launcher', - 'karma-mocha', - 'karma-mocha-reporter', - ], - customLaunchers: { - ChromeHeadlessGL: { - base: 'Chrome', - flags: [ - '--headless=new', - '--enable-gpu', - '--enable-webgl', - ], - }, - }, - }); -}; +module.exports = function (config) +{ + config.set({ + basePath: '../', // base is the javascript folder + files: [ + { pattern: '_build/JsMaterialXGenShader.js', watched: false, included: true, served: true }, + { pattern: '_build/JsMaterialXGenShader.wasm', watched: false, included: false, served: true }, + { pattern: '_build/JsMaterialXGenShader.data', watched: false, included: false, served: true, nocache: true }, + { pattern: 'browser/*.spec.js', watched: true, included: true, served: true }, + ], + mime: { + 'application/wasm': ['wasm'], + 'application/octet-stream; charset=UTF-8': ['data'], + }, + proxies: { + '/JsMaterialXGenShader.data': '/base/_build/JsMaterialXGenShader.data', + }, + reporters: ['mocha'], + client: { + mocha: { + reporter: 'html' + } + }, + browsers: ['Chrome'], + port: 8080, + autoWatch: true, + concurrency: Infinity, + // logLevel: config.LOG_DEBUG, + frameworks: ['mocha', 'chai'], + plugins: [ + 'karma-chai', + 'karma-chrome-launcher', + 'karma-mocha', + 'karma-mocha-reporter', + ], + }); +}; diff --git a/MaterialX/javascript/MaterialXTest/browser/shaderGenerator.spec.js b/MaterialX/javascript/MaterialXTest/browser/shaderGenerator.spec.js old mode 100644 new mode 100755 index af001aa..ec66116 --- a/MaterialX/javascript/MaterialXTest/browser/shaderGenerator.spec.js +++ b/MaterialX/javascript/MaterialXTest/browser/shaderGenerator.spec.js @@ -1,131 +1,104 @@ -// MaterialX is served through a script tag in the test setup. - -function createStandardSurfaceMaterial(mx) -{ - const doc = mx.createDocument(); - const ssName = 'SR_default'; - const ssNode = doc.addChildOfCategory('standard_surface', ssName); - ssNode.setType('surfaceshader'); - const smNode = doc.addChildOfCategory('surfacematerial', 'Default'); - smNode.setType('material'); - const shaderElement = smNode.addInput('surfaceshader'); - shaderElement.setType('surfaceshader'); - shaderElement.setNodeName(ssName); - expect(doc.validate()).to.be.true; - // Release local wrappers - shaderElement.delete(); - smNode.delete(); - ssNode.delete(); - return doc; -} - -describe('Generate Shaders', function () -{ - let mx; - const canvas = document.createElement('canvas'); - const gl = canvas.getContext('webgl2'); - - this.timeout(60000); - - before(async function () - { - mx = await MaterialX(); - }); - - it('Compile Shaders', () => - { - const doc = createStandardSurfaceMaterial(mx); - - const generators = [] - if (typeof mx.EsslShaderGenerator != 'undefined') - generators.push(mx.EsslShaderGenerator.create()); - if (typeof mx.GlslShaderGenerator != 'undefined') - generators.push(mx.GlslShaderGenerator.create()); - if (typeof mx.MslShaderGenerator != 'undefined') - generators.push(mx.MslShaderGenerator.create()); - if (typeof mx.OslShaderGenerator != 'undefined') - generators.push(mx.OslShaderGenerator.create()); - if (typeof mx.VkShaderGenerator != 'undefined') - generators.push(mx.VkShaderGenerator.create()); - if (typeof mx.WgslShaderGenerator != 'undefined') - generators.push(mx.WgslShaderGenerator.create()); - if (typeof mx.MdlShaderGenerator != 'undefined') - generators.push(mx.MdlShaderGenerator.create()); - if (typeof mx.SlangShaderGenerator != 'undefined') - generators.push(mx.SlangShaderGenerator.create()); - - const elem = mx.findRenderableElement(doc); - for (let gen of generators) - { - console.log("Generating shader for " + gen.getTarget() + "..."); - - const genContext = new mx.GenContext(gen); - const stdlib = mx.loadStandardLibraries(genContext); - doc.importLibrary(stdlib); - - try - { - const mxShader = gen.generate(elem.getNamePath(), elem, genContext); - - const fShader = mxShader.getSourceCode("pixel"); - - if (gen.getTarget() == 'essl') - { - const vShader = mxShader.getSourceCode("vertex"); - - const glVertexShader = gl.createShader(gl.VERTEX_SHADER); - gl.shaderSource(glVertexShader, vShader); - gl.compileShader(glVertexShader); - if (!gl.getShaderParameter(glVertexShader, gl.COMPILE_STATUS)) - { - console.error("-------- VERTEX SHADER FAILED TO COMPILE: ----------------"); - console.error("--- VERTEX SHADER LOG ---"); - console.error(gl.getShaderInfoLog(glVertexShader)); - console.error("--- VERTEX SHADER START ---"); - console.error(fShader); - console.error("--- VERTEX SHADER END ---"); - } - expect(gl.getShaderParameter(glVertexShader, gl.COMPILE_STATUS)).to.equal(true); - - const glPixelShader = gl.createShader(gl.FRAGMENT_SHADER); - gl.shaderSource(glPixelShader, fShader); - gl.compileShader(glPixelShader); - if (!gl.getShaderParameter(glPixelShader, gl.COMPILE_STATUS)) - { - console.error("-------- PIXEL SHADER FAILED TO COMPILE: ----------------"); - console.error("--- PIXEL SHADER LOG ---"); - console.error(gl.getShaderInfoLog(glPixelShader)); - console.error("--- PIXEL SHADER START ---"); - console.error(fShader); - console.error("--- PIXEL SHADER END ---"); - } - expect(gl.getShaderParameter(glPixelShader, gl.COMPILE_STATUS)).to.equal(true); - // Cleanup GL shaders - gl.deleteShader(glVertexShader); - gl.deleteShader(glPixelShader); - } - // Cleanup shader wrapper - mxShader.delete(); - } - catch (errPtr) - { - console.error("-------- Failed code generation: ----------------"); - if (typeof mx.getExceptionMessage === 'function') - { - console.error(mx.getExceptionMessage(errPtr)); - } - else - { - console.error(errPtr); - } - } - // Cleanup per-generator wrappers - stdlib.delete(); - genContext.delete(); - gen.delete(); - } - // Cleanup element and document - elem.delete(); - doc.delete(); - }); -}); +// MaterialX is served through a script tag in the test setup. + +function createStandardSurfaceMaterial(mx) +{ + const doc = mx.createDocument(); + const ssName = 'SR_default'; + const ssNode = doc.addChildOfCategory('standard_surface', ssName); + ssNode.setType('surfaceshader'); + const smNode = doc.addChildOfCategory('surfacematerial', 'Default'); + smNode.setType('material'); + const shaderElement = smNode.addInput('surfaceshader'); + shaderElement.setType('surfaceshader'); + shaderElement.setNodeName(ssName); + expect(doc.validate()).to.be.true; + return doc; +} + +describe('Generate Shaders', function () +{ + let mx; + const canvas = document.createElement('canvas'); + const gl = canvas.getContext('webgl2'); + + this.timeout(60000); + + before(async function () + { + mx = await MaterialX(); + }); + + it('Compile Shaders', () => + { + const doc = createStandardSurfaceMaterial(mx); + + const generators = [] + if (typeof mx.EsslShaderGenerator != 'undefined') + generators.push(new mx.EsslShaderGenerator()); + if (typeof mx.GlslShaderGenerator != 'undefined') + generators.push(new mx.GlslShaderGenerator()); + if (typeof mx.MslShaderGenerator != 'undefined') + generators.push(new mx.MslShaderGenerator()); + if (typeof mx.OslShaderGenerator != 'undefined') + generators.push(new mx.OslShaderGenerator()); + if (typeof mx.VkShaderGenerator != 'undefined') + generators.push(new mx.VkShaderGenerator()); + if (typeof mx.MdlShaderGenerator != 'undefined') + generators.push(new mx.MdlShaderGenerator()); + + const elem = mx.findRenderableElement(doc); + for (let gen of generators) + { + console.log("Generating shader for " + gen.getTarget() + "..."); + + const genContext = new mx.GenContext(gen); + const stdlib = mx.loadStandardLibraries(genContext); + doc.importLibrary(stdlib); + + try + { + const mxShader = gen.generate(elem.getNamePath(), elem, genContext); + + const fShader = mxShader.getSourceCode("pixel"); + + if (gen.getTarget() == 'essl') + { + const vShader = mxShader.getSourceCode("vertex"); + + const glVertexShader = gl.createShader(gl.VERTEX_SHADER); + gl.shaderSource(glVertexShader, vShader); + gl.compileShader(glVertexShader); + if (!gl.getShaderParameter(glVertexShader, gl.COMPILE_STATUS)) + { + console.error("-------- VERTEX SHADER FAILED TO COMPILE: ----------------"); + console.error("--- VERTEX SHADER LOG ---"); + console.error(gl.getShaderInfoLog(glVertexShader)); + console.error("--- VERTEX SHADER START ---"); + console.error(fShader); + console.error("--- VERTEX SHADER END ---"); + } + expect(gl.getShaderParameter(glVertexShader, gl.COMPILE_STATUS)).to.equal(true); + + const glPixelShader = gl.createShader(gl.FRAGMENT_SHADER); + gl.shaderSource(glPixelShader, fShader); + gl.compileShader(glPixelShader); + if (!gl.getShaderParameter(glPixelShader, gl.COMPILE_STATUS)) + { + console.error("-------- PIXEL SHADER FAILED TO COMPILE: ----------------"); + console.error("--- PIXEL SHADER LOG ---"); + console.error(gl.getShaderInfoLog(glPixelShader)); + console.error("--- PIXEL SHADER START ---"); + console.error(fShader); + console.error("--- PIXEL SHADER END ---"); + } + expect(gl.getShaderParameter(glPixelShader, gl.COMPILE_STATUS)).to.equal(true); + } + } + catch (errPtr) + { + console.error("-------- Failed code generation: ----------------"); + console.error(mx.getExceptionMessage(errPtr)); + } + } + }); +}); diff --git a/MaterialX/javascript/MaterialXTest/codeExamples.spec.js b/MaterialX/javascript/MaterialXTest/codeExamples.spec.js old mode 100644 new mode 100755 index abd4394..d4f1eeb --- a/MaterialX/javascript/MaterialXTest/codeExamples.spec.js +++ b/MaterialX/javascript/MaterialXTest/codeExamples.spec.js @@ -1,145 +1,151 @@ -import { expect } from 'chai'; -import Module from './_build/JsMaterialXCore.js'; -import { getMtlxStrings } from './testHelpers'; - -describe('Code Examples', () => -{ - it('Building a MaterialX Document', async () => - { - const mx = await Module(); - // Create a document. - const doc = mx.createDocument(); - - // Create a node graph with a single image node and output. - const nodeGraph = doc.addNodeGraph(); - expect(doc.getNodeGraphs().length).to.equal(1); - const image = nodeGraph.addNode('image'); - const nodes = nodeGraph.getNodes(); - expect(nodes.length).to.equal(1); - expect(nodes[0]).to.eql(image); - - image.setInputValueString('file', 'image1.tif', 'filename'); - const input = image.getInput('file'); - expect(input).to.not.be.null; - expect(input.getValue().getData()).to.equal('image1.tif'); - - const output = nodeGraph.addOutput(); - const outputs = nodeGraph.getOutputs(); - expect(outputs.length).to.equal(1); - expect(outputs[0]).to.eql(output); - - output.setConnectedNode(image); - const connectedNode = output.getConnectedNode(); - expect(connectedNode).to.not.be.null; - expect(connectedNode instanceof mx.Node).to.be.true; - - // Create a simple shader interface. - const simpleSrf = doc.addNodeDef('ND_simpleSrf', 'surfaceshader', 'simpleSrf'); - const nodeDefs = doc.getNodeDefs(); - expect(nodeDefs.length).to.equal(1); - expect(nodeDefs[0]).to.eql(simpleSrf); - - simpleSrf.setInputValueColor3('diffColor', new mx.Color3(1.0, 1.0, 1.0)); - let inputValue = simpleSrf.getInputValue('diffColor'); - expect(inputValue).to.not.be.null; - expect(inputValue.getData()).to.eql(new mx.Color3(1.0, 1.0, 1.0)); - - simpleSrf.setInputValueColor3('specColor', new mx.Color3(0.0, 0.0, 0.0)); - inputValue = simpleSrf.getInputValue('specColor'); - expect(inputValue).to.not.be.null; - expect(inputValue.getData()).to.eql(new mx.Color3(0.0, 0.0, 0.0)); - - const roughness = simpleSrf.setInputValueFloat('roughness', 0.25); - inputValue = simpleSrf.getInputValue('roughness'); - expect(inputValue).to.not.be.null; - expect(inputValue.getData()).to.equal(0.25); - - // // Create a material that instantiates the shader. - // const material = doc.addMaterial(); - // const materials = doc.getMaterials(); - // expect(materials.length).to.equal(1); - // expect(materials[0]).to.eql(material); - // const refSimpleSrf = material.addShaderRef('SR_simpleSrf', 'simpleSrf'); - // const shaderRefs = material.getShaderRefs(); - // expect(shaderRefs.length).to.equal(1); - // expect(shaderRefs[0]).to.eql(refSimpleSrf); - // expect(shaderRefs[0].getName()).to.equal('SR_simpleSrf'); - - // // Bind roughness to a new value within this material. - // const bindInput = refSimpleSrf.addBindInput('roughness'); - // const bindInputs = refSimpleSrf.getBindInputs(); - // expect(bindInputs.length).to.equal(1); - // expect(bindInputs[0]).to.eql(bindInput); - // bindInput.setValuefloat(0.5); - // expect(bindInput.getValue()).to.not.be.null; - // expect(bindInput.getValue().getData()).to.equal(0.5); - - // // Validate the value of roughness in the context of this material. - // expect(roughness.getBoundValue(material).getValueString()).to.equal('0.5'); - // Cleanup wrappers - nodeDefs.forEach(nd => nd.delete()); - output.delete(); - image.delete(); - nodeGraph.delete(); - doc.delete(); - }); - - it('Traversing a Document Tree', async () => - { - const xmlStr = getMtlxStrings( - ['standard_surface_greysphere_calibration.mtlx'], - '../../resources/Materials/Examples/StandardSurface' - )[0]; - const mx = await Module(); - - // Read a document from disk. - const doc = mx.createDocument(); - await mx.readFromXmlString(doc, xmlStr); - - // Traverse the document tree in depth-first order. - const elements = doc.traverseTree(); - let imageCount = 0; - for (let elem of elements) - { - if (elem.isANode('image')) - { - imageCount++; - } - } - expect(imageCount).to.greaterThan(0); - doc.delete(); - }); - - it('Building a MaterialX Document', async () => - { - const xmlStr = getMtlxStrings(['standard_surface_marble_solid.mtlx'], '../../resources/Materials/Examples/StandardSurface')[0]; - const mx = await Module(); - - // Read a document from disk. - const doc = mx.createDocument(); - await mx.readFromXmlString(doc, xmlStr); - - // let materialCount = 0; - // let shaderInputCount = 0; - // // Iterate through 1.37 materials for which there should be none - // const materials = doc.getMaterials(); - // materials.forEach((material) => { - // materialCount++; - - // // For each shader input, find all upstream images in the dataflow graph. - // const primaryShaderInputs = material.getPrimaryShaderInputs(); - // primaryShaderInputs.forEach((input) => { - // const graphIter = input.traverseGraph(material); - // let edge = graphIter.next(); - // while (edge) { - // shaderInputCount++; - // edge = graphIter.next(); - // } - // }); - // }); - - // expect(materialCount).to.equal(0); - // expect(shaderInputCount).to.equal(0); - doc.delete(); - }); -}); +import { expect } from 'chai'; +import Module from './_build/JsMaterialXCore.js'; +import { getMtlxStrings } from './testHelpers'; + +describe('Code Examples', () => +{ + it('Building a MaterialX Document', async () => + { + const mx = await Module(); + // Create a document. + const doc = mx.createDocument(); + + // Create a node graph with a single image node and output. + const nodeGraph = doc.addNodeGraph(); + expect(doc.getNodeGraphs().length).to.equal(1); + const image = nodeGraph.addNode('image'); + const nodes = nodeGraph.getNodes(); + expect(nodes.length).to.equal(1); + expect(nodes[0]).to.eql(image); + + image.setInputValueString('file', 'image1.tif', 'filename'); + const input = image.getInput('file'); + expect(input).to.not.be.null; + expect(input.getValue().getData()).to.equal('image1.tif'); + + const output = nodeGraph.addOutput(); + const outputs = nodeGraph.getOutputs(); + expect(outputs.length).to.equal(1); + expect(outputs[0]).to.eql(output); + + output.setConnectedNode(image); + const connectedNode = output.getConnectedNode(); + expect(connectedNode).to.not.be.null; + expect(connectedNode instanceof mx.Node).to.be.true; + + // Create a simple shader interface. + const simpleSrf = doc.addNodeDef('ND_simpleSrf', 'surfaceshader', 'simpleSrf'); + const nodeDefs = doc.getNodeDefs(); + expect(nodeDefs.length).to.equal(1); + expect(nodeDefs[0]).to.eql(simpleSrf); + + simpleSrf.setInputValueColor3('diffColor', new mx.Color3(1.0, 1.0, 1.0)); + let inputValue = simpleSrf.getInputValue('diffColor'); + expect(inputValue).to.not.be.null; + expect(inputValue.getData()).to.eql(new mx.Color3(1.0, 1.0, 1.0)); + + simpleSrf.setInputValueColor3('specColor', new mx.Color3(0.0, 0.0, 0.0)); + inputValue = simpleSrf.getInputValue('specColor'); + expect(inputValue).to.not.be.null; + expect(inputValue.getData()).to.eql(new mx.Color3(0.0, 0.0, 0.0)); + + const roughness = simpleSrf.setInputValueFloat('roughness', 0.25); + inputValue = simpleSrf.getInputValue('roughness'); + expect(inputValue).to.not.be.null; + expect(inputValue.getData()).to.equal(0.25); + + // // Create a material that instantiates the shader. + // const material = doc.addMaterial(); + // const materials = doc.getMaterials(); + // expect(materials.length).to.equal(1); + // expect(materials[0]).to.eql(material); + // const refSimpleSrf = material.addShaderRef('SR_simpleSrf', 'simpleSrf'); + // const shaderRefs = material.getShaderRefs(); + // expect(shaderRefs.length).to.equal(1); + // expect(shaderRefs[0]).to.eql(refSimpleSrf); + // expect(shaderRefs[0].getName()).to.equal('SR_simpleSrf'); + + // // Bind roughness to a new value within this material. + // const bindInput = refSimpleSrf.addBindInput('roughness'); + // const bindInputs = refSimpleSrf.getBindInputs(); + // expect(bindInputs.length).to.equal(1); + // expect(bindInputs[0]).to.eql(bindInput); + // bindInput.setValuefloat(0.5); + // expect(bindInput.getValue()).to.not.be.null; + // expect(bindInput.getValue().getData()).to.equal(0.5); + + // // Validate the value of roughness in the context of this material. + // expect(roughness.getBoundValue(material).getValueString()).to.equal('0.5'); + }); + + it('Traversing a Document Tree', async () => + { + const xmlStr = getMtlxStrings( + ['standard_surface_greysphere_calibration.mtlx'], + '../../resources/Materials/Examples/StandardSurface' + )[0]; + const mx = await Module(); + + // Read a document from disk. + const doc = mx.createDocument(); + await mx.readFromXmlString(doc, xmlStr); + + // Traverse the document tree in depth-first order. + const elements = doc.traverseTree(); + let elementCount = 0; + let nodeCount = 0; + let fileCount = 0; + for (let elem of elements) + { + elementCount++; + // Display the filename of each image node. + if (elem.isANode('image')) + { + nodeCount++; + const input = elem.getInput('file'); + if (input) + { + fileCount++; + const filename = input.getValueString(); + expect(elem.getName()).to.equal('image1'); + expect(filename).to.equal('greysphere_calibration.png'); + } + } + } + expect(elementCount).to.equal(21); + expect(nodeCount).to.equal(1); + expect(fileCount).to.equal(1); + }); + + it('Building a MaterialX Document', async () => + { + const xmlStr = getMtlxStrings(['standard_surface_marble_solid.mtlx'], '../../resources/Materials/Examples/StandardSurface')[0]; + const mx = await Module(); + + // Read a document from disk. + const doc = mx.createDocument(); + await mx.readFromXmlString(doc, xmlStr); + + // let materialCount = 0; + // let shaderInputCount = 0; + // // Iterate through 1.37 materials for which there should be none + // const materials = doc.getMaterials(); + // materials.forEach((material) => { + // materialCount++; + + // // For each shader input, find all upstream images in the dataflow graph. + // const primaryShaderInputs = material.getPrimaryShaderInputs(); + // primaryShaderInputs.forEach((input) => { + // const graphIter = input.traverseGraph(material); + // let edge = graphIter.next(); + // while (edge) { + // shaderInputCount++; + // edge = graphIter.next(); + // } + // }); + // }); + + // expect(materialCount).to.equal(0); + // expect(shaderInputCount).to.equal(0); + }); +}); diff --git a/MaterialX/javascript/MaterialXTest/customBindings.spec.js b/MaterialX/javascript/MaterialXTest/customBindings.spec.js old mode 100644 new mode 100755 index af2c336..28bb157 --- a/MaterialX/javascript/MaterialXTest/customBindings.spec.js +++ b/MaterialX/javascript/MaterialXTest/customBindings.spec.js @@ -1,250 +1,218 @@ -import { expect } from 'chai'; -import Module from './_build/JsMaterialXCore.js'; -import { getMtlxStrings } from './testHelpers'; - -describe('Custom Bindings', () => -{ - const examplesPath = '../../resources/Materials/Examples/StandardSurface'; - - let mx; - before(async () => - { - mx = await Module(); - }); - - it('Optional parameters work as expected', () => - { - const doc = mx.createDocument(); - // Call a method without optional argument - const nodeGraph = doc.addNodeGraph(); - expect(nodeGraph).to.be.instanceof(mx.NodeGraph); - expect(nodeGraph.getName()).to.equal('nodegraph1'); // Auto-constructed default value - // Call a method with optional argument - const nodeGraph2 = doc.addNodeGraph('myGraph'); - expect(nodeGraph2).to.be.instanceof(mx.NodeGraph); - expect(nodeGraph2.getName()).to.equal('myGraph'); - - // Call a method that requires at least one parameter - const node = nodeGraph.addNode('node'); - expect(node).to.be.instanceof(mx.Node); - - // Omitting non-optional parameter should throw - expect(() => { nodeGraph.addNode(); }).to.throw; - - // Cleanup - node.delete(); - nodeGraph2.delete(); - nodeGraph.delete(); - doc.delete(); - }); - - it('Vector <-> Array conversion', () => - { - // Functions that return vectors in C++ should return an array in JS - const doc = mx.createDocument(); - const nodeGraph = doc.addNodeGraph(); - const nodeGraphB = doc.addNodeGraph(); - const nodeGraphs = doc.getNodeGraphs(); - expect(nodeGraphs).to.be.an.instanceof(Array); - expect(nodeGraphs.length).to.equal(2); - - // Elements fetched through the vector -> array conversion should be editable and changes should be reflected - // in the original objects. - // Note: We cannot simply compare these objects for equality, since they're separately constructed pointers - // to the same object. - const backdrop = nodeGraph.addBackdrop(); - const backDrops = nodeGraphs[0].getBackdrops(); - expect(backDrops.length).to.equal(1); - nodeGraphs[0].addBackdrop(); - expect(nodeGraph.getBackdrops().length).to.equal(2); - - // Functions that expect vectors as parameters in C++ should accept arrays in JS - // Built-in types (strings) - const pathSegments = ['path', 'to', 'something']; - const namePath = mx.createNamePath(pathSegments); - expect(namePath).to.equal(pathSegments.join(mx.NAME_PATH_SEPARATOR)); - - // Complex (smart pointer) types - const node1 = nodeGraph.addNode('node'); - const node2 = nodeGraph.addNode('node'); - const node3 = nodeGraph.addNode('node', 'anotherNode'); - backdrop.setContainsElements([node1, node2, node3]); - const nodes = backdrop.getContainsElements(); - expect(nodes.length).to.equal(3); - expect(nodes[0].getName()).to.equal('node1'); // Name auto-constructed from category - expect(nodes[1].getName()).to.equal('node2'); // Name auto-constructed from category - expect(nodes[2].getName()).to.equal('anotherNode'); // Name set explicitly at creation time - - // Cleanup created wrappers - nodes.forEach(n => n.delete()); - backdrop.delete(); - node3.delete(); - node2.delete(); - node1.delete(); - nodeGraphB.delete(); - nodeGraph.delete(); - doc.delete(); - }); - - it('C++ exception handling', () => - { - // Exceptions that are thrown and caught in C++ shouldn't bubble up to JS - const doc = mx.createDocument(); - const nodeGraph1 = doc.addNodeGraph(); - const nodeGraph2 = doc.addNodeGraph(); - nodeGraph1.setInheritsFrom(nodeGraph2); - nodeGraph2.setInheritsFrom(nodeGraph1); - expect(nodeGraph1.hasInheritanceCycle()).to.not.throw; - expect(nodeGraph1.hasInheritanceCycle()).to.be.true; - - // Exceptions that are not caught in C++ should throw - nodeGraph1.addNode('node', 'node1'); - expect(() => { nodeGraph1.addNode('node', 'node1'); }).to.throw; - try - { - nodeGraph1.addNode('node', 'node1'); - } catch (err) - { - expect(mx.getExceptionMessage(err)).to.be.a('string'); - } - // Cleanup - nodeGraph2.delete(); - nodeGraph1.delete(); - doc.delete(); - }); - - it('getReferencedSourceUris', async () => - { - const doc = mx.createDocument(); - const filename = 'standard_surface_look_brass_tiled.mtlx'; - await mx.readFromXmlFile(doc, filename, examplesPath); - const sourceUris = doc.getReferencedSourceUris(); - expect(sourceUris).to.be.instanceof(Array); - expect(sourceUris.length).to.equal(3); - expect(sourceUris[0]).to.be.a('string'); - expect(sourceUris.includes('standard_surface_brass_tiled.mtlx')).to.be.true; - doc.delete(); - }); - - it('Should invoke correct instance of \'validate\'', () => - { - // We check whether the correct function is called by provoking an error message that is specific to the - // function that we expect to be called. - const message = {}; - - // Should invoke Document::validate. - const doc = mx.createDocument(); - expect(doc.validate()).to.be.true; - doc.removeAttribute(mx.InterfaceElement.VERSION_ATTRIBUTE); - expect(doc.validate()).to.be.true; - - // Should invoke Node::validate - const node = doc.addNode('node'); - expect(node.validate()).to.be.true; - node.setCategory(''); - expect(node.validate()).to.be.false; - expect(node.validate(message)).to.be.false; - expect(message.message).to.include('Node element is missing a category'); - - // Should invoke inherited ValueElement::validate - const token = new mx.Token(node, 'token'); - expect(token.validate()).to.be.true; - token.setUnitType('bogus'); - expect(token.validate()).to.be.false; - expect(token.validate(message)).to.be.false; - expect(message.message).to.include('Unit type definition does not exist in document') - - // Cleanup - token.delete(); - node.delete(); - doc.delete(); - }); - - it('StringResolver name substitution getters', () => - { - const fnTestData = { - fnKey: 'fnValue', - fnKey1: 'fnValue1' - }; - const fnTestKeys = Object.keys(fnTestData); - - const gnTestData = { - gnKey: 'gnValue', - gnKey1: 'gnValue1' - }; - const gnTestKeys = Object.keys(gnTestData); - - const resolver = mx.StringResolver.create(); - - resolver.setFilenameSubstitution(fnTestKeys[0], fnTestData[fnTestKeys[0]]); - resolver.setFilenameSubstitution(fnTestKeys[1], fnTestData[fnTestKeys[1]]); - const fnSubs = resolver.getFilenameSubstitutions(); - expect(fnSubs).to.be.instanceof(Object); - expect(Object.keys(fnSubs).length).to.equal(2); - expect(fnSubs).to.deep.equal(fnTestData); - - resolver.setGeomNameSubstitution(gnTestKeys[0], gnTestData[gnTestKeys[0]]); - resolver.setGeomNameSubstitution(gnTestKeys[1], gnTestData[gnTestKeys[1]]); - const gnSubs = resolver.getGeomNameSubstitutions(); - expect(gnSubs).to.be.instanceof(Object); - expect(Object.keys(gnSubs).length).to.equal(2); - expect(gnSubs).to.deep.equal(gnTestData); - resolver.delete(); - }); - - it('getShaderNodes', async () => - { - const doc = mx.createDocument(); - const fileNames = ['standard_surface_marble_solid.mtlx']; - const mtlxStrs = getMtlxStrings(fileNames, examplesPath); - await mx.readFromXmlString(doc, mtlxStrs[0]); - let matNodes = doc.getMaterialNodes(); - expect(matNodes.length).to.equal(1); - const matNode = matNodes[0]; - - // Should return a surface shader node but no displacement shader node - let shaderNodes = mx.getShaderNodes(matNode); - expect(shaderNodes).to.be.instanceof(Array); - expect(shaderNodes.length).to.equal(1); - expect(shaderNodes[0].getType()).to.equal(mx.SURFACE_SHADER_TYPE_STRING); - shaderNodes = mx.getShaderNodes(matNode, mx.DISPLACEMENT_SHADER_TYPE_STRING); - expect(shaderNodes).to.be.instanceof(Array); - expect(shaderNodes.length).to.equal(0); - - // Cleanup wrappers - shaderNodes.forEach(s => s.delete()); - matNodes.forEach(n => n.delete()); - doc.delete(); - }); - - it('createValidName', () => - { - const testString = '_Note_:Please,turn.this+-into*1#valid\nname for_me'; - const replaceRegex = /[^a-zA-Z0-9_:]/g - expect(mx.createValidName(testString)).to.equal(testString.replace(replaceRegex, '_')); - expect(mx.createValidName(testString, '-')).to.equal(testString.replace(replaceRegex, '-')); - }); - - it('getVersionIntegers', () => - { - const versionStringArr = mx.getVersionString().split('.').map((value) => parseInt(value, 10)); - - // Global getVersionIntegers - const globalVersion = mx.getVersionIntegers(); - expect(globalVersion).to.be.instanceof(Array); - expect(globalVersion.length).to.equal(3); - expect(globalVersion).to.deep.equal(versionStringArr); - - // Document.getVersionIntegers - versionStringArr.pop(); - const doc = mx.createDocument(); - const docVersion = doc.getVersionIntegers(); - expect(docVersion).to.be.instanceof(Array); - expect(docVersion.length).to.equal(2); - expect(docVersion).to.deep.equal(versionStringArr); - doc.delete(); - - // InterfaceElement.getVersionIntegers (via NodeDef) - // TODO: This function can currently not be called, since we have a linker issue that messes up this function. - }); -}); +import { expect } from 'chai'; +import Module from './_build/JsMaterialXCore.js'; +import { getMtlxStrings } from './testHelpers'; + +describe('Custom Bindings', () => +{ + const examplesPath = '../../resources/Materials/Examples/StandardSurface'; + + let mx; + before(async () => + { + mx = await Module(); + }); + + it('Optional parameters work as expected', () => + { + const doc = mx.createDocument(); + // Call a method without optional argument + const nodeGraph = doc.addNodeGraph(); + expect(nodeGraph).to.be.instanceof(mx.NodeGraph); + expect(nodeGraph.getName()).to.equal('nodegraph1'); // Auto-constructed default value + // Call a method with optional argument + const nodeGraph2 = doc.addNodeGraph('myGraph'); + expect(nodeGraph2).to.be.instanceof(mx.NodeGraph); + expect(nodeGraph2.getName()).to.equal('myGraph'); + + // Call a method that requires at least one parameter + const node = nodeGraph.addNode('node'); + expect(node).to.be.instanceof(mx.Node); + + // Omitting non-optional parameter should throw + expect(() => { nodeGraph.addNode(); }).to.throw; + }); + + it('Vector <-> Array conversion', () => + { + // Functions that return vectors in C++ should return an array in JS + const doc = mx.createDocument(); + const nodeGraph = doc.addNodeGraph(); + doc.addNodeGraph(); + const nodeGraphs = doc.getNodeGraphs(); + expect(nodeGraphs).to.be.an.instanceof(Array); + expect(nodeGraphs.length).to.equal(2); + + // Elements fetched through the vector -> array conversion should be editable and changes should be reflected + // in the original objects. + // Note: We cannot simply compare these objects for equality, since they're separately constructed pointers + // to the same object. + const backdrop = nodeGraph.addBackdrop(); + const backDrops = nodeGraphs[0].getBackdrops(); + expect(backDrops.length).to.equal(1); + nodeGraphs[0].addBackdrop(); + expect(nodeGraph.getBackdrops().length).to.equal(2); + + // Functions that expect vectors as parameters in C++ should accept arrays in JS + // Built-in types (strings) + const pathSegments = ['path', 'to', 'something']; + const namePath = mx.createNamePath(pathSegments); + expect(namePath).to.equal(pathSegments.join(mx.NAME_PATH_SEPARATOR)); + + // Complex (smart pointer) types + const node1 = nodeGraph.addNode('node'); + const node2 = nodeGraph.addNode('node'); + const node3 = nodeGraph.addNode('node', 'anotherNode'); + backdrop.setContainsElements([node1, node2, node3]); + const nodes = backdrop.getContainsElements(); + expect(nodes.length).to.equal(3); + expect(nodes[0].getName()).to.equal('node1'); // Name auto-constructed from category + expect(nodes[1].getName()).to.equal('node2'); // Name auto-constructed from category + expect(nodes[2].getName()).to.equal('anotherNode'); // Name set explicitly at creation time + }); + + it('C++ exception handling', () => + { + // Exceptions that are thrown and caught in C++ shouldn't bubble up to JS + const doc = mx.createDocument(); + const nodeGraph1 = doc.addNodeGraph(); + const nodeGraph2 = doc.addNodeGraph(); + nodeGraph1.setInheritsFrom(nodeGraph2); + nodeGraph2.setInheritsFrom(nodeGraph1); + expect(nodeGraph1.hasInheritanceCycle()).to.not.throw; + expect(nodeGraph1.hasInheritanceCycle()).to.be.true; + + // Exceptions that are not caught in C++ should throw with an exception pointer + nodeGraph1.addNode('node', 'node1'); + expect(() => { nodeGraph1.addNode('node', 'node1'); }).to.throw; + try + { + nodeGraph1.addNode('node', 'node1'); + } catch (errPtr) + { + expect(errPtr).to.be.a('number'); + expect(mx.getExceptionMessage(errPtr)).to.be.a('string'); + } + }); + + it('getReferencedSourceUris', async () => + { + const doc = mx.createDocument(); + const filename = 'standard_surface_look_brass_tiled.mtlx'; + await mx.readFromXmlFile(doc, filename, examplesPath); + const sourceUris = doc.getReferencedSourceUris(); + expect(sourceUris).to.be.instanceof(Array); + expect(sourceUris.length).to.equal(3); + expect(sourceUris[0]).to.be.a('string'); + expect(sourceUris.includes('standard_surface_brass_tiled.mtlx')).to.be.true; + }); + + it('Should invoke correct instance of \'validate\'', () => + { + // We check whether the correct function is called by provoking an error message that is specific to the + // function that we expect to be called. + const message = {}; + + // Should invoke Document::validate. + const doc = mx.createDocument(); + expect(doc.validate()).to.be.true; + doc.removeAttribute(mx.InterfaceElement.VERSION_ATTRIBUTE); + expect(doc.validate()).to.be.true; + + // Should invoke Node::validate + const node = doc.addNode('node'); + expect(node.validate()).to.be.true; + node.setCategory(''); + expect(node.validate()).to.be.false; + expect(node.validate(message)).to.be.false; + expect(message.message).to.include('Node element is missing a category'); + + // Should invoke inherited ValueElement::validate + const token = new mx.Token(node, 'token'); + expect(token.validate()).to.be.true; + token.setUnitType('bogus'); + expect(token.validate()).to.be.false; + expect(token.validate(message)).to.be.false; + expect(message.message).to.include('Unit type definition does not exist in document') + }); + + it('StringResolver name substitution getters', () => + { + const fnTestData = { + fnKey: 'fnValue', + fnKey1: 'fnValue1' + }; + const fnTestKeys = Object.keys(fnTestData); + + const gnTestData = { + gnKey: 'gnValue', + gnKey1: 'gnValue1' + }; + const gnTestKeys = Object.keys(gnTestData); + + const resolver = mx.StringResolver.create(); + + resolver.setFilenameSubstitution(fnTestKeys[0], fnTestData[fnTestKeys[0]]); + resolver.setFilenameSubstitution(fnTestKeys[1], fnTestData[fnTestKeys[1]]); + const fnSubs = resolver.getFilenameSubstitutions(); + expect(fnSubs).to.be.instanceof(Object); + expect(Object.keys(fnSubs).length).to.equal(2); + expect(fnSubs).to.deep.equal(fnTestData); + + resolver.setGeomNameSubstitution(gnTestKeys[0], gnTestData[gnTestKeys[0]]); + resolver.setGeomNameSubstitution(gnTestKeys[1], gnTestData[gnTestKeys[1]]); + const gnSubs = resolver.getGeomNameSubstitutions(); + expect(gnSubs).to.be.instanceof(Object); + expect(Object.keys(gnSubs).length).to.equal(2); + expect(gnSubs).to.deep.equal(gnTestData); + }); + + it('getShaderNodes', async () => + { + const doc = mx.createDocument(); + const fileNames = ['standard_surface_marble_solid.mtlx']; + const mtlxStrs = getMtlxStrings(fileNames, examplesPath); + await mx.readFromXmlString(doc, mtlxStrs[0]); + let matNodes = doc.getMaterialNodes(); + expect(matNodes.length).to.equal(1); + const matNode = matNodes[0]; + + // Should return a surface shader node but no displacement shader node + let shaderNodes = mx.getShaderNodes(matNode); + expect(shaderNodes).to.be.instanceof(Array); + expect(shaderNodes.length).to.equal(1); + expect(shaderNodes[0].getType()).to.equal(mx.SURFACE_SHADER_TYPE_STRING); + shaderNodes = mx.getShaderNodes(matNode, mx.DISPLACEMENT_SHADER_TYPE_STRING); + expect(shaderNodes).to.be.instanceof(Array); + expect(shaderNodes.length).to.equal(0); + }); + + it('createValidName', () => + { + const testString = '_Note_:Please,turn.this+-into*1#valid\nname for_me'; + const replaceRegex = /[^a-zA-Z0-9_:]/g + expect(mx.createValidName(testString)).to.equal(testString.replace(replaceRegex, '_')); + expect(mx.createValidName(testString, '-')).to.equal(testString.replace(replaceRegex, '-')); + }); + + it('getVersionIntegers', () => + { + const versionStringArr = mx.getVersionString().split('.').map((value) => parseInt(value, 10)); + + // Global getVersionIntegers + const globalVersion = mx.getVersionIntegers(); + expect(globalVersion).to.be.instanceof(Array); + expect(globalVersion.length).to.equal(3); + expect(globalVersion).to.deep.equal(versionStringArr); + + // Document.getVersionIntegers + versionStringArr.pop(); + const doc = mx.createDocument(); + const docVersion = doc.getVersionIntegers(); + expect(docVersion).to.be.instanceof(Array); + expect(docVersion.length).to.equal(2); + expect(docVersion).to.deep.equal(versionStringArr); + + // InterfaceElement.getVersionIntegers (via NodeDef) + // TODO: This function can currently not be called, since we have a linker issue that messes up this function. + }); +}); diff --git a/MaterialX/javascript/MaterialXTest/data/includes/cycle.mtlx b/MaterialX/javascript/MaterialXTest/data/includes/cycle.mtlx old mode 100644 new mode 100755 index 98dd0a9..c27dad5 --- a/MaterialX/javascript/MaterialXTest/data/includes/cycle.mtlx +++ b/MaterialX/javascript/MaterialXTest/data/includes/cycle.mtlx @@ -1,4 +1,4 @@ - - - - + + + + diff --git a/MaterialX/javascript/MaterialXTest/data/includes/folder/include2.mtlx b/MaterialX/javascript/MaterialXTest/data/includes/folder/include2.mtlx old mode 100644 new mode 100755 index 86edb26..bdbfe5b --- a/MaterialX/javascript/MaterialXTest/data/includes/folder/include2.mtlx +++ b/MaterialX/javascript/MaterialXTest/data/includes/folder/include2.mtlx @@ -1,4 +1,4 @@ - - - - + + + + diff --git a/MaterialX/javascript/MaterialXTest/data/includes/folder2/include3.mtlx b/MaterialX/javascript/MaterialXTest/data/includes/folder2/include3.mtlx old mode 100644 new mode 100755 index d327e4b..1fb00c4 --- a/MaterialX/javascript/MaterialXTest/data/includes/folder2/include3.mtlx +++ b/MaterialX/javascript/MaterialXTest/data/includes/folder2/include3.mtlx @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/MaterialX/javascript/MaterialXTest/data/includes/include1.mtlx b/MaterialX/javascript/MaterialXTest/data/includes/include1.mtlx old mode 100644 new mode 100755 index 744b1c5..28f608e --- a/MaterialX/javascript/MaterialXTest/data/includes/include1.mtlx +++ b/MaterialX/javascript/MaterialXTest/data/includes/include1.mtlx @@ -1,4 +1,4 @@ - - - - + + + + diff --git a/MaterialX/javascript/MaterialXTest/data/includes/non_relative_includes.mtlx b/MaterialX/javascript/MaterialXTest/data/includes/non_relative_includes.mtlx old mode 100644 new mode 100755 index a71faef..5c7e158 --- a/MaterialX/javascript/MaterialXTest/data/includes/non_relative_includes.mtlx +++ b/MaterialX/javascript/MaterialXTest/data/includes/non_relative_includes.mtlx @@ -1,4 +1,4 @@ - - - - + + + + diff --git a/MaterialX/javascript/MaterialXTest/data/includes/root.mtlx b/MaterialX/javascript/MaterialXTest/data/includes/root.mtlx old mode 100644 new mode 100755 index d1f1501..389cc58 --- a/MaterialX/javascript/MaterialXTest/data/includes/root.mtlx +++ b/MaterialX/javascript/MaterialXTest/data/includes/root.mtlx @@ -1,5 +1,5 @@ - - - - - + + + + + diff --git a/MaterialX/javascript/MaterialXTest/document.spec.js b/MaterialX/javascript/MaterialXTest/document.spec.js old mode 100644 new mode 100755 index 9b18339..88e04f0 --- a/MaterialX/javascript/MaterialXTest/document.spec.js +++ b/MaterialX/javascript/MaterialXTest/document.spec.js @@ -1,188 +1,166 @@ -import { expect } from 'chai'; -import Module from './_build/JsMaterialXCore.js'; - -describe('Document', () => -{ - let mx, doc; - before(async () => - { - mx = await Module(); - // Create a document. - doc = mx.createDocument(); - }); - - function expectError(type, cb) - { - try - { - cb(); - throw new Error('Expected function to throw!'); - } catch (exceptionPtr) - { - const message = mx.getExceptionMessage(exceptionPtr); - expect(message.indexOf(type) !== -1).to.be.true; - } - } - - let nodeGraph; - it('Build document', () => - { - // Create a node graph with constant and image sources. - nodeGraph = doc.addNodeGraph(); - expect(nodeGraph).to.exist; - expectError('Child name is not unique: nodegraph1', () => - { - doc.addNodeGraph(nodeGraph.getName()); - }); - const constant = nodeGraph.addNode('constant'); - const image = nodeGraph.addNode('image'); - - // Connect sources to outputs - const output1 = nodeGraph.addOutput(); - const output2 = nodeGraph.addOutput(); - output1.setConnectedNode(constant); - output2.setConnectedNode(image); - expect(output1.getConnectedNode()).to.eql(constant); - expect(output2.getConnectedNode()).to.eql(image); - expect(output1.getUpstreamElement()).to.eql(constant); - expect(output2.getUpstreamElement()).to.eql(image); - - // Set constant node color - const color = new mx.Color3(0.1, 0.2, 0.3); - constant.setInputValueColor3('value', color); - expect(constant.getInputValue('value').getData()).to.eql(color); - - // Set image node file - const file = 'image1.tif'; - image.setInputValueString('file', file, 'filename'); - expect(image.getInputValue('file').getData()).to.eql(file); - - // Create a custom nodedef - const nodeDef = doc.addNodeDef('nodeDef1', 'float', 'turbulence3d'); - nodeDef.setInputValueInteger('octaves', 3); - nodeDef.setInputValueFloat('lacunarity', 2.0); - nodeDef.setInputValueFloat('gain', 0.5); - - // Reference the custom nodedef - const custom = nodeGraph.addNode('turbulence3d', 'turbulence1', 'float'); - expect(custom.getInputValue('octaves').getData()).to.equal(3); - custom.setInputValueInteger('octaves', 5); - expect(custom.getInputValue('octaves').getData()).to.equal(5); - - // Test scoped attributes - nodeGraph.setFilePrefix('folder/'); - nodeGraph.setColorSpace('lin_rec709'); - expect(image.getInput('file').getResolvedValueString()).to.equal('folder/image1.tif'); - expect(constant.getActiveColorSpace()).to.equal('lin_rec709'); - - // Create a simple shader interface - const simpleSrf = doc.addNodeDef('', 'surfaceshader', 'simpleSrf'); - simpleSrf.setInputValueColor3('diffColor', new mx.Color3(1.0, 1.0, 1.0)); - simpleSrf.setInputValueColor3('specColor', new mx.Color3(0.0, 0.0, 0.0)); - const roughness = simpleSrf.setInputValueFloat('roughness', 0.25); - expect(roughness.getIsUniform()).to.be.false; - roughness.setIsUniform(true); - expect(roughness.getIsUniform()).to.be.true; - - // Instantiate shader and material nodes - const shaderNode = doc.addNodeInstance(simpleSrf); - const materialNode = doc.addMaterialNode('', shaderNode); - expect(materialNode.getUpstreamElement().equals(shaderNode)).to.be.true; - - // Bind the diffuse color input to the constant color output - shaderNode.setConnectedOutput('diffColor', output1); - expect(shaderNode.getUpstreamElement().equals(constant)).to.be.true; - - // Bind the roughness input to a value - const instanceRoughness = shaderNode.setInputValueFloat('roughness', 0.5); - expect(instanceRoughness.getValue().getData()).to.equal(0.5); - expect(instanceRoughness.getDefaultValue().getData()).to.equal(0.25); - - // Create a look for the material - const look = doc.addLook(); - expect(doc.getLooks().length).to.equal(1); - - // Bind the material to a geometry string - let matAssign1 = look.addMaterialAssign('matAssign1', materialNode.getName()); - matAssign1 = look.getMaterialAssign('matAssign1'); - expect(matAssign1); - matAssign1.setGeom('/robot1'); - expect(matAssign1.getReferencedMaterial().equals(materialNode)).to.be.true; - expect(mx.getGeometryBindings(materialNode, '/robot1').length).to.equal(1); - expect(mx.getGeometryBindings(materialNode, '/robot2').length).to.equal(0); - - // Bind the material to a collection - let matAssign2 = look.addMaterialAssign('matAssign2', materialNode.getName()); - matAssign2 = look.getMaterialAssign('matAssign1'); - expect(matAssign2); - const collection = doc.addCollection(); - collection.setIncludeGeom('/robot2'); - collection.setExcludeGeom('/robot2/left_arm'); - matAssign2.setCollection(collection); - expect(matAssign2.getReferencedMaterial().equals(materialNode)).to.be.true; - expect(mx.getGeometryBindings(materialNode, '/robot2').length).to.equal(1); - expect(mx.getGeometryBindings(materialNode, '/robot2/right_arm').length).to.equal(1); - expect(mx.getGeometryBindings(materialNode, '/robot2/left_arm').length).to.equal(0); - - const materialAssigns = look.getMaterialAssigns(); - expect(materialAssigns.length).to.equal(2); - - // Create a property assignment - const propertyAssign = look.addPropertyAssign(); - propertyAssign.setProperty('twosided'); - propertyAssign.setGeom('/robot1'); - propertyAssign.setValueBoolean(true); - expect(propertyAssign.getProperty()).to.equal('twosided'); - expect(propertyAssign.getGeom()).to.equal('/robot1'); - expect(propertyAssign.getValue().getData()).to.equal(true); - let propertyAssigns = look.getPropertyAssigns(); - expect(propertyAssigns.length).to.equal(1); - - // Create a property set assignment - const propertySet = doc.addPropertySet(); - propertySet.setPropertyValueBoolean('matte', false); - expect(propertySet.getPropertyValue('matte').getData()).to.equal(false); - const propertySetAssign = look.addPropertySetAssign(); - propertySetAssign.setPropertySet(propertySet); - propertySetAssign.setGeom('/robot1'); - expect(propertySetAssign.getPropertySet().equals(propertySet)).to.be.true; - expect(propertySetAssign.getGeom()).to.equal('/robot1'); - - // Create a variant set - const variantSet = doc.addVariantSet(); - variantSet.addVariant('original'); - variantSet.addVariant('damaged'); - expect(variantSet.getVariants().length).to.equal(2); - - // Validate the document - expect(doc.validate()).to.be.true; - - // Disconnect output from sources - output1.setConnectedNode(null); - output2.setConnectedNode(null); - expect(output1.getConnectedNode()).to.equal(null); - expect(output2.getConnectedNode()).to.equal(null); - // Cleanup created wrappers - propertySetAssign.delete(); - propertySet.delete(); - propertyAssign.delete(); - variantSet.delete(); - collection.delete(); - matAssign2.delete(); - matAssign1.delete(); - look.delete(); - instanceRoughness.delete(); - shaderNode.delete(); - materialNode.delete(); - simpleSrf.delete(); - output2.delete(); - output1.delete(); - custom.delete(); - color.delete(); - image.delete(); - constant.delete(); - nodeDef.delete(); - nodeGraph.delete(); - doc.delete(); - }); -}); +import { expect } from 'chai'; +import Module from './_build/JsMaterialXCore.js'; + +describe('Document', () => +{ + let mx, doc; + before(async () => + { + mx = await Module(); + // Create a document. + doc = mx.createDocument(); + }); + + function expectError(type, cb) + { + try + { + cb(); + throw new Error('Expected function to throw!'); + } catch (exceptionPtr) + { + const message = mx.getExceptionMessage(exceptionPtr); + expect(message.indexOf(type) !== -1).to.be.true; + } + } + + let nodeGraph; + it('Build document', () => + { + // Create a node graph with constant and image sources. + nodeGraph = doc.addNodeGraph(); + expect(nodeGraph).to.exist; + expectError('Child name is not unique: nodegraph1', () => + { + doc.addNodeGraph(nodeGraph.getName()); + }); + const constant = nodeGraph.addNode('constant'); + const image = nodeGraph.addNode('image'); + + // Connect sources to outputs + const output1 = nodeGraph.addOutput(); + const output2 = nodeGraph.addOutput(); + output1.setConnectedNode(constant); + output2.setConnectedNode(image); + expect(output1.getConnectedNode()).to.eql(constant); + expect(output2.getConnectedNode()).to.eql(image); + expect(output1.getUpstreamElement()).to.eql(constant); + expect(output2.getUpstreamElement()).to.eql(image); + + // Set constant node color + const color = new mx.Color3(0.1, 0.2, 0.3); + constant.setInputValueColor3('value', color); + expect(constant.getInputValue('value').getData()).to.eql(color); + + // Set image node file + const file = 'image1.tif'; + image.setInputValueString('file', file, 'filename'); + expect(image.getInputValue('file').getData()).to.eql(file); + + // Create a custom nodedef + const nodeDef = doc.addNodeDef('nodeDef1', 'float', 'turbulence3d'); + nodeDef.setInputValueInteger('octaves', 3); + nodeDef.setInputValueFloat('lacunarity', 2.0); + nodeDef.setInputValueFloat('gain', 0.5); + + // Reference the custom nodedef + const custom = nodeGraph.addNode('turbulence3d', 'turbulence1', 'float'); + expect(custom.getInputValue('octaves').getData()).to.equal(3); + custom.setInputValueInteger('octaves', 5); + expect(custom.getInputValue('octaves').getData()).to.equal(5); + + // Test scoped attributes + nodeGraph.setFilePrefix('folder/'); + nodeGraph.setColorSpace('lin_rec709'); + expect(image.getInput('file').getResolvedValueString()).to.equal('folder/image1.tif'); + expect(constant.getActiveColorSpace()).to.equal('lin_rec709'); + + // Create a simple shader interface + const simpleSrf = doc.addNodeDef('', 'surfaceshader', 'simpleSrf'); + simpleSrf.setInputValueColor3('diffColor', new mx.Color3(1.0, 1.0, 1.0)); + simpleSrf.setInputValueColor3('specColor', new mx.Color3(0.0, 0.0, 0.0)); + const roughness = simpleSrf.setInputValueFloat('roughness', 0.25); + expect(roughness.getIsUniform()).to.be.false; + roughness.setIsUniform(true); + expect(roughness.getIsUniform()).to.be.true; + + // Instantiate shader and material nodes + const shaderNode = doc.addNodeInstance(simpleSrf); + const materialNode = doc.addMaterialNode('', shaderNode); + expect(materialNode.getUpstreamElement().equals(shaderNode)).to.be.true; + + // Bind the diffuse color input to the constant color output + shaderNode.setConnectedOutput('diffColor', output1); + expect(shaderNode.getUpstreamElement().equals(constant)).to.be.true; + + // Bind the roughness input to a value + const instanceRoughness = shaderNode.setInputValueFloat('roughness', 0.5); + expect(instanceRoughness.getValue().getData()).to.equal(0.5); + expect(instanceRoughness.getDefaultValue().getData()).to.equal(0.25); + + // Create a look for the material + const look = doc.addLook(); + expect(doc.getLooks().length).to.equal(1); + + // Bind the material to a geometry string + let matAssign1 = look.addMaterialAssign('matAssign1', materialNode.getName()); + matAssign1 = look.getMaterialAssign('matAssign1'); + expect(matAssign1); + matAssign1.setGeom('/robot1'); + expect(matAssign1.getReferencedMaterial().equals(materialNode)).to.be.true; + expect(mx.getGeometryBindings(materialNode, '/robot1').length).to.equal(1); + expect(mx.getGeometryBindings(materialNode, '/robot2').length).to.equal(0); + + // Bind the material to a collection + let matAssign2 = look.addMaterialAssign('matAssign2', materialNode.getName()); + matAssign2 = look.getMaterialAssign('matAssign1'); + expect(matAssign2); + const collection = doc.addCollection(); + collection.setIncludeGeom('/robot2'); + collection.setExcludeGeom('/robot2/left_arm'); + matAssign2.setCollection(collection); + expect(matAssign2.getReferencedMaterial().equals(materialNode)).to.be.true; + expect(mx.getGeometryBindings(materialNode, '/robot2').length).to.equal(1); + expect(mx.getGeometryBindings(materialNode, '/robot2/right_arm').length).to.equal(1); + expect(mx.getGeometryBindings(materialNode, '/robot2/left_arm').length).to.equal(0); + + const materialAssigns = look.getMaterialAssigns(); + expect(materialAssigns.length).to.equal(2); + + // Create a property assignment + const propertyAssign = look.addPropertyAssign(); + propertyAssign.setProperty('twosided'); + propertyAssign.setGeom('/robot1'); + propertyAssign.setValueBoolean(true); + expect(propertyAssign.getProperty()).to.equal('twosided'); + expect(propertyAssign.getGeom()).to.equal('/robot1'); + expect(propertyAssign.getValue().getData()).to.equal(true); + let propertyAssigns = look.getPropertyAssigns(); + expect(propertyAssigns.length).to.equal(1); + + // Create a property set assignment + const propertySet = doc.addPropertySet(); + propertySet.setPropertyValueBoolean('matte', false); + expect(propertySet.getPropertyValue('matte').getData()).to.equal(false); + const propertySetAssign = look.addPropertySetAssign(); + propertySetAssign.setPropertySet(propertySet); + propertySetAssign.setGeom('/robot1'); + expect(propertySetAssign.getPropertySet().equals(propertySet)).to.be.true; + expect(propertySetAssign.getGeom()).to.equal('/robot1'); + + // Create a variant set + const variantSet = doc.addVariantSet(); + variantSet.addVariant('original'); + variantSet.addVariant('damaged'); + expect(variantSet.getVariants().length).to.equal(2); + + // Validate the document + expect(doc.validate()).to.be.true; + + // Disconnect output from sources + output1.setConnectedNode(null); + output2.setConnectedNode(null); + expect(output1.getConnectedNode()).to.equal(null); + expect(output2.getConnectedNode()).to.equal(null); + }); +}); diff --git a/MaterialX/javascript/MaterialXTest/element.spec.js b/MaterialX/javascript/MaterialXTest/element.spec.js old mode 100644 new mode 100755 index 79abaa4..640ae61 --- a/MaterialX/javascript/MaterialXTest/element.spec.js +++ b/MaterialX/javascript/MaterialXTest/element.spec.js @@ -1,201 +1,166 @@ -import { expect } from 'chai'; -import Module from './_build/JsMaterialXCore.js'; - -describe('Element', () => -{ - let mx, doc, valueTypes; - - const primitiveValueTypes = { - Integer: 10, - Boolean: true, - String: 'test', - Float: 15, - IntegerArray: [1, 2, 3, 4, 5], - FloatArray: [12, 14], // Not using actual floats to avoid precision problems - StringArray: ['first', 'second'], - BooleanArray: [true, true, false], - } - - before(async () => - { - mx = await Module(); - doc = mx.createDocument(); - valueTypes = { - Color3: new mx.Color3(1, 0, 0.5), - Color4: new mx.Color4(0, 1, 0.5, 1), - Vector2: new mx.Vector2(0, 1), - Vector3: new mx.Vector3(0, 1, 2), - Vector4: new mx.Vector4(0, 1, 2, 1), - Matrix33: new mx.Matrix33(0, 1, 2, 3, 4, 5, 6, 7, 8), - Matrix44: new mx.Matrix44(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), - }; - }); - - after(() => - { - // Cleanup typed helper objects and document - Object.values(valueTypes).forEach(v => v.delete()); - doc.delete(); - }); - - describe('value setters', () => - { - const checkValue = (types, assertionCallback) => - { - const elem = doc.addChildOfCategory('geomprop'); - Object.keys(types).forEach((typeName) => - { - const setFn = `setValue${typeName}`; - elem[setFn](types[typeName]); - assertionCallback(elem.getValue().getData(), typeName); - }); - elem.delete(); - }; - - it('should work with expected type', () => - { - checkValue(valueTypes, (returnedValue, typeName) => - { - expect(returnedValue).to.be.an.instanceof(mx[`${typeName}`]); - expect(returnedValue.equals(valueTypes[typeName])).to.equal(true); - }); - }); - - it('should work with expected primitive type', () => - { - checkValue(primitiveValueTypes, (returnedValue, typeName) => - { - expect(returnedValue).to.eql(primitiveValueTypes[typeName]); - }); - }); - - it('should fail for incorrect type', () => - { - const elem = doc.addChildOfCategory('geomprop'); - expect(() => elem.Matrix33(true)).to.throw(); - }); - }); - - describe('typed value setters', () => - { - const checkTypes = (types, assertionCallback) => - { - const elem = doc.addChildOfCategory('geomprop'); - Object.keys(types).forEach((typeName) => - { - const setFn = `setTypedAttribute${typeName}`; - const getFn = `getTypedAttribute${typeName}`; - elem[setFn](typeName, types[typeName]); - assertionCallback(elem[getFn](typeName), types[typeName]); - }); - elem.delete(); - }; - - it('should work with expected custom type', () => - { - checkTypes(valueTypes, (returnedValue, originalValue) => - { - expect(returnedValue.equals(originalValue)).to.equal(true); - }); - }); - - it('should work with expected primitive type', () => - { - checkTypes(primitiveValueTypes, (returnedValue, originalValue) => - { - expect(returnedValue).to.eql(originalValue); - }); - }); - - it('should fail for incorrect type', () => - { - const elem = doc.addChildOfCategory('geomprop'); - expect(() => elem.setTypedAttributeColor3('wrongType', true)).to.throw(); - }); - }); - - it('factory invocation should match specialized functions', () => - { - // List based in source/MaterialXCore/Element.cpp - const elemtypeArr = [ - 'Backdrop', - 'Collection', - 'GeomInfo', - 'MaterialAssign', - 'PropertySetAssign', - 'Visibility', - 'GeomPropDef', - 'Look', - 'LookGroup', - 'PropertySet', - 'TypeDef', - 'AttributeDef', - 'NodeGraph', - 'Implementation', - 'Node', - 'NodeDef', - 'Variant', - 'Member', - 'TargetDef', - 'GeomProp', - 'Input', - 'Output', - 'Property', - 'PropertyAssign', - 'Unit', - 'UnitDef', - 'UnitTypeDef', - 'VariantAssign', - 'VariantSet', - ]; - - elemtypeArr.forEach((typeName) => - { - const specializedFn = `addChild${typeName}`; - const factoryName = typeName.toLowerCase(); - const type = mx[typeName]; - expect(doc[specializedFn]()).to.be.an.instanceof(type); - expect(doc.addChildOfCategory(factoryName)).to.be.an.instanceof(type); - }); - - const specialElemType = { - 'MaterialX': mx.Document, - 'Comment': mx.CommentElement, - 'Generic': mx.GenericElement, - }; - - Object.keys(specialElemType).forEach((typeName) => - { - const specializedFn = `addChild${typeName}`; - const factoryName = typeName.toLowerCase(); - expect(doc[specializedFn]()).to.be.an.instanceof(specialElemType[typeName]); - expect(doc.addChildOfCategory(factoryName)).to.be.an.instanceof(specialElemType[typeName]); - }); - // No doc.delete() here; cleaned up in after() - }); -}); - -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; - }); -}); +import { expect } from 'chai'; +import Module from './_build/JsMaterialXCore.js'; + +describe('Element', () => +{ + let mx, doc, valueTypes; + + const primitiveValueTypes = { + Integer: 10, + Boolean: true, + String: 'test', + Float: 15, + IntegerArray: [1, 2, 3, 4, 5], + FloatArray: [12, 14], // Not using actual floats to avoid precision problems + StringArray: ['first', 'second'], + BooleanArray: [true, true, false], + } + + before(async () => + { + mx = await Module(); + doc = mx.createDocument(); + valueTypes = { + Color3: new mx.Color3(1, 0, 0.5), + Color4: new mx.Color4(0, 1, 0.5, 1), + Vector2: new mx.Vector2(0, 1), + Vector3: new mx.Vector3(0, 1, 2), + Vector4: new mx.Vector4(0, 1, 2, 1), + Matrix33: new mx.Matrix33(0, 1, 2, 3, 4, 5, 6, 7, 8), + Matrix44: new mx.Matrix44(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), + }; + }); + + describe('value setters', () => + { + const checkValue = (types, assertionCallback) => + { + const elem = doc.addChildOfCategory('geomprop'); + Object.keys(types).forEach((typeName) => + { + const setFn = `setValue${typeName}`; + elem[setFn](types[typeName]); + assertionCallback(elem.getValue().getData(), typeName); + }); + }; + + it('should work with expected type', () => + { + checkValue(valueTypes, (returnedValue, typeName) => + { + expect(returnedValue).to.be.an.instanceof(mx[`${typeName}`]); + expect(returnedValue.equals(valueTypes[typeName])).to.equal(true); + }); + }); + + it('should work with expected primitive type', () => + { + checkValue(primitiveValueTypes, (returnedValue, typeName) => + { + expect(returnedValue).to.eql(primitiveValueTypes[typeName]); + }); + }); + + it('should fail for incorrect type', () => + { + const elem = doc.addChildOfCategory('geomprop'); + expect(() => elem.Matrix33(true)).to.throw(); + }); + }); + + describe('typed value setters', () => + { + const checkTypes = (types, assertionCallback) => + { + const elem = doc.addChildOfCategory('geomprop'); + Object.keys(types).forEach((typeName) => + { + const setFn = `setTypedAttribute${typeName}`; + const getFn = `getTypedAttribute${typeName}`; + elem[setFn](typeName, types[typeName]); + assertionCallback(elem[getFn](typeName), types[typeName]); + }); + }; + + it('should work with expected custom type', () => + { + checkTypes(valueTypes, (returnedValue, originalValue) => + { + expect(returnedValue.equals(originalValue)).to.equal(true); + }); + }); + + it('should work with expected primitive type', () => + { + checkTypes(primitiveValueTypes, (returnedValue, originalValue) => + { + expect(returnedValue).to.eql(originalValue); + }); + }); + + it('should fail for incorrect type', () => + { + const elem = doc.addChildOfCategory('geomprop'); + expect(() => elem.setTypedAttributeColor3('wrongType', true)).to.throw(); + }); + }); + + it('factory invocation should match specialized functions', () => + { + // List based in source/MaterialXCore/Element.cpp + const elemtypeArr = [ + 'Backdrop', + 'Collection', + 'GeomInfo', + 'MaterialAssign', + 'PropertySetAssign', + 'Visibility', + 'GeomPropDef', + 'Look', + 'LookGroup', + 'PropertySet', + 'TypeDef', + 'AttributeDef', + 'NodeGraph', + 'Implementation', + 'Node', + 'NodeDef', + 'Variant', + 'Member', + 'TargetDef', + 'GeomProp', + 'Input', + 'Output', + 'Property', + 'PropertyAssign', + 'Unit', + 'UnitDef', + 'UnitTypeDef', + 'VariantAssign', + 'VariantSet', + ]; + + elemtypeArr.forEach((typeName) => + { + const specializedFn = `addChild${typeName}`; + const factoryName = typeName.toLowerCase(); + const type = mx[typeName]; + expect(doc[specializedFn]()).to.be.an.instanceof(type); + expect(doc.addChildOfCategory(factoryName)).to.be.an.instanceof(type); + }); + + const specialElemType = { + 'MaterialX': mx.Document, + 'Comment': mx.CommentElement, + 'Generic': mx.GenericElement, + }; + + Object.keys(specialElemType).forEach((typeName) => + { + const specializedFn = `addChild${typeName}`; + const factoryName = typeName.toLowerCase(); + expect(doc[specializedFn]()).to.be.an.instanceof(specialElemType[typeName]); + expect(doc.addChildOfCategory(factoryName)).to.be.an.instanceof(specialElemType[typeName]); + }); + }); +}); diff --git a/MaterialX/javascript/MaterialXTest/environ.spec.js b/MaterialX/javascript/MaterialXTest/environ.spec.js old mode 100644 new mode 100755 index 2277e0b..e2fc26d --- a/MaterialX/javascript/MaterialXTest/environ.spec.js +++ b/MaterialX/javascript/MaterialXTest/environ.spec.js @@ -1,20 +1,20 @@ -import { expect } from 'chai';; -import Module from './_build/JsMaterialXCore.js'; - -describe('Environ', () => -{ - let mx; - before(async () => - { - mx = await Module(); - }); - - it('Environment variables', () => - { - expect(mx.getEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR)).to.equal(''); - mx.setEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR, 'test'); - expect(mx.getEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR)).to.equal('test'); - mx.removeEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR); - expect(mx.getEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR)).to.equal(''); - }); -}); +import { expect } from 'chai';; +import Module from './_build/JsMaterialXCore.js'; + +describe('Environ', () => +{ + let mx; + before(async () => + { + mx = await Module(); + }); + + it('Environment variables', () => + { + expect(mx.getEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR)).to.equal(''); + mx.setEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR, 'test'); + expect(mx.getEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR)).to.equal('test'); + mx.removeEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR); + expect(mx.getEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR)).to.equal(''); + }); +}); diff --git a/MaterialX/javascript/MaterialXTest/package-lock.json b/MaterialX/javascript/MaterialXTest/package-lock.json old mode 100644 new mode 100755 index 156c259..bb9d5a4 --- a/MaterialX/javascript/MaterialXTest/package-lock.json +++ b/MaterialX/javascript/MaterialXTest/package-lock.json @@ -1,5670 +1,5329 @@ -{ - "name": "MaterialXTest", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "MaterialXTest", - "version": "1.0.0", - "license": "ISC", - "devDependencies": { - "@babel/core": "^7.28.5", - "@babel/preset-env": "^7.28.5", - "@babel/register": "^7.28.3", - "chai": "^4.5.0", - "copyfiles": "^2.4.1", - "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": "^11.7.5", - "rimraf": "^3.0.2" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.3" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", - "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.5", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", - "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "regexpu-core": "^6.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", - "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", - "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "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.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", - "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", - "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", - "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", - "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", - "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", - "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", - "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", - "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", - "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", - "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.5", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.4", - "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-dotall-regex": "^7.27.1", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.28.5", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.28.5", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.4", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.28.5", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.4", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "core-js-compat": "^3.43.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/register": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.28.3.tgz", - "integrity": "sha512-CieDOtd8u208eI49bYl4z1J22ySFw87IGwE+IswFEExH7e3rLgKb0WNQeumnacQ1+VoDJLYI5QFA3AJZuyZQfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone-deep": "^4.0.1", - "find-cache-dir": "^2.0.0", - "make-dir": "^2.1.0", - "pirates": "^4.0.6", - "source-map-support": "^0.5.16" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/cors": { - "version": "2.8.19", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", - "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "24.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", - "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^4.5.0 || >= 5.9" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.29.tgz", - "integrity": "sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/body-parser": { - "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": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true, - "license": "ISC" - }, - "node_modules/browserslist": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", - "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.8.25", - "caniuse-lite": "^1.0.30001754", - "electron-to-chromium": "^1.5.249", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.1.4" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001755", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001755.tgz", - "integrity": "sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "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" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/copyfiles": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", - "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "glob": "^7.0.5", - "minimatch": "^3.0.3", - "mkdirp": "^1.0.4", - "noms": "0.0.0", - "through2": "^2.0.1", - "untildify": "^4.0.0", - "yargs": "^16.1.0" - }, - "bin": { - "copyfiles": "copyfiles", - "copyup": "copyfiles" - } - }, - "node_modules/core-js-compat": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", - "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", - "dev": true, - "license": "MIT" - }, - "node_modules/date-format": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", - "dev": true, - "license": "MIT" - }, - "node_modules/diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.256", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.256.tgz", - "integrity": "sha512-uqYq1IQhpXXLX+HgiXdyOZml7spy4xfy42yPxcCCRjswp0fYM2X+JwCON07lqnpLEGVCj739B7Yr+FngmHBMEQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "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/engine.io": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", - "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.7.2", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/engine.io-parser": { - "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": { - "node": ">=10.0.0" - } - }, - "node_modules/engine.io/node_modules/debug": { - "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.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/ent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.2.tgz", - "integrity": "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "punycode": "^1.4.1", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "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": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true, - "license": "MIT" - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/finalhandler/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isbinaryfile": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/karma": { - "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": { - "@colors/colors": "1.5.0", - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.5.1", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.7", - "graceful-fs": "^4.2.6", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.8", - "lodash": "^4.17.21", - "log4js": "^6.4.1", - "mime": "^2.5.2", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.5", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^4.7.2", - "source-map": "^0.6.1", - "tmp": "^0.2.1", - "ua-parser-js": "^0.7.30", - "yargs": "^16.1.1" - }, - "bin": { - "karma": "bin/karma" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/karma-chai": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", - "integrity": "sha512-mqKCkHwzPMhgTYca10S90aCEX9+HjVjjrBFAsw36Zj7BlQNbokXXCAe6Ji04VUMsxcY5RLP7YphpfO06XOubdg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "chai": "*", - "karma": ">=0.10.9" - } - }, - "node_modules/karma-chrome-launcher": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", - "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "which": "^1.2.1" - } - }, - "node_modules/karma-mocha": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-2.0.1.tgz", - "integrity": "sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.3" - } - }, - "node_modules/karma-mocha-reporter": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz", - "integrity": "sha512-Hr6nhkIp0GIJJrvzY8JFeHpQZNseuIakGac4bpw8K1+5F0tLb6l7uvXRa8mt2Z+NVwYgCct4QAfp2R2QP6o00w==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^2.1.0", - "log-symbols": "^2.1.0", - "strip-ansi": "^4.0.0" - }, - "peerDependencies": { - "karma": ">=0.13" - } - }, - "node_modules/karma/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/log4js": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", - "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha": { - "version": "11.7.5", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", - "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", - "dev": true, - "license": "MIT", - "dependencies": { - "browser-stdout": "^1.3.1", - "chokidar": "^4.0.1", - "debug": "^4.3.5", - "diff": "^7.0.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^10.4.5", - "he": "^1.2.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^9.0.5", - "ms": "^2.1.3", - "picocolors": "^1.1.1", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^9.2.0", - "yargs": "^17.7.2", - "yargs-parser": "^21.1.1", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/mocha/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/mocha/node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/mocha/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mocha/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/mocha/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "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", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/mocha/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/mocha/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "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/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/noms": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", - "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", - "dev": true, - "license": "ISC", - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "~1.0.31" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "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", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.9" - } - }, - "node_modules/qs": { - "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.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.2", - "regjsgen": "^0.8.0", - "regjsparser": "^0.13.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.2.1" - }, - "engines": { - "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.13.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", - "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "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": { - "randombytes": "^2.1.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/socket.io": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", - "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.6.0", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/socket.io-adapter": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", - "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "~4.3.4", - "ws": "~8.17.1" - } - }, - "node_modules/socket.io-adapter/node_modules/debug": { - "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.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-parser/node_modules/debug": { - "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.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io/node_modules/debug": { - "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.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/streamroller": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/through2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/through2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/through2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/tmp": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/type-detect": { - "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": { - "node": ">=4" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ua-parser-js": { - "version": "0.7.41", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.41.tgz", - "integrity": "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - }, - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" - } - ], - "license": "MIT", - "bin": { - "ua-parser-js": "script/cli.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "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": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", - "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", - "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/workerpool": { - "version": "9.3.4", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", - "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/yargs-parser": { - "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": { - "node": ">=10" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} +{ + "name": "MaterialXTest", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "MaterialXTest", + "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", + "copyfiles": "^2.4.1", + "karma": "^6.4.3", + "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", + "rimraf": "^3.0.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "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", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "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", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.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==", + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "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" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "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==", + "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", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "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/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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==", + "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/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-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@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/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-regenerator": "^0.6.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.6", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@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==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.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==", + "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", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.6.tgz", + "integrity": "sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "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==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "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" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "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" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/copyfiles": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", + "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.0.5", + "minimatch": "^3.0.3", + "mkdirp": "^1.0.4", + "noms": "0.0.0", + "through2": "^2.0.1", + "untildify": "^4.0.0", + "yargs": "^16.1.0" + }, + "bin": { + "copyfiles": "copyfiles", + "copyup": "copyfiles" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true, + "license": "MIT" + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true, + "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==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "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==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "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/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "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==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/karma": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz", + "integrity": "sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.7.2", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chai": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", + "integrity": "sha512-mqKCkHwzPMhgTYca10S90aCEX9+HjVjjrBFAsw36Zj7BlQNbokXXCAe6Ji04VUMsxcY5RLP7YphpfO06XOubdg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "chai": "*", + "karma": ">=0.10.9" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", + "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-mocha": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-2.0.1.tgz", + "integrity": "sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.3" + } + }, + "node_modules/karma-mocha-reporter": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz", + "integrity": "sha512-Hr6nhkIp0GIJJrvzY8JFeHpQZNseuIakGac4bpw8K1+5F0tLb6l7uvXRa8mt2Z+NVwYgCct4QAfp2R2QP6o00w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.1.0", + "log-symbols": "^2.1.0", + "strip-ansi": "^4.0.0" + }, + "peerDependencies": { + "karma": ">=0.13" + } + }, + "node_modules/karma/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "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" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/mocha/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/mocha/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "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", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/mocha/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "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", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "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", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "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/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/noms": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", + "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", + "dev": true, + "license": "ISC", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "~1.0.31" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~0.5.0" + }, + "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", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "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==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "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==", + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/MaterialX/javascript/MaterialXTest/package.json b/MaterialX/javascript/MaterialXTest/package.json old mode 100644 new mode 100755 index 17f2e3b..bc70bd2 --- a/MaterialX/javascript/MaterialXTest/package.json +++ b/MaterialX/javascript/MaterialXTest/package.json @@ -1,32 +1,32 @@ -{ - "name": "MaterialXTest", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "clean": "rimraf ./_build/", - "copyBuild": "copyfiles -f ../build/bin/JsMaterialX* _build", - "pretest": "npm run clean && npm run copyBuild", - "test": "npm run mocha", - "test:browser": "npm run karma -- --browsers ChromeHeadlessGL --singleRun true", - "mocha": "mocha *.spec.js --require @babel/register --timeout 5000", - "karma": "karma start browser/karma.conf.js" - }, - "keywords": [], - "author": "", - "license": "ISC", - "devDependencies": { - "@babel/core": "^7.28.5", - "@babel/preset-env": "^7.28.5", - "@babel/register": "^7.28.3", - "chai": "^4.5.0", - "copyfiles": "^2.4.1", - "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": "^11.7.5", - "rimraf": "^3.0.2" - } -} +{ + "name": "MaterialXTest", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "clean": "rimraf ./_build/", + "copyBuild": "copyfiles -f ../build/bin/JsMaterialX* _build", + "pretest": "npm run clean && npm run copyBuild", + "test": "npm run mocha", + "test:browser": "npm run karma -- --browsers ChromeHeadless --singleRun true", + "mocha": "mocha '*.spec.js' --require @babel/register --timeout 5000", + "karma": "karma start browser/karma.conf.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@babel/core": "^7.24.7", + "@babel/preset-env": "^7.24.7", + "@babel/register": "^7.24.6", + "chai": "^4.4.1", + "copyfiles": "^2.4.1", + "karma": "^6.4.3", + "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", + "rimraf": "^3.0.2" + } +} diff --git a/MaterialX/javascript/MaterialXTest/testHelpers.js b/MaterialX/javascript/MaterialXTest/testHelpers.js old mode 100644 new mode 100755 index a75c2e6..5a3882b --- a/MaterialX/javascript/MaterialXTest/testHelpers.js +++ b/MaterialX/javascript/MaterialXTest/testHelpers.js @@ -1,14 +1,14 @@ -var fs = require('fs'); -var path = require('path'); - -export function getMtlxStrings(fileNames, subPath) -{ - const mtlxStrs = []; - for (let i = 0; i < fileNames.length; i++) - { - const p = path.resolve(subPath, fileNames[parseInt(i, 10)]); - const t = fs.readFileSync(p, 'utf8'); - mtlxStrs.push(t); - } - return mtlxStrs; -} +var fs = require('fs'); +var path = require('path'); + +export function getMtlxStrings(fileNames, subPath) +{ + const mtlxStrs = []; + for (let i = 0; i < fileNames.length; i++) + { + const p = path.resolve(subPath, fileNames[parseInt(i, 10)]); + const t = fs.readFileSync(p, 'utf8'); + mtlxStrs.push(t); + } + return mtlxStrs; +} diff --git a/MaterialX/javascript/MaterialXTest/traversal.spec.js b/MaterialX/javascript/MaterialXTest/traversal.spec.js old mode 100644 new mode 100755 index 831269d..2ff3441 --- a/MaterialX/javascript/MaterialXTest/traversal.spec.js +++ b/MaterialX/javascript/MaterialXTest/traversal.spec.js @@ -1,236 +1,205 @@ -import { expect } from 'chai'; -import Module from './_build/JsMaterialXCore.js'; - -describe('Traversal', () => -{ - let mx; - before(async () => - { - mx = await Module(); - }); - - it('Traverse Graph', () => - { - // Create a document. - const doc = mx.createDocument(); - // Create a node graph with the following structure: - // - // [image1] [constant] [image2] - // \ / | - // [multiply] [contrast] [noise3d] - // \____________ | ____________/ - // [mix] - // | - // [output] - // - const nodeGraph = doc.addNodeGraph(); - const image1 = nodeGraph.addNode('image'); - const image2 = nodeGraph.addNode('image'); - const constant = nodeGraph.addNode('constant'); - const multiply = nodeGraph.addNode('multiply'); - const contrast = nodeGraph.addNode('contrast'); - const noise3d = nodeGraph.addNode('noise3d'); - const mix = nodeGraph.addNode('mix'); - const output = nodeGraph.addOutput(); - multiply.setConnectedNode('in1', image1); - multiply.setConnectedNode('in2', constant); - contrast.setConnectedNode('in', image2); - mix.setConnectedNode('fg', multiply); - mix.setConnectedNode('bg', contrast); - mix.setConnectedNode('mask', noise3d); - output.setConnectedNode(mix); - - expect(doc.validate()).to.be.true; - - // Traverse the document tree (implicit iterator). - let nodeCount = 0; - for (let elem of doc.traverseTree()) - { - if (elem instanceof mx.Node) - { - nodeCount++; - } - elem.delete(); - } - expect(nodeCount).to.equal(7); - - // Traverse the document tree (explicit iterator) - let treeIter = doc.traverseTree(); - nodeCount = 0; - let maxElementDepth = 0; - for (let elem of treeIter) - { - if (elem instanceof mx.Node) - { - nodeCount++; - } - maxElementDepth = Math.max(maxElementDepth, treeIter.getElementDepth()); - elem.delete(); - } - expect(nodeCount).to.equal(7); - expect(maxElementDepth).to.equal(3); - - // Traverse the document tree (prune subtree). - nodeCount = 0; - treeIter = doc.traverseTree(); - for (let elem of treeIter) - { - if (elem instanceof mx.Node) - { - nodeCount++; - } - if (elem instanceof mx.NodeGraph) - { - treeIter.setPruneSubtree(true); - } - elem.delete(); - } - expect(nodeCount).to.equal(0); - - // Traverse upstream from the graph output (implicit iterator) - nodeCount = 0; - for (let edge of output.traverseGraph()) - { - const upstreamElem = edge.getUpstreamElement(); - const connectingElem = edge.getConnectingElement(); - const downstreamElem = edge.getDownstreamElement(); - if (upstreamElem instanceof mx.Node) - { - nodeCount++; - if (downstreamElem instanceof mx.Node) - { - expect(connectingElem instanceof mx.Input).to.be.true; - } - } - if (upstreamElem) upstreamElem.delete(); - if (connectingElem) connectingElem.delete(); - if (downstreamElem) downstreamElem.delete(); - if (edge) edge.delete(); - } - expect(nodeCount).to.equal(7); - - // Traverse upstream from the graph output (explicit iterator) - nodeCount = 0; - maxElementDepth = 0; - let maxNodeDepth = 0; - let graphIter = output.traverseGraph(); - for (let edge of graphIter) - { - const upstreamElem = edge.getUpstreamElement(); - if (upstreamElem instanceof mx.Node) - { - nodeCount++; - } - maxElementDepth = Math.max(maxElementDepth, graphIter.getElementDepth()); - maxNodeDepth = Math.max(maxNodeDepth, graphIter.getNodeDepth()); - if (upstreamElem) upstreamElem.delete(); - if (edge) edge.delete(); - } - expect(nodeCount).to.equal(7); - expect(maxElementDepth).to.equal(3); - expect(maxNodeDepth).to.equal(3); - - // Traverse upstream from the graph output (prune subgraph) - nodeCount = 0; - graphIter = output.traverseGraph(); - for (let edge of graphIter) - { - const upstreamElem = edge.getUpstreamElement(); - expect(upstreamElem.getSelf()).to.be.an.instanceof(mx.Element); - if (upstreamElem instanceof mx.Node) - { - nodeCount++; - } - if (upstreamElem.getCategory() === 'multiply') - { - graphIter.setPruneSubgraph(true); - } - if (upstreamElem) upstreamElem.delete(); - if (edge) edge.delete(); - } - expect(nodeCount).to.equal(5); - - // Create and detect a cycle - multiply.setConnectedNode('in2', mix); - expect(output.hasUpstreamCycle()).to.be.true; - expect(doc.validate()).to.be.false; - multiply.setConnectedNode('in2', constant); - expect(output.hasUpstreamCycle()).to.be.false; - expect(doc.validate()).to.be.true; - - // Create and detect a loop - contrast.setConnectedNode('in', contrast); - expect(output.hasUpstreamCycle()).to.be.true; - expect(doc.validate()).to.be.false; - contrast.setConnectedNode('in', image2); - expect(output.hasUpstreamCycle()).to.be.false; - expect(doc.validate()).to.be.true; - - // Cleanup wrappers - output.delete(); - mix.delete(); - noise3d.delete(); - contrast.delete(); - multiply.delete(); - constant.delete(); - image2.delete(); - image1.delete(); - nodeGraph.delete(); - doc.delete(); - }); - - describe("Traverse inheritance", () => - { - let nodeDefInheritanceLevel2, nodeDefInheritanceLevel1, nodeDefParent; - let doc; - beforeEach(() => - { - doc = mx.createDocument(); - nodeDefParent = doc.addNodeDef(); - nodeDefParent.setName('BaseClass'); - nodeDefInheritanceLevel1 = doc.addNodeDef(); - nodeDefInheritanceLevel1.setName('InheritanceLevel1'); - nodeDefInheritanceLevel2 = doc.addNodeDef(); - nodeDefInheritanceLevel2.setName('InheritanceLevel2'); - nodeDefInheritanceLevel2.setInheritsFrom(nodeDefInheritanceLevel1); - nodeDefInheritanceLevel1.setInheritsFrom(nodeDefParent); - }); - afterEach(() => - { - nodeDefInheritanceLevel2.delete(); - nodeDefInheritanceLevel1.delete(); - nodeDefParent.delete(); - doc.delete(); - }); - - it('for of loop', () => - { - const inheritanceIterator = nodeDefInheritanceLevel2.traverseInheritance(); - let inheritanceChainLength = 0; - for (const elem of inheritanceIterator) - { - if (elem instanceof mx.NodeDef) - { - inheritanceChainLength++; - } - } - expect(inheritanceChainLength).to.equal(2);; - }); - - it('while loop', () => - { - const inheritanceIterator = nodeDefInheritanceLevel2.traverseInheritance(); - let inheritanceChainLength = 0; - let elem = inheritanceIterator.next(); - while (!elem.done) - { - if (elem.value instanceof mx.NodeDef) - { - inheritanceChainLength++; - } - elem = inheritanceIterator.next(); - } - expect(inheritanceChainLength).to.equal(2);; - }); - }); -}); +import { expect } from 'chai'; +import Module from './_build/JsMaterialXCore.js'; + +describe('Traversal', () => +{ + let mx; + before(async () => + { + mx = await Module(); + }); + + it('Traverse Graph', () => + { + // Create a document. + const doc = mx.createDocument(); + // Create a node graph with the following structure: + // + // [image1] [constant] [image2] + // \ / | + // [multiply] [contrast] [noise3d] + // \____________ | ____________/ + // [mix] + // | + // [output] + // + const nodeGraph = doc.addNodeGraph(); + const image1 = nodeGraph.addNode('image'); + const image2 = nodeGraph.addNode('image'); + const constant = nodeGraph.addNode('constant'); + const multiply = nodeGraph.addNode('multiply'); + const contrast = nodeGraph.addNode('contrast'); + const noise3d = nodeGraph.addNode('noise3d'); + const mix = nodeGraph.addNode('mix'); + const output = nodeGraph.addOutput(); + multiply.setConnectedNode('in1', image1); + multiply.setConnectedNode('in2', constant); + contrast.setConnectedNode('in', image2); + mix.setConnectedNode('fg', multiply); + mix.setConnectedNode('bg', contrast); + mix.setConnectedNode('mask', noise3d); + output.setConnectedNode(mix); + + expect(doc.validate()).to.be.true; + + // Traverse the document tree (implicit iterator). + let nodeCount = 0; + for (let elem of doc.traverseTree()) + { + if (elem instanceof mx.Node) + { + nodeCount++; + } + } + expect(nodeCount).to.equal(7); + + // Traverse the document tree (explicit iterator) + let treeIter = doc.traverseTree(); + nodeCount = 0; + let maxElementDepth = 0; + for (let elem of treeIter) + { + if (elem instanceof mx.Node) + { + nodeCount++; + } + maxElementDepth = Math.max(maxElementDepth, treeIter.getElementDepth()); + } + expect(nodeCount).to.equal(7); + expect(maxElementDepth).to.equal(3); + + // Traverse the document tree (prune subtree). + nodeCount = 0; + treeIter = doc.traverseTree(); + for (let elem of treeIter) + { + if (elem instanceof mx.Node) + { + nodeCount++; + } + if (elem instanceof mx.NodeGraph) + { + treeIter.setPruneSubtree(true); + } + } + expect(nodeCount).to.equal(0); + + // Traverse upstream from the graph output (implicit iterator) + nodeCount = 0; + for (let edge of output.traverseGraph()) + { + const upstreamElem = edge.getUpstreamElement(); + const connectingElem = edge.getConnectingElement(); + const downstreamElem = edge.getDownstreamElement(); + if (upstreamElem instanceof mx.Node) + { + nodeCount++; + if (downstreamElem instanceof mx.Node) + { + expect(connectingElem instanceof mx.Input).to.be.true; + } + } + } + expect(nodeCount).to.equal(7); + + // Traverse upstream from the graph output (explicit iterator) + nodeCount = 0; + maxElementDepth = 0; + let maxNodeDepth = 0; + let graphIter = output.traverseGraph(); + for (let edge of graphIter) + { + const upstreamElem = edge.getUpstreamElement(); + if (upstreamElem instanceof mx.Node) + { + nodeCount++; + } + maxElementDepth = Math.max(maxElementDepth, graphIter.getElementDepth()); + maxNodeDepth = Math.max(maxNodeDepth, graphIter.getNodeDepth()); + } + expect(nodeCount).to.equal(7); + expect(maxElementDepth).to.equal(3); + expect(maxNodeDepth).to.equal(3); + + // Traverse upstream from the graph output (prune subgraph) + nodeCount = 0; + graphIter = output.traverseGraph(); + for (let edge of graphIter) + { + const upstreamElem = edge.getUpstreamElement(); + expect(upstreamElem.getSelf()).to.be.an.instanceof(mx.Element); + if (upstreamElem instanceof mx.Node) + { + nodeCount++; + } + if (upstreamElem.getCategory() === 'multiply') + { + graphIter.setPruneSubgraph(true); + } + } + expect(nodeCount).to.equal(5); + + // Create and detect a cycle + multiply.setConnectedNode('in2', mix); + expect(output.hasUpstreamCycle()).to.be.true; + expect(doc.validate()).to.be.false; + multiply.setConnectedNode('in2', constant); + expect(output.hasUpstreamCycle()).to.be.false; + expect(doc.validate()).to.be.true; + + // Create and detect a loop + contrast.setConnectedNode('in', contrast); + expect(output.hasUpstreamCycle()).to.be.true; + expect(doc.validate()).to.be.false; + contrast.setConnectedNode('in', image2); + expect(output.hasUpstreamCycle()).to.be.false; + expect(doc.validate()).to.be.true; + }); + + describe("Traverse inheritance", () => + { + let nodeDefInheritanceLevel2, nodeDefInheritanceLevel1, nodeDefParent; + beforeEach(() => + { + const doc = mx.createDocument(); + nodeDefParent = doc.addNodeDef(); + nodeDefParent.setName('BaseClass'); + nodeDefInheritanceLevel1 = doc.addNodeDef(); + nodeDefInheritanceLevel1.setName('InheritanceLevel1'); + nodeDefInheritanceLevel2 = doc.addNodeDef(); + nodeDefInheritanceLevel2.setName('InheritanceLevel2'); + nodeDefInheritanceLevel2.setInheritsFrom(nodeDefInheritanceLevel1); + nodeDefInheritanceLevel1.setInheritsFrom(nodeDefParent); + }); + + it('for of loop', () => + { + const inheritanceIterator = nodeDefInheritanceLevel2.traverseInheritance(); + let inheritanceChainLength = 0; + for (const elem of inheritanceIterator) + { + if (elem instanceof mx.NodeDef) + { + inheritanceChainLength++; + } + } + expect(inheritanceChainLength).to.equal(2);; + }); + + it('while loop', () => + { + const inheritanceIterator = nodeDefInheritanceLevel2.traverseInheritance(); + let inheritanceChainLength = 0; + let elem = inheritanceIterator.next(); + while (!elem.done) + { + if (elem.value instanceof mx.NodeDef) + { + inheritanceChainLength++; + } + elem = inheritanceIterator.next(); + } + expect(inheritanceChainLength).to.equal(2);; + }); + }); +}); diff --git a/MaterialX/javascript/MaterialXTest/types.spec.js b/MaterialX/javascript/MaterialXTest/types.spec.js old mode 100644 new mode 100755 index fc909c8..6516731 --- a/MaterialX/javascript/MaterialXTest/types.spec.js +++ b/MaterialX/javascript/MaterialXTest/types.spec.js @@ -1,178 +1,178 @@ -import { expect } from 'chai';; -import Module from './_build/JsMaterialXCore.js'; - -describe('Types', () => -{ - let mx; - before(async () => - { - mx = await Module(); - }); - - it('Vectors', () => - { - const v1 = new mx.Vector3(1, 2, 3); - let v2 = new mx.Vector3(2, 4, 6); - - // Indexing operators - expect(v1.getItem(2)).to.equal(3); - - v1.setItem(2, 4); - expect(v1.getItem(2)).to.equal(4); - v1.setItem(2, 3); - // Component-wise operators - let res = v2.add(v1); - expect(res.equals(new mx.Vector3(3, 6, 9))).to.be.true; - - res = v2.sub(v1); - expect(res.equals(new mx.Vector3(1, 2, 3))).to.be.true; - - res = v2.multiply(v1); - expect(res.equals(new mx.Vector3(2, 8, 18))).to.be.true; - - res = v2.divide(v1); - expect(res.equals(new mx.Vector3(2, 2, 2))).to.be.true; - - v2 = v2.add(v1); - expect(v2.equals(new mx.Vector3(3, 6, 9))).to.be.true; - - v2 = v2.sub(v1); - expect(v2.equals(new mx.Vector3(2, 4, 6))).to.be.true; - - v2 = v2.multiply(v1); - expect(v2.equals(new mx.Vector3(2, 8, 18))).to.be.true; - - v2 = v2.divide(v1); - expect(v2.equals(new mx.Vector3(2, 4, 6))).to.be.true; - - expect(v1.multiply(new mx.Vector3(2, 2, 2)).equals(v2)).to.be.true; - expect(v2.divide(new mx.Vector3(2, 2, 2)).equals(v1)).to.be.true; - - // Geometric methods - let v3 = new mx.Vector4(4, 4, 4, 4); - expect(v3.getMagnitude()).to.equal(8); - expect(v3.getNormalized().getMagnitude()).to.equal(1); - expect(v1.dot(v2)).to.equal(28); - expect(v1.cross(v2).equals(new mx.Vector3())).to.be.true; - - // Vector copy - const v4 = v2.copy(); - expect(v4.equals(v2)).to.be.true; - v4.setItem(0, v4.getItem(0) + 1); - expect(v4.notEquals(v2)).to.be.true; - }); - - function multiplyMatrix(matrix, val) - { - const clonedMatrix = matrix.copy(); - for (let i = 0; i < clonedMatrix.numRows(); ++i) - { - for (let k = 0; k < clonedMatrix.numColumns(); ++k) - { - const v = clonedMatrix.getItem(i, k); - clonedMatrix.setItem(i, k, v * val); - } - } - return clonedMatrix; - } - - function divideMatrix(matrix, val) - { - const clonedMatrix = matrix.copy(); - for (let i = 0; i < clonedMatrix.numRows(); ++i) - { - for (let k = 0; k < clonedMatrix.numColumns(); ++k) - { - const v = clonedMatrix.getItem(i, k); - clonedMatrix.setItem(i, k, v / val); - } - } - return clonedMatrix; - } - - it('Matrices', () => - { - // Translation and scale - const trans = mx.Matrix44.createTranslation(new mx.Vector3(1, 2, 3)); - const scale = mx.Matrix44.createScale(new mx.Vector3(2, 2, 2)); - expect(trans.equals(new mx.Matrix44(1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 2, 3, 1))); - expect(scale.equals(new mx.Matrix44(2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, 2, 0, - 0, 0, 0, 1))); - - // Indexing operators - expect(trans.getItem(3, 2)).to.equal(3); - trans.setItem(3, 2, 4); - expect(trans.getItem(3, 2)).to.equal(4); - trans.setItem(3, 2, 3); - - // Matrix methods - expect(trans.getTranspose().equals( - new mx.Matrix44(1, 0, 0, 1, - 0, 1, 0, 2, - 0, 0, 1, 3, - 0, 0, 0, 1) - )).to.be.true; - expect(scale.getTranspose().equals(scale)).to.be.true; - expect(trans.getDeterminant()).to.equal(1); - expect(scale.getDeterminant()).to.equal(8); - expect(trans.getInverse().equals( - mx.Matrix44.createTranslation(new mx.Vector3(-1, -2, -3)))).to.be.true; - - // Matrix product - const prod1 = trans.multiply(scale); - const prod2 = scale.multiply(trans); - const prod3 = multiplyMatrix(trans, 2); - let prod4 = trans; - prod4 = prod4.multiply(scale); - expect(prod1.equals(new mx.Matrix44(2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, 2, 0, - 2, 4, 6, 1))); - expect(prod2.equals(new mx.Matrix44(2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, 2, 0, - 1, 2, 3, 1))); - expect(prod3.equals(new mx.Matrix44(2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, 2, 0, - 2, 4, 6, 2))); - expect(prod4.equals(prod1)); - - // Matrix division - const quot1 = prod1.divide(scale); - const quot2 = prod2.divide(trans); - const quot3 = divideMatrix(prod3, 2); - let quot4 = quot1; - quot4 = quot4.divide(trans); - expect(quot1.equals(trans)).to.be.true; - expect(quot2.equals(scale)).to.be.true; - expect(quot3.equals(trans)).to.be.true; - - // 2D rotation - const _epsilon = 1e-4; - const rot1 = mx.Matrix33.createRotation(Math.PI / 2); - const rot2 = mx.Matrix33.createRotation(Math.PI); - expect(rot1.multiply(rot1).isEquivalent(rot2, _epsilon)); - expect(rot2.isEquivalent(mx.Matrix33.createScale(new mx.Vector2(-1, -1)), _epsilon)); - expect(rot2.multiply(rot2).isEquivalent(mx.Matrix33.IDENTITY, _epsilon)); - - // 3D rotation - const rotX = mx.Matrix44.createRotationX(Math.PI); - const rotY = mx.Matrix44.createRotationY(Math.PI); - const rotZ = mx.Matrix44.createRotationZ(Math.PI); - expect(rotX.multiply(rotY).isEquivalent(mx.Matrix44.createScale(new mx.Vector3(-1, -1, 1)), _epsilon)); - expect(rotX.multiply(rotZ).isEquivalent(mx.Matrix44.createScale(new mx.Vector3(-1, 1, -1)), _epsilon)); - expect(rotY.multiply(rotZ).isEquivalent(mx.Matrix44.createScale(new mx.Vector3(1, -1, -1)), _epsilon)); - - // Matrix copy - const trans2 = trans.copy(); - expect(trans2.equals(trans)).to.be.true; - trans2.setItem(0, 0, trans2.getItem(0, 0) + 1); - expect(trans2.notEquals(trans)).to.be.true; - }); -}); +import { expect } from 'chai';; +import Module from './_build/JsMaterialXCore.js'; + +describe('Types', () => +{ + let mx; + before(async () => + { + mx = await Module(); + }); + + it('Vectors', () => + { + const v1 = new mx.Vector3(1, 2, 3); + let v2 = new mx.Vector3(2, 4, 6); + + // Indexing operators + expect(v1.getItem(2)).to.equal(3); + + v1.setItem(2, 4); + expect(v1.getItem(2)).to.equal(4); + v1.setItem(2, 3); + // Component-wise operators + let res = v2.add(v1); + expect(res.equals(new mx.Vector3(3, 6, 9))).to.be.true; + + res = v2.sub(v1); + expect(res.equals(new mx.Vector3(1, 2, 3))).to.be.true; + + res = v2.multiply(v1); + expect(res.equals(new mx.Vector3(2, 8, 18))).to.be.true; + + res = v2.divide(v1); + expect(res.equals(new mx.Vector3(2, 2, 2))).to.be.true; + + v2 = v2.add(v1); + expect(v2.equals(new mx.Vector3(3, 6, 9))).to.be.true; + + v2 = v2.sub(v1); + expect(v2.equals(new mx.Vector3(2, 4, 6))).to.be.true; + + v2 = v2.multiply(v1); + expect(v2.equals(new mx.Vector3(2, 8, 18))).to.be.true; + + v2 = v2.divide(v1); + expect(v2.equals(new mx.Vector3(2, 4, 6))).to.be.true; + + expect(v1.multiply(new mx.Vector3(2, 2, 2)).equals(v2)).to.be.true; + expect(v2.divide(new mx.Vector3(2, 2, 2)).equals(v1)).to.be.true; + + // Geometric methods + let v3 = new mx.Vector4(4, 4, 4, 4); + expect(v3.getMagnitude()).to.equal(8); + expect(v3.getNormalized().getMagnitude()).to.equal(1); + expect(v1.dot(v2)).to.equal(28); + expect(v1.cross(v2).equals(new mx.Vector3())).to.be.true; + + // Vector copy + const v4 = v2.copy(); + expect(v4.equals(v2)).to.be.true; + v4.setItem(0, v4.getItem(0) + 1); + expect(v4.notEquals(v2)).to.be.true; + }); + + function multiplyMatrix(matrix, val) + { + const clonedMatrix = matrix.copy(); + for (let i = 0; i < clonedMatrix.numRows(); ++i) + { + for (let k = 0; k < clonedMatrix.numColumns(); ++k) + { + const v = clonedMatrix.getItem(i, k); + clonedMatrix.setItem(i, k, v * val); + } + } + return clonedMatrix; + } + + function divideMatrix(matrix, val) + { + const clonedMatrix = matrix.copy(); + for (let i = 0; i < clonedMatrix.numRows(); ++i) + { + for (let k = 0; k < clonedMatrix.numColumns(); ++k) + { + const v = clonedMatrix.getItem(i, k); + clonedMatrix.setItem(i, k, v / val); + } + } + return clonedMatrix; + } + + it('Matrices', () => + { + // Translation and scale + const trans = mx.Matrix44.createTranslation(new mx.Vector3(1, 2, 3)); + const scale = mx.Matrix44.createScale(new mx.Vector3(2, 2, 2)); + expect(trans.equals(new mx.Matrix44(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 1, 2, 3, 1))); + expect(scale.equals(new mx.Matrix44(2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 2, 0, + 0, 0, 0, 1))); + + // Indexing operators + expect(trans.getItem(3, 2)).to.equal(3); + trans.setItem(3, 2, 4); + expect(trans.getItem(3, 2)).to.equal(4); + trans.setItem(3, 2, 3); + + // Matrix methods + expect(trans.getTranspose().equals( + new mx.Matrix44(1, 0, 0, 1, + 0, 1, 0, 2, + 0, 0, 1, 3, + 0, 0, 0, 1) + )).to.be.true; + expect(scale.getTranspose().equals(scale)).to.be.true; + expect(trans.getDeterminant()).to.equal(1); + expect(scale.getDeterminant()).to.equal(8); + expect(trans.getInverse().equals( + mx.Matrix44.createTranslation(new mx.Vector3(-1, -2, -3)))).to.be.true; + + // Matrix product + const prod1 = trans.multiply(scale); + const prod2 = scale.multiply(trans); + const prod3 = multiplyMatrix(trans, 2); + let prod4 = trans; + prod4 = prod4.multiply(scale); + expect(prod1.equals(new mx.Matrix44(2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 2, 0, + 2, 4, 6, 1))); + expect(prod2.equals(new mx.Matrix44(2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 2, 0, + 1, 2, 3, 1))); + expect(prod3.equals(new mx.Matrix44(2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 2, 0, + 2, 4, 6, 2))); + expect(prod4.equals(prod1)); + + // Matrix division + const quot1 = prod1.divide(scale); + const quot2 = prod2.divide(trans); + const quot3 = divideMatrix(prod3, 2); + let quot4 = quot1; + quot4 = quot4.divide(trans); + expect(quot1.equals(trans)).to.be.true; + expect(quot2.equals(scale)).to.be.true; + expect(quot3.equals(trans)).to.be.true; + + // 2D rotation + const _epsilon = 1e-4; + const rot1 = mx.Matrix33.createRotation(Math.PI / 2); + const rot2 = mx.Matrix33.createRotation(Math.PI); + expect(rot1.multiply(rot1).isEquivalent(rot2, _epsilon)); + expect(rot2.isEquivalent(mx.Matrix33.createScale(new mx.Vector2(-1, -1)), _epsilon)); + expect(rot2.multiply(rot2).isEquivalent(mx.Matrix33.IDENTITY, _epsilon)); + + // 3D rotation + const rotX = mx.Matrix44.createRotationX(Math.PI); + const rotY = mx.Matrix44.createRotationY(Math.PI); + const rotZ = mx.Matrix44.createRotationZ(Math.PI); + expect(rotX.multiply(rotY).isEquivalent(mx.Matrix44.createScale(new mx.Vector3(-1, -1, 1)), _epsilon)); + expect(rotX.multiply(rotZ).isEquivalent(mx.Matrix44.createScale(new mx.Vector3(-1, 1, -1)), _epsilon)); + expect(rotY.multiply(rotZ).isEquivalent(mx.Matrix44.createScale(new mx.Vector3(1, -1, -1)), _epsilon)); + + // Matrix copy + const trans2 = trans.copy(); + expect(trans2.equals(trans)).to.be.true; + trans2.setItem(0, 0, trans2.getItem(0, 0) + 1); + expect(trans2.notEquals(trans)).to.be.true; + }); +}); diff --git a/MaterialX/javascript/MaterialXTest/value.spec.js b/MaterialX/javascript/MaterialXTest/value.spec.js old mode 100644 new mode 100755 index 6a9091c..aca3140 --- a/MaterialX/javascript/MaterialXTest/value.spec.js +++ b/MaterialX/javascript/MaterialXTest/value.spec.js @@ -1,42 +1,42 @@ -import { expect } from 'chai';; -import Module from './_build/JsMaterialXCore.js'; - -describe('Value', () => -{ - let mx; - before(async () => - { - mx = await Module(); - }); - - it('Create values of different types', () => - { - const testValues = { - integer: '1', - boolean: 'true', - float: '1.1', - color3: '0.1, 0.2, 0.3', - color4: '0.1, 0.2, 0.3, 0.4', - vector2: '1.1, 2.1', - vector3: '1.1, 2.1, 3.1', - vector4: '1.1, 2.1, 3.1, 4.1', - matrix33: '0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1', - matrix44: '1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1', - string: 'value', - integerarray: '1, 2, 3', - booleanarray: 'false, true, false', - floatarray: '1.1, 2.1, 3.1', - stringarray: "'one', 'two', 'three'", - }; - - for (let type in testValues) - { - const value = testValues[String(type)]; - const newValue = mx.Value.createValueFromStrings(value, type); - const typeString = newValue.getTypeString(); - const valueString = newValue.getValueString(); - expect(typeString).to.equal(type); - expect(valueString).to.equal(value); - } - }); -}); +import { expect } from 'chai';; +import Module from './_build/JsMaterialXCore.js'; + +describe('Value', () => +{ + let mx; + before(async () => + { + mx = await Module(); + }); + + it('Create values of different types', () => + { + const testValues = { + integer: '1', + boolean: 'true', + float: '1.1', + color3: '0.1, 0.2, 0.3', + color4: '0.1, 0.2, 0.3, 0.4', + vector2: '1.1, 2.1', + vector3: '1.1, 2.1, 3.1', + vector4: '1.1, 2.1, 3.1, 4.1', + matrix33: '0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1', + matrix44: '1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1, 1.1', + string: 'value', + integerarray: '1, 2, 3', + booleanarray: 'false, true, false', + floatarray: '1.1, 2.1, 3.1', + stringarray: "'one', 'two', 'three'", + }; + + for (let type in testValues) + { + const value = testValues[String(type)]; + const newValue = mx.Value.createValueFromStrings(value, type); + const typeString = newValue.getTypeString(); + const valueString = newValue.getValueString(); + expect(typeString).to.equal(type); + expect(valueString).to.equal(value); + } + }); +}); diff --git a/MaterialX/javascript/MaterialXTest/xmlIo.spec.js b/MaterialX/javascript/MaterialXTest/xmlIo.spec.js old mode 100644 new mode 100755 index c4ddbc9..1cc5ae2 --- a/MaterialX/javascript/MaterialXTest/xmlIo.spec.js +++ b/MaterialX/javascript/MaterialXTest/xmlIo.spec.js @@ -1,304 +1,278 @@ -import Module from './_build/JsMaterialXCore.js'; -import { expect } from 'chai'; -import { getMtlxStrings } from './testHelpers'; - -const TIMEOUT = 60000; - -describe('XmlIo', () => -{ - let mx; - - // These should be relative to cwd - const includeTestPath = 'data/includes'; - const libraryPath = '../../libraries/stdlib'; - const examplesPath = '../../resources/Materials/Examples'; - // TODO: Is there a better way to get these filenames than hardcoding them here? - // The C++ tests load all files in the given directories. This would work in Node, but not in the browser. - // Should we use a pre-test script that fetches the files and makes them available somehow? - const libraryFilenames = ['stdlib_defs.mtlx', 'stdlib_ng.mtlx']; - const exampleFilenames = [ - 'StandardSurface/standard_surface_brass_tiled.mtlx', - 'StandardSurface/standard_surface_brick_procedural.mtlx', - 'StandardSurface/standard_surface_carpaint.mtlx', - 'StandardSurface/standard_surface_marble_solid.mtlx', - 'UsdPreviewSurface/usd_preview_surface_gold.mtlx', - 'UsdPreviewSurface/usd_preview_surface_plastic.mtlx', - ]; - - async function readStdLibrary(asString = false) - { - const libs = []; - let iterable = libraryFilenames; - if (asString) - { - const libraryMtlxStrings = getMtlxStrings(libraryFilenames, libraryPath); - iterable = libraryMtlxStrings; - } - for (let file of iterable) - { - const lib = mx.createDocument(); - if (asString) - { - await mx.readFromXmlString(lib, file, libraryPath); - } else - { - await mx.readFromXmlFile(lib, file, libraryPath); - } - libs.push(lib); - }; - return libs; - } - - async function readAndValidateExamples(examples, libraries, readFunc, searchPath = undefined) - { - for (let file of examples) - { - const doc = mx.createDocument(); - await readFunc(doc, file, searchPath); - // Import stdlib into the current document and validate it. - for (let lib of libraries) - { - doc.importLibrary(lib); - } - expect(doc.validate()).to.be.true; - - // Make sure the document does actually contain something. - let valueElementCount = 0; - const treeIter = doc.traverseTree(); - for (const elem of treeIter) - { - if (elem instanceof mx.ValueElement) - { - valueElementCount++; - } - // Release wrapper created by iterator - elem.delete(); - } - expect(valueElementCount).to.be.greaterThan(0); - doc.delete(); - }; - } - - before(async () => - { - mx = await Module(); - }); - - it('Read XML from file', async () => - { - // Read the standard library - const libs = await readStdLibrary(false); - - // Read and validate the example documents. - await readAndValidateExamples(exampleFilenames, libs, - async (document, file, sp) => - { - await mx.readFromXmlFile(document, file, sp); - }, examplesPath); - - // Read the same document twice, and verify that duplicate elements - // are skipped. - const doc = mx.createDocument(); - const filename = 'StandardSurface/standard_surface_carpaint.mtlx'; - await mx.readFromXmlFile(doc, filename, examplesPath); - const copy = doc.copy(); - await mx.readFromXmlFile(doc, filename, examplesPath); - expect(doc.validate()).to.be.true; - expect(copy.equals(doc)).to.be.true; - copy.delete(); - doc.delete(); - libs.forEach(l => l.delete()); - }).timeout(TIMEOUT); - - it('Read XML from string', async () => - { - // Read the standard library - const libs = await readStdLibrary(true); - - // Read and validate each example document. - const examplesStrings = getMtlxStrings(exampleFilenames, examplesPath); - await readAndValidateExamples(examplesStrings, libs, - async (document, file) => - { - await mx.readFromXmlString(document, file); - }); - - // Read the same document twice, and verify that duplicate elements - // are skipped. - const doc = mx.createDocument(); - const file = examplesStrings[exampleFilenames.indexOf('StandardSurface/standard_surface_carpaint.mtlx')]; - await mx.readFromXmlString(doc, file); - const copy = doc.copy(); - await mx.readFromXmlString(doc, file); - expect(doc.validate()).to.be.true; - expect(copy.equals(doc)).to.be.true; - copy.delete(); - doc.delete(); - libs.forEach(l => l.delete()); - }).timeout(TIMEOUT); - - it('Read XML with recursive includes', async () => - { - const doc = mx.createDocument(); - await mx.readFromXmlFile(doc, includeTestPath + '/root.mtlx'); - expect(doc.getChild('paint_semigloss')).to.exist; - expect(doc.validate()).to.be.true; - doc.delete(); - }); - - it('Locate XML includes via search path', async () => - { - const searchPath = includeTestPath + ';' + includeTestPath + '/folder'; - const filename = 'non_relative_includes.mtlx'; - const doc = mx.createDocument(); - expect(async () => await mx.readFromXmlFile(doc, filename, includeTestPath)).to.throw; - await mx.readFromXmlFile(doc, filename, searchPath); - expect(doc.getChild('paint_semigloss')).to.exist; - expect(doc.validate()).to.be.true; - - const doc2 = mx.createDocument(); - const mtlxString = getMtlxStrings([filename], includeTestPath); - expect(async () => await mx.readFromXmlString(doc2, mtlxString[0])).to.throw; - await mx.readFromXmlString(doc2, mtlxString[0], searchPath); - expect(doc2.getChild('paint_semigloss')).to.exist; - expect(doc2.validate()).to.be.true; - expect(doc2.equals(doc)).to.be.true; - doc2.delete(); - doc.delete(); - }); - - it('Locate XML includes via environment variable', async () => - { - const searchPath = includeTestPath + ';' + includeTestPath + '/folder'; - const filename = 'non_relative_includes.mtlx'; - - const doc = mx.createDocument(); - expect(async () => await mx.readFromXmlFile(doc, includeTestPath + '/' + filename)).to.throw; - mx.setEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR, searchPath); - await mx.readFromXmlFile(doc, filename); - mx.removeEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR); - expect(doc.getChild('paint_semigloss')).to.exist; - expect(doc.validate()).to.be.true; - - const doc2 = mx.createDocument(); - const mtlxString = getMtlxStrings([filename], includeTestPath); - expect(async () => await mx.readFromXmlString(doc2, mtlxString[0])).to.throw; - mx.setEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR, searchPath); - await mx.readFromXmlString(doc2, mtlxString[0]); - mx.removeEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR); - expect(doc2.getChild('paint_semigloss')).to.exist; - expect(doc2.validate()).to.be.true; - expect(doc2.equals(doc)).to.be.true; - doc2.delete(); - doc.delete(); - }); - - it('Locate XML includes via absolute search paths', async () => - { - let absolutePath; - if (typeof window === 'object') - { - // We're in the browser - const cwd = window.location.origin + window.location.pathname; - absolutePath = cwd + '/' + includeTestPath; - } else if (typeof process === 'object') - { - // We're in Node - const nodePath = require('path'); - absolutePath = nodePath.resolve(includeTestPath); - } - const doc = mx.createDocument(); - await mx.readFromXmlFile(doc, 'root.mtlx', absolutePath); - doc.delete(); - }); - - it('Detect XML include cycles', async () => - { - const doc = mx.createDocument(); - expect(async () => await mx.readFromXmlFile(doc, includeTestPath + '/cycle.mtlx')).to.throw; - doc.delete(); - }); - - it('Disabling XML includes', async () => - { - const doc = mx.createDocument(); - const readOptions = new mx.XmlReadOptions(); - readOptions.readXIncludes = false; - expect(async () => await mx.readFromXmlFile(doc, includeTestPath + '/cycle.mtlx', readOptions)).to.not.throw; - doc.delete(); - }); - - it('Write to XML string', async () => - { - // Read all example documents and write them to an XML string - const searchPath = libraryPath + ';' + examplesPath; - for (let filename of exampleFilenames) - { - const doc = mx.createDocument(); - await mx.readFromXmlFile(doc, filename, searchPath); - - // Serialize to XML. - const writeOptions = new mx.XmlWriteOptions(); - writeOptions.writeXIncludeEnable = false; - const xmlString = mx.writeToXmlString(doc, writeOptions); - writeOptions.delete(); - - // Verify that the serialized document is identical. - const writtenDoc = mx.createDocument(); - await mx.readFromXmlString(writtenDoc, xmlString); - expect(writtenDoc).to.eql(doc); - writtenDoc.delete(); - doc.delete(); - }; - }); - - it('Prepend include tag', () => - { - const doc = mx.createDocument(); - const includePath = "SomePath"; - const writeOptions = new mx.XmlWriteOptions(); - mx.prependXInclude(doc, includePath); - const xmlString = mx.writeToXmlString(doc, writeOptions); - expect(xmlString).to.include(includePath); - writeOptions.delete(); - doc.delete(); - }); - - // Node only, because we cannot read from a downloaded file in the browser - it('Write XML to file', async () => - { - const filename = '_build/testFile.mtlx'; - const includeRegex = //g; - const doc = mx.createDocument(); - await mx.readFromXmlFile(doc, 'root.mtlx', includeTestPath); - - // Write using includes - mx.writeToXmlFile(doc, filename); - // Read written document and compare with the original - const doc2 = mx.createDocument(); - await mx.readFromXmlFile(doc2, filename, includeTestPath); - expect(doc2.equals(doc)); - // Read written file content and verify that includes are preserved - let fileString = getMtlxStrings([filename], '')[0]; - let matches = Array.from(fileString.matchAll(includeRegex)); - expect(matches.length).to.be.greaterThan(0); - - // Write inlining included content - const writeOptions = new mx.XmlWriteOptions(); - writeOptions.writeXIncludeEnable = false; - mx.writeToXmlFile(doc, filename, writeOptions); - // Read written document and compare with the original - const doc3 = mx.createDocument(); - await mx.readFromXmlFile(doc3, filename); - expect(doc3.equals(doc)); - expect(doc.getChild('paint_semigloss')).to.exist; - // Read written file content and verify that includes are inlined - fileString = getMtlxStrings([filename], '')[0]; - matches = Array.from(fileString.matchAll(includeRegex)); - expect(matches.length).to.equal(0); - doc3.delete(); - doc2.delete(); - doc.delete(); - writeOptions.delete(); - }); -}); +import Module from './_build/JsMaterialXCore.js'; +import { expect } from 'chai'; +import { getMtlxStrings } from './testHelpers'; + +const TIMEOUT = 60000; + +describe('XmlIo', () => +{ + let mx; + + // These should be relative to cwd + const includeTestPath = 'data/includes'; + const libraryPath = '../../libraries/stdlib'; + const examplesPath = '../../resources/Materials/Examples'; + // TODO: Is there a better way to get these filenames than hardcoding them here? + // The C++ tests load all files in the given directories. This would work in Node, but not in the browser. + // Should we use a pre-test script that fetches the files and makes them available somehow? + const libraryFilenames = ['stdlib_defs.mtlx', 'stdlib_ng.mtlx']; + const exampleFilenames = [ + 'StandardSurface/standard_surface_brass_tiled.mtlx', + 'StandardSurface/standard_surface_brick_procedural.mtlx', + 'StandardSurface/standard_surface_carpaint.mtlx', + 'StandardSurface/standard_surface_marble_solid.mtlx', + 'UsdPreviewSurface/usd_preview_surface_gold.mtlx', + 'UsdPreviewSurface/usd_preview_surface_plastic.mtlx', + ]; + + async function readStdLibrary(asString = false) + { + const libs = []; + let iterable = libraryFilenames; + if (asString) + { + const libraryMtlxStrings = getMtlxStrings(libraryFilenames, libraryPath); + iterable = libraryMtlxStrings; + } + for (let file of iterable) + { + const lib = mx.createDocument(); + if (asString) + { + await mx.readFromXmlString(lib, file, libraryPath); + } else + { + await mx.readFromXmlFile(lib, file, libraryPath); + } + libs.push(lib); + }; + return libs; + } + + async function readAndValidateExamples(examples, libraries, readFunc, searchPath = undefined) + { + for (let file of examples) + { + const doc = mx.createDocument(); + await readFunc(doc, file, searchPath); + // Import stdlib into the current document and validate it. + for (let lib of libraries) + { + doc.importLibrary(lib); + } + expect(doc.validate()).to.be.true; + + // Make sure the document does actually contain something. + let valueElementCount = 0; + const treeIter = doc.traverseTree(); + for (const elem of treeIter) + { + if (elem instanceof mx.ValueElement) + { + valueElementCount++; + } + } + expect(valueElementCount).to.be.greaterThan(0); + }; + } + + before(async () => + { + mx = await Module(); + }); + + it('Read XML from file', async () => + { + // Read the standard library + const libs = await readStdLibrary(false); + + // Read and validate the example documents. + await readAndValidateExamples(exampleFilenames, libs, + async (document, file, sp) => + { + await mx.readFromXmlFile(document, file, sp); + }, examplesPath); + + // Read the same document twice, and verify that duplicate elements + // are skipped. + const doc = mx.createDocument(); + const filename = 'StandardSurface/standard_surface_carpaint.mtlx'; + await mx.readFromXmlFile(doc, filename, examplesPath); + const copy = doc.copy(); + await mx.readFromXmlFile(doc, filename, examplesPath); + expect(doc.validate()).to.be.true; + expect(copy.equals(doc)).to.be.true; + }).timeout(TIMEOUT); + + it('Read XML from string', async () => + { + // Read the standard library + const libs = await readStdLibrary(true); + + // Read and validate each example document. + const examplesStrings = getMtlxStrings(exampleFilenames, examplesPath); + await readAndValidateExamples(examplesStrings, libs, + async (document, file) => + { + await mx.readFromXmlString(document, file); + }); + + // Read the same document twice, and verify that duplicate elements + // are skipped. + const doc = mx.createDocument(); + const file = examplesStrings[exampleFilenames.indexOf('StandardSurface/standard_surface_carpaint.mtlx')]; + await mx.readFromXmlString(doc, file); + const copy = doc.copy(); + await mx.readFromXmlString(doc, file); + expect(doc.validate()).to.be.true; + expect(copy.equals(doc)).to.be.true; + }).timeout(TIMEOUT); + + it('Read XML with recursive includes', async () => + { + const doc = mx.createDocument(); + await mx.readFromXmlFile(doc, includeTestPath + '/root.mtlx'); + expect(doc.getChild('paint_semigloss')).to.exist; + expect(doc.validate()).to.be.true; + }); + + it('Locate XML includes via search path', async () => + { + const searchPath = includeTestPath + ';' + includeTestPath + '/folder'; + const filename = 'non_relative_includes.mtlx'; + const doc = mx.createDocument(); + expect(async () => await mx.readFromXmlFile(doc, filename, includeTestPath)).to.throw; + await mx.readFromXmlFile(doc, filename, searchPath); + expect(doc.getChild('paint_semigloss')).to.exist; + expect(doc.validate()).to.be.true; + + const doc2 = mx.createDocument(); + const mtlxString = getMtlxStrings([filename], includeTestPath); + expect(async () => await mx.readFromXmlString(doc2, mtlxString[0])).to.throw; + await mx.readFromXmlString(doc2, mtlxString[0], searchPath); + expect(doc2.getChild('paint_semigloss')).to.exist; + expect(doc2.validate()).to.be.true; + expect(doc2.equals(doc)).to.be.true; + }); + + it('Locate XML includes via environment variable', async () => + { + const searchPath = includeTestPath + ';' + includeTestPath + '/folder'; + const filename = 'non_relative_includes.mtlx'; + + const doc = mx.createDocument(); + expect(async () => await mx.readFromXmlFile(doc, includeTestPath + '/' + filename)).to.throw; + mx.setEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR, searchPath); + await mx.readFromXmlFile(doc, filename); + mx.removeEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR); + expect(doc.getChild('paint_semigloss')).to.exist; + expect(doc.validate()).to.be.true; + + const doc2 = mx.createDocument(); + const mtlxString = getMtlxStrings([filename], includeTestPath); + expect(async () => await mx.readFromXmlString(doc2, mtlxString[0])).to.throw; + mx.setEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR, searchPath); + await mx.readFromXmlString(doc2, mtlxString[0]); + mx.removeEnviron(mx.MATERIALX_SEARCH_PATH_ENV_VAR); + expect(doc2.getChild('paint_semigloss')).to.exist; + expect(doc2.validate()).to.be.true; + expect(doc2.equals(doc)).to.be.true; + }); + + it('Locate XML includes via absolute search paths', async () => + { + let absolutePath; + if (typeof window === 'object') + { + // We're in the browser + const cwd = window.location.origin + window.location.pathname; + absolutePath = cwd + '/' + includeTestPath; + } else if (typeof process === 'object') + { + // We're in Node + const nodePath = require('path'); + absolutePath = nodePath.resolve(includeTestPath); + } + const doc = mx.createDocument(); + await mx.readFromXmlFile(doc, 'root.mtlx', absolutePath); + }); + + it('Detect XML include cycles', async () => + { + const doc = mx.createDocument(); + expect(async () => await mx.readFromXmlFile(doc, includeTestPath + '/cycle.mtlx')).to.throw; + }); + + it('Disabling XML includes', async () => + { + const doc = mx.createDocument(); + const readOptions = new mx.XmlReadOptions(); + readOptions.readXIncludes = false; + expect(async () => await mx.readFromXmlFile(doc, includeTestPath + '/cycle.mtlx', readOptions)).to.not.throw; + }); + + it('Write to XML string', async () => + { + // Read all example documents and write them to an XML string + const searchPath = libraryPath + ';' + examplesPath; + for (let filename of exampleFilenames) + { + const doc = mx.createDocument(); + await mx.readFromXmlFile(doc, filename, searchPath); + + // Serialize to XML. + const writeOptions = new mx.XmlWriteOptions(); + writeOptions.writeXIncludeEnable = false; + const xmlString = mx.writeToXmlString(doc, writeOptions); + + // Verify that the serialized document is identical. + const writtenDoc = mx.createDocument(); + await mx.readFromXmlString(writtenDoc, xmlString); + expect(writtenDoc).to.eql(doc); + }; + }); + + it('Prepend include tag', () => + { + const doc = mx.createDocument(); + const includePath = "SomePath"; + const writeOptions = new mx.XmlWriteOptions(); + mx.prependXInclude(doc, includePath); + const xmlString = mx.writeToXmlString(doc, writeOptions); + expect(xmlString).to.include(includePath); + }); + + // Node only, because we cannot read from a downloaded file in the browser + it('Write XML to file', async () => + { + const filename = '_build/testFile.mtlx'; + const includeRegex = //g; + const doc = mx.createDocument(); + await mx.readFromXmlFile(doc, 'root.mtlx', includeTestPath); + + // Write using includes + mx.writeToXmlFile(doc, filename); + // Read written document and compare with the original + const doc2 = mx.createDocument(); + await mx.readFromXmlFile(doc2, filename, includeTestPath); + expect(doc2.equals(doc)); + // Read written file content and verify that includes are preserved + let fileString = getMtlxStrings([filename], '')[0]; + let matches = Array.from(fileString.matchAll(includeRegex)); + expect(matches.length).to.be.greaterThan(0); + + // Write inlining included content + const writeOptions = new mx.XmlWriteOptions(); + writeOptions.writeXIncludeEnable = false; + mx.writeToXmlFile(doc, filename, writeOptions); + // Read written document and compare with the original + const doc3 = mx.createDocument(); + await mx.readFromXmlFile(doc3, filename); + expect(doc3.equals(doc)); + expect(doc.getChild('paint_semigloss')).to.exist; + // Read written file content and verify that includes are inlined + fileString = getMtlxStrings([filename], '')[0]; + matches = Array.from(fileString.matchAll(includeRegex)); + expect(matches.length).to.equal(0); + }); +}); diff --git a/MaterialX/javascript/MaterialXView/example_materials.json b/MaterialX/javascript/MaterialXView/example_materials.json deleted file mode 100644 index 7f612d4..0000000 --- a/MaterialX/javascript/MaterialXView/example_materials.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "materials": [ - { - "name": "StandardSurface", - "path": "../../resources/Materials/Examples/StandardSurface", - "baseURL": "Materials/Examples/StandardSurface" - }, - { - "name": "UsdPreviewSurface", - "path": "../../resources/Materials/Examples/UsdPreviewSurface", - "baseURL": "Materials/Examples/UsdPreviewSurface" - }, - { - "name": "GltfPbr", - "path": "../../resources/Materials/Examples/GltfPbr", - "baseURL": "Materials/Examples/GltfPbr" - }, - { - "name": "OpenPbr", - "path": "../../resources/Materials/Examples/OpenPbr", - "baseURL": "Materials/Examples/OpenPbr" - } - ] -} diff --git a/MaterialX/javascript/MaterialXView/index.ejs b/MaterialX/javascript/MaterialXView/index.ejs old mode 100644 new mode 100755 index 8f27805..abc1420 --- a/MaterialX/javascript/MaterialXView/index.ejs +++ b/MaterialX/javascript/MaterialXView/index.ejs @@ -1,57 +1,57 @@ - - - - - - MaterialX Web Viewer - - - - -

-
- - -
-
- - -
- -
- - - + + + + + + MaterialX Web Viewer + + + + +
+
+ + +
+
+ + +
+ +
+ + + diff --git a/MaterialX/javascript/MaterialXView/package-lock.json b/MaterialX/javascript/MaterialXView/package-lock.json old mode 100644 new mode 100755 index d21f588..2015cb6 --- a/MaterialX/javascript/MaterialXView/package-lock.json +++ b/MaterialX/javascript/MaterialXView/package-lock.json @@ -1,4509 +1,4508 @@ -{ - "name": "MaterialXView", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "MaterialXView", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "lil-gui": "^0.19.2", - "three": "^0.152.2", - "webpack": "^5.103.0" - }, - "devDependencies": { - "copy-webpack-plugin": "^12.0.2", - "html-webpack-plugin": "^5.6.5", - "webpack-cli": "^6.0.1", - "webpack-dev-server": "^5.2.2" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", - "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.17.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@jsonjoy.com/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/buffers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", - "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/codegen": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", - "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/json-pack": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", - "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/base64": "^1.1.2", - "@jsonjoy.com/buffers": "^1.2.0", - "@jsonjoy.com/codegen": "^1.0.0", - "@jsonjoy.com/json-pointer": "^1.0.2", - "@jsonjoy.com/util": "^1.9.0", - "hyperdyperid": "^1.2.0", - "thingies": "^2.5.0", - "tree-dump": "^1.1.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/json-pointer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", - "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/codegen": "^1.0.0", - "@jsonjoy.com/util": "^1.9.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@jsonjoy.com/util": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", - "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/buffers": "^1.0.0", - "@jsonjoy.com/codegen": "^1.0.0" - }, - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sindresorhus/merge-streams": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", - "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "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.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "license": "MIT" - }, - "node_modules/@types/express": { - "version": "4.17.25", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", - "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "^1" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", - "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/http-proxy": { - "version": "1.17.17", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", - "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "license": "MIT" - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "24.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", - "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, - "node_modules/@types/node-forge": { - "version": "1.3.14", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", - "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/retry": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", - "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", - "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "<1" - } - }, - "node_modules/@types/serve-static/node_modules/@types/send": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", - "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "license": "MIT", - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "license": "Apache-2.0", - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "license": "MIT" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", - "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", - "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", - "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "webpack": "^5.82.0", - "webpack-cli": "6.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "license": "BSD-3-Clause" - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "license": "Apache-2.0" - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", - "license": "MIT", - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "acorn": "^8.14.0" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "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" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "license": "Apache-2.0", - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.29.tgz", - "integrity": "sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==", - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true, - "license": "MIT" - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/body-parser": { - "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": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/bonjour-service": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", - "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, - "license": "ISC" - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", - "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.8.25", - "caniuse-lite": "^1.0.30001754", - "electron-to-chromium": "^1.5.249", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.1.4" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, - "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "run-applescript": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001755", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001755.tgz", - "integrity": "sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "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" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "license": "MIT", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/clean-css": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", - "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 10.0" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/copy-webpack-plugin": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz", - "integrity": "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.1", - "globby": "^14.0.0", - "normalize-path": "^3.0.0", - "schema-utils": "^4.2.0", - "serialize-javascript": "^6.0.2" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/default-browser": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", - "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", - "dev": true, - "license": "MIT", - "dependencies": { - "bundle-name": "^4.1.0", - "default-browser-id": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", - "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "license": "MIT" - }, - "node_modules/dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "license": "MIT", - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.256", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.256.tgz", - "integrity": "sha512-uqYq1IQhpXXLX+HgiXdyOZml7spy4xfy42yPxcCCRjswp0fYM2X+JwCON07lqnpLEGVCj739B7Yr+FngmHBMEQ==", - "license": "ISC" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "license": "BSD-2-Clause", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/envinfo": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.20.0.tgz", - "integrity": "sha512-+zUomDcLXsVkQ37vUqWBvQwLaLlj8eZPSi61llaEFAVBY5mhcXdaSw1pSJVl4yTYD5g/gEfpNl28YYk4IPvrrg==", - "dev": true, - "license": "MIT", - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "license": "MIT" - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "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" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true, - "license": "MIT" - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "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": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob-to-regex.js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", - "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "license": "BSD-2-Clause" - }, - "node_modules/globby": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", - "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/merge-streams": "^2.1.0", - "fast-glob": "^3.3.3", - "ignore": "^7.0.3", - "path-type": "^6.0.0", - "slash": "^5.1.0", - "unicorn-magic": "^0.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true, - "license": "MIT" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-webpack-plugin": { - "version": "5.6.5", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.5.tgz", - "integrity": "sha512-4xynFbKNNk+WlzXeQQ+6YYsH2g7mpfPszQZUi3ovKlj+pDmngQ7vRXjrrmGROabmKwyQkcgcX5hqfOwHbFmK5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.20.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-middleware": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", - "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } - }, - "node_modules/hyperdyperid": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", - "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.18" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-local": { - "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": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-network-error": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.0.tgz", - "integrity": "sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/launch-editor": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.12.0.tgz", - "integrity": "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^1.1.1", - "shell-quote": "^1.8.3" - } - }, - "node_modules/lil-gui": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.19.2.tgz", - "integrity": "sha512-nU8j4ND702ouGfQZoaTN4dfXxacvGOAVK0DtmZBVcUYUAeYQXLQAjAN50igMHiba3T5jZyKEjXZU+Ntm1Qs6ZQ==", - "license": "MIT" - }, - "node_modules/loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", - "license": "MIT", - "engines": { - "node": ">=6.11.5" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true, - "license": "MIT" - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.51.0.tgz", - "integrity": "sha512-4zngfkVM/GpIhC8YazOsM6E8hoB33NP0BCESPOA6z7qaL6umPJNqkO8CNYaLV2FB2MV6H1O3x2luHHOSqppv+A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jsonjoy.com/json-pack": "^1.11.0", - "@jsonjoy.com/util": "^1.9.0", - "glob-to-regex.js": "^1.0.1", - "thingies": "^2.5.0", - "tree-dump": "^1.0.3", - "tslib": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - } - }, - "node_modules/merge-descriptors": { - "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", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "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": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC" - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dev": true, - "license": "MIT", - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "license": "MIT" - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "license": "MIT" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT" - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/open": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", - "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "default-browser": "^5.2.1", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "wsl-utils": "^0.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-retry": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", - "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/retry": "0.12.2", - "is-network-error": "^1.0.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "license": "MIT", - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-type": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", - "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "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.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve": "^1.20.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-applescript": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", - "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true, - "license": "MIT" - }, - "node_modules/selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "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": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "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", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC" - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-static": { - "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": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/slash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/spdy-transport/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/spdy-transport/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/spdy/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/spdy/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/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/terser": { - "version": "5.44.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz", - "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.14", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", - "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", - "terser": "^5.31.1" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, - "node_modules/thingies": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", - "integrity": "sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "^2" - } - }, - "node_modules/three": { - "version": "0.152.2", - "resolved": "https://registry.npmjs.org/three/-/three-0.152.2.tgz", - "integrity": "sha512-Ff9zIpSfkkqcBcpdiFo2f35vA9ZucO+N8TNacJOqaEE6DrB0eufItVMib8bK8Pcju/ZNT6a7blE1GhTpkdsILw==", - "license": "MIT" - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true, - "license": "MIT" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tree-dump": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", - "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/streamich" - }, - "peerDependencies": { - "tslib": "2" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "license": "MIT" - }, - "node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", - "dev": true, - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/watchpack": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", - "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", - "license": "MIT", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/webpack": { - "version": "5.103.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz", - "integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==", - "license": "MIT", - "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.8", - "@types/json-schema": "^7.0.15", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", - "acorn-import-phases": "^1.0.3", - "browserslist": "^4.26.3", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.3", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.3.1", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^4.3.3", - "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.11", - "watchpack": "^2.4.4", - "webpack-sources": "^3.3.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-cli": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", - "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@discoveryjs/json-ext": "^0.6.1", - "@webpack-cli/configtest": "^3.0.1", - "@webpack-cli/info": "^3.0.1", - "@webpack-cli/serve": "^3.0.1", - "colorette": "^2.0.14", - "commander": "^12.1.0", - "cross-spawn": "^7.0.3", - "envinfo": "^7.14.0", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", - "webpack-merge": "^6.0.1" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.82.0" - }, - "peerDependenciesMeta": { - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/webpack-dev-middleware": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", - "integrity": "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^4.43.1", - "mime-types": "^3.0.1", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - } - } - }, - "node_modules/webpack-dev-middleware/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-middleware/node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-server": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz", - "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/bonjour": "^3.5.13", - "@types/connect-history-api-fallback": "^1.5.4", - "@types/express": "^4.17.21", - "@types/express-serve-static-core": "^4.17.21", - "@types/serve-index": "^1.9.4", - "@types/serve-static": "^1.15.5", - "@types/sockjs": "^0.3.36", - "@types/ws": "^8.5.10", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.2.1", - "chokidar": "^3.6.0", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "express": "^4.21.2", - "graceful-fs": "^4.2.6", - "http-proxy-middleware": "^2.0.9", - "ipaddr.js": "^2.1.0", - "launch-editor": "^2.6.1", - "open": "^10.0.3", - "p-retry": "^6.2.0", - "schema-utils": "^4.2.0", - "selfsigned": "^2.4.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^7.4.2", - "ws": "^8.18.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-merge": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", - "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", - "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/wsl-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", - "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-wsl": "^3.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} +{ + "name": "MaterialXView", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "MaterialXView", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "lil-gui": "^0.19.2", + "three": "^0.152.2", + "webpack": "^5.92.1" + }, + "devDependencies": { + "copy-webpack-plugin": "^8.1.1", + "html-webpack-plugin": "^5.6.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.15.2" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@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==", + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "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==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", + "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "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" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "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==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "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" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-webpack-plugin": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-8.1.1.tgz", + "integrity": "sha512-rYM2uzRxrLRpcyPqGceRBDpxxUV8vcDqIKxAUKfcnFpcrPxT5+XvhTxv7XLjo5AvEJFPdAE3zCogG2JVahqgSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "^3.2.5", + "glob-parent": "^5.1.1", + "globby": "^11.0.3", + "normalize-path": "^3.0.0", + "p-limit": "^3.1.0", + "schema-utils": "^3.0.0", + "serialize-javascript": "^5.0.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "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==", + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", + "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "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==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "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==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "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", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "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==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/lil-gui": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.19.2.tgz", + "integrity": "sha512-nU8j4ND702ouGfQZoaTN4dfXxacvGOAVK0DtmZBVcUYUAeYQXLQAjAN50igMHiba3T5jZyKEjXZU+Ntm1Qs6ZQ==", + "license": "MIT" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "license": "MIT", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "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==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true, + "license": "MIT" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/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/serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true, + "license": "ISC" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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==", + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/three": { + "version": "0.152.2", + "resolved": "https://registry.npmjs.org/three/-/three-0.152.2.tgz", + "integrity": "sha512-Ff9zIpSfkkqcBcpdiFo2f35vA9ZucO+N8TNacJOqaEE6DrB0eufItVMib8bK8Pcju/ZNT6a7blE1GhTpkdsILw==", + "license": "MIT" + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webpack": { + "version": "5.92.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", + "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "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", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/MaterialX/javascript/MaterialXView/package.json b/MaterialX/javascript/MaterialXView/package.json old mode 100644 new mode 100755 index 76dc5f5..a9f425c --- a/MaterialX/javascript/MaterialXView/package.json +++ b/MaterialX/javascript/MaterialXView/package.json @@ -1,23 +1,23 @@ -{ - "name": "MaterialXView", - "version": "1.0.0", - "description": "MaterialX Web Viewer", - "main": "source/index.js", - "scripts": { - "start": "webpack serve", - "build": "webpack" - }, - "author": "", - "license": "ISC", - "dependencies": { - "lil-gui": "^0.19.2", - "three": "^0.152.2", - "webpack": "^5.103.0" - }, - "devDependencies": { - "copy-webpack-plugin": "^12.0.2", - "html-webpack-plugin": "^5.6.5", - "webpack-cli": "^6.0.1", - "webpack-dev-server": "^5.2.2" - } -} +{ + "name": "MaterialXView", + "version": "1.0.0", + "description": "MaterialX Web Viewer", + "main": "source/index.js", + "scripts": { + "start": "webpack serve", + "build": "webpack" + }, + "author": "", + "license": "ISC", + "dependencies": { + "lil-gui": "^0.19.2", + "three": "^0.152.2", + "webpack": "^5.92.1" + }, + "devDependencies": { + "copy-webpack-plugin": "^8.1.1", + "html-webpack-plugin": "^5.6.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.15.2" + } +} diff --git a/MaterialX/javascript/MaterialXView/public/favicon.ico b/MaterialX/javascript/MaterialXView/public/favicon.ico old mode 100644 new mode 100755 diff --git a/MaterialX/javascript/MaterialXView/public/shader_ball.svg b/MaterialX/javascript/MaterialXView/public/shader_ball.svg old mode 100644 new mode 100755 index 2b51705..17ff924 --- a/MaterialX/javascript/MaterialXView/public/shader_ball.svg +++ b/MaterialX/javascript/MaterialXView/public/shader_ball.svg @@ -1,5 +1,5 @@ - - - - - + + + + + diff --git a/MaterialX/javascript/MaterialXView/public/shader_ball2.svg b/MaterialX/javascript/MaterialXView/public/shader_ball2.svg old mode 100644 new mode 100755 index 62907b5..b8f570c --- a/MaterialX/javascript/MaterialXView/public/shader_ball2.svg +++ b/MaterialX/javascript/MaterialXView/public/shader_ball2.svg @@ -1,8 +1,8 @@ - - - - - - - - + + + + + + + + diff --git a/MaterialX/javascript/MaterialXView/source/dropHandling.js b/MaterialX/javascript/MaterialXView/source/dropHandling.js old mode 100644 new mode 100755 index f54b771..3b4d71a --- a/MaterialX/javascript/MaterialXView/source/dropHandling.js +++ b/MaterialX/javascript/MaterialXView/source/dropHandling.js @@ -1,375 +1,375 @@ -import * as THREE from 'three'; -import * as fflate from 'three/examples/jsm/libs/fflate.module.js'; - -const debugFileHandling = false; -let loadingCallback = null; -let sceneLoadingCallback = null; - -export function setLoadingCallback(cb) -{ - loadingCallback = cb; -} - -export function setSceneLoadingCallback(cb) -{ - sceneLoadingCallback = cb; -} - -export function dropHandler(ev) -{ - if (debugFileHandling) console.log('File(s) dropped', ev.dataTransfer.items, ev.dataTransfer.files); - - // Prevent default behavior (Prevent file from being opened) - ev.preventDefault(); - - if (ev.dataTransfer.items) - { - const allEntries = []; - - let haveGetAsEntry = false; - if (ev.dataTransfer.items.length > 0) - haveGetAsEntry = - ("getAsEntry" in ev.dataTransfer.items[0]) || - ("webkitGetAsEntry" in ev.dataTransfer.items[0]); - - // Useful for debugging file handling on platforms that don't support newer file system APIs - // haveGetAsEntry = false; - - if (haveGetAsEntry) - { - for (var i = 0; i < ev.dataTransfer.items.length; i++) - { - let item = ev.dataTransfer.items[i]; - let entry = ("getAsEntry" in item) ? item.getAsEntry() : item.webkitGetAsEntry(); - allEntries.push(entry); - } - handleFilesystemEntries(allEntries); - return; - } - - for (var i = 0; i < ev.dataTransfer.items.length; i++) - { - let item = ev.dataTransfer.items[i]; - - // API when there's no "getAsEntry" support - console.log(item.kind, item); - if (item.kind === 'file') - { - var file = item.getAsFile(); - testAndLoadFile(file); - } - // could also be a directory - else if (item.kind === 'directory') - { - var dirReader = item.createReader(); - dirReader.readEntries(function (entries) - { - for (var i = 0; i < entries.length; i++) - { - console.log(entries[i].name); - var entry = entries[i]; - if (entry.isFile) - { - entry.file(function (file) - { - testAndLoadFile(file); - }); - } - } - }); - } - } - } else - { - for (var i = 0; i < ev.dataTransfer.files.length; i++) - { - let file = ev.dataTransfer.files[i]; - testAndLoadFile(file); - } - } -} - -export function dragOverHandler(ev) -{ - ev.preventDefault(); -} - -async function getBufferFromFile(fileEntry) -{ - - if (fileEntry instanceof ArrayBuffer) return fileEntry; - if (fileEntry instanceof String) return fileEntry; - - const name = fileEntry.fullPath || fileEntry.name; - const ext = name.split('.').pop(); - const readAsText = ext === 'mtlx'; - - if (debugFileHandling) console.log("reading ", fileEntry, "as text?", readAsText); - - if (debugFileHandling) console.log("getBufferFromFile", fileEntry); - const buffer = await new Promise((resolve, reject) => - { - function readFile(file) - { - var reader = new FileReader(); - reader.onloadend = function (e) - { - if (debugFileHandling) console.log("loaded", "should be text?", readAsText, this.result); - resolve(this.result); - }; - - if (readAsText) - reader.readAsText(file); - else - reader.readAsArrayBuffer(file); - } - - if ("file" in fileEntry) - { - fileEntry.file(function (file) - { - readFile(file); - }, (e) => - { - console.error("Error reading file ", e); - }); - } - else - { - readFile(fileEntry); - } - }); - return buffer; -} - -async function handleFilesystemEntries(entries) -{ - const allFiles = []; - const fileIgnoreList = [ - '.gitignore', - 'README.md', - '.DS_Store', - ] - const dirIgnoreList = [ - '.git', - 'node_modules', - ] - - let isGLB = false; - let haveMtlx = false; - for (let entry of entries) - { - if (debugFileHandling) console.log("file entry", entry) - if (entry.isFile) - { - if (debugFileHandling) - console.log("single file", entry); - if (fileIgnoreList.includes(entry.name)) - { - continue; - } - allFiles.push(entry); - - if (entry.name.endsWith('glb')) - { - isGLB = true; - break; - } - } - else if (entry.isDirectory) - { - if (dirIgnoreList.includes(entry.name)) - { - continue; - } - const files = await readDirectory(entry); - if (debugFileHandling) console.log("all files", files); - for (const file of files) - { - if (fileIgnoreList.includes(file.name)) - { - continue; - } - allFiles.push(file); - } - } - } - - const imageLoader = new THREE.ImageLoader(); - - // unpack zip files first - for (const fileEntry of allFiles) - { - // special case: zip archives - if (fileEntry.fullPath.toLowerCase().endsWith('.zip')) - { - await new Promise(async (resolve, reject) => - { - const arrayBuffer = await getBufferFromFile(fileEntry); - - // use fflate to unpack them and add the files to the cache - fflate.unzip(new Uint8Array(arrayBuffer), (error, unzipped) => - { - // push these files into allFiles - for (const [filePath, buffer] of Object.entries(unzipped)) - { - - // mock FileEntry for easier usage downstream - const blob = new Blob([buffer]); - const newFileEntry = { - fullPath: "/" + filePath, - name: filePath.split('/').pop(), - file: (callback) => - { - callback(blob); - }, - isFile: true, - }; - allFiles.push(newFileEntry); - } - - resolve(); - }); - }); - } - } - - // sort so mtlx files come first - allFiles.sort((a, b) => - { - if (a.name.endsWith('.mtlx') && !b.name.endsWith('.mtlx')) - { - return -1; - } - if (!a.name.endsWith('.mtlx') && b.name.endsWith('.mtlx')) - { - return 1; - } - return 0; - }); - - if (isGLB) - { - console.log("Load GLB file", allFiles[0]); - - const rootFile = allFiles[0]; - THREE.Cache.add(rootFile.fullPath, await getBufferFromFile(rootFile)); - - if (debugFileHandling) console.log("CACHE", THREE.Cache.files); - - sceneLoadingCallback(rootFile); - return; - } - - if (!allFiles[0].name.endsWith('mtlx')) - { - console.log("No MaterialX files dropped. Skipping content."); - return; - } - - if (debugFileHandling) - { - console.log("- All files", allFiles); - } - - // put all files in three' Cache - for (const fileEntry of allFiles) - { - - const allowedFileTypes = [ - 'png', 'jpg', 'jpeg' - ]; - - const ext = fileEntry.fullPath.split('.').pop(); - if (!allowedFileTypes.includes(ext)) - { - // console.log("skipping file", fileEntry.fullPath); - continue; - } - - const buffer = await getBufferFromFile(fileEntry); - const img = await imageLoader.loadAsync(URL.createObjectURL(new Blob([buffer]))); - if (debugFileHandling) console.log("caching file", fileEntry.fullPath, img); - THREE.Cache.add(fileEntry.fullPath, img); - } - - // TODO we could also allow dropping of multiple MaterialX files (or folders with them inside) - // and seed the dropdown from that. - // At that point, actually reading files and textures into memory should be deferred until they are actually used. - if (allFiles.length > 0) - { - const rootFile = allFiles[0]; - THREE.Cache.add(rootFile.fullPath, await getBufferFromFile(rootFile)); - - if (debugFileHandling) console.log("CACHE", THREE.Cache.files); - - loadingCallback(rootFile); - } - else - { - console.log('No files to add cache.') - } -} - -async function readDirectory(directory) -{ - let entries = []; - let getEntries = async (directory) => - { - let dirReader = directory.createReader(); - await new Promise((resolve, reject) => - { - dirReader.readEntries( - async (results) => - { - if (results.length) - { - // entries = entries.concat(results); - for (let entry of results) - { - if (entry.isDirectory) - { - await getEntries(entry); - } - else - { - entries.push(entry); - } - } - } - resolve(); - }, - (error) => - { - /* handle error — error is a FileError object */ - }, - ) - } - ) - }; - - await getEntries(directory); - return entries; -} - -async function testAndLoadFile(file) -{ - let ext = file.name.split('.').pop(); - if (debugFileHandling) console.log(file.name + ", " + file.size + ", " + ext); - - const arrayBuffer = await getBufferFromFile(file); - console.log(arrayBuffer) - - // mock a fileEntry and pass through the same loading logic - const newFileEntry = { - fullPath: "/" + file.name, - name: file.name.split('/').pop(), - isFile: true, - file: (callback) => - { - callback(file); - } - }; - - handleFilesystemEntries([newFileEntry]); +import * as THREE from 'three'; +import * as fflate from 'three/examples/jsm/libs/fflate.module.js'; + +const debugFileHandling = false; +let loadingCallback = null; +let sceneLoadingCallback = null; + +export function setLoadingCallback(cb) +{ + loadingCallback = cb; +} + +export function setSceneLoadingCallback(cb) +{ + sceneLoadingCallback = cb; +} + +export function dropHandler(ev) +{ + if (debugFileHandling) console.log('File(s) dropped', ev.dataTransfer.items, ev.dataTransfer.files); + + // Prevent default behavior (Prevent file from being opened) + ev.preventDefault(); + + if (ev.dataTransfer.items) + { + const allEntries = []; + + let haveGetAsEntry = false; + if (ev.dataTransfer.items.length > 0) + haveGetAsEntry = + ("getAsEntry" in ev.dataTransfer.items[0]) || + ("webkitGetAsEntry" in ev.dataTransfer.items[0]); + + // Useful for debugging file handling on platforms that don't support newer file system APIs + // haveGetAsEntry = false; + + if (haveGetAsEntry) + { + for (var i = 0; i < ev.dataTransfer.items.length; i++) + { + let item = ev.dataTransfer.items[i]; + let entry = ("getAsEntry" in item) ? item.getAsEntry() : item.webkitGetAsEntry(); + allEntries.push(entry); + } + handleFilesystemEntries(allEntries); + return; + } + + for (var i = 0; i < ev.dataTransfer.items.length; i++) + { + let item = ev.dataTransfer.items[i]; + + // API when there's no "getAsEntry" support + console.log(item.kind, item); + if (item.kind === 'file') + { + var file = item.getAsFile(); + testAndLoadFile(file); + } + // could also be a directory + else if (item.kind === 'directory') + { + var dirReader = item.createReader(); + dirReader.readEntries(function (entries) + { + for (var i = 0; i < entries.length; i++) + { + console.log(entries[i].name); + var entry = entries[i]; + if (entry.isFile) + { + entry.file(function (file) + { + testAndLoadFile(file); + }); + } + } + }); + } + } + } else + { + for (var i = 0; i < ev.dataTransfer.files.length; i++) + { + let file = ev.dataTransfer.files[i]; + testAndLoadFile(file); + } + } +} + +export function dragOverHandler(ev) +{ + ev.preventDefault(); +} + +async function getBufferFromFile(fileEntry) +{ + + if (fileEntry instanceof ArrayBuffer) return fileEntry; + if (fileEntry instanceof String) return fileEntry; + + const name = fileEntry.fullPath || fileEntry.name; + const ext = name.split('.').pop(); + const readAsText = ext === 'mtlx'; + + if (debugFileHandling) console.log("reading ", fileEntry, "as text?", readAsText); + + if (debugFileHandling) console.log("getBufferFromFile", fileEntry); + const buffer = await new Promise((resolve, reject) => + { + function readFile(file) + { + var reader = new FileReader(); + reader.onloadend = function (e) + { + if (debugFileHandling) console.log("loaded", "should be text?", readAsText, this.result); + resolve(this.result); + }; + + if (readAsText) + reader.readAsText(file); + else + reader.readAsArrayBuffer(file); + } + + if ("file" in fileEntry) + { + fileEntry.file(function (file) + { + readFile(file); + }, (e) => + { + console.error("Error reading file ", e); + }); + } + else + { + readFile(fileEntry); + } + }); + return buffer; +} + +async function handleFilesystemEntries(entries) +{ + const allFiles = []; + const fileIgnoreList = [ + '.gitignore', + 'README.md', + '.DS_Store', + ] + const dirIgnoreList = [ + '.git', + 'node_modules', + ] + + let isGLB = false; + let haveMtlx = false; + for (let entry of entries) + { + if (debugFileHandling) console.log("file entry", entry) + if (entry.isFile) + { + if (debugFileHandling) + console.log("single file", entry); + if (fileIgnoreList.includes(entry.name)) + { + continue; + } + allFiles.push(entry); + + if (entry.name.endsWith('glb')) + { + isGLB = true; + break; + } + } + else if (entry.isDirectory) + { + if (dirIgnoreList.includes(entry.name)) + { + continue; + } + const files = await readDirectory(entry); + if (debugFileHandling) console.log("all files", files); + for (const file of files) + { + if (fileIgnoreList.includes(file.name)) + { + continue; + } + allFiles.push(file); + } + } + } + + const imageLoader = new THREE.ImageLoader(); + + // unpack zip files first + for (const fileEntry of allFiles) + { + // special case: zip archives + if (fileEntry.fullPath.toLowerCase().endsWith('.zip')) + { + await new Promise(async (resolve, reject) => + { + const arrayBuffer = await getBufferFromFile(fileEntry); + + // use fflate to unpack them and add the files to the cache + fflate.unzip(new Uint8Array(arrayBuffer), (error, unzipped) => + { + // push these files into allFiles + for (const [filePath, buffer] of Object.entries(unzipped)) + { + + // mock FileEntry for easier usage downstream + const blob = new Blob([buffer]); + const newFileEntry = { + fullPath: "/" + filePath, + name: filePath.split('/').pop(), + file: (callback) => + { + callback(blob); + }, + isFile: true, + }; + allFiles.push(newFileEntry); + } + + resolve(); + }); + }); + } + } + + // sort so mtlx files come first + allFiles.sort((a, b) => + { + if (a.name.endsWith('.mtlx') && !b.name.endsWith('.mtlx')) + { + return -1; + } + if (!a.name.endsWith('.mtlx') && b.name.endsWith('.mtlx')) + { + return 1; + } + return 0; + }); + + if (isGLB) + { + console.log("Load GLB file", allFiles[0]); + + const rootFile = allFiles[0]; + THREE.Cache.add(rootFile.fullPath, await getBufferFromFile(rootFile)); + + if (debugFileHandling) console.log("CACHE", THREE.Cache.files); + + sceneLoadingCallback(rootFile); + return; + } + + if (!allFiles[0].name.endsWith('mtlx')) + { + console.log("No MaterialX files dropped. Skipping content."); + return; + } + + if (debugFileHandling) + { + console.log("- All files", allFiles); + } + + // put all files in three' Cache + for (const fileEntry of allFiles) + { + + const allowedFileTypes = [ + 'png', 'jpg', 'jpeg' + ]; + + const ext = fileEntry.fullPath.split('.').pop(); + if (!allowedFileTypes.includes(ext)) + { + // console.log("skipping file", fileEntry.fullPath); + continue; + } + + const buffer = await getBufferFromFile(fileEntry); + const img = await imageLoader.loadAsync(URL.createObjectURL(new Blob([buffer]))); + if (debugFileHandling) console.log("caching file", fileEntry.fullPath, img); + THREE.Cache.add(fileEntry.fullPath, img); + } + + // TODO we could also allow dropping of multiple MaterialX files (or folders with them inside) + // and seed the dropdown from that. + // At that point, actually reading files and textures into memory should be deferred until they are actually used. + if (allFiles.length > 0) + { + const rootFile = allFiles[0]; + THREE.Cache.add(rootFile.fullPath, await getBufferFromFile(rootFile)); + + if (debugFileHandling) console.log("CACHE", THREE.Cache.files); + + loadingCallback(rootFile); + } + else + { + console.log('No files to add cache.') + } +} + +async function readDirectory(directory) +{ + let entries = []; + let getEntries = async (directory) => + { + let dirReader = directory.createReader(); + await new Promise((resolve, reject) => + { + dirReader.readEntries( + async (results) => + { + if (results.length) + { + // entries = entries.concat(results); + for (let entry of results) + { + if (entry.isDirectory) + { + await getEntries(entry); + } + else + { + entries.push(entry); + } + } + } + resolve(); + }, + (error) => + { + /* handle error — error is a FileError object */ + }, + ) + } + ) + }; + + await getEntries(directory); + return entries; +} + +async function testAndLoadFile(file) +{ + let ext = file.name.split('.').pop(); + if (debugFileHandling) console.log(file.name + ", " + file.size + ", " + ext); + + const arrayBuffer = await getBufferFromFile(file); + console.log(arrayBuffer) + + // mock a fileEntry and pass through the same loading logic + const newFileEntry = { + fullPath: "/" + file.name, + name: file.name.split('/').pop(), + isFile: true, + file: (callback) => + { + callback(file); + } + }; + + handleFilesystemEntries([newFileEntry]); } \ No newline at end of file diff --git a/MaterialX/javascript/MaterialXView/source/helper.js b/MaterialX/javascript/MaterialXView/source/helper.js old mode 100644 new mode 100755 index 3f3be46..870133f --- a/MaterialX/javascript/MaterialXView/source/helper.js +++ b/MaterialX/javascript/MaterialXView/source/helper.js @@ -1,352 +1,307 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -import * as THREE from 'three'; - -const IMAGE_PROPERTY_SEPARATOR = "_"; -const UADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + "uaddressmode"; -const VADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + "vaddressmode"; -const FILTER_TYPE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + "filtertype"; -const IMAGE_PATH_SEPARATOR = "/"; - -/** - * Initialized the environment texture as MaterialX expects it - * @param {THREE.Texture} texture - * @param {Object} capabilities - * @returns {THREE.Texture} - */ -export function prepareEnvTexture(texture, capabilities) -{ - let newTexture = new THREE.DataTexture(texture.image.data, texture.image.width, texture.image.height, texture.format, texture.type); - newTexture.wrapS = THREE.RepeatWrapping; - newTexture.anisotropy = capabilities.getMaxAnisotropy(); - newTexture.minFilter = THREE.LinearMipmapLinearFilter; - newTexture.magFilter = THREE.LinearFilter; - newTexture.generateMipmaps = true; - newTexture.needsUpdate = true; - - return newTexture; -} - -/** - * Get Three uniform from MaterialX vector - * @param {any} value - * @param {any} dimension - * @returns {THREE.Uniform} - */ -function fromVector(value, dimension) -{ - let outValue; - if (value) - { - outValue = value.data(); - } - else - { - outValue = []; - for (let i = 0; i < dimension; ++i) - outValue.push(0.0); - } - - return outValue; -} - -/** - * Get Three uniform from MaterialX matrix - * @param {mx.matrix} matrix - * @param {mx.matrix.size} dimension - */ -function fromMatrix(matrix, dimension) -{ - let vec = []; - if (matrix) - { - for (let i = 0; i < matrix.numRows(); ++i) - { - for (let k = 0; k < matrix.numColumns(); ++k) - { - vec.push(matrix.getItem(i, k)); - } - } - } else - { - for (let i = 0; i < dimension; ++i) - vec.push(0.0); - } - - return vec; -} - -/** - * Get Three uniform from MaterialX value - * @param {mx.Uniform.type} type - * @param {mx.Uniform.value} value - * @param {mx.Uniform.name} name - * @param {mx.Uniforms} uniforms - * @param {THREE.textureLoader} textureLoader - */ -function toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, flipY) -{ - let outValue = null; - switch (type) - { - case 'float': - case 'integer': - case 'boolean': - outValue = value; - break; - case 'vector2': - outValue = fromVector(value, 2); - break; - case 'vector3': - case 'color3': - outValue = fromVector(value, 3); - break; - case 'vector4': - case 'color4': - outValue = fromVector(value, 4); - break; - case 'matrix33': - outValue = fromMatrix(value, 9); - break; - case 'matrix44': - outValue = fromMatrix(value, 16); - break; - case 'filename': - if (value) - { - // 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': - break; - default: - console.log('Value type not supported: ' + type); - outValue = null; - } - - return outValue; -} - -/** - * Get Three wrapping mode - * @param {mx.TextureFilter.wrap} mode - * @returns {THREE.Wrapping} - */ -function getWrapping(mode) -{ - let wrap; - switch (mode) - { - case 1: - wrap = THREE.ClampToEdgeWrapping; - break; - case 2: - wrap = THREE.RepeatWrapping; - break; - case 3: - wrap = THREE.MirroredRepeatWrapping; - break; - default: - wrap = THREE.RepeatWrapping; - break; - } - return wrap; -} - -/** - * Get Three minification filter - * @param {mx.TextureFilter.minFilter} type - * @param {mx.TextureFilter.generateMipmaps} generateMipmaps - */ -function getMinFilter(type, generateMipmaps) -{ - const filterType = generateMipmaps ? THREE.LinearMipMapLinearFilter : THREE.LinearFilter; - if (type === 0) - { - filterType = generateMipmaps ? THREE.NearestMipMapNearestFilter : THREE.NearestFilter; - } - return filterType; -} - -/** - * Set Three texture parameters - * @param {THREE.Texture} texture - * @param {mx.Uniform.name} name - * @param {mx.Uniforms} uniforms - * @param {mx.TextureFilter.generateMipmaps} generateMipmaps - */ -function setTextureParameters(texture, name, uniforms, flipY = true, generateMipmaps = true) -{ - const idx = name.lastIndexOf(IMAGE_PROPERTY_SEPARATOR); - const base = name.substring(0, idx) || name; - - texture.generateMipmaps = generateMipmaps; - texture.wrapS = THREE.RepeatWrapping; - texture.wrapT = THREE.RepeatWrapping; - texture.magFilter = THREE.LinearFilter; - texture.flipY = flipY; - - if (uniforms.find(base + UADDRESS_MODE_SUFFIX)) - { - const uaddressmode = uniforms.find(base + UADDRESS_MODE_SUFFIX).getValue().getData(); - texture.wrapS = getWrapping(uaddressmode); - } - - if (uniforms.find(base + VADDRESS_MODE_SUFFIX)) - { - const vaddressmode = uniforms.find(base + VADDRESS_MODE_SUFFIX).getValue().getData(); - texture.wrapT = getWrapping(vaddressmode); - } - - const filterType = uniforms.find(base + FILTER_TYPE_SUFFIX) ? uniforms.get(base + FILTER_TYPE_SUFFIX).value : -1; - texture.minFilter = getMinFilter(filterType, generateMipmaps); -} - -/** - * Return the global light rotation matrix - */ -export function getLightRotation() -{ - return new THREE.Matrix4().makeRotationY(Math.PI / 2); -} - -/** - * Returns all lights nodes in a MaterialX document - * @param {mx.Document} doc - * @returns {Array.} - */ -export function findLights(doc) -{ - let lights = []; - for (let node of doc.getNodes()) - { - if (node.getType() === "lightshader") - lights.push(node); - } - return lights; -} - -/** - * Register lights in shader generation context - * @param {Object} mx MaterialX Module - * @param {Array.} lights Light nodes - * @param {mx.GenContext} genContext Shader generation context - * @returns {Array.} - */ -export function registerLights(mx, lights, genContext) -{ - mx.HwShaderGenerator.unbindLightShaders(genContext); - - const lightTypesBound = {}; - const lightData = []; - let lightId = 1; - for (let light of lights) - { - let nodeDef = light.getNodeDef(); - let nodeName = nodeDef.getName(); - if (!lightTypesBound[nodeName]) - { - lightTypesBound[nodeName] = lightId; - mx.HwShaderGenerator.bindLightShader(nodeDef, lightId++, genContext); - } - - const lightDirection = light.getValueElement("direction").getValue().getData().data(); - const lightColor = light.getValueElement("color").getValue().getData().data(); - const lightIntensity = light.getValueElement("intensity").getValue().getData(); - - let rotatedLightDirection = new THREE.Vector3(...lightDirection) - rotatedLightDirection.transformDirection(getLightRotation()) - - lightData.push({ - type: lightTypesBound[nodeName], - direction: rotatedLightDirection, - color: new THREE.Vector3(...lightColor), - intensity: lightIntensity - }); - } - - // Make sure max light count is large enough - genContext.getOptions().hwMaxActiveLightSources = Math.max(genContext.getOptions().hwMaxActiveLightSources, lights.length); - - return lightData; -} - -/** - * Get uniform values for a shader - * @param {mx.shaderStage} shaderStage - * @param {THREE.TextureLoader} textureLoader - */ -export function getUniformValues(shaderStage, textureLoader, searchPath, flipY) -{ - let threeUniforms = {}; - - const uniformBlocks = Object.values(shaderStage.getUniformBlocks()); - uniformBlocks.forEach(uniforms => - { - if (!uniforms.empty()) - { - for (let i = 0; i < uniforms.size(); ++i) - { - const variable = uniforms.get(i); - const value = variable.getValue()?.getData(); - const name = variable.getVariable(); - threeUniforms[name] = new THREE.Uniform(toThreeUniform(variable.getType().getName(), value, name, uniforms, - textureLoader, searchPath, flipY)); - } - } - }); - - return threeUniforms; -} +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +import * as THREE from 'three'; + +const IMAGE_PROPERTY_SEPARATOR = "_"; +const UADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + "uaddressmode"; +const VADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + "vaddressmode"; +const FILTER_TYPE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + "filtertype"; +const IMAGE_PATH_SEPARATOR = "/"; + +/** + * Initialized the environment texture as MaterialX expects it + * @param {THREE.Texture} texture + * @param {Object} capabilities + * @returns {THREE.Texture} + */ +export function prepareEnvTexture(texture, capabilities) +{ + let newTexture = new THREE.DataTexture(texture.image.data, texture.image.width, texture.image.height, texture.format, texture.type); + newTexture.wrapS = THREE.RepeatWrapping; + newTexture.anisotropy = capabilities.getMaxAnisotropy(); + newTexture.minFilter = THREE.LinearMipmapLinearFilter; + newTexture.magFilter = THREE.LinearFilter; + newTexture.generateMipmaps = true; + newTexture.needsUpdate = true; + + return newTexture; +} + +/** + * Get Three uniform from MaterialX vector + * @param {any} value + * @param {any} dimension + * @returns {THREE.Uniform} + */ +function fromVector(value, dimension) +{ + let outValue; + if (value) + { + outValue = value.data(); + } + else + { + outValue = []; + for (let i = 0; i < dimension; ++i) + outValue.push(0.0); + } + + return outValue; +} + +/** + * Get Three uniform from MaterialX matrix + * @param {mx.matrix} matrix + * @param {mx.matrix.size} dimension + */ +function fromMatrix(matrix, dimension) +{ + let vec = []; + if (matrix) + { + for (let i = 0; i < matrix.numRows(); ++i) + { + for (let k = 0; k < matrix.numColumns(); ++k) + { + vec.push(matrix.getItem(i, k)); + } + } + } else + { + for (let i = 0; i < dimension; ++i) + vec.push(0.0); + } + + return vec; +} + +/** + * Get Three uniform from MaterialX value + * @param {mx.Uniform.type} type + * @param {mx.Uniform.value} value + * @param {mx.Uniform.name} name + * @param {mx.Uniforms} uniforms + * @param {THREE.textureLoader} textureLoader + */ +function toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, flipY) +{ + let outValue; + switch (type) + { + case 'float': + case 'integer': + case 'boolean': + outValue = value; + break; + case 'vector2': + outValue = fromVector(value, 2); + break; + case 'vector3': + case 'color3': + outValue = fromVector(value, 3); + break; + case 'vector4': + case 'color4': + outValue = fromVector(value, 4); + break; + case 'matrix33': + outValue = fromMatrix(value, 9); + break; + case 'matrix44': + outValue = fromMatrix(value, 16); + break; + 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; + } + break; + case 'samplerCube': + case 'string': + default: + break; + } + + return outValue; +} + +/** + * Get Three wrapping mode + * @param {mx.TextureFilter.wrap} mode + * @returns {THREE.Wrapping} + */ +function getWrapping(mode) +{ + let wrap; + switch (mode) + { + case 1: + wrap = THREE.ClampToEdgeWrapping; + break; + case 2: + wrap = THREE.RepeatWrapping; + break; + case 3: + wrap = THREE.MirroredRepeatWrapping; + break; + default: + wrap = THREE.RepeatWrapping; + break; + } + return wrap; +} + +/** + * Get Three minification filter + * @param {mx.TextureFilter.minFilter} type + * @param {mx.TextureFilter.generateMipmaps} generateMipmaps + */ +function getMinFilter(type, generateMipmaps) +{ + const filterType = generateMipmaps ? THREE.LinearMipMapLinearFilter : THREE.LinearFilter; + if (type === 0) + { + filterType = generateMipmaps ? THREE.NearestMipMapNearestFilter : THREE.NearestFilter; + } + return filterType; +} + +/** + * Set Three texture parameters + * @param {THREE.Texture} texture + * @param {mx.Uniform.name} name + * @param {mx.Uniforms} uniforms + * @param {mx.TextureFilter.generateMipmaps} generateMipmaps + */ +function setTextureParameters(texture, name, uniforms, flipY = true, generateMipmaps = true) +{ + const idx = name.lastIndexOf(IMAGE_PROPERTY_SEPARATOR); + const base = name.substring(0, idx) || name; + + texture.generateMipmaps = generateMipmaps; + texture.wrapS = THREE.RepeatWrapping; + texture.wrapT = THREE.RepeatWrapping; + texture.magFilter = THREE.LinearFilter; + texture.flipY = flipY; + + if (uniforms.find(base + UADDRESS_MODE_SUFFIX)) + { + const uaddressmode = uniforms.find(base + UADDRESS_MODE_SUFFIX).getValue().getData(); + texture.wrapS = getWrapping(uaddressmode); + } + + if (uniforms.find(base + VADDRESS_MODE_SUFFIX)) + { + const vaddressmode = uniforms.find(base + VADDRESS_MODE_SUFFIX).getValue().getData(); + texture.wrapT = getWrapping(vaddressmode); + } + + const filterType = uniforms.find(base + FILTER_TYPE_SUFFIX) ? uniforms.get(base + FILTER_TYPE_SUFFIX).value : -1; + texture.minFilter = getMinFilter(filterType, generateMipmaps); +} + +/** + * Return the global light rotation matrix + */ +export function getLightRotation() +{ + return new THREE.Matrix4().makeRotationY(Math.PI / 2); +} + +/** + * Returns all lights nodes in a MaterialX document + * @param {mx.Document} doc + * @returns {Array.} + */ +export function findLights(doc) +{ + let lights = []; + for (let node of doc.getNodes()) + { + if (node.getType() === "lightshader") + lights.push(node); + } + return lights; +} + +/** + * Register lights in shader generation context + * @param {Object} mx MaterialX Module + * @param {Array.} lights Light nodes + * @param {mx.GenContext} genContext Shader generation context + * @returns {Array.} + */ +export function registerLights(mx, lights, genContext) +{ + mx.HwShaderGenerator.unbindLightShaders(genContext); + + const lightTypesBound = {}; + const lightData = []; + let lightId = 1; + for (let light of lights) + { + let nodeDef = light.getNodeDef(); + let nodeName = nodeDef.getName(); + if (!lightTypesBound[nodeName]) + { + lightTypesBound[nodeName] = lightId; + mx.HwShaderGenerator.bindLightShader(nodeDef, lightId++, genContext); + } + + const lightDirection = light.getValueElement("direction").getValue().getData().data(); + const lightColor = light.getValueElement("color").getValue().getData().data(); + const lightIntensity = light.getValueElement("intensity").getValue().getData(); + + let rotatedLightDirection = new THREE.Vector3(...lightDirection) + rotatedLightDirection.transformDirection(getLightRotation()) + + lightData.push({ + type: lightTypesBound[nodeName], + direction: rotatedLightDirection, + color: new THREE.Vector3(...lightColor), + intensity: lightIntensity + }); + } + + // Make sure max light count is large enough + genContext.getOptions().hwMaxActiveLightSources = Math.max(genContext.getOptions().hwMaxActiveLightSources, lights.length); + + return lightData; +} + +/** + * Get uniform values for a shader + * @param {mx.shaderStage} shaderStage + * @param {THREE.TextureLoader} textureLoader + */ +export function getUniformValues(shaderStage, textureLoader, searchPath, flipY) +{ + let threeUniforms = {}; + + const uniformBlocks = Object.values(shaderStage.getUniformBlocks()); + uniformBlocks.forEach(uniforms => + { + if (!uniforms.empty()) + { + for (let i = 0; i < uniforms.size(); ++i) + { + const variable = uniforms.get(i); + const value = variable.getValue()?.getData(); + const name = variable.getVariable(); + threeUniforms[name] = new THREE.Uniform(toThreeUniform(variable.getType().getName(), value, name, uniforms, + textureLoader, searchPath, flipY)); + } + } + }); + + return threeUniforms; +} diff --git a/MaterialX/javascript/MaterialXView/source/index.js b/MaterialX/javascript/MaterialXView/source/index.js old mode 100644 new mode 100755 index a261d70..a7f93fc --- a/MaterialX/javascript/MaterialXView/source/index.js +++ b/MaterialX/javascript/MaterialXView/source/index.js @@ -1,198 +1,205 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -import * as THREE from 'three'; -import { Viewer } from './viewer.js' -import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; -import { dropHandler, dragOverHandler, setLoadingCallback, setSceneLoadingCallback } from './dropHandling.js'; - -let renderer, orbitControls; - -// Turntable option. For now the step size is fixed. -let turntableEnabled = false; -let turntableSteps = 360; -let turntableStep = 0; - -let captureRequested = false; - -// Get URL options. Fallback to defaults if not specified. -let materialFilename = new URLSearchParams(document.location.search).get("file"); -if (!materialFilename) -{ - materialFilename = 'Materials/Examples/StandardSurface/standard_surface_default.mtlx'; -} - -let viewer = Viewer.create(); -init(); -viewer.getEditor().updateProperties(0.9); - -// Capture the current frame and save an image file. -function captureFrame() -{ - let canvas = document.getElementById('webglcanvas'); - var url = canvas.toDataURL(); - var link = document.createElement('a'); - link.setAttribute('href', url); - link.setAttribute('target', '_blank'); - link.setAttribute('download', 'screenshot.png'); - link.click(); -} - -function init() -{ - let canvas = document.getElementById('webglcanvas'); - - // Handle material selection changes - let materialsSelect = document.getElementById('materials'); - materialsSelect.value = materialFilename; - materialsSelect.addEventListener('change', (e) => - { - materialFilename = e.target.value; - viewer.getEditor().initialize(); - viewer.getMaterial().loadMaterials(viewer, materialFilename); - viewer.getEditor().updateProperties(0.9); - }); - - // Handle geometry selection changes - const scene = viewer.getScene(); - let geometrySelect = document.getElementById('geometry'); - geometrySelect.value = scene.getGeometryURL(); - geometrySelect.addEventListener('change', (e) => - { - console.log('Change geometry to:', e.target.value); - scene.setGeometryURL(e.target.value); - scene.loadGeometry(viewer, orbitControls); - }); - - // Set up scene - scene.initialize(); - - // Set up renderer - renderer = new THREE.WebGLRenderer({ antialias: true, canvas }); - renderer.setSize(window.innerWidth, window.innerHeight); - renderer.debug.checkShaderErrors = false; - - window.addEventListener('resize', onWindowResize); - - // Set up controls - orbitControls = new OrbitControls(scene.getCamera(), renderer.domElement); - - // Add hotkey 'f' to capture the current frame and save an image file. - // See check inside the render loop when a capture can be performed. - document.addEventListener('keydown', (event) => - { - if (event.key === 'f') - { - captureRequested = true; - } - }); - - // Initialize editor - viewer.getEditor().initialize(); - - const hdrLoader = viewer.getHdrLoader(); - const fileLoader = viewer.getFileLoader(); - Promise.all([ - new Promise(resolve => hdrLoader.load('Lights/san_giuseppe_bridge_split.hdr', resolve)), - new Promise(resolve => hdrLoader.load('Lights/irradiance/san_giuseppe_bridge_split.hdr', resolve)), - new Promise(resolve => fileLoader.load('Lights/san_giuseppe_bridge_split.mtlx', resolve)), - new Promise(function (resolve) - { - MaterialX().then((module) => - { - resolve(module); - }); - }) - ]).then(async ([radianceTexture, irradianceTexture, lightRigXml, mxIn]) => - { - // Initialize viewer + lighting - await viewer.initialize(mxIn, renderer, radianceTexture, irradianceTexture, lightRigXml); - - // Load geometry - let scene = viewer.getScene(); - scene.loadGeometry(viewer, orbitControls); - - // Load materials - viewer.getMaterial().loadMaterials(viewer, materialFilename); - - // Update assignments - viewer.getMaterial().updateMaterialAssignments(viewer); - - canvas.addEventListener("keydown", handleKeyEvents, true); - - }).then(() => - { - animate(); - }).catch(err => - { - console.error(Number.isInteger(err) ? this.getMx().getExceptionMessage(err) : err); - }) - - // allow dropping files and directories - document.addEventListener('drop', dropHandler, false); - document.addEventListener('dragover', dragOverHandler, false); - - setLoadingCallback(file => - { - materialFilename = file.fullPath || file.name; - viewer.getEditor().initialize(); - viewer.getMaterial().loadMaterials(viewer, materialFilename); - viewer.getEditor().updateProperties(0.9); - }); - - setSceneLoadingCallback(file => - { - let glbFileName = file.fullPath || file.name; - console.log('Drop geometry to:', glbFileName); - scene.setGeometryURL(glbFileName); - scene.loadGeometry(viewer, orbitControls); - }); - - // enable three.js Cache so that dropped files can reference each other - THREE.Cache.enabled = true; -} - -function onWindowResize() -{ - viewer.getScene().updateCamera(); - renderer.setSize(window.innerWidth, window.innerHeight); -} - -function animate() -{ - requestAnimationFrame(animate); - const scene = viewer.getScene(); - - if (turntableEnabled) - { - turntableStep = (turntableStep + 1) % 360; - var turntableAngle = turntableStep * (360.0 / turntableSteps) / 180.0 * Math.PI; - scene._scene.rotation.y = turntableAngle; - } - - scene.updateTimeUniforms(); - renderer.render(scene.getScene(), scene.getCamera()); - - if (captureRequested) - { - captureFrame(); - captureRequested = false; - } -} - -function handleKeyEvents(event) -{ - const V_KEY = 86; - const P_KEY = 80; - - if (event.keyCode == V_KEY) - { - viewer.getScene().toggleBackgroundTexture(); - } - else if (event.keyCode == P_KEY) - { - turntableEnabled = !turntableEnabled; - } -} +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +import * as THREE from 'three'; +import { Viewer } from './viewer.js' +import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; +import { dropHandler, dragOverHandler, setLoadingCallback, setSceneLoadingCallback } from './dropHandling.js'; + +let renderer, orbitControls; + +// Turntable option. For now the step size is fixed. +let turntableEnabled = false; +let turntableSteps = 360; +let turntableStep = 0; + +let captureRequested = false; + +// Get URL options. Fallback to defaults if not specified. +let materialFilename = new URLSearchParams(document.location.search).get("file"); +if (!materialFilename) +{ + materialFilename = 'Materials/Examples/StandardSurface/standard_surface_default.mtlx'; +} + +let viewer = Viewer.create(); +init(); +viewer.getEditor().updateProperties(0.9); + +// Capture the current frame and save an image file. +function captureFrame() +{ + let canvas = document.getElementById('webglcanvas'); + var url = canvas.toDataURL(); + var link = document.createElement('a'); + link.setAttribute('href', url); + link.setAttribute('target', '_blank'); + link.setAttribute('download', 'screenshot.png'); + link.click(); +} + +function init() +{ + let canvas = document.getElementById('webglcanvas'); + + // Handle material selection changes + let materialsSelect = document.getElementById('materials'); + materialsSelect.value = materialFilename; + materialsSelect.addEventListener('change', (e) => + { + materialFilename = e.target.value; + viewer.getEditor().initialize(); + viewer.getMaterial().loadMaterials(viewer, materialFilename); + viewer.getEditor().updateProperties(0.9); + viewer.getScene().setUpdateTransforms(); + }); + + // Handle geometry selection changes + const scene = viewer.getScene(); + let geometrySelect = document.getElementById('geometry'); + geometrySelect.value = scene.getGeometryURL(); + geometrySelect.addEventListener('change', (e) => + { + console.log('Change geometry to:', e.target.value); + scene.setGeometryURL(e.target.value); + scene.loadGeometry(viewer, orbitControls); + }); + + // Set up scene + scene.initialize(); + + // Set up renderer + renderer = new THREE.WebGLRenderer({ antialias: true, canvas }); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.debug.checkShaderErrors = false; + + window.addEventListener('resize', onWindowResize); + + // Set up controls + orbitControls = new OrbitControls(scene.getCamera(), renderer.domElement); + orbitControls.addEventListener('change', () => + { + viewer.getScene().setUpdateTransforms(); + }) + + // Add hotkey 'f' to capture the current frame and save an image file. + // See check inside the render loop when a capture can be performed. + document.addEventListener('keydown', (event) => + { + if (event.key === 'f') + { + captureRequested = true; + } + }); + + // Initialize editor + viewer.getEditor().initialize(); + + const hdrLoader = viewer.getHdrLoader(); + const fileLoader = viewer.getFileLoader(); + Promise.all([ + new Promise(resolve => hdrLoader.load('Lights/san_giuseppe_bridge_split.hdr', resolve)), + new Promise(resolve => hdrLoader.load('Lights/irradiance/san_giuseppe_bridge_split.hdr', resolve)), + new Promise(resolve => fileLoader.load('Lights/san_giuseppe_bridge_split.mtlx', resolve)), + new Promise(function (resolve) + { + MaterialX().then((module) => + { + resolve(module); + }); + }) + ]).then(async ([radianceTexture, irradianceTexture, lightRigXml, mxIn]) => + { + // Initialize viewer + lighting + await viewer.initialize(mxIn, renderer, radianceTexture, irradianceTexture, lightRigXml); + + // Load geometry + let scene = viewer.getScene(); + scene.loadGeometry(viewer, orbitControls); + + // Load materials + viewer.getMaterial().loadMaterials(viewer, materialFilename); + + // Update assignments + viewer.getMaterial().updateMaterialAssignments(viewer); + + canvas.addEventListener("keydown", handleKeyEvents, true); + + }).then(() => + { + animate(); + }).catch(err => + { + console.error(Number.isInteger(err) ? this.getMx().getExceptionMessage(err) : err); + }) + + // allow dropping files and directories + document.addEventListener('drop', dropHandler, false); + document.addEventListener('dragover', dragOverHandler, false); + + setLoadingCallback(file => + { + materialFilename = file.fullPath || file.name; + viewer.getEditor().initialize(); + viewer.getMaterial().loadMaterials(viewer, materialFilename); + viewer.getEditor().updateProperties(0.9); + viewer.getScene().setUpdateTransforms(); + }); + + setSceneLoadingCallback(file => + { + let glbFileName = file.fullPath || file.name; + console.log('Drop geometry to:', glbFileName); + scene.setGeometryURL(glbFileName); + scene.loadGeometry(viewer, orbitControls); + }); + + // enable three.js Cache so that dropped files can reference each other + THREE.Cache.enabled = true; +} + +function onWindowResize() +{ + viewer.getScene().updateCamera(); + viewer.getScene().setUpdateTransforms(); + renderer.setSize(window.innerWidth, window.innerHeight); +} + +function animate() +{ + requestAnimationFrame(animate); + + if (turntableEnabled) + { + turntableStep = (turntableStep + 1) % 360; + var turntableAngle = turntableStep * (360.0 / turntableSteps) / 180.0 * Math.PI; + viewer.getScene()._scene.rotation.y = turntableAngle; + viewer.getScene().setUpdateTransforms(); + } + + renderer.render(viewer.getScene().getScene(), viewer.getScene().getCamera()); + viewer.getScene().updateTransforms(); + + if (captureRequested) + { + captureFrame(); + captureRequested = false; + } +} + +function handleKeyEvents(event) +{ + const V_KEY = 86; + const P_KEY = 80; + + if (event.keyCode == V_KEY) + { + viewer.getScene().toggleBackgroundTexture(); + } + else if (event.keyCode == P_KEY) + { + turntableEnabled = !turntableEnabled; + } +} diff --git a/MaterialX/javascript/MaterialXView/source/viewer.js b/MaterialX/javascript/MaterialXView/source/viewer.js old mode 100644 new mode 100755 index e66974f..4081564 --- a/MaterialX/javascript/MaterialXView/source/viewer.js +++ b/MaterialX/javascript/MaterialXView/source/viewer.js @@ -1,1679 +1,1617 @@ -// -// Copyright Contributors to the MaterialX Project -// SPDX-License-Identifier: Apache-2.0 -// - -import * as THREE from 'three'; -import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; -import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'; - -import { prepareEnvTexture, getLightRotation, findLights, registerLights, getUniformValues } from './helper.js' -import { Group } from 'three'; -import GUI from 'lil-gui'; - -const ALL_GEOMETRY_SPECIFIER = "*"; -const NO_GEOMETRY_SPECIFIER = ""; -const DAG_PATH_SEPERATOR = "/"; - -// Logging toggle -var logDetailedTime = false; - -/* - Scene management -*/ -export class Scene -{ - constructor() - { - this._geometryURL = new URLSearchParams(document.location.search).get("geom"); - if (!this._geometryURL) - { - this._geometryURL = 'Geometry/shaderball.glb'; - } - } - - initialize() - { - this._scene = new THREE.Scene(); - this._scene.background = new THREE.Color(this.#_backgroundColor); - this._scene.background.convertSRGBToLinear(); - - const aspectRatio = window.innerWidth / window.innerHeight; - const cameraNearDist = 0.05; - const cameraFarDist = 100.0; - const cameraFOV = 60.0; - this._camera = new THREE.PerspectiveCamera(cameraFOV, aspectRatio, cameraNearDist, cameraFarDist); - this._frame = 0; - - this.#_gltfLoader = new GLTFLoader(); - - this.#_normalMat = new THREE.Matrix3(); - this.#_viewProjMat = new THREE.Matrix4(); - this.#_worldViewPos = new THREE.Vector3(); - } - - // Set whether to flip UVs in V for loaded geometry - setFlipGeometryV(val) - { - this.#_flipV = val; - } - - // Get whether to flip UVs in V for loaded geometry - getFlipGeometryV() - { - return this.#_flipV; - } - - // Utility to perform geometry file load - loadGeometryFile(geometryFilename, loader) - { - return new Promise((resolve, reject) => - { - loader.load(geometryFilename, data => resolve(data), null, reject); - }); - } - - // - // Load in geometry specified by a given file name, - // then update the scene geometry and camera. - // - async loadGeometry(viewer, orbitControls) - { - var startTime = performance.now(); - var geomLoadTime = startTime; - - const gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_gltfLoader); - - const scene = this.getScene(); - while (scene.children.length > 0) - { - scene.remove(scene.children[0]); - } - - this.#_rootNode = null; - 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); - model = new Group(); - model.add(cube); - } - else - { - this.#_rootNode = model; - } - scene.add(model); - - // Set up onBeforeRender callbacks so that we can update uniforms per object right before rendering. - model.traverse((child) => - { - child.onBeforeRender = (_renderer, _scene, camera, _geometry, material, _group) => - { - this.updateObjectUniforms(child, material, camera); - }; - }) - - console.log("- Scene load time: ", performance.now() - geomLoadTime, "ms"); - - // Always reset controls based on camera for each load. - orbitControls.reset(); - this.updateScene(viewer, orbitControls); - - console.log("Total geometry load time: ", performance.now() - startTime, " ms."); - - viewer.getMaterial().clearSoloMaterialUI(); - viewer.getMaterial().updateMaterialAssignments(viewer, ""); - } - - // - // Update the geometry buffer, assigned materials, and camera controls. - // - updateScene(viewer, orbitControls) - { - var startUpdateSceneTime = performance.now(); - var uvTime = 0; - var normalTime = 0; - var tangentTime = 0; - var streamTime = 0; - var bboxTime = 0; - - var startBboxTime = performance.now(); - const bbox = new THREE.Box3().setFromObject(this._scene); - const bsphere = new THREE.Sphere(); - bbox.getBoundingSphere(bsphere); - bboxTime = performance.now() - startBboxTime; - - let theScene = viewer.getScene(); - let flipV = theScene.getFlipGeometryV(); - - - this._scene.traverse((child) => - { - if (child.isMesh) - { - var startUVTime = performance.now(); - if (!child.geometry.attributes.uv) - { - const posCount = child.geometry.attributes.position.count; - const uvs = []; - const pos = child.geometry.attributes.position.array; - - for (let i = 0; i < posCount; i++) - { - uvs.push((pos[i * 3] - bsphere.center.x) / bsphere.radius); - uvs.push((pos[i * 3 + 1] - bsphere.center.y) / bsphere.radius); - } - - child.geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), 2)); - } - else if (flipV) - { - const uvCount = child.geometry.attributes.position.count; - const uvs = child.geometry.attributes.uv.array; - for (let i = 0; i < uvCount; i++) - { - let v = 1.0 - (uvs[i * 2 + 1]); - uvs[i * 2 + 1] = v; - } - } - uvTime += performance.now() - startUVTime; - - if (!child.geometry.attributes.normal) - { - var startNormalTime = performance.now(); - child.geometry.computeVertexNormals(); - normalTime += performance.now() - startNormalTime; - } - - if (child.geometry.getIndex()) - { - if (!child.geometry.attributes.tangent) - { - var startTangentTime = performance.now(); - child.geometry.computeTangents(); - tangentTime += performance.now() - startTangentTime; - } - } - - // Use default MaterialX naming convention. - var startStreamTime = performance.now(); - child.geometry.attributes.i_position = child.geometry.attributes.position; - if (child.geometry.attributes.normal) - child.geometry.attributes.i_normal = child.geometry.attributes.normal; - if (child.geometry.attributes.tangent) - child.geometry.attributes.i_tangent = child.geometry.attributes.tangent; - if (child.geometry.attributes.color) - child.geometry.attributes.i_color_0 = child.geometry.attributes.color; - if (child.geometry.attributes.color_1) - child.geometry.attributes.i_color_1 = child.geometry.attributes.color_1; - if (child.geometry.attributes.uv) - child.geometry.attributes.i_texcoord_0 = child.geometry.attributes.uv; - if (child.geometry.attributes.uv1) - child.geometry.attributes.i_texcoord_1 = child.geometry.attributes.uv1; - if (child.geometry.attributes.uv2) - child.geometry.attributes.i_texcoord_2 = child.geometry.attributes.uv2; - streamTime += performance.now() - startStreamTime; - } - }); - - console.log("- Stream update time: ", performance.now() - startUpdateSceneTime, "ms"); - if (logDetailedTime) - { - console.log(' - UV time: ', uvTime); - console.log(' - Normal time: ', normalTime); - console.log(' - Tangent time: ', tangentTime); - console.log(' - Stream Update time: ', streamTime); - console.log(' - Bounds compute time: ', bboxTime); - } - - // Update the background - this._scene.background = this.getBackground(); - - // Fit camera to model - const camera = this.getCamera(); - camera.position.y = bsphere.center.y; - camera.position.z = bsphere.radius * 2.0; - camera.updateProjectionMatrix(); - - orbitControls.target = bsphere.center; - orbitControls.update(); - } - - updateObjectUniforms(child, material, camera) - { - if (!child || !material || !camera) return; - const uniforms = material.uniforms; - if (!uniforms) return; - - uniforms.u_worldMatrix.value = child.matrixWorld; - uniforms.u_viewProjectionMatrix.value = this.#_viewProjMat.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); - - if (uniforms.u_viewPosition) - uniforms.u_viewPosition.value = camera.getWorldPosition(this.#_worldViewPos); - - if (uniforms.u_worldInverseTransposeMatrix) - uniforms.u_worldInverseTransposeMatrix.value = - new THREE.Matrix4().setFromMatrix3(this.#_normalMat.getNormalMatrix(child.matrixWorld)); - - material.uniformsNeedUpdate = true; - } - - /** - * Update uniforms for all scene objects. This is called once per frame - * and updates time and frame count uniforms. - */ - updateTimeUniforms() { - this._frame++; - - const scene = this.getScene(); - const time = performance.now() / 1000.0; - const frame = this._frame; - - scene.traverse((child) => - { - if (child.isMesh && child.material && child.material.uniforms) - { - const uniforms = child.material.uniforms; - if (uniforms) - { - if (uniforms.u_time) - uniforms.u_time.value = time; - if (uniforms.u_frame) - uniforms.u_frame.value = frame; - } - } - }); - } - - // Determine string DAG path based on individual node names. - getDagPath(node) - { - const rootNode = this.#_rootNode; - - let path = [node.userData?.name || node.name]; - while (node.parent) - { - node = node.parent; - if (node) - { - // Stop at the root of the scene read in. - if (node == rootNode) - { - break; - } - path.unshift(node.userData?.name || node.name); - } - } - return path; - } - - // Assign material shader to associated geometry - updateMaterial(matassign) - { - let assigned = 0; - - const shader = matassign.getShader(); - const material = matassign.getMaterial().getName(); - const geometry = matassign.getGeometry(); - const collection = matassign.getCollection(); - - const scene = this.getScene(); - const camera = this.getCamera(); - scene.traverse((child) => - { - if (child.isMesh) - { - const dagPath = this.getDagPath(child).join('/'); - - // Note that this is a very simplistic - // assignment resolve and assumes basic - // regular expression name match. - let matches = (geometry == ALL_GEOMETRY_SPECIFIER); - if (!matches) - { - if (collection) - { - if (collection.matchesGeomString(dagPath)) - { - matches = true; - } - } - else - { - if (geometry != NO_GEOMETRY_SPECIFIER) - { - const paths = geometry.split(','); - for (let path of paths) - { - if (dagPath.match(path)) - { - matches = true; - break; - } - } - } - } - } - if (matches) - { - child.material = shader; - assigned++; - } - } - }); - - return assigned; - } - - updateCamera() - { - const camera = this.getCamera(); - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - } - - getScene() - { - return this._scene; - } - - getCamera() - { - return this._camera; - } - - getGeometryURL() - { - return this._geometryURL; - } - - setGeometryURL(url) - { - this._geometryURL = url; - } - - setBackgroundTexture(texture) - { - this.#_backgroundTexture = texture; - } - - getShowBackgroundTexture() - { - return this.#_showBackgroundTexture; - } - - setShowBackgroundTexture(enable) - { - this.#_showBackgroundTexture = enable; - } - - getBackground() - { - if (this.#_backgroundTexture && this.#_showBackgroundTexture) - { - return this.#_backgroundTexture; - } - var color = new THREE.Color(this.#_backgroundColor); - color.convertSRGBToLinear(); - return color; - } - - toggleBackgroundTexture() - { - this.#_showBackgroundTexture = !this.#_showBackgroundTexture; - this._scene.background = this.getBackground(); - } - - // Geometry file - #_geometryURL = ''; - // Geometry loader - #_gltfLoader = null; - // Flip V coordinate of texture coordinates. - // Set to true to be consistent with desktop viewer. - #_flipV = true; - - // Scene - #_scene = null; - - // Camera - #_camera = null; - - // Background color - #_backgroundColor = 0x4c4c52; - - // Background texture - #_backgroundTexture = null; - #_showBackgroundTexture = true; - - // Transform matrices - #_normalMat = new THREE.Matrix3(); - #_viewProjMat = new THREE.Matrix4(); - #_worldViewPos = new THREE.Vector3(); - - // Root node of imported scene - #_rootNode = null; -} - -/* - Property editor -*/ -export class Editor -{ - // Initialize the editor, clearing any elements from previous materials. - initialize() - { - Array.from(document.getElementsByClassName('lil-gui')).forEach( - function (element, index, array) - { - if (element.className) - { - element.remove(); - } - } - ); - - this._gui = new GUI({ title: "Property Editor" }); - this._gui.close(); - } - - // Update ui properties - // - Hide close button - // - Update transparency so scene shows through if overlapping - updateProperties(targetOpacity = 1) - { - // Set opacity - Array.from(document.getElementsByClassName('dg')).forEach( - function (element, index, array) - { - element.style.opacity = targetOpacity; - } - ); - } - - getGUI() - { - return this._gui; - } - - _gui = null; -} - -class MaterialAssign -{ - constructor(material, geometry, collection) - { - this._material = material; - this._geometry = geometry; - this._collection = collection; - this._shader = null; - this._materialUI = null; - } - - setMaterialUI(value) - { - this._materialUI = value; - } - - getMaterialUI() - { - return this._materialUI; - } - - setShader(shader) - { - this._shader = shader; - } - - getShader() - { - return this._shader; - } - - getMaterial() - { - return this._material; - } - - getGeometry() - { - return this._geometry; - } - - setGeometry(value) - { - this._geometry = value; - } - - getCollection() - { - return this._collection; - } - - // MaterialX material node name - _material; - - // MaterialX assignment geometry string - _geometry; - - // MaterialX assignment collection - _collection; - - // THREE.JS shader - _shader; -} - -export class Material -{ - constructor() - { - this._materials = []; - this._defaultMaterial = null; - this._soloMaterial = ""; - } - - clearMaterials() - { - this._materials.length = 0; - this._defaultMaterial = null; - this._soloMaterial = ""; - } - - setSoloMaterial(value) - { - this._soloMaterial = value; - } - - getSoloMaterial() - { - return this._soloMaterial; - } - - // If no material file is selected, we programmatically create a default material as a fallback - static createFallbackMaterial(doc) - { - let ssNode = doc.getChild('Generated_Default_Shader'); - if (ssNode) - { - return ssNode; - } - const ssName = 'Generated_Default_Shader'; - ssNode = doc.addChildOfCategory('standard_surface', ssName); - ssNode.setType('surfaceshader'); - const smNode = doc.addChildOfCategory('surfacematerial', 'Default'); - smNode.setType('material'); - const shaderElement = smNode.addInput('surfaceshader'); - shaderElement.setType('surfaceshader'); - shaderElement.setNodeName(ssName); - - return ssNode; - } - - async loadMaterialFile(loader, materialFilename) - { - return new Promise((resolve, reject) => - { - loader.load(materialFilename, data => resolve(data), null, reject); - }); - } - - async loadMaterials(viewer, materialFilename) - { - var startTime = performance.now(); - - const mx = viewer.getMx(); - - // Re-initialize document - var startDocTime = performance.now(); - var doc = mx.createDocument(); - doc.setDataLibrary(viewer.getLibrary()); - viewer.setDocument(doc); - - const fileloader = viewer.getFileLoader(); - - let mtlxMaterial = await viewer.getMaterial().loadMaterialFile(fileloader, materialFilename); - - // Load lighting setup into document - doc.importLibrary(viewer.getLightRig()); - - console.log("- Material document load time: ", performance.now() - startDocTime, "ms."); - - // Set search path. Assumes images are relative to current file - // location. - if (!materialFilename) materialFilename = "/"; - const paths = materialFilename.split('/'); - paths.pop(); - const searchPath = paths.join('/'); - - // Load material - if (mtlxMaterial) - try { - await mx.readFromXmlString(doc, mtlxMaterial, searchPath); - } - catch (error) { - console.log('Error loading material file: ', error); - } - else - Material.createFallbackMaterial(doc); - - // Check if there are any looks defined in the document - // If so then traverse the looks for all material assignments. - // Generate code and compile for any associated surface shader - // and assign to the associated geometry. If there are no looks - // then the first material is found and assignment to all the - // geometry. - this.clearMaterials(); - var looks = doc.getLooks(); - if (looks.length) - { - for (let look of looks) - { - const materialAssigns = look.getMaterialAssigns(); - for (let materialAssign of materialAssigns) - { - let matName = materialAssign.getMaterial(); - if (matName) - { - let mat = doc.getChild(matName); - var shader; - if (mat) - { - var shaders = mx.getShaderNodes(mat); - if (shaders.length) - { - shader = shaders[0]; - } - } - let collection = materialAssign.getCollection(); - let geom = materialAssign.getGeom(); - let newAssignment; - if (collection || geom) - { - // Remove leading "/" from collection and geom for - // later assignment comparison checking - if (collection && collection.charAt(0) == "/") - { - collection = collection.slice(1); - } - if (geom && geom.charAt(0) == "/") - { - geom = geom.slice(1); - } - newAssignment = new MaterialAssign(shader, geom, collection); - } - else - { - newAssignment = new MaterialAssign(shader, NO_GEOMETRY_SPECIFIER, null); - } - - if (newAssignment) - { - this._materials.push(newAssignment); - } - } - } - } - } - else - { - // Search for any surface shaders. The first found - // is assumed to be assigned to the entire scene - // The identifier used is "*" to mean the entire scene. - const materialNodes = doc.getMaterialNodes(); - let shaderList = []; - let foundRenderable = false; - for (let i = 0; i < materialNodes.length; ++i) - { - let materialNode = materialNodes[i]; - if (materialNode) - { - console.log('Scan material: ', materialNode.getNamePath()); - let shaderNodes = mx.getShaderNodes(materialNode) - if (shaderNodes.length > 0) - { - let shaderNodePath = shaderNodes[0].getNamePath() - if (!shaderList.includes(shaderNodePath)) - { - let assignment = NO_GEOMETRY_SPECIFIER; - if (foundRenderable == false) - { - assignment = ALL_GEOMETRY_SPECIFIER; - foundRenderable = true; - } - console.log('-- add shader: ', shaderNodePath); - shaderList.push(shaderNodePath); - this._materials.push(new MaterialAssign(shaderNodes[0], assignment)); - } - } - } - } - const nodeGraphs = doc.getNodeGraphs(); - for (let i = 0; i < nodeGraphs.length; ++i) - { - let nodeGraph = nodeGraphs[i]; - if (nodeGraph) - { - if (nodeGraph.hasAttribute('nodedef') || nodeGraph.hasSourceUri()) - { - continue; - } - // Skip any nodegraph that is connected to something downstream - if (nodeGraph.getDownstreamPorts().length > 0) - { - continue - } - let outputs = nodeGraph.getOutputs(); - for (let j = 0; j < outputs.length; ++j) - { - let output = outputs[j]; - { - let assignment = NO_GEOMETRY_SPECIFIER; - if (foundRenderable == false) - { - assignment = ALL_GEOMETRY_SPECIFIER; - foundRenderable = true; - } - let newMat = new MaterialAssign(output, assignment, null); - this._materials.push(newMat); - } - } - } - } - const outputs = doc.getOutputs(); - for (let i = 0; i < outputs.length; ++i) - { - let output = outputs[i]; - if (output) - { - let assignment = NO_GEOMETRY_SPECIFIER; - if (foundRenderable == false) - { - assignment = ALL_GEOMETRY_SPECIFIER; - foundRenderable = true; - } - this._materials.push(new MaterialAssign(output, assignment)); - } - } - - const shaderNodes = []; - for (let i = 0; i < shaderNodes.length; ++i) - { - let shaderNode = shaderNodes[i]; - let shaderNodePath = shaderNode.getNamePath() - if (!shaderList.includes(shaderNodePath)) - { - let assignment = NO_GEOMETRY_SPECIFIER; - if (foundRenderable == false) - { - assignment = ALL_GEOMETRY_SPECIFIER; - foundRenderable = true; - } - shaderList.push(shaderNodePath); - this._materials.push(new MaterialAssign(shaderNode, assignment)); - } - } - } - - // Assign to default material if none found - if (this._materials.length == 0) - { - const defaultNode = Material.createFallbackMaterial(doc); - this._materials.push(new MaterialAssign(defaultNode, ALL_GEOMETRY_SPECIFIER)); - } - - // Create a new shader for each material node. - // Only create the shader once even if assigned more than once. - var startGenTime = performance.now(); - let shaderMap = new Map(); - let closeUI = false; - for (let matassign of this._materials) - { - // Need to use path vs name to get a unique key. - let materialName = matassign.getMaterial().getNamePath(); - let shader = shaderMap[materialName]; - if (!shader) - { - shader = viewer.getMaterial().generateMaterial(matassign, viewer, searchPath, closeUI); - shaderMap[materialName] = shader; - } - matassign.setShader(shader); - closeUI = true; - } - console.log("- Generate (", this._materials.length, ") shader(s) time: ", performance.now() - startGenTime, " ms.",); - - // Update scene shader assignments - this.updateMaterialAssignments(viewer, ""); - - console.log("Total material time: ", (performance.now() - startTime), "ms"); - } - - // - // Update the assignments for scene objects based on the - // material assignment information stored in the viewer. - // Note: If none of the MaterialX assignments match the geometry - // in the scene, then the first material assignment shader is assigned - // to the entire scene. - // - async updateMaterialAssignments(viewer, soloMaterial) - { - console.log("Update material assignments. Solo=", soloMaterial); - var startTime = performance.now(); - - let assigned = 0; - let assignedSolo = false; - for (let matassign of this._materials) - { - if (matassign.getShader()) - { - if (soloMaterial.length) - { - if (matassign.getMaterial().getNamePath() == soloMaterial) - { - let temp = matassign.getGeometry(); - matassign.setGeometry(ALL_GEOMETRY_SPECIFIER); - assigned += viewer.getScene().updateMaterial(matassign); - matassign.setGeometry(temp); - assignedSolo = true; - break; - } - } - else - { - assigned += viewer.getScene().updateMaterial(matassign); - } - } - } - if (assigned == 0 && this._materials.length) - { - this._defaultMaterial = new MaterialAssign(this._materials[0].getMaterial(), ALL_GEOMETRY_SPECIFIER); - this._defaultMaterial.setShader(this._materials[0].getShader()); - viewer.getScene().updateMaterial(this._defaultMaterial); - } - - if (assigned > 0) - { - console.log('Material assignment time: ', performance.now() - startTime, " ms."); - } - } - - // - // Generate a new material for a given element - // - generateMaterial(matassign, viewer, searchPath, closeUI) - { - var elem = matassign.getMaterial(); - - var startGenerateMat = performance.now(); - - const mx = viewer.getMx(); - const textureLoader = new THREE.TextureLoader(); - - const lights = viewer.getLights(); - const lightData = viewer.getLightData(); - const radianceTexture = viewer.getRadianceTexture(); - const irradianceTexture = viewer.getIrradianceTexture(); - const gen = viewer.getGenerator(); - const genContext = viewer.getGenContext(); - genContext.getOptions().hwSrgbEncodeOutput = true; - - // Perform transparency check on renderable item - var startTranspCheckTime = performance.now(); - const isTransparent = mx.isTransparentSurface(elem, gen.getTarget()); - genContext.getOptions().hwTransparency = isTransparent; - // Always set to complete. - // Can consider option to set to reduced as the parsing of large numbers of uniforms (e.g. on shading models) - // can be quite expensive. - genContext.getOptions().shaderInterfaceType = mx.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE; - - if (logDetailedTime) - console.log(" - Transparency check time: ", performance.now() - startTranspCheckTime, "ms"); - - // Generate GLES code - var startMTLXGenTime = performance.now(); - let shader = gen.generate(elem.getNamePath(), elem, genContext); - if (logDetailedTime) - console.log(" - MaterialX gen time: ", performance.now() - startMTLXGenTime, "ms"); - - var startUniformUpdate = performance.now(); - - // Get shaders and uniform values - let vShader = shader.getSourceCode("vertex"); - let fShader = shader.getSourceCode("pixel"); - - let theScene = viewer.getScene(); - let flipV = theScene.getFlipGeometryV(); - let uniforms = { - ...getUniformValues(shader.getStage('vertex'), textureLoader, searchPath, flipV), - ...getUniformValues(shader.getStage('pixel'), textureLoader, searchPath, flipV), - } - - Object.assign(uniforms, { - u_numActiveLightSources: { value: lights.length }, - u_lightData: { value: lightData }, - u_envMatrix: { value: getLightRotation() }, - u_envRadiance: { value: radianceTexture }, - u_envRadianceMips: { value: Math.trunc(Math.log2(Math.max(radianceTexture.image.width, radianceTexture.image.height))) + 1 }, - u_envRadianceSamples: { value: 16 }, - u_envIrradiance: { value: irradianceTexture }, - u_refractionEnv: { value: true } - }); - - // Create Three JS Material - let newMaterial = new THREE.RawShaderMaterial({ - uniforms: uniforms, - vertexShader: vShader, - fragmentShader: fShader, - transparent: isTransparent, - blendEquation: THREE.AddEquation, - blendSrc: THREE.OneMinusSrcAlphaFactor, - blendDst: THREE.SrcAlphaFactor, - side: THREE.DoubleSide, - name: elem.getName(), - }); - - if (logDetailedTime) - console.log(" - Three material update time: ", performance.now() - startUniformUpdate, "ms"); - - // Update property editor - const gui = viewer.getEditor().getGUI(); - this.updateEditor(matassign, shader, newMaterial, gui, closeUI, viewer); - - if (logDetailedTime) - console.log("- Per material generate time: ", performance.now() - startGenerateMat, "ms"); - - return newMaterial; - } - - clearSoloMaterialUI() - { - for (let i = 0; i < this._materials.length; ++i) - { - let matassign = this._materials[i]; - let matUI = matassign.getMaterialUI(); - if (matUI) - { - let matTitle = matUI.domElement.getElementsByClassName('title')[0]; - matTitle.classList.remove('peditor_material_assigned'); - let img = matTitle.getElementsByTagName('img')[0]; - img.src = 'public/shader_ball.svg'; - //matTitle.classList.remove('peditor_material_unassigned'); - } - } - } - - static updateSoloMaterial(viewer, elemPath, materials, event) - { - // Prevent the event from being passed to parent folder - event.stopPropagation(); - - for (let i = 0; i < materials.length; ++i) - { - let matassign = materials[i]; - // Need to use path vs name to get a unique key. - let materialName = matassign.getMaterial().getNamePath(); - var matUI = matassign.getMaterialUI(); - let matTitle = matUI.domElement.getElementsByClassName('title')[0]; - let img = matTitle.getElementsByTagName('img')[0]; - if (materialName == elemPath) - { - if (this._soloMaterial == elemPath) - { - img.src = 'public/shader_ball.svg'; - matTitle.classList.remove('peditor_material_assigned'); - this._soloMaterial = ""; - } - else - { - img.src = 'public/shader_ball2.svg'; - matTitle.classList.add('peditor_material_assigned'); - this._soloMaterial = elemPath; - } - } - else - { - img.src = 'public/shader_ball.svg'; - matTitle.classList.remove('peditor_material_assigned'); - } - } - viewer.getMaterial().updateMaterialAssignments(viewer, this._soloMaterial); - } - - // - // Update property editor for a given MaterialX element, it's shader, and - // Three material - // - updateEditor(matassign, shader, material, gui, closeUI, viewer) - { - var elem = matassign.getMaterial(); - var materials = this._materials; - - const DEFAULT_MIN = 0; - const DEFAULT_MAX = 100; - - var startTime = performance.now(); - - const elemPath = elem.getNamePath(); - - // Create and cache associated UI - var matUI = gui.addFolder(elemPath); - matassign.setMaterialUI(matUI); - - let matTitle = matUI.domElement.getElementsByClassName('title')[0]; - // Add a icon to the title to allow for assigning the material to geometry - // Clicking on the icon will "solo" the material to the geometry. - // Clicking on the title will open/close the material folder. - matTitle.innerHTML = "" + elem.getNamePath(); - let img = matTitle.getElementsByTagName('img')[0]; - if (img) - { - // Add event listener to icon to call updateSoloMaterial function - img.addEventListener('click', function (event) - { - Material.updateSoloMaterial(viewer, elemPath, materials, event); - }); - } - - if (closeUI) - { - matUI.close(); - } - const uniformBlocks = Object.values(shader.getStage('pixel').getUniformBlocks()); - var uniformToUpdate; - const ignoreList = ['u_envRadianceMips', 'u_envRadianceSamples', 'u_alphaThreshold']; - - var folderList = new Map(); - folderList[elemPath] = matUI; - - uniformBlocks.forEach(uniforms => - { - if (!uniforms.empty()) - { - for (let i = 0; i < uniforms.size(); ++i) - { - const variable = uniforms.get(i); - const value = variable.getValue()?.getData(); - let name = variable.getVariable(); - - if (ignoreList.includes(name)) - { - continue; - } - - let currentFolder = matUI; - let currentElemPath = variable.getPath(); - if (!currentElemPath || currentElemPath.length == 0) - { - continue; - } - let currentElem = elem.getDocument().getDescendant(currentElemPath); - if (!currentElem) - { - continue; - } - - // Skip non-input types and anything > 2 levels deep - if (!currentElem.asAInput() || currentElem.getNamePath().split('/').length > 2) - { - continue; - } - - let currentNode = null; - if (currentElem.getParent() && currentElem.getParent().getNamePath() != "") - { - currentNode = currentElem.getParent(); - } - let uiname = ""; - let nodeDefInput = null; - if (currentNode) - { - - let currentNodePath = currentNode.getNamePath(); - var pathSplit = currentNodePath.split('/'); - if (pathSplit.length) - { - currentNodePath = pathSplit[0]; - } - currentFolder = folderList[currentNodePath]; - if (!currentFolder) - { - currentFolder = matUI.addFolder(currentNodePath); - folderList[currentNodePath] = currentFolder; - } - - // Check for ui attributes - var nodeDef = currentNode.getNodeDef(); - if (nodeDef) - { - // Remove node name from shader uniform name for non root nodes - let lookup_name = name.replace(currentNode.getName() + '_', ''); - nodeDefInput = nodeDef.getActiveInput(lookup_name); - if (nodeDefInput) - { - uiname = nodeDefInput.getAttribute('uiname'); - let uifolderName = nodeDefInput.getAttribute('uifolder'); - if (uifolderName && uifolderName.length) - { - let newFolderName = currentNodePath + '/' + uifolderName; - currentFolder = folderList[newFolderName]; - if (!currentFolder) - { - currentFolder = matUI.addFolder(uifolderName); - currentFolder.domElement.classList.add('peditorfolder'); - folderList[newFolderName] = currentFolder; - } - } - } - } - } - - // Determine UI name to use - let path = name; - let interfaceName = currentElem.getAttribute("interfacename"); - if (interfaceName && interfaceName.length) - { - const graph = currentNode.getParent(); - if (graph) - { - const graphInput = graph.getInput(interfaceName); - if (graphInput) - { - let uiname = graphInput.getAttribute('uiname'); - if (uiname.length) - { - path = uiname; - } - else - { - path = graphInput.getName(); - } - } - } - else - { - path = interfaceName; - } - } - else - { - if (!uiname) - { - uiname = currentElem.getAttribute('uiname'); - } - if (uiname && uiname.length) - { - path = uiname; - } - } - - // Skip if already added to current folder - let found = false; - for (let i = 0; i < currentFolder.children.length; ++i) - { - if (currentFolder.children[i]._name == path) - { - found = true; - break; - } - } - if (found) - { - continue; - } - - switch (variable.getType().getName()) - { - case 'float': - uniformToUpdate = material.uniforms[name]; - if (uniformToUpdate && value != null) - { - var minValue = DEFAULT_MIN; - if (value < minValue) - { - minValue = value; - } - var maxValue = DEFAULT_MAX; - if (value > maxValue) - { - maxValue = value; - } - var step = 0; - if (nodeDefInput) - { - if (nodeDefInput.hasAttribute('uisoftmin')) - minValue = parseFloat(nodeDefInput.getAttribute('uisoftmin')); - else if (nodeDefInput.hasAttribute('uimin')) - minValue = parseFloat(nodeDefInput.getAttribute('uimin')); - - if (nodeDefInput.hasAttribute('uisoftmax')) - maxValue = parseFloat(nodeDefInput.getAttribute('uisoftmax')); - else if (nodeDefInput.hasAttribute('uimax')) - maxValue = parseFloat(nodeDefInput.getAttribute('uimax')); - - if (nodeDefInput.hasAttribute('uistep')) - step = parseFloat(nodeDefInput.getAttribute('uistep')); - } - if (step == 0) - { - step = (maxValue - minValue) / 1000.0; - } - const w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path); - w.domElement.classList.add('peditoritem'); - } - break; - - case 'integer': - uniformToUpdate = material.uniforms[name]; - if (uniformToUpdate && value != null) - { - var minValue = DEFAULT_MIN; - if (value < minValue) - { - minValue = value; - } - var maxValue = DEFAULT_MAX; - if (value > maxValue) - { - maxValue = value; - } - var step = 0; - var enumList = [] - var enumValues = [] - if (nodeDefInput) - { - if (nodeDefInput.hasAttribute('enum')) - { - // Get enum and enum values attributes (if present) - enumList = nodeDefInput.getAttribute('enum').split(','); - if (nodeDefInput.hasAttribute('enumvalues')) - { - enumValues = nodeDefInput.getAttribute('enumvalues').split(',').map(Number); - } - } - else - { - if (nodeDefInput.hasAttribute('uisoftmin')) - minValue = parseInt(nodeDefInput.getAttribute('uisoftmin')); - else if (nodeDefInput.hasAttribute('uimin')) - minValue = parseInt(nodeDefInput.getAttribute('uimin')); - - if (nodeDefInput.hasAttribute('uisoftmax')) - maxValue = parseInt(nodeDefInput.getAttribute('uisoftmax')); - else if (nodeDefInput.hasAttribute('uimax')) - maxValue = parseInt(nodeDefInput.getAttribute('uimax')); - - if (nodeDefInput.hasAttribute('uistep')) - step = parseInt(nodeDefInput.getAttribute('uistep')); - } - } - if (enumList.length == 0) - { - if (step == 0) - { - step = 1 / (maxValue - minValue); - step = Math.ceil(step); - if (step == 0) - { - step = 1; - } - } - } - if (enumList.length == 0) - { - let w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path); - w.domElement.classList.add('peditoritem'); - } - else - { - // Map enumList strings to values - // Map to 0..N if no values are specified via enumvalues attribute - if (enumValues.length == 0) - { - for (let i = 0; i < enumList.length; ++i) - { - enumValues.push(i); - } - } - const enumeration = {}; - enumList.forEach((str, index) => - { - enumeration[str] = enumValues[index]; - }); - - // Function to handle enum drop-down - function handleDropdownChange(value) - { - if (material.uniforms[name]) - { - material.uniforms[name].value = value; - } - } - const defaultOption = enumList[value]; // Set the default selected option - const dropdownController = currentFolder.add(enumeration, defaultOption, enumeration).name(path); - dropdownController.onChange(handleDropdownChange); - dropdownController.domElement.classList.add('peditoritem'); - } - } - break; - - case 'boolean': - uniformToUpdate = material.uniforms[name]; - if (uniformToUpdate && value != null) - { - let w = currentFolder.add(material.uniforms[name], 'value').name(path); - w.domElement.classList.add('peditoritem'); - } - break; - - case 'vector2': - case 'vector3': - case 'vector4': - uniformToUpdate = material.uniforms[name]; - if (uniformToUpdate && value != null) - { - var minValue = [DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN]; - var maxValue = [DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX]; - var step = [0, 0, 0, 0]; - - if (nodeDefInput) - { - if (nodeDefInput.hasAttribute('uisoftmin')) - minValue = nodeDefInput.getAttribute('uisoftmin').split(',').map(Number); - else if (nodeDefInput.hasAttribute('uimin')) - minValue = nodeDefInput.getAttribute('uimin').split(',').map(Number); - - if (nodeDefInput.hasAttribute('uisoftmax')) - maxValue = nodeDefInput.getAttribute('uisoftmax').split(',').map(Number); - else if (nodeDefInput.hasAttribute('uimax')) - maxValue = nodeDefInput.getAttribute('uimax').split(',').map(Number); - - if (nodeDefInput.hasAttribute('uistep')) - step = nodeDefInput.getAttribute('uistep').split(',').map(Number); - } - for (let i = 0; i < 4; ++i) - { - if (step[i] == 0) - { - step[i] = 1 / (maxValue[i] - minValue[i]); - } - } - - const keyString = ["x", "y", "z", "w"]; - let vecFolder = currentFolder.addFolder(path); - Object.keys(material.uniforms[name].value).forEach((key) => - { - let w = vecFolder.add(material.uniforms[name].value, - key, minValue[key], maxValue[key], step[key]).name(keyString[key]); - w.domElement.classList.add('peditoritem'); - }) - } - break; - - case 'color3': - // Irksome way to map arrays to colors and back - uniformToUpdate = material.uniforms[name]; - if (uniformToUpdate && value != null) - { - var dummy = - { - color: 0xFF0000 - }; - const color3 = new THREE.Color(dummy.color); - color3.fromArray(material.uniforms[name].value); - dummy.color = color3.getHex(); - let w = currentFolder.addColor(dummy, 'color').name(path) - .onChange(function (value) - { - const color3 = new THREE.Color(value); - material.uniforms[name].value.set(color3.toArray()); - }); - w.domElement.classList.add('peditoritem'); - } - break; - - case 'color4': - uniformToUpdate = material.uniforms[name]; - if (uniformToUpdate && value != null) - { - var dummy = - { - color: 0xFF0000 - }; - // Extract RGB from the color4 value - const color3 = new THREE.Color(); - color3.fromArray(material.uniforms[name].value); - dummy.color = color3.getHex(); - let alphaValue = material.uniforms[name].value[3]; // Get alpha component - - // Add the RGB color picker as one item - let colorPicker = currentFolder.addColor(dummy, 'color').name(path + '.rgb') - .onChange(function (value) - { - const color3 = new THREE.Color(value); - // Update RGB while preserving alpha - material.uniforms[name].value[0] = color3.r; - material.uniforms[name].value[1] = color3.g; - material.uniforms[name].value[2] = color3.b; - }); - colorPicker.domElement.classList.add('peditoritem'); - - // Add the alpha slider as a separate item at the same level - var alphaObj = { value: alphaValue }; - let alphaSlider = currentFolder.add(alphaObj, 'value', 0, 1, 0.01).name(path + '.alpha') - .onChange(function (value) - { - material.uniforms[name].value[3] = value; - }); - alphaSlider.domElement.classList.add('peditoritem'); - } - break; - - case 'matrix33': - case 'matrix44': - case 'samplerCube': - case 'filename': - break; - case 'string': - if (value != null) - { - var dummy = - { - thevalue: value - } - let item = currentFolder.add(dummy, 'thevalue'); - item.name(path); - item.disable(true); - item.domElement.classList.add('peditoritem'); - } - break; - default: - break; - } - } - } - }); - - if (logDetailedTime) - { - console.log(" - Editor update time: ", performance.now() - startTime, "ms"); - } - } - - // List of material assignments: { MaterialX node, geometry assignment string, and hardware shader } - _materials; - - // Fallback material if nothing was assigned explicitly - _defaultMaterial; -} - -/* - Viewer class - - Keeps track of local scene, and property editor as well as current MaterialX document - and associated material, shader and lighting information. -*/ -export class Viewer -{ - static create() - { - return new Viewer(); - } - - constructor() - { - this.scene = new Scene(); - this.editor = new Editor(); - this.materials.push(new Material()); - - this.fileLoader = new THREE.FileLoader(); - this.hdrLoader = new RGBELoader(); - } - - // - // Create shader generator, generation context and "base" document which - // contains the standard definition libraries and lighting elements. - // - async initialize(mtlxIn, renderer, radianceTexture, irradianceTexture, lightRigXml) - { - this.mx = mtlxIn; - - // Initialize base document - this.generator = this.mx.EsslShaderGenerator.create(); - this.genContext = new this.mx.GenContext(this.generator); - - this.document = this.mx.createDocument(); - this.stdlib = this.mx.loadStandardLibraries(this.genContext); - this.document.setDataLibrary(this.stdlib); - - this.initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml); - - radianceTexture.mapping = THREE.EquirectangularReflectionMapping; - this.getScene().setBackgroundTexture(radianceTexture); - } - - // - // Load in lighting rig document and register lights with generation context - // Initialize environment lighting (IBLs). - // - async initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml) - { - // Load lighting setup into document - const mx = this.getMx(); - this.lightRigDoc = mx.createDocument(); - await mx.readFromXmlString(this.lightRigDoc, lightRigXml); - this.document.importLibrary(this.lightRigDoc); - - // Register lights with generation context - this.lights = findLights(this.document); - this.lightData = registerLights(mx, this.lights, this.genContext); - - this.radianceTexture = prepareEnvTexture(radianceTexture, renderer.capabilities); - this.irradianceTexture = prepareEnvTexture(irradianceTexture, renderer.capabilities); - } - - getEditor() - { - return this.editor; - } - - getScene() - { - return this.scene; - } - - getMaterial() - { - return this.materials[0]; - } - - getFileLoader() - { - return this.fileLoader; - } - - getHdrLoader() - { - return this.hdrLoader; - } - - setDocument(doc) - { - this.doc = doc; - } - getDocument() - { - return this.doc; - } - - getLibrary() - { - return this.stdlib; - } - - getLightRig() - { - return this.lightRigDoc; - } - - getMx() - { - return this.mx; - } - - getGenerator() - { - return this.generator; - } - - getGenContext() - { - return this.genContext; - } - - getLights() - { - return this.lights; - } - - getLightData() - { - return this.lightData; - } - - getRadianceTexture() - { - return this.radianceTexture; - } - - getIrradianceTexture() - { - return this.irradianceTexture; - } - - // Three scene and materials. - scene = null; - materials = []; - - // Property editor - editor = null; - - // Utility loaders - fileloader = null; - hdrLoader = null; - - // MaterialX module, current document and support documents. - mx = null; - doc = null; - stdlib = null; - lightRigDoc = null; - - // MaterialX code generator and context - generator = null; - genContext = null; - - // Lighting information - lights = null; - lightData = null; - radianceTexture = null; - irradianceTexture = null; -} +// +// Copyright Contributors to the MaterialX Project +// SPDX-License-Identifier: Apache-2.0 +// + +import * as THREE from 'three'; +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; +import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'; + +import { prepareEnvTexture, getLightRotation, findLights, registerLights, getUniformValues } from './helper.js' +import { Group } from 'three'; +import GUI from 'lil-gui'; + +const ALL_GEOMETRY_SPECIFIER = "*"; +const NO_GEOMETRY_SPECIFIER = ""; +const DAG_PATH_SEPERATOR = "/"; + +// Logging toggle +var logDetailedTime = false; + +/* + Scene management +*/ +export class Scene +{ + constructor() + { + this._geometryURL = new URLSearchParams(document.location.search).get("geom"); + if (!this._geometryURL) + { + this._geometryURL = 'Geometry/shaderball.glb'; + } + } + + initialize() + { + this._scene = new THREE.Scene(); + this._scene.background = new THREE.Color(this.#_backgroundColor); + this._scene.background.convertSRGBToLinear(); + + const aspectRatio = window.innerWidth / window.innerHeight; + const cameraNearDist = 0.05; + const cameraFarDist = 100.0; + const cameraFOV = 60.0; + this._camera = new THREE.PerspectiveCamera(cameraFOV, aspectRatio, cameraNearDist, cameraFarDist); + + this.#_gltfLoader = new GLTFLoader(); + + this.#_normalMat = new THREE.Matrix3(); + this.#_viewProjMat = new THREE.Matrix4(); + this.#_worldViewPos = new THREE.Vector3(); + } + + // Set whether to flip UVs in V for loaded geometry + setFlipGeometryV(val) + { + this.#_flipV = val; + } + + // Get whether to flip UVs in V for loaded geometry + getFlipGeometryV() + { + return this.#_flipV; + } + + // Utility to perform geometry file load + loadGeometryFile(geometryFilename, loader) + { + return new Promise((resolve, reject) => + { + loader.load(geometryFilename, data => resolve(data), null, reject); + }); + } + + // + // Load in geometry specified by a given file name, + // then update the scene geometry and camera. + // + async loadGeometry(viewer, orbitControls) + { + var startTime = performance.now(); + var geomLoadTime = startTime; + + const gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_gltfLoader); + + const scene = this.getScene(); + while (scene.children.length > 0) + { + scene.remove(scene.children[0]); + } + + this.#_rootNode = null; + const 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); + } + else + { + this.#_rootNode = model; + } + scene.add(model); + + console.log("- Scene load time: ", performance.now() - geomLoadTime, "ms"); + + // Always reset controls based on camera for each load. + orbitControls.reset(); + this.updateScene(viewer, orbitControls); + + console.log("Total geometry load time: ", performance.now() - startTime, " ms."); + + viewer.getMaterial().clearSoloMaterialUI(); + viewer.getMaterial().updateMaterialAssignments(viewer, ""); + this.setUpdateTransforms(); + } + + // + // Update the geometry buffer, assigned materials, and camera controls. + // + updateScene(viewer, orbitControls) + { + var startUpdateSceneTime = performance.now(); + var uvTime = 0; + var normalTime = 0; + var tangentTime = 0; + var streamTime = 0; + var bboxTime = 0; + + var startBboxTime = performance.now(); + const bbox = new THREE.Box3().setFromObject(this._scene); + const bsphere = new THREE.Sphere(); + bbox.getBoundingSphere(bsphere); + bboxTime = performance.now() - startBboxTime; + + let theScene = viewer.getScene(); + let flipV = theScene.getFlipGeometryV(); + + + this._scene.traverse((child) => + { + if (child.isMesh) + { + var startUVTime = performance.now(); + if (!child.geometry.attributes.uv) + { + const posCount = child.geometry.attributes.position.count; + const uvs = []; + const pos = child.geometry.attributes.position.array; + + for (let i = 0; i < posCount; i++) + { + uvs.push((pos[i * 3] - bsphere.center.x) / bsphere.radius); + uvs.push((pos[i * 3 + 1] - bsphere.center.y) / bsphere.radius); + } + + child.geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), 2)); + } + else if (flipV) + { + const uvCount = child.geometry.attributes.position.count; + const uvs = child.geometry.attributes.uv.array; + for (let i = 0; i < uvCount; i++) + { + let v = 1.0 - (uvs[i * 2 + 1]); + uvs[i * 2 + 1] = v; + } + } + uvTime += performance.now() - startUVTime; + + if (!child.geometry.attributes.normal) + { + var startNormalTime = performance.new(); + child.geometry.computeVertexNormals(); + normalTime += performance.now() - startNormalTime; + } + + if (child.geometry.getIndex()) + { + if (!child.geometry.attributes.tangent) + { + var startTangentTime = performance.now(); + child.geometry.computeTangents(); + tangentTime += performance.now() - startTangentTime; + } + } + + // Use default MaterialX naming convention. + var startStreamTime = performance.now(); + child.geometry.attributes.i_position = child.geometry.attributes.position; + child.geometry.attributes.i_normal = child.geometry.attributes.normal; + child.geometry.attributes.i_tangent = child.geometry.attributes.tangent; + child.geometry.attributes.i_texcoord_0 = child.geometry.attributes.uv; + streamTime += performance.now() - startStreamTime; + } + }); + + console.log("- Stream update time: ", performance.now() - startUpdateSceneTime, "ms"); + if (logDetailedTime) + { + console.log(' - UV time: ', uvTime); + console.log(' - Normal time: ', normalTime); + console.log(' - Tangent time: ', tangentTime); + console.log(' - Stream Update time: ', streamTime); + console.log(' - Bounds compute time: ', bboxTime); + } + + // Update the background + this._scene.background = this.getBackground(); + + // Fit camera to model + const camera = this.getCamera(); + camera.position.y = bsphere.center.y; + camera.position.z = bsphere.radius * 2.0; + camera.updateProjectionMatrix(); + + orbitControls.target = bsphere.center; + orbitControls.update(); + } + + setUpdateTransforms() + { + this.#_updateTransforms = true; + } + + updateTransforms() + { + // Only update on demand versus continuously. + // Call setUpdateTransforms() to trigger an update here. + // Required for: scene geometry, camera change and viewport resize. + if (!this.#_updateTransforms) + { + return; + } + this.#_updateTransforms = false; + + const scene = this.getScene(); + const camera = this.getCamera(); + scene.traverse((child) => + { + if (child.isMesh) + { + const uniforms = child.material.uniforms; + if (uniforms) + { + uniforms.u_worldMatrix.value = child.matrixWorld; + uniforms.u_viewProjectionMatrix.value = this.#_viewProjMat.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); + + if (uniforms.u_viewPosition) + uniforms.u_viewPosition.value = camera.getWorldPosition(this.#_worldViewPos); + + if (uniforms.u_worldInverseTransposeMatrix) + uniforms.u_worldInverseTransposeMatrix.value = + new THREE.Matrix4().setFromMatrix3(this.#_normalMat.getNormalMatrix(child.matrixWorld)); + } + } + }); + } + + // Determine string DAG path based on individual node names. + getDagPath(node) + { + const rootNode = this.#_rootNode; + + let path = [node.name]; + while (node.parent) + { + node = node.parent; + if (node) + { + // Stop at the root of the scene read in. + if (node == rootNode) + { + break; + } + path.unshift(node.name); + } + } + return path; + } + + // Assign material shader to associated geometry + updateMaterial(matassign) + { + let assigned = 0; + + const shader = matassign.getShader(); + const material = matassign.getMaterial().getName(); + const geometry = matassign.getGeometry(); + const collection = matassign.getCollection(); + + const scene = this.getScene(); + const camera = this.getCamera(); + scene.traverse((child) => + { + if (child.isMesh) + { + const dagPath = this.getDagPath(child).join('/'); + + // Note that this is a very simplistic + // assignment resolve and assumes basic + // regular expression name match. + let matches = (geometry == ALL_GEOMETRY_SPECIFIER); + if (!matches) + { + if (collection) + { + if (collection.matchesGeomString(dagPath)) + { + matches = true; + } + } + else + { + if (geometry != NO_GEOMETRY_SPECIFIER) + { + const paths = geometry.split(','); + for (let path of paths) + { + if (dagPath.match(path)) + { + matches = true; + break; + } + } + } + } + } + if (matches) + { + child.material = shader; + assigned++; + } + } + }); + + return assigned; + } + + updateCamera() + { + const camera = this.getCamera(); + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + } + + getScene() + { + return this._scene; + } + + getCamera() + { + return this._camera; + } + + getGeometryURL() + { + return this._geometryURL; + } + + setGeometryURL(url) + { + this._geometryURL = url; + } + + setBackgroundTexture(texture) + { + this.#_backgroundTexture = texture; + } + + getShowBackgroundTexture() + { + return this.#_showBackgroundTexture; + } + + setShowBackgroundTexture(enable) + { + this.#_showBackgroundTexture = enable; + } + + getBackground() + { + if (this.#_backgroundTexture && this.#_showBackgroundTexture) + { + return this.#_backgroundTexture; + } + var color = new THREE.Color(this.#_backgroundColor); + color.convertSRGBToLinear(); + return color; + } + + toggleBackgroundTexture() + { + this.#_showBackgroundTexture = !this.#_showBackgroundTexture; + this._scene.background = this.getBackground(); + } + + // Geometry file + #_geometryURL = ''; + // Geometry loader + #_gltfLoader = null; + // Flip V coordinate of texture coordinates. + // Set to true to be consistent with desktop viewer. + #_flipV = true; + + // Scene + #_scene = null; + + // Camera + #_camera = null; + + // Background color + #_backgroundColor = 0x4c4c52; + + // Background texture + #_backgroundTexture = null; + #_showBackgroundTexture = true; + + // Transform matrices + #_normalMat = new THREE.Matrix3(); + #_viewProjMat = new THREE.Matrix4(); + #_worldViewPos = new THREE.Vector3(); + #_updateTransforms = true; + + // Root node of imported scene + #_rootNode = null; +} + +/* + Property editor +*/ +export class Editor +{ + // Initialize the editor, clearing any elements from previous materials. + initialize() + { + Array.from(document.getElementsByClassName('lil-gui')).forEach( + function (element, index, array) + { + if (element.className) + { + element.remove(); + } + } + ); + + this._gui = new GUI({ title: "Property Editor" }); + this._gui.close(); + } + + // Update ui properties + // - Hide close button + // - Update transparency so scene shows through if overlapping + updateProperties(targetOpacity = 1) + { + // Set opacity + Array.from(document.getElementsByClassName('dg')).forEach( + function (element, index, array) + { + element.style.opacity = targetOpacity; + } + ); + } + + getGUI() + { + return this._gui; + } + + _gui = null; +} + +class MaterialAssign +{ + constructor(material, geometry, collection) + { + this._material = material; + this._geometry = geometry; + this._collection = collection; + this._shader = null; + this._materialUI = null; + } + + setMaterialUI(value) + { + this._materialUI = value; + } + + getMaterialUI() + { + return this._materialUI; + } + + setShader(shader) + { + this._shader = shader; + } + + getShader() + { + return this._shader; + } + + getMaterial() + { + return this._material; + } + + getGeometry() + { + return this._geometry; + } + + setGeometry(value) + { + this._geometry = value; + } + + getCollection() + { + return this._collection; + } + + // MaterialX material node name + _material; + + // MaterialX assignment geometry string + _geometry; + + // MaterialX assignment collection + _collection; + + // THREE.JS shader + _shader; +} + +export class Material +{ + constructor() + { + this._materials = []; + this._defaultMaterial = null; + this._soloMaterial = ""; + } + + clearMaterials() + { + this._materials.length = 0; + this._defaultMaterial = null; + this._soloMaterial = ""; + } + + setSoloMaterial(value) + { + this._soloMaterial = value; + } + + getSoloMaterial() + { + return this._soloMaterial; + } + + // If no material file is selected, we programmatically create a default material as a fallback + static createFallbackMaterial(doc) + { + let ssNode = doc.getChild('Generated_Default_Shader'); + if (ssNode) + { + return ssNode; + } + const ssName = 'Generated_Default_Shader'; + ssNode = doc.addChildOfCategory('standard_surface', ssName); + ssNode.setType('surfaceshader'); + const smNode = doc.addChildOfCategory('surfacematerial', 'Default'); + smNode.setType('material'); + const shaderElement = smNode.addInput('surfaceshader'); + shaderElement.setType('surfaceshader'); + shaderElement.setNodeName(ssName); + + return ssNode; + } + + async loadMaterialFile(loader, materialFilename) + { + return new Promise((resolve, reject) => + { + loader.load(materialFilename, data => resolve(data), null, reject); + }); + } + + async loadMaterials(viewer, materialFilename) + { + var startTime = performance.now(); + + const mx = viewer.getMx(); + + // Re-initialize document + var startDocTime = performance.now(); + var doc = mx.createDocument(); + doc.importLibrary(viewer.getLibrary()); + viewer.setDocument(doc); + + const fileloader = viewer.getFileLoader(); + + let mtlxMaterial = await viewer.getMaterial().loadMaterialFile(fileloader, materialFilename); + + // Load lighting setup into document + doc.importLibrary(viewer.getLightRig()); + + console.log("- Material document load time: ", performance.now() - startDocTime, "ms."); + + // Set search path. Assumes images are relative to current file + // location. + if (!materialFilename) materialFilename = "/"; + const paths = materialFilename.split('/'); + paths.pop(); + const searchPath = paths.join('/'); + + // Load material + if (mtlxMaterial) + await mx.readFromXmlString(doc, mtlxMaterial, searchPath); + else + Material.createFallbackMaterial(doc); + + // Check if there are any looks defined in the document + // If so then traverse the looks for all material assignments. + // Generate code and compile for any associated surface shader + // and assign to the associated geometry. If there are no looks + // then the first material is found and assignment to all the + // geometry. + this.clearMaterials(); + var looks = doc.getLooks(); + if (looks.length) + { + for (let look of looks) + { + const materialAssigns = look.getMaterialAssigns(); + for (let materialAssign of materialAssigns) + { + let matName = materialAssign.getMaterial(); + if (matName) + { + let mat = doc.getChild(matName); + var shader; + if (mat) + { + var shaders = mx.getShaderNodes(mat); + if (shaders.length) + { + shader = shaders[0]; + } + } + let collection = materialAssign.getCollection(); + let geom = materialAssign.getGeom(); + let newAssignment; + if (collection || geom) + { + // Remove leading "/" from collection and geom for + // later assignment comparison checking + if (collection && collection.charAt(0) == "/") + { + collection = collection.slice(1); + } + if (geom && geom.charAt(0) == "/") + { + geom = geom.slice(1); + } + newAssignment = new MaterialAssign(shader, geom, collection); + } + else + { + newAssignment = new MaterialAssign(shader, NO_GEOMETRY_SPECIFIER, null); + } + + if (newAssignment) + { + this._materials.push(newAssignment); + } + } + } + } + } + else + { + // Search for any surface shaders. The first found + // is assumed to be assigned to the entire scene + // The identifier used is "*" to mean the entire scene. + const materialNodes = doc.getMaterialNodes(); + let shaderList = []; + let foundRenderable = false; + for (let i = 0; i < materialNodes.length; ++i) + { + let materialNode = materialNodes[i]; + if (materialNode) + { + console.log('Scan material: ', materialNode.getNamePath()); + let shaderNodes = mx.getShaderNodes(materialNode) + if (shaderNodes.length > 0) + { + let shaderNodePath = shaderNodes[0].getNamePath() + if (!shaderList.includes(shaderNodePath)) + { + let assignment = NO_GEOMETRY_SPECIFIER; + if (foundRenderable == false) + { + assignment = ALL_GEOMETRY_SPECIFIER; + foundRenderable = true; + } + console.log('-- add shader: ', shaderNodePath); + shaderList.push(shaderNodePath); + this._materials.push(new MaterialAssign(shaderNodes[0], assignment)); + } + } + } + } + const nodeGraphs = doc.getNodeGraphs(); + for (let i = 0; i < nodeGraphs.length; ++i) + { + let nodeGraph = nodeGraphs[i]; + if (nodeGraph) + { + if (nodeGraph.hasAttribute('nodedef') || nodeGraph.hasSourceUri()) + { + continue; + } + // Skip any nodegraph that is connected to something downstream + if (nodeGraph.getDownstreamPorts().length > 0) + { + continue + } + let outputs = nodeGraph.getOutputs(); + for (let j = 0; j < outputs.length; ++j) + { + let output = outputs[j]; + { + let assignment = NO_GEOMETRY_SPECIFIER; + if (foundRenderable == false) + { + assignment = ALL_GEOMETRY_SPECIFIER; + foundRenderable = true; + } + let newMat = new MaterialAssign(output, assignment, null); + this._materials.push(newMat); + } + } + } + } + const outputs = doc.getOutputs(); + for (let i = 0; i < outputs.length; ++i) + { + let output = outputs[i]; + if (output) + { + let assignment = NO_GEOMETRY_SPECIFIER; + if (foundRenderable == false) + { + assignment = ALL_GEOMETRY_SPECIFIER; + foundRenderable = true; + } + this._materials.push(new MaterialAssign(output, assignment)); + } + } + + const shaderNodes = []; + for (let i = 0; i < shaderNodes.length; ++i) + { + let shaderNode = shaderNodes[i]; + let shaderNodePath = shaderNode.getNamePath() + if (!shaderList.includes(shaderNodePath)) + { + let assignment = NO_GEOMETRY_SPECIFIER; + if (foundRenderable == false) + { + assignment = ALL_GEOMETRY_SPECIFIER; + foundRenderable = true; + } + shaderList.push(shaderNodePath); + this._materials.push(new MaterialAssign(shaderNode, assignment)); + } + } + } + + // Assign to default material if none found + if (this._materials.length == 0) + { + const defaultNode = Material.createFallbackMaterial(doc); + this._materials.push(new MaterialAssign(defaultNode, ALL_GEOMETRY_SPECIFIER)); + } + + // Create a new shader for each material node. + // Only create the shader once even if assigned more than once. + var startGenTime = performance.now(); + let shaderMap = new Map(); + let closeUI = false; + for (let matassign of this._materials) + { + // Need to use path vs name to get a unique key. + let materialName = matassign.getMaterial().getNamePath(); + let shader = shaderMap[materialName]; + if (!shader) + { + shader = viewer.getMaterial().generateMaterial(matassign, viewer, searchPath, closeUI); + shaderMap[materialName] = shader; + } + matassign.setShader(shader); + closeUI = true; + } + console.log("- Generate (", this._materials.length, ") shader(s) time: ", performance.now() - startGenTime, " ms.",); + + // Update scene shader assignments + this.updateMaterialAssignments(viewer, ""); + + // Mark transform update + viewer.getScene().setUpdateTransforms(); + + console.log("Total material time: ", (performance.now() - startTime), "ms"); + } + + // + // Update the assignments for scene objects based on the + // material assignment information stored in the viewer. + // Note: If none of the MaterialX assignments match the geometry + // in the scene, then the first material assignment shader is assigned + // to the entire scene. + // + async updateMaterialAssignments(viewer, soloMaterial) + { + console.log("Update material assignments. Solo=", soloMaterial); + var startTime = performance.now(); + + let assigned = 0; + let assignedSolo = false; + for (let matassign of this._materials) + { + if (matassign.getShader()) + { + if (soloMaterial.length) + { + if (matassign.getMaterial().getNamePath() == soloMaterial) + { + let temp = matassign.getGeometry(); + matassign.setGeometry(ALL_GEOMETRY_SPECIFIER); + assigned += viewer.getScene().updateMaterial(matassign); + matassign.setGeometry(temp); + assignedSolo = true; + break + } + } + else + { + assigned += viewer.getScene().updateMaterial(matassign); + } + } + } + if (assigned == 0 && this._materials.length) + { + this._defaultMaterial = new MaterialAssign(this._materials[0].getMaterial(), ALL_GEOMETRY_SPECIFIER); + this._defaultMaterial.setShader(this._materials[0].getShader()); + viewer.getScene().updateMaterial(this._defaultMaterial); + } + + if (assigned > 0) + { + console.log('Material assignment time: ', performance.now() - startTime, " ms."); + } + } + + // + // Generate a new material for a given element + // + generateMaterial(matassign, viewer, searchPath, closeUI) + { + var elem = matassign.getMaterial(); + + var startGenerateMat = performance.now(); + + const mx = viewer.getMx(); + const textureLoader = new THREE.TextureLoader(); + + const lights = viewer.getLights(); + const lightData = viewer.getLightData(); + const radianceTexture = viewer.getRadianceTexture(); + const irradianceTexture = viewer.getIrradianceTexture(); + const gen = viewer.getGenerator(); + const genContext = viewer.getGenContext(); + genContext.getOptions().hwSrgbEncodeOutput = true; + + // Perform transparency check on renderable item + var startTranspCheckTime = performance.now(); + const isTransparent = mx.isTransparentSurface(elem, gen.getTarget()); + genContext.getOptions().hwTransparency = isTransparent; + // Always set to complete. + // Can consider option to set to reduced as the parsing of large numbers of uniforms (e.g. on shading models) + // can be quite expensive. + genContext.getOptions().shaderInterfaceType = mx.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE; + + if (logDetailedTime) + console.log(" - Transparency check time: ", performance.now() - startTranspCheckTime, "ms"); + + // Generate GLES code + var startMTLXGenTime = performance.now(); + let shader = gen.generate(elem.getNamePath(), elem, genContext); + if (logDetailedTime) + console.log(" - MaterialX gen time: ", performance.now() - startMTLXGenTime, "ms"); + + var startUniformUpdate = performance.now(); + + // Get shaders and uniform values + let vShader = shader.getSourceCode("vertex"); + let fShader = shader.getSourceCode("pixel"); + + let theScene = viewer.getScene(); + let flipV = theScene.getFlipGeometryV(); + let uniforms = { + ...getUniformValues(shader.getStage('vertex'), textureLoader, searchPath, flipV), + ...getUniformValues(shader.getStage('pixel'), textureLoader, searchPath, flipV), + } + + Object.assign(uniforms, { + u_numActiveLightSources: { value: lights.length }, + u_lightData: { value: lightData }, + u_envMatrix: { value: getLightRotation() }, + u_envRadiance: { value: radianceTexture }, + u_envRadianceMips: { value: Math.trunc(Math.log2(Math.max(radianceTexture.image.width, radianceTexture.image.height))) + 1 }, + u_envRadianceSamples: { value: 16 }, + u_envIrradiance: { value: irradianceTexture }, + u_refractionEnv: { value: true } + }); + + // Create Three JS Material + let newMaterial = new THREE.RawShaderMaterial({ + uniforms: uniforms, + vertexShader: vShader, + fragmentShader: fShader, + transparent: isTransparent, + blendEquation: THREE.AddEquation, + blendSrc: THREE.OneMinusSrcAlphaFactor, + blendDst: THREE.SrcAlphaFactor, + side: THREE.DoubleSide + }); + + if (logDetailedTime) + console.log(" - Three material update time: ", performance.now() - startUniformUpdate, "ms"); + + // Update property editor + const gui = viewer.getEditor().getGUI(); + this.updateEditor(matassign, shader, newMaterial, gui, closeUI, viewer); + + if (logDetailedTime) + console.log("- Per material generate time: ", performance.now() - startGenerateMat, "ms"); + + return newMaterial; + } + + clearSoloMaterialUI() + { + for (let i = 0; i < this._materials.length; ++i) + { + let matassign = this._materials[i]; + let matUI = matassign.getMaterialUI(); + if (matUI) + { + let matTitle = matUI.domElement.getElementsByClassName('title')[0]; + matTitle.classList.remove('peditor_material_assigned'); + let img = matTitle.getElementsByTagName('img')[0]; + img.src = 'public/shader_ball.svg'; + //matTitle.classList.remove('peditor_material_unassigned'); + } + } + } + + static updateSoloMaterial(viewer, elemPath, materials, event) + { + // Prevent the event from being passed to parent folder + event.stopPropagation(); + + for (let i = 0; i < materials.length; ++i) + { + let matassign = materials[i]; + // Need to use path vs name to get a unique key. + let materialName = matassign.getMaterial().getNamePath(); + var matUI = matassign.getMaterialUI(); + let matTitle = matUI.domElement.getElementsByClassName('title')[0]; + let img = matTitle.getElementsByTagName('img')[0]; + if (materialName == elemPath) + { + if (this._soloMaterial == elemPath) + { + img.src = 'public/shader_ball.svg'; + matTitle.classList.remove('peditor_material_assigned'); + this._soloMaterial = ""; + } + else + { + img.src = 'public/shader_ball2.svg'; + matTitle.classList.add('peditor_material_assigned'); + this._soloMaterial = elemPath; + } + } + else + { + img.src = 'public/shader_ball.svg'; + matTitle.classList.remove('peditor_material_assigned'); + } + } + viewer.getMaterial().updateMaterialAssignments(viewer, this._soloMaterial); + viewer.getScene().setUpdateTransforms(); + } + + // + // Update property editor for a given MaterialX element, it's shader, and + // Three material + // + updateEditor(matassign, shader, material, gui, closeUI, viewer) + { + var elem = matassign.getMaterial(); + var materials = this._materials; + + const DEFAULT_MIN = 0; + const DEFAULT_MAX = 100; + + var startTime = performance.now(); + + const elemPath = elem.getNamePath(); + + // Create and cache associated UI + var matUI = gui.addFolder(elemPath); + matassign.setMaterialUI(matUI); + + let matTitle = matUI.domElement.getElementsByClassName('title')[0]; + // Add a icon to the title to allow for assigning the material to geometry + // Clicking on the icon will "solo" the material to the geometry. + // Clicking on the title will open/close the material folder. + matTitle.innerHTML = "" + elem.getNamePath(); + let img = matTitle.getElementsByTagName('img')[0]; + if (img) + { + // Add event listener to icon to call updateSoloMaterial function + img.addEventListener('click', function (event) + { + Material.updateSoloMaterial(viewer, elemPath, materials, event); + }); + } + + if (closeUI) + { + matUI.close(); + } + const uniformBlocks = Object.values(shader.getStage('pixel').getUniformBlocks()); + var uniformToUpdate; + const ignoreList = ['u_envRadianceMips', 'u_envRadianceSamples', 'u_alphaThreshold']; + + var folderList = new Map(); + folderList[elemPath] = matUI; + + uniformBlocks.forEach(uniforms => + { + if (!uniforms.empty()) + { + for (let i = 0; i < uniforms.size(); ++i) + { + const variable = uniforms.get(i); + const value = variable.getValue()?.getData(); + let name = variable.getVariable(); + + if (ignoreList.includes(name)) + { + continue; + } + + let currentFolder = matUI; + let currentElemPath = variable.getPath(); + if (!currentElemPath || currentElemPath.length == 0) + { + continue; + } + let currentElem = elem.getDocument().getDescendant(currentElemPath); + if (!currentElem) + { + continue; + } + + // Skip non-input types and anything > 2 levels deep + if (!currentElem.asAInput() || currentElem.getNamePath().split('/').length > 2) + { + continue; + } + + let currentNode = null; + if (currentElem.getParent() && currentElem.getParent().getNamePath() != "") + { + currentNode = currentElem.getParent(); + } + let uiname = ""; + let nodeDefInput = null; + if (currentNode) + { + + let currentNodePath = currentNode.getNamePath(); + var pathSplit = currentNodePath.split('/'); + if (pathSplit.length) + { + currentNodePath = pathSplit[0]; + } + currentFolder = folderList[currentNodePath]; + if (!currentFolder) + { + currentFolder = matUI.addFolder(currentNodePath); + folderList[currentNodePath] = currentFolder; + } + + // Check for ui attributes + var nodeDef = currentNode.getNodeDef(); + if (nodeDef) + { + // Remove node name from shader uniform name for non root nodes + let lookup_name = name.replace(currentNode.getName() + '_', ''); + nodeDefInput = nodeDef.getActiveInput(lookup_name); + if (nodeDefInput) + { + uiname = nodeDefInput.getAttribute('uiname'); + let uifolderName = nodeDefInput.getAttribute('uifolder'); + if (uifolderName && uifolderName.length) + { + let newFolderName = currentNodePath + '/' + uifolderName; + currentFolder = folderList[newFolderName]; + if (!currentFolder) + { + currentFolder = matUI.addFolder(uifolderName); + currentFolder.domElement.classList.add('peditorfolder'); + folderList[newFolderName] = currentFolder; + } + } + } + } + } + + // Determine UI name to use + let path = name; + let interfaceName = currentElem.getAttribute("interfacename"); + if (interfaceName && interfaceName.length) + { + const graph = currentNode.getParent(); + if (graph) + { + const graphInput = graph.getInput(interfaceName); + if (graphInput) + { + let uiname = graphInput.getAttribute('uiname'); + if (uiname.length) + { + path = uiname; + } + else + { + path = graphInput.getName(); + } + } + } + else + { + path = interfaceName; + } + } + else + { + if (!uiname) + { + uiname = currentElem.getAttribute('uiname'); + } + if (uiname && uiname.length) + { + path = uiname; + } + } + + // Skip if already added to current folder + let found = false; + for (let i = 0; i < currentFolder.children.length; ++i) + { + if (currentFolder.children[i]._name == path) + { + found = true; + break; + } + } + if (found) + { + continue; + } + + switch (variable.getType().getName()) + { + case 'float': + uniformToUpdate = material.uniforms[name]; + if (uniformToUpdate && value != null) + { + var minValue = DEFAULT_MIN; + if (value < minValue) + { + minValue = value; + } + var maxValue = DEFAULT_MAX; + if (value > maxValue) + { + maxValue = value; + } + var step = 0; + if (nodeDefInput) + { + if (nodeDefInput.hasAttribute('uisoftmin')) + minValue = parseFloat(nodeDefInput.getAttribute('uisoftmin')); + else if (nodeDefInput.hasAttribute('uimin')) + minValue = parseFloat(nodeDefInput.getAttribute('uimin')); + + if (nodeDefInput.hasAttribute('uisoftmax')) + maxValue = parseFloat(nodeDefInput.getAttribute('uisoftmax')); + else if (nodeDefInput.hasAttribute('uimax')) + maxValue = parseFloat(nodeDefInput.getAttribute('uimax')); + + if (nodeDefInput.hasAttribute('uistep')) + step = parseFloat(nodeDefInput.getAttribute('uistep')); + } + if (step == 0) + { + step = (maxValue - minValue) / 1000.0; + } + const w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path); + w.domElement.classList.add('peditoritem'); + } + break; + + case 'integer': + uniformToUpdate = material.uniforms[name]; + if (uniformToUpdate && value != null) + { + var minValue = DEFAULT_MIN; + if (value < minValue) + { + minValue = value; + } + var maxValue = DEFAULT_MAX; + if (value > maxValue) + { + maxValue = value; + } + var step = 0; + var enumList = [] + var enumValues = [] + if (nodeDefInput) + { + if (nodeDefInput.hasAttribute('enum')) + { + // Get enum and enum values attributes (if present) + enumList = nodeDefInput.getAttribute('enum').split(','); + if (nodeDefInput.hasAttribute('enumvalues')) + { + enumValues = nodeDefInput.getAttribute('enumvalues').split(',').map(Number); + } + } + else + { + if (nodeDefInput.hasAttribute('uisoftmin')) + minValue = parseInt(nodeDefInput.getAttribute('uisoftmin')); + else if (nodeDefInput.hasAttribute('uimin')) + minValue = parseInt(nodeDefInput.getAttribute('uimin')); + + if (nodeDefInput.hasAttribute('uisoftmax')) + maxValue = parseInt(nodeDefInput.getAttribute('uisoftmax')); + else if (nodeDefInput.hasAttribute('uimax')) + maxValue = parseInt(nodeDefInput.getAttribute('uimax')); + + if (nodeDefInput.hasAttribute('uistep')) + step = parseInt(nodeDefInput.getAttribute('uistep')); + } + } + if (enumList.length == 0) + { + if (step == 0) + { + step = 1 / (maxValue - minValue); + step = Math.ceil(step); + if (step == 0) + { + step = 1; + } + } + } + if (enumList.length == 0) + { + let w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path); + w.domElement.classList.add('peditoritem'); + } + else + { + // Map enumList strings to values + // Map to 0..N if no values are specified via enumvalues attribute + if (enumValues.length == 0) + { + for (let i = 0; i < enumList.length; ++i) + { + enumValues.push(i); + } + } + const enumeration = {}; + enumList.forEach((str, index) => + { + enumeration[str] = enumValues[index]; + }); + + // Function to handle enum drop-down + function handleDropdownChange(value) + { + if (material.uniforms[name]) + { + material.uniforms[name].value = value; + } + } + const defaultOption = enumList[value]; // Set the default selected option + const dropdownController = currentFolder.add(enumeration, defaultOption, enumeration).name(path); + dropdownController.onChange(handleDropdownChange); + dropdownController.domElement.classList.add('peditoritem'); + } + } + break; + + case 'boolean': + uniformToUpdate = material.uniforms[name]; + if (uniformToUpdate && value != null) + { + let w = currentFolder.add(material.uniforms[name], 'value').name(path); + w.domElement.classList.add('peditoritem'); + } + break; + + case 'vector2': + case 'vector3': + case 'vector4': + uniformToUpdate = material.uniforms[name]; + if (uniformToUpdate && value != null) + { + var minValue = [DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN]; + var maxValue = [DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX]; + var step = [0, 0, 0, 0]; + + if (nodeDefInput) + { + if (nodeDefInput.hasAttribute('uisoftmin')) + minValue = nodeDefInput.getAttribute('uisoftmin').split(',').map(Number); + else if (nodeDefInput.hasAttribute('uimin')) + minValue = nodeDefInput.getAttribute('uimin').split(',').map(Number); + + if (nodeDefInput.hasAttribute('uisoftmax')) + maxValue = nodeDefInput.getAttribute('uisoftmax').split(',').map(Number); + else if (nodeDefInput.hasAttribute('uimax')) + maxValue = nodeDefInput.getAttribute('uimax').split(',').map(Number); + + if (nodeDefInput.hasAttribute('uistep')) + step = nodeDefInput.getAttribute('uistep').split(',').map(Number); + } + for (let i = 0; i < 4; ++i) + { + if (step[i] == 0) + { + step[i] = 1 / (maxValue[i] - minValue[i]); + } + } + + const keyString = ["x", "y", "z", "w"]; + let vecFolder = currentFolder.addFolder(path); + Object.keys(material.uniforms[name].value).forEach((key) => + { + let w = vecFolder.add(material.uniforms[name].value, + key, minValue[key], maxValue[key], step[key]).name(keyString[key]); + w.domElement.classList.add('peditoritem'); + }) + } + break; + + case 'color3': + // Irksome way to map arrays to colors and back + uniformToUpdate = material.uniforms[name]; + if (uniformToUpdate && value != null) + { + var dummy = + { + color: 0xFF0000 + }; + const color3 = new THREE.Color(dummy.color); + color3.fromArray(material.uniforms[name].value); + dummy.color = color3.getHex(); + let w = currentFolder.addColor(dummy, 'color').name(path) + .onChange(function (value) + { + const color3 = new THREE.Color(value); + material.uniforms[name].value.set(color3.toArray()); + }); + w.domElement.classList.add('peditoritem'); + } + break; + + case 'color4': + break; + + case 'matrix33': + case 'matrix44': + case 'samplerCube': + case 'filename': + break; + case 'string': + if (value != null) + { + var dummy = + { + thevalue: value + } + let item = currentFolder.add(dummy, 'thevalue'); + item.name(path); + item.disable(true); + item.domElement.classList.add('peditoritem'); + } + break; + default: + break; + } + } + } + }); + + if (logDetailedTime) + { + console.log(" - Editor update time: ", performance.now() - startTime, "ms"); + } + } + + // List of material assignments: { MaterialX node, geometry assignment string, and hardware shader } + _materials; + + // Fallback material if nothing was assigned explicitly + _defaultMaterial; +} + +/* + Viewer class + + Keeps track of local scene, and property editor as well as current MaterialX document + and assocaited material, shader and lighting information. +*/ +export class Viewer +{ + static create() + { + return new Viewer(); + } + + constructor() + { + this.scene = new Scene(); + this.editor = new Editor(); + this.materials.push(new Material()); + + this.fileLoader = new THREE.FileLoader(); + this.hdrLoader = new RGBELoader(); + } + + // + // Create shader generator, generation context and "base" document which + // contains the standard definition libraries and lighting elements. + // + async initialize(mtlxIn, renderer, radianceTexture, irradianceTexture, lightRigXml) + { + this.mx = mtlxIn; + + // Initialize base document + this.generator = new this.mx.EsslShaderGenerator(); + this.genContext = new this.mx.GenContext(this.generator); + + this.document = this.mx.createDocument(); + this.stdlib = this.mx.loadStandardLibraries(this.genContext); + this.document.importLibrary(this.stdlib); + + this.initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml); + + radianceTexture.mapping = THREE.EquirectangularReflectionMapping; + this.getScene().setBackgroundTexture(radianceTexture); + } + + // + // Load in lighting rig document and register lights with generation context + // Initialize environment lighting (IBLs). + // + async initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml) + { + // Load lighting setup into document + const mx = this.getMx(); + this.lightRigDoc = mx.createDocument(); + await mx.readFromXmlString(this.lightRigDoc, lightRigXml); + this.document.importLibrary(this.lightRigDoc); + + // Register lights with generation context + this.lights = findLights(this.document); + this.lightData = registerLights(mx, this.lights, this.genContext); + + this.radianceTexture = prepareEnvTexture(radianceTexture, renderer.capabilities); + this.irradianceTexture = prepareEnvTexture(irradianceTexture, renderer.capabilities); + } + + getEditor() + { + return this.editor; + } + + getScene() + { + return this.scene; + } + + getMaterial() + { + return this.materials[0]; + } + + getFileLoader() + { + return this.fileLoader; + } + + getHdrLoader() + { + return this.hdrLoader; + } + + setDocument(doc) + { + this.doc = doc; + } + getDocument() + { + return this.doc; + } + + getLibrary() + { + return this.stdlib; + } + + getLightRig() + { + return this.lightRigDoc; + } + + getMx() + { + return this.mx; + } + + getGenerator() + { + return this.generator; + } + + getGenContext() + { + return this.genContext; + } + + getLights() + { + return this.lights; + } + + getLightData() + { + return this.lightData; + } + + getRadianceTexture() + { + return this.radianceTexture; + } + + getIrradianceTexture() + { + return this.irradianceTexture; + } + + // Three scene and materials. + scene = null; + materials = []; + + // Property editor + editor = null; + + // Utility loaders + fileloader = null; + hdrLoader = null; + + // MaterialX module, current document and support documents. + mx = null; + doc = null; + stdlib = null; + lightRigDoc = null; + + // MaterialX code generator and context + generator = null; + genContext = null; + + // Lighting information + lights = null; + lightData = null; + radianceTexture = null; + irradianceTexture = null; +} diff --git a/MaterialX/javascript/MaterialXView/webpack.config.js b/MaterialX/javascript/MaterialXView/webpack.config.js old mode 100644 new mode 100755 index b3f0e33..688877a --- a/MaterialX/javascript/MaterialXView/webpack.config.js +++ b/MaterialX/javascript/MaterialXView/webpack.config.js @@ -1,78 +1,92 @@ -const path = require('path'); -const fs = require('fs'); -const CopyPlugin = require("copy-webpack-plugin"); -const HtmlWebpackPlugin = require('html-webpack-plugin') - -// Load material configuration from external JSON file -const materialConfig = JSON.parse(fs.readFileSync('./example_materials.json', 'utf8')); - -// Function to process materials from a given path -function processMaterialPath(materialPath, baseURL) { - const dirent = fs.readdirSync(materialPath).filter( - function (file) { if (file.lastIndexOf(".mtlx") > -1) return file; } - ); - return dirent.map((fileName) => ({ - name: fileName, - value: `${baseURL}/${fileName}` - })); -} - -// Generate materials array from configuration -let materials = []; -materialConfig.materials.forEach(materialType => { - const materialFiles = processMaterialPath(materialType.path, materialType.baseURL); - materials = materials.concat(materialFiles); -}); - -const geometryFiles = "../../resources/Geometry"; -const geometryFilesURL = "Geometry"; -dirent = fs.readdirSync(geometryFiles).filter( - function (file) { if (file.lastIndexOf(".glb") > -1) return file; } -) -let geometry = dirent - .map((fileName) => ({ name: fileName, value: `${geometryFilesURL}/${fileName}` })); - -module.exports = { - entry: './source/index.js', - output: { - filename: 'main.js', - path: path.resolve(__dirname, 'dist') - }, - mode: "development", - plugins: [ - new HtmlWebpackPlugin({ - templateParameters: { - materials, - geometry - }, - template: 'index.ejs' - }), - new CopyPlugin({ - patterns: [ - { - context: "../../resources/Images", - from: "*.*", - to: "Images", - }, - { - context: "../../resources/Geometry/", - from: "*.glb", - to: "Geometry", - }, - { from: "./public", to: 'public' }, - { context: "../../resources/Lights", from: "*.*", to: "Lights" }, - { context: "../../resources/Lights/irradiance", from: "*.*", to: "Lights/irradiance" }, - // Dynamically generate material copy patterns from configuration - ...materialConfig.materials.map(materialType => ({ - from: materialType.path, - to: materialType.baseURL - })), - { from: "../build/bin/JsMaterialXCore.wasm" }, - { from: "../build/bin/JsMaterialXCore.js" }, - { from: "../build/bin/JsMaterialXGenShader.wasm" }, - { from: "../build/bin/JsMaterialXGenShader.js" }, - { from: "../build/bin/JsMaterialXGenShader.data" }, - ], - }), - ] -}; +const path = require('path'); +const fs = require('fs'); +const CopyPlugin = require("copy-webpack-plugin"); +const HtmlWebpackPlugin = require('html-webpack-plugin') + +const stdSurfaceMaterials = "../../resources/Materials/Examples/StandardSurface"; +const stdSurfaceMaterialsBaseURL = "Materials/Examples/StandardSurface"; +let dirent = fs.readdirSync(stdSurfaceMaterials).filter( + function (file) { if (file.lastIndexOf(".mtlx") > -1) return file; } +) +let materials = dirent + .map((fileName) => ({ name: fileName, value: `${stdSurfaceMaterialsBaseURL}/${fileName}` })); + +const usdSurfaceMaterials = "../../resources/Materials/Examples/UsdPreviewSurface"; +const usdSurfaceMaterialsBaseURL = "Materials/Examples/UsdPreviewSurface"; +dirent = fs.readdirSync(usdSurfaceMaterials).filter( + function (file) { if (file.lastIndexOf(".mtlx") > -1) return file; } +) +let usdMaterials = dirent + .map((fileName) => ({ name: fileName, value: `${usdSurfaceMaterialsBaseURL}/${fileName}` })); + +const gltfPbrMaterials = "../../resources/Materials/Examples/GltfPbr"; +const gltfPbrMaterialsBaseURL = "Materials/Examples/GltfPbr"; +dirent = fs.readdirSync(gltfPbrMaterials).filter( + function (file) { if (file.lastIndexOf(".mtlx") > -1) return file; } +) +let gltfMaterials = dirent + .map((fileName) => ({ name: fileName, value: `${gltfPbrMaterialsBaseURL}/${fileName}` })); + +const openPbrMaterials = "../../resources/Materials/Examples/OpenPbr"; +const openPbrMaterialsBaseURL = "Materials/Examples/OpenPbr"; +dirent = fs.readdirSync(openPbrMaterials).filter( + function (file) { if (file.lastIndexOf(".mtlx") > -1) return file; } +) +let openMaterials = dirent + .map((fileName) => ({ name: fileName, value: `${openPbrMaterialsBaseURL}/${fileName}` })); + +materials = materials.concat(usdMaterials); +materials = materials.concat(gltfMaterials); +materials = materials.concat(openMaterials); + +const geometryFiles = "../../resources/Geometry"; +const geometryFilesURL = "Geometry"; +dirent = fs.readdirSync(geometryFiles).filter( + function (file) { if (file.lastIndexOf(".glb") > -1) return file; } +) +let geometry = dirent + .map((fileName) => ({ name: fileName, value: `${geometryFilesURL}/${fileName}` })); + +module.exports = { + entry: './source/index.js', + output: { + filename: 'main.js', + path: path.resolve(__dirname, 'dist') + }, + mode: "development", + plugins: [ + new HtmlWebpackPlugin({ + templateParameters: { + materials, + geometry + }, + template: 'index.ejs' + }), + new CopyPlugin({ + patterns: [ + { + context: "../../resources/Images", + from: "*.*", + to: "Images", + }, + { + context: "../../resources/Geometry/", + from: "*.glb", + to: "Geometry", + }, + { from: "./public", to: 'public' }, + { context: "../../resources/Lights", from: "*.*", to: "Lights" }, + { context: "../../resources/Lights/irradiance", from: "*.*", to: "Lights/irradiance" }, + { from: stdSurfaceMaterials, to: stdSurfaceMaterialsBaseURL }, + { from: usdSurfaceMaterials, to: usdSurfaceMaterialsBaseURL }, + { from: gltfPbrMaterials, to: gltfPbrMaterialsBaseURL }, + { from: openPbrMaterials, to: openPbrMaterialsBaseURL }, + { from: "../build/bin/JsMaterialXCore.wasm" }, + { from: "../build/bin/JsMaterialXCore.js" }, + { from: "../build/bin/JsMaterialXGenShader.wasm" }, + { from: "../build/bin/JsMaterialXGenShader.js" }, + { from: "../build/bin/JsMaterialXGenShader.data" }, + ], + }), + ] +}; diff --git a/MaterialX/javascript/README.md b/MaterialX/javascript/README.md old mode 100644 new mode 100755 index e4ec449..e4fdc57 --- a/MaterialX/javascript/README.md +++ b/MaterialX/javascript/README.md @@ -1,307 +1,266 @@ -# MaterialX JavaScript - -This folder contains tests and examples that leverage the JavaScript bindings for the MaterialX library. The bindings are generated using the emscripten SDK. - -## Generating the Bindings - -### Prerequisites - -The emscripten SDK is required to generate the JavaScript bindings. There are several ways of using the SDK on different platforms. In general, we recommend to install the SDK directly, following the instructions below. Alternative options are explained [below](#alternative-options-to-use-the-emscripten-sdk). - -To install the SDK directly, follow the instructions of the [emscripten SDK installation Guide](https://emscripten.org/docs/getting_started/downloads.html#installation-instructions-using-the-emsdk-recommended). Make sure to install prerequisites depending on your platform and read usage hints first (e.g. differences between Unix / Windows scripts). - -The recommended version is `4.0.8`. Do not automatically update to the latest version to avoid build issues. - -Note that following the instructions will set some environment variables that are required to use the SDK. These variables are only set temporarily for the current terminal, though. Setting the environment variables in other terminals can be achieved by running -```sh -source ./emsdk_env.sh -``` -inside of the `emsdk` folder (check the documentation for the Windows equivalent). In case of the MaterialX project, it is not required to have these environment variables set. You can also use a CMake build flag instead, as described in the [build instructions](#build-steps) below. - -Emscripten installs its own Node.js runtime. We recommend using the Node.js bundled with your active emsdk to avoid package/runtime mismatches. - -Setting the environment variables permanently is also possible, either by adding a `--permanent` flag to the `activate` command, or by sourcing the `emsdk_env` script every time a shell is launched, e.g. by adding the `source` call to `~/.bash_profile` or an equivalent file. Note however, that the environment variables set by the emscripten SDK might override existing system settings, like the default Python, Java or NodeJs version, so setting them permanently might not be desired on all systems. - -### Alternative options to use the emscripten SDK -If installing the emscripten SDK directly isn't desired, e.g. because you prefer to keep development environments cleanly separated, it can be provided in different ways. - -On Windows, using WSL2 (e.g. with an Ubuntu image) is a viable alternative to isolate the build environment from your main system. Simply set up the build environment in that Linux container. - -Another alternative is to use a [Docker](https://docs.docker.com/) image. With Docker installed, use the [emscripten Docker image](https://hub.docker.com/r/emscripten/emsdk) as described in the [Docker build instructions](#docker) below. - -### Build Steps -Run the following commands in the root folder of this repository. - -Create a build folder in the javascript folder below the *root* of the repository and navigate to that folder: -```sh -mkdir ./javascript/build -cd ./javascript/build -``` - -If you are using the emsdk directly on Windows, note that the emscripten SDK doesn't work with Microsoft's Visual Studio build tools. You need to use an alternative CMake generator like [MinGW](http://mingw-w64.org/doku.php) Makefiles or [Ninja](https://ninja-build.org/). We recommend to use Ninja (unless you already have MinGW installed), since it's pretty lightweight and a pure build system, instead of a full compiler suite. Download Ninja for Windows and unzip the ninja.exe file to some suitable directory in your path (use the command "echo $PATH" or similar to view your PATH variable). - -Generate the build files with CMake. When building the JavaScript bindings, you can optionally specify the emsdk path with the `MATERIALX_EMSDK_PATH` option. This option can be omitted if the `emsdk/emsdk_env.sh` script was run beforehand. -```sh -cmake .. -DMATERIALX_BUILD_JS=ON -DMATERIALX_BUILD_RENDER=OFF --DMATERIALX_BUILD_TESTS=OFF --DMATERIALX_BUILD_GEN_OSL=OFF --DMATERIALX_BUILD_GEN_MDL=OFF --DMATERIALX_EMSDK_PATH= -``` -On Windows, remember to set the CMake generator via the `-G` flag , e.g. `-G "Ninja"`. - -To build the project, run -```sh -cmake --build . --target install -j8 -``` -Change the value of the `-j` option to the number of threads you want to build with. -#### Docker -In order to build using the Docker image, execute the following command in a terminal (in the root of this repository, after creating the build folder), using the CMake commands introduced above. -```sh -docker run --rm -v {path_to_MaterialX_repo}:/src emscripten/emsdk sh -c "cd build && && " -``` - -For follow-up builds (i.e. after changing the source code), remove the `` step from the above call. - -### Output -After building the project the `JsMaterialXCore.wasm`, `JsMaterialXCore.js`, `JsMaterialXGenShader.wasm`, `JsMaterialXGenShader.js` and `JsMaterialXGenShader.data` files can be found in the global install directory of this project. - -## Testing -JavaScript unit tests are located in the `MaterialXTest` folder and use the `.spec.js` suffix. A sample browser is located in the `MaterialXView` folder which allows preview of some of provided sample MaterialX materials. - -### Unit Tests -These tests require `node.js`, which is shipped with the emscripten environment. Make sure to `source` the `emsdk/emsdk_env.sh` script before running the steps described below, if you don't have NodeJs installed on your system already (running the command is not required otherwise). - -1. From the `MaterialXTest` directory, install the npm packages. - ```sh - npm install - ``` - -2. Run the tests from the MaterialXTest directory. - ```sh - npm run test # Core library tests - npm run test:browser # Code generation library test - ``` - -### Sample Viewer - -1. From the `MaterialXView` directory, install the npm packages and build the viewer. - ```sh - npm install - call npm run build - ``` - -2. Start a local host and open in a browser. In this example `http-server` is being used but any utility which can open a local host can be used. - ```sh - call npm install http-server -g - call http-server . -p 8000 - # Open browser - ``` -## Sample build scripts -Note that a sample build script is provided in -`javascript/build_javascript_win.bat` with a corresponding script to clean the build area in -`javascript/clean_javascript_win.bat`. Modify the Emscripten SDK and MaterialX build locations as needed. - -Additionally the github actions workflow YAML file (`.github/workflows/main.yml`) can be examined as well. - -## Using the Bindings -### Consuming the Module -The JavaScript bindings come in two different flavors. `JsMaterialXCore.js` contains all bindings for the MaterialXCore and MaterialXFormat packages, allowing to load, traverse, modify and write MaterialX documents. `JsMaterialXGenShader.js` contains the Core and Format bindings, as well as the bindings required to generate WebGL-compatible shader code from a MaterialX document. Since this involves shipping additional data, we recommend to the `JsMaterialXCore.js` if shader generation is not required. - -The bindings can be consumed via a script tag in the browser: -```html - - -``` - -In NodeJs, simply `require` the MaterialX module like this: -```javascript -const MaterialX = require('./JsMaterialXCore.js'); - -MaterialX().then(mx => { - mx.createDocument(); - ... -}); -``` - -### JavaScript API -In general, the JavaScript API is the same as the C++ API. Sometimes, it doesn't make sense to bind certain functions or even classes, for example when there is already an alternative in native JS. Other special cases are explained in the following sections. - -#### Data Type Conversions -Data types are automatically converted from C++ types to the corresponding JavaScript types, to provide a more natural interface on the JavaScript side. For example, a string that is returned from a C++ function as an `std::string` won't have the C++ string interface, but will be a JavaScript string instead. While this is usually straight-forward, it has some implications when it comes to containers. - -C++ vectors will be converted to JS arrays (and vice versa). Other C++ containers/collections are converted to either JS arrays or objects as well. While this provides a more natural interface on the JS side, it comes with the side-effect that modifications to such containers on the JS side will not be reflected in C++. For example, pushing an element to a JS array that was returned in place of a C++ vector will not update the vector in C++. Elements within the array can be modified and their updates will be reflected in C++, though (this does only apply to class types, not primitives or strings, of course). - -#### Template Functions -Functions that handle generic types in C++ via templates are mapped to JavaScript by creating multiple bindings, one for each type. For example, the `InterfaceElement::setInputValue` function is mapped as `setInputValueString`, `setInputValueBoolean`, `setInputValueInteger` and so on. - -#### Iterators -MaterialX comes with a number of iterators (e.g. `TreeIterator`, `GraphIterator`). These iterators implement the iterable (and iterator) protocol in JS, and can therefore be used in `for ... of` loops. - -#### Memory Management (Embind) -Objects that originate from C++ (e.g. `Document`, `Node`, `Shader`, `GenContext`) are backed by C++ instances. When you're done with them, explicitly call `.delete()` to release the underlying C++ object. This is especially important for objects returned as smart pointers in C++ (such as elements yielded by iterators or getters), otherwise you may see warnings like "Embind found a leaked C++ instance". - -Examples: - -```javascript -// Documents and elements -const doc = mx.createDocument(); -const node = doc.addNode('image'); -// ... use node ... -node.delete(); -doc.delete(); - -// Iterator-yielded elements -for (const elem of doc.traverseTree()) { - // ... use elem ... - elem.delete(); -} - -// Edges in graph traversal -for (const edge of output.traverseGraph()) { - const up = edge.getUpstreamElement(); - const conn = edge.getConnectingElement(); - const down = edge.getDownstreamElement(); - // ... use them ... - up.delete(); - conn.delete(); - down.delete(); - edge.delete(); -} -``` - -#### Exception Handling -When a C++ function throws an exception, the JS binding throws as well. Depending on the Emscripten version, the caught value may be either a numeric pointer to the C++ exception (legacy) or an exception object (Error-like). Use `getExceptionMessage` on the caught value in both cases: - -```javascript -const doc = mx.createDocument(); -doc.addNode('category', 'node1'); - -try { - doc.addNode('category', 'node1'); -} catch (err) { - // Works with both a numeric pointer and an exception object - console.log(mx.getExceptionMessage(err)); // 'Child name is not unique: node1' -} -``` - -#### Loading MaterialX files -The bindings expose the `readFromXmlString` and `readFromXmlFile` functions. Their usage is similar to C++ and should work in browsers and NodeJs. Note that these functions are asynchronous in JavaScript, so you need to either `await` them or place depending code in a `.then()` block. - -By default, the functions will resolve referenced (i.e. included) documents. This can be disabled by setting the `readOptions.readXIncludes` to `false`: -```javascript -const readOptions = new mx.XmlReadOptions(); -readOptions.readXIncludes = false; -await readFromXmlFile(doc, filename, searchPath, readOptions); // will only read the top-level file, no includes -``` -Note that the `readXIncludesFunction` option that exists on the C++ read options is not supported in JavaScript. - -The `searchPath` is a semicolon-separated list of absolute or relative paths. Relative paths will be evaluated with regards to the current working directory. In case of using absolute search paths in web browsers (i.e. urls), note that urls like `mydomain.com/path` or `localhost/path` might be considered relative paths. To ensure they're used as absolute paths, make them fully formed urls, i.e. have a protocol prefix like `https://`. - -#### Writing MaterialX files -Documents can be written to strings via the `writeToXmlString` method, and to files with the `writeToXmlFile` method. In NodeJs, the latter will write the file to the path provided to the method (relative paths will be evaluated with respect to the current working directory). In the browser, the written file will be downloaded automatically, so only the file name matters. - -Note that the `XmlWriteOptions.elementPredicate` option is not supported in JavaScript. - -### Using the EsslShaderGenerator JavaScript bindings -#### Setup -Make sure to consume `JsMaterialXGenShader.js` instead of `JsMaterialXCore.js` as described [here](#consuming-the-module). Additionally, ensure that the app serves `JsMaterialXGenShader.data` and `JsMaterialXGenShader.wasm`. The `.data` file includes the prepackaged library files containing the shader snippets and MaterialX node definitions/implementations required for generating the shader code. - -#### Generating Essl Shader Code & Compiling with WebGL -To generate WebGL 2 compatible shader code a generator context and an instance of the `EsslShaderGenerator` class is required. -```javascript -const gen = mx.EsslShaderGenerator.create(); -const genContext = new mx.GenContext(gen); -``` -The standard libraries need to be loaded and imported into the document. This step is required as the standard libraries contain all the definitions and snippets needed for assembly of the shader code. -```javascript -const stdlib = mx.loadStandardLibraries(genContext); -const doc = mx.createDocument(); -doc.importLibrary(stdlib); -``` -Now it is either time to load a document from a file as outline [here](#loading-materialx-files) or create one using the API. -Generating the code consists of finding a renderable element (the javascript binding returns the first renderable element) and calling the `generate` method from the `EsslShaderGenerator` class. The shader code for the vertex/pixel shader may be requested from the resulting `Shader` instance. -```javascript -const elem = mx.findRenderableElement(doc); -const shader = gen.generate(elem.getNamePath(), elem, genContext); -const fShader = shader.getSourceCode("pixel"); -const vShader = shader.getSourceCode("vertex"); -// Cleanup when done -shader.delete(); -stdlib.delete(); -genContext.delete(); -gen.delete(); -``` -Shader generation options may be changed by getting the options from the context and altering its properties. Changes to these options must occur after the standard libraries have been loaded as the call to `mx.loadStandardLibraries(genContext)` sets the options to some defaults. -```javascript -genContext.getOptions().fileTextureVerticalFlip = false; -``` -Compilation using a WebGL 2 context (`gl`) is straight forward. -```javascript -const glVertexShader = gl.createShader(gl.VERTEX_SHADER); -gl.shaderSource(glVertexShader, vShader); -gl.compileShader(glVertexShader); -const glPixelShader = gl.createShader(gl.FRAGMENT_SHADER); -gl.shaderSource(glPixelShader, fShader); -gl.compileShader(glPixelShader); -``` -However, any rendering framework that supports custom shaders should do. In the [Web Viewer sample app](./MaterialXView/src/index.js) we use the [RawShaderMaterial](https://threejs.org/docs/index.html?q=RawSh#api/en/materials/RawShaderMaterial) class from [three.js](https://threejs.org/). - -#### Getting the shader uniforms -The uniform values can be obtained from the shader as a JSON, either for the vertex or the pixel shader. -```javascript -shader.getUniformValues("vertex"); -shader.getUniformValues("pixel") -``` -Each entry corresponds to a uniform name and the value is an object which contains the type as specified in the generators Syntax class and the stringified value. Some of the commonly used uniform names in the generated shader are listed [here](../../documents/DeveloperGuide/ShaderGeneration.md#162-variable-naming-convention). -An example that parses the JSON and feeds the uniform data to a three.js based application can be found in the [Web Viewer Sample App](./MaterialXView/src/index.js). - -## Maintaining the Bindings -This section provides some background on binding creation for contributors. In general, we recommend to look at existing bindings for examples. - -### What to Bind? -In general, we aim for 100% coverage of the MaterialX API, at least for the Core and Format packages. However, there are functions and even classes where creating bindings wouldn't make much sense. The `splitString` utility function is such an example, because the JavaScript string class does already have a `split` method. The `FilePath` and `FileSearchPath` classes of the Format package are simply represented as strings on the JavaScript side, even though they provide complex APIs in C++. This is because most of their APIs do not apply to browsers, since they are specific to file system operations. In NodeJs, they would present a competing implementation of the core `fs` module, and therefore be redundant (even though they might be convenient in some cases). - -The examples above illustrate that it does not always make sense to create bindings, if there is no easy way to map them to both browsers and NodeJs, or if there is already an alternative in native JS. The overhead, both in maintenance and bundle size, wouldn't pay off. - -### Emscripten's optional_override -Emscripten's `optional_override` allows to provide custom binding implementations in-place and enables function overloading by parameter count, which is otherwise not supported in JavaScript. Contributors need to be careful when using it, though, since there is a small pitfall. - -If a function binding has multiple overloads defined via `optional_override` to support optional parameters, this binding must only be defined once on the base class (i.e. the class that defines the function initially). Virtual functions that are overridden in deriving classes must not be bound again when creating bindings for these derived classes. Doing so can lead to the wrong function (i.e. base class' vs derived class' implementation) being called at runtime. - -### Optional Parameters -Many C++ functions have optional parameters. Unfortunately, emscripten does not automatically deal with optional parameters. Binding these functions the 'normal' way will require users to provide all parameters in JavaScript, including optional ones. We provide helper macros to cicumvent this issue. Different flavors of the `BIND_*_FUNC` macros defined in `Helpers.h` can be used to conveniently bind functions with optional parameters. See uses of these macros in the existing bindings for examples. - -NOTE: Since these macros use `optional_override` internally, the restrictions explained above go for them as well. Only define bindings for virtual functions once on the base class with these macros. - -### Template Functions -Generic functions that deal with multiple types cannot be bound directly to JavaScript. Instead, we create multiple bindings, one per type. The binding name follows the pattern `functionName`. For convenience, we usually provide a custom macro that takes the type and constructs the corresponding binding. See the existing bindings for examples. - -### Array <-> Vector conversion -As explained in the user documentation, types are automatically converted between C++ and JavaScript. While there are multiple examples for custom marshalling of types (e.g. `std::pair` to array, or `FileSearchPath` to string), the most common use case is the conversion of C++ vectors to JS arrays, and vice versa. This conversion can automatically be achieved by including the `VectorHelper.h` header in each binding file that covers functions which either accept or return vectors in C++. - -### Custom JavaScript Code -Some bindings cannot be direct mappings to a C++ function. In particular when operations are asynchronous in JavaScript (e.g. loading files), it's easier to provide custom JavaScript implementations for the affected functions. This is how `readFromXmlString` and `readFromXmlFile` are implemented, for example. Such JavaScript code can be provided using the post-JS feature of emscripten. There should be one `post.js` file per MaterialX module, if that module requires any custom JS code. Note that these files need to be added to `CMakeLists.txt` in the `JsMaterialX` source folder. We recommend to provide custom code that depends on the WebAssembly module like this: -```javascript -onModuleReady(function () { - -}); -``` -This will register your code after the module has been initialized. The wasm module will be available as `Module`. -Since the module itself is ES5 code, we recommend to write custom code in ES5 as well, even though ES6 should work as well in most cases. - -In order to avoid conflicting definitions in post.js files, we recommend to wrap custom code in an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) (Immediately Invoked Function Expression). - -### Testing strategy -Testing every binding doesn't seem desirable, since most of them will directly map to the C++ implementation, which should already be tested in the C++ tests. Instead, we only test common workflows (e.g. iterating/parsing a document), bindings with custom implementations, and our custom binding mechanisms. The latter involves custom marshalling, e.g. of the vector <-> array conversion, or support for optional parameters. Additionally, all features that might behave different on the web, compared to desktop, should be tested as well. - -The C++ and [Python binding tests](../../python/MaterialXTest/main.py) follow a different approach than the JS unit tests, by testing larger workflows instead of single features. In order to cover at least as much functionality in JS as in Python, the tests have been ported to JS. However, JS tests are organized in the same file structure as the bindings, so these workflow tests have been added to the file where they fit in best (e.g. the `Traverse Graph` test is in `traversal.spec.js`). This is equivalent to how tests are organized in C++. - -## CI -Emscripten builds and test runs are specified in `.github/workflows/build_wasm.yml`. - +# MaterialX JavaScript + +This folder contains tests and examples that leverage the JavaScript bindings for the MaterialX library. The bindings are generated using the emscripten SDK. + +## Generating the Bindings + +### Prerequisites + +The emscripten SDK is required to generate the JavaScript bindings. There are several ways of using the SDK on different platforms. In general, we recommend to install the SDK directly, following the instructions below. Alternative options are explained [below](#alternative-options-to-use-the-emscripten-sdk). + +To install the SDK directly, follow the instructions of the [emscripten SDK installation Guide](https://emscripten.org/docs/getting_started/downloads.html#installation-instructions-using-the-emsdk-recommended). Make sure to install prerequisites depending on your platform and read usage hints first (e.g. differences between Unix / Windows scripts). + +Note that following the instructions will set some environment variables that are required to use the SDK. These variables are only set temporarily for the current terminal, though. Setting the environment variables in other terminals can be achieved by running +```sh +source ./emsdk_env.sh +``` +inside of the `emsdk` folder (check the documentation for the Windows equivalent). In case of the MaterialX project, it is not required to have these environment variables set. You can also use a CMake build flag instead, as described in the [build instructions](#build-steps) below. + +Setting the environment variables permanently is also possible, either by adding a `--permanent` flag to the `activate` command, or by sourcing the `emsdk_env` script every time a shell is launched, e.g. by adding the `source` call to `~/.bash_profile` or an equivalent file. Note however, that the environment variables set by the emscripten SDK might override existing system settings, like the default Python, Java or NodeJs version, so setting them permanently might not be desired on all systems. + +### Alternative options to use the emscripten SDK +If installing the emscripten SDK directly isn't desired, e.g. because you prefer to keep development environments cleanly separated, it can be provided in different ways. + +On Windows, using WSL2 (e.g. with an Ubuntu image) is a viable alternative to isolate the build environment from your main system. Simply set up the build environment in that Linux container. + +Another alternative is to use a [Docker](https://docs.docker.com/) image. With Docker installed, use the [emscripten Docker image](https://hub.docker.com/r/emscripten/emsdk) as described in the [Docker build instructions](#docker) below. + +### Build Steps +Run the following commands in the root folder of this repository. + +Create a build folder in the javascript folder below the *root* of the repository and navigate to that folder: +```sh +mkdir ./javascript/build +cd ./javascript/build +``` + +If you are using the emsdk directly on Windows, note that the emscripten SDK doesn't work with Microsoft's Visual Studio build tools. You need to use an alternative CMake generator like [MinGW](http://mingw-w64.org/doku.php) Makefiles or [Ninja](https://ninja-build.org/). We recommend to use Ninja (unless you already have MinGW installed), since it's pretty lightweight and a pure build system, instead of a full compiler suite. Download Ninja for Windows and unzip the ninja.exe file to some suitable directory in your path (use the command "echo $PATH" or similar to view your PATH variable). + +Generate the build files with CMake. When building the JavaScript bindings, you can optionally specify the emsdk path with the `MATERIALX_EMSDK_PATH` option. This option can be omitted if the `emsdk/emsdk_env.sh` script was run beforehand. +```sh +cmake .. -DMATERIALX_BUILD_JS=ON -DMATERIALX_BUILD_RENDER=OFF +-DMATERIALX_BUILD_TESTS=OFF +-DMATERIALX_BUILD_GEN_OSL=OFF +-DMATERIALX_BUILD_GEN_MDL=OFF +-DMATERIALX_EMSDK_PATH= +``` +On Windows, remember to set the CMake generator via the `-G` flag , e.g. `-G "Ninja"`. + +To build the project, run +```sh +cmake --build . --target install -j8 +``` +Change the value of the `-j` option to the number of threads you want to build with. +#### Docker +In order to build using the Docker image, execute the following command in a terminal (in the root of this repository, after creating the build folder), using the CMake commands introduced above. +```sh +docker run --rm -v {path_to_MaterialX_repo}:/src emscripten/emsdk sh -c "cd build && && " +``` + +For follow-up builds (i.e. after changing the source code), remove the `` step from the above call. + +### Output +After building the project the `JsMaterialXCore.wasm`, `JsMaterialXCore.js`, `JsMaterialXGenShader.wasm`, `JsMaterialXGenShader.js` and `JsMaterialXGenShader.data` files can be found in the global install directory of this project. + +## Testing +JavaScript unit tests are located in the `MaterialXTest` folder and use the `.spec.js` suffix. A sample browser is located in the `MaterialXView` folder which allows preview of some of provided sample MaterialX materials. + +### Unit Tests +These tests require `node.js`, which is shipped with the emscripten environment. Make sure to `source` the `emsdk/emsdk_env.sh` script before running the steps described below, if you don't have NodeJs installed on your system already (running the command is not required otherwise). + +1. From the `MaterialXTest` directory, install the npm packages. + ```sh + npm install + ``` + +2. Run the tests from the MaterialXTest directory. + ```sh + npm run test # Core library tests + npm run test:browser # Code generation library test + ``` + +### Sample Viewer + +1. From the `MaterialXView` directory, install the npm packages and build the viewer. + ```sh + npm install + call npm run build + ``` + +2. Start a local host and open in a browser. In this example `http-server` is being used but any utility which can open a local host can be used. + ```sh + call npm install http-server -g + call http-server . -p 8000 + # Open browser + ``` +## Sample build scripts +Note that a sample build script is provided in +`javascript/build_javascript_win.bat` with a corresponding script to clean the build area in +`javascript/clean_javascript_win.bat`. Modify the Emscripten SDK and MaterialX build locations as needed. + +Additionaly the github actions workflow YAML file (`.github/workflows/main.yml`) can be examined as well. + +## Using the Bindings +### Consuming the Module +The JavaScript bindings come in two different flavors. `JsMaterialXCore.js` contains all bindings for the MaterialXCore and MaterialXFormat packages, allowing to load, traverse, modify and write MaterialX documents. `JsMaterialXGenShader.js` contains the Core and Format bindings, as well as the bindings required to generate WebGL-compatible shader code from a MaterialX document. Since this involves shipping additional data, we recommend to the `JsMaterialXCore.js` if shader generation is not required. + +The bindings can be consumed via a script tag in the browser: +```html + + +``` + +In NodeJs, simply `require` the MaterialX module like this: +```javascript +const MaterialX = require('./JsMaterialXCore.js'); + +MaterialX().then(mx => { + mx.createDocument(); + ... +}); +``` + +### JavaScript API +In general, the JavaScript API is the same as the C++ API. Sometimes, it doesn't make sense to bind certain functions or even classes, for example when there is already an alternative in native JS. Other special cases are explained in the following sections. + +#### Data Type Conversions +Data types are automatically converted from C++ types to the corresponding JavaScript types, to provide a more natural interface on the JavaScript side. For example, a string that is returned from a C++ function as an `std::string` won't have the C++ string interface, but will be a JavaScript string instead. While this is usually straight-forward, it has some implications when it comes to containers. + +C++ vectors will be converted to JS arrays (and vice versa). Other C++ containers/collections are converted to either JS arrays or objects as well. While this provides a more natural interface on the JS side, it comes with the side-effect that modifications to such containers on the JS side will not be reflected in C++. For example, pushing an element to a JS array that was returned in place of a C++ vector will not update the vector in C++. Elements within the array can be modified and their updates will be reflected in C++, though (this does only apply to class types, not primitives or strings, of course). + +#### Template Functions +Functions that handle generic types in C++ via templates are mapped to JavaScript by creating multiple bindings, one for each type. For example, the `InterfaceElement::setInputValue` function is mapped as `setInputValueString`, `setInputValueBoolean`, `setInputValueInteger` and so on. + +#### Iterators +MaterialX comes with a number of iterators (e.g. `TreeIterator`, `GraphIterator`). These iterators implement the iterable (and iterator) protocol in JS, and can therefore be used in `for ... of` loops. + +#### Exception Handling +When a C++ function throws an exception, this exception will also be thrown by the corresponding JS function. However, you will only get a pointer (i.e. a number in JS) to the C++ exception object in a `try ... catch ...` block, due to some exception handling limitations of emscripten. The helper method `getExceptionMessage` can be used to extract the exception message from that pointer: + +```javascript +const doc = mx.createDocument(); +doc.addNode('category', 'node1'); + +try { + doc.addNode('category', 'node1'); +} catch (errPtr) { + // typeof errPtr === 'number' yields 'true' + console.log(mx.getExceptionMessage(errPtr)); // Prints 'Child name is not unique: node1' +} +``` + +#### Loading MaterialX files +The bindings expose the `readFromXmlString` and `readFromXmlFile` functions. Their usage is similar to C++ and should work in browsers and NodeJs. Note that these functions are asynchronous in JavaScript, so you need to either `await` them or place depending code in a `.then()` block. + +By default, the functions will resolve referenced (i.e. included) documents. This can be disabled by setting the `readOptions.readXIncludes` to `false`: +```javascript +const readOptions = new mx.XmlReadOptions(); +readOptions.readXIncludes = false; +await readFromXmlFile(doc, filename, searchPath, readOptions); // will only read the top-level file, no includes +``` +Note that the `readXIncludesFunction` option that exists on the C++ read options is not supported in JavaScript. + +The `searchPath` is a semicolon-separated list of absolute or relative paths. Relative paths will be evaluated with regards to the current working directory. In case of using absolute search paths in web browsers (i.e. urls), note that urls like `mydomain.com/path` or `localhost/path` might be considered relative paths. To ensure they're used as absolute paths, make them fully formed urls, i.e. have a protocol prefix like `https://`. + +#### Writing MaterialX files +Documents can be written to strings via the `writeToXmlString` method, and to files with the `writeToXmlFile` method. In NodeJs, the latter will write the file to the path provided to the method (relative paths will be evaluated with respect to the current working directory). In the browser, the written file will be downloaded automatically, so only the file name matters. + +Note that the `XmlWriteOptions.elementPredicate` option is not supported in JavaScript. + +### Using the EsslShaderGenerator JavaScript bindings +#### Setup +Make sure to consume `JsMaterialXGenShader.js` instead of `JsMaterialXCore.js` as described [here](#consuming-the-module). Additionally, ensure that the app serves `JsMaterialXGenShader.data` and `JsMaterialXGenShader.wasm`. The `.data` file includes the prepackaged library files containing the shader snippets and MaterialX node definitions/implementations required for generating the shader code. + +#### Generating Essl Shader Code & Compiling with WebGL +To generate WebGL 2 compatible shader code a generator context and an instance of the `EsslShaderGenerator` class is required. +```javascript +const gen = new mx.EsslShaderGenerator(); +const genContext = new mx.GenContext(gen); +``` +The standard libraries need to be loaded and imported into the document. This step is required as the standard libraries contain all the definitions and snippets needed for assembly of the shader code. +```javascript +const stdlib = mx.loadStandardLibraries(genContext); +const doc = mx.createDocument(); +doc.importLibrary(stdlib); +``` +Now it is either time to load a document from a file as outline [here](#loading-materialx-files) or create one using the API. +Generating the code consists of finding a renderable element (the javascript binding returns the first renderable element) and calling the `generate` method from the `EsslShaderGenerator` class. The shader code for the vertex/pixel shader may be requested from the resulting `Shader` instance. +```javascript +const elem = mx.findRenderableElement(doc); +const shader = gen.generate(elem.getNamePath(), elem, genContext); +const fShader = shader.getSourceCode("pixel"); +const vShader = shader.getSourceCode("vertex"); +``` +Shader generation options may be changed by getting the options from the context and altering its properties. Changes to these options must occur after the standard libraries have been loaded as the call to `mx.loadStandardLibraries(genContext)` sets the options to some defaults. +```javascript +genContext.getOptions().fileTextureVerticalFlip = false; +``` +Compilation using a WebGL 2 context (`gl`) is straight forward. +```javascript +const glVertexShader = gl.createShader(gl.VERTEX_SHADER); +gl.shaderSource(glVertexShader, vShader); +gl.compileShader(glVertexShader); +const glPixelShader = gl.createShader(gl.FRAGMENT_SHADER); +gl.shaderSource(glPixelShader, fShader); +gl.compileShader(glPixelShader); +``` +However, any rendering framework that supports custom shaders should do. In the [Web Viewer sample app](./MaterialXView/src/index.js) we use the [RawShaderMaterial](https://threejs.org/docs/index.html?q=RawSh#api/en/materials/RawShaderMaterial) class from [three.js](https://threejs.org/). + +#### Getting the shader uniforms +The uniform values can be obtained from the shader as a JSON, either for the vertex or the pixel shader. +```javascript +shader.getUniformValues("vertex"); +shader.getUniformValues("pixel") +``` +Each entry corresponds to a uniform name and the value is an object which contains the type as specified in the generators Syntax class and the stringified value. Some of the commonly used uniform names in the generated shader are listed [here](../../documents/DeveloperGuide/ShaderGeneration.md#162-variable-naming-convention). +An example that parses the JSON and feeds the uniform data to a three.js based application can be found in the [Web Viewer Sample App](./MaterialXView/src/index.js). + +## Maintaining the Bindings +This section provides some background on binding creation for contributors. In general, we recommed to look at existing bindings for examples. + +### What to Bind? +In general, we aim for 100% coverage of the MaterialX API, at least for the Core and Format packages. However, there are functions and even classes where creating bindings wouldn't make much sense. The `splitString` utility function is such an example, because the JavaScript string class does already have a `split` method. The `FilePath` and `FileSearchPath` classes of the Format package are simply represented as strings on the JavaScript side, even though they provide complex APIs in C++. This is because most of their APIs do not apply to browsers, since they are specific to file system operations. In NodeJs, they would present a competing implementation of the core `fs` module, and therefore be redundant (even though they might be convenient in some cases). + +The examples above illustrate that it does not always make sense to create bindings, if there is no easy way to map them to both browsers and NodeJs, or if there is already an alternative in native JS. The overhead, both in maintenance and bundle size, wouldn't pay off. + +### Emscripten's optional_override +Emscripten's `optional_override` allows to provide custom binding implementations in-place and enables function overloading by parameter count, which is otherwise not supported in JavaScript. Contributors need to be careful when using it, though, since there is a small pitfall. + +If a function binding has multiple overloads defined via `optional_override` to support optional parameters, this binding must only be defined once on the base class (i.e. the class that defines the function initially). Virtual functions that are overriden in deriving classes must not be bound again when creating bindings for these derived classes. Doing so can lead to the wrong function (i.e. base class' vs derived class' implementation) being called at runtime. + +### Optional Parameters +Many C++ functions have optional parameters. Unfortunately, emscripten does not automatically deal with optional parameters. Binding these functions the 'normal' way will require users to provide all parameters in JavaScript, including optional ones. We provide helper macros to cicumvent this issue. Different flavors of the `BIND_*_FUNC` macros defined in `Helpers.h` can be used to conveniently bind functions with optional parameters. See uses of these macros in the existing bindings for examples. + +NOTE: Since these macros use `optional_override` internally, the restrictions explained above go for them as well. Only define bindings for virtual functions once on the base class with these macros. + +### Template Functions +Generic functions that deal with multiple types cannot be bound directly to JavaScript. Instead, we create multiple bindings, one per type. The binding name follows the pattern `functionName`. For convenience, we usually provide a custom macro that takes the type and constructs the corresponding binding. See the existing bindings for examples. + +### Array <-> Vector conversion +As explained in the user documentation, types are automatically converted between C++ and JavaScript. While there are multiple examples for custom marshalling of types (e.g. `std::pair` to array, or `FileSearchPath` to string), the most common use case is the conversion of C++ vectors to JS arrays, and vice versa. This conversion can automatically be achieved by including the `VectorHelper.h` header in each binding file that covers functions which either accept or return vectors in C++. + +### Custom JavaScript Code +Some bindings cannot be direct mappings to a C++ function. In particular when operations are asynchronous in JavaScript (e.g. loading files), it's easier to provide custom JavaScript implementations for the affected functions. This is how `readFromXmlString` and `readFromXmlFile` are implemented, for example. Such JavaScript code can be provided using the post-JS feature of emscripten. There should be one `post.js` file per MaterialX module, if that module requires any custom JS code. Note that these files need to be added to `CMakeLists.txt` in the `JsMaterialX` source folder. We recommend to provide custom code that depends on the WebAssembly module like this: +```javascript +onModuleReady(function () { + +}); +``` +This will register your code after the module has been initialized. The wasm module will be available as `Module`. +Since the module itself is ES5 code, we recommend to write custom code in ES5 as well, even though ES6 should work as well in most cases. + +In order to avoid conflicting definitions in post.js files, we recommend to wrap custom code in an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) (Immediately Invoked Function Expression). + +### Testing strategy +Testing every binding doesn't seem desirable, since most of them will directly map to the C++ implementation, which should already be tested in the C++ tests. Instead, we only test common workflows (e.g. iterating/parsing a document), bindings with custom implementations, and our custom binding mechanisms. The latter involves custom marshalling, e.g. of the vector <-> array conversion, or support for optional parameters. Additionally, all features that might behave different on the web, compared to desktop, should be tested as well. + +The C++ and [Python binding tests](../../python/MaterialXTest/main.py) follow a different approach than the JS unit tests, by testing larger workflows instead of single features. In order to cover at least as much functionality in JS as in Python, the tests have been ported to JS. However, JS tests are organized in the same file structure as the bindings, so these workflow tests have been added to the file where they fit in best (e.g. the `Traverse Graph` test is in `traversal.spec.js`). This is equivalent to how tests are organized in C++. + +## CI +Emscripten builds and test runs are specified in `.github/workflows/build_wasm.yml`. + diff --git a/MaterialX/javascript/build_javascript_win.bat b/MaterialX/javascript/build_javascript_win.bat old mode 100644 new mode 100755 index 80f87a8..d6b90d6 --- a/MaterialX/javascript/build_javascript_win.bat +++ b/MaterialX/javascript/build_javascript_win.bat @@ -1,30 +1,30 @@ -@rem This script builds MaterialX JavaScript on Windows. The final command starts a local server, allowing you to -@rem run the MaterialX Web Viewer locally by entering 'http://localhost:8080' in the search bar of your browser. -@echo --------------------- Setup Emscripten --------------------- -@echo on -@rem Edit the following paths to match your local locations for the Emscripten and MaterialX projects. -set EMSDK_LOCATION=C:/GitHub/emsdk -set MATERIALX_LOCATION=C:/GitHub/MaterialX -call %EMSDK_LOCATION%/emsdk.bat install 4.0.8 -call %EMSDK_LOCATION%/emsdk.bat activate 4.0.8 -if NOT ["%errorlevel%"]==["0"] pause -@echo --------------------- Build MaterialX With JavaScript --------------------- -@echo on -cd %MATERIALX_LOCATION% -cmake -S . -B javascript/build -DMATERIALX_BUILD_JS=ON -DMATERIALX_EMSDK_PATH=%EMSDK_LOCATION% -G Ninja -cmake --build javascript/build --target install --config RelWithDebInfo --parallel 2 -if NOT ["%errorlevel%"]==["0"] pause -@echo --------------------- Run JavaScript Tests --------------------- -@echo on -cd javascript/MaterialXTest -call npm install -call npm run test -call npm run test:browser -if NOT ["%errorlevel%"]==["0"] pause -@echo --------------------- Run Interactive Viewer --------------------- -@echo on -cd ../MaterialXView -call npm install -call npm run build -call npm run start -if NOT ["%errorlevel%"]==["0"] pause +@rem This script builds MaterialX JavaScript on Windows. The final command starts a local server, allowing you to +@rem run the MaterialX Web Viewer locally by entering 'http://localhost:8080' in the search bar of your browser. +@echo --------------------- Setup Emscripten --------------------- +@echo on +@rem Edit the following paths to match your local locations for the Emscripten and MaterialX projects. +set EMSDK_LOCATION=C:/GitHub/emsdk +set MATERIALX_LOCATION=C:/GitHub/MaterialX +call %EMSDK_LOCATION%/emsdk.bat install latest +call %EMSDK_LOCATION%/emsdk.bat activate latest +if NOT ["%errorlevel%"]==["0"] pause +@echo --------------------- Build MaterialX With JavaScript --------------------- +@echo on +cd %MATERIALX_LOCATION% +cmake -S . -B javascript/build -DMATERIALX_BUILD_JS=ON -DMATERIALX_EMSDK_PATH=%EMSDK_LOCATION% -G Ninja +cmake --build javascript/build --target install --config RelWithDebInfo --parallel 2 +if NOT ["%errorlevel%"]==["0"] pause +@echo --------------------- Run JavaScript Tests --------------------- +@echo on +cd javascript/MaterialXTest +call npm install +call npm run test +call npm run test:browser +if NOT ["%errorlevel%"]==["0"] pause +@echo --------------------- Run Interactive Viewer --------------------- +@echo on +cd ../MaterialXView +call npm install +call npm run build +call npm run start +if NOT ["%errorlevel%"]==["0"] pause diff --git a/MaterialX/javascript/clean_javascript_win.bat b/MaterialX/javascript/clean_javascript_win.bat old mode 100644 new mode 100755 index 8d94b61..40c0d9e --- a/MaterialX/javascript/clean_javascript_win.bat +++ b/MaterialX/javascript/clean_javascript_win.bat @@ -1,5 +1,5 @@ -rmdir build /s /q -rmdir MaterialXTest\_build /s /q -rmdir MaterialXTest\node_modules /s /q -rmdir MaterialXView\dist /s /q -rmdir MaterialXView\node_modules /s /q +rmdir build /s /q +rmdir MaterialXTest\_build /s /q +rmdir MaterialXTest\node_modules /s /q +rmdir MaterialXView\dist /s /q +rmdir MaterialXView\node_modules /s /q diff --git a/MaterialX/javascript/package-lock.json b/MaterialX/javascript/package-lock.json old mode 100644 new mode 100755 index 21f6da6..58cbc73 --- a/MaterialX/javascript/package-lock.json +++ b/MaterialX/javascript/package-lock.json @@ -1,6 +1,6 @@ -{ - "name": "javascript", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} +{ + "name": "javascript", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/MaterialX/libraries/CMakeLists.txt b/MaterialX/libraries/CMakeLists.txt old mode 100644 new mode 100755 index 432df18..8c19414 --- a/MaterialX/libraries/CMakeLists.txt +++ b/MaterialX/libraries/CMakeLists.txt @@ -1,80 +1,28 @@ -if(MATERIALX_BUILD_DATA_LIBRARY) - # Build generated products from the MaterialX data library. - # Initially, this step is a simple copy across folders, but our intent - # is for it to include meaningful work in the future. - - set(DATA_LIBRARY_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/DataLibraryBuild) - - file(GLOB_RECURSE MATERIALX_DATA_LIBRARY_SOURCE_FILES - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - LIST_DIRECTORIES false - *.mtlx - *.md - *.glsl - *.osl - *.h - *.metal - *.slang) - - foreach(SOURCE_FILE IN LISTS MATERIALX_DATA_LIBRARY_SOURCE_FILES) - set(SOURCE_FILEPATH ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE}) - set(DEST_FILEPATH ${DATA_LIBRARY_BUILD_DIR}/${SOURCE_FILE}) - add_custom_command( - OUTPUT ${DEST_FILEPATH} - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SOURCE_FILEPATH} ${DEST_FILEPATH} - DEPENDS ${SOURCE_FILEPATH}) - list(APPEND MATERIALX_DATA_LIBRARY_BUILD_FILES ${DEST_FILEPATH}) - endforeach() - - add_custom_target(MaterialXBuildData ALL - DEPENDS ${MATERIALX_DATA_LIBRARY_BUILD_FILES}) - - if (MATERIALX_BUILD_OSOS AND MATERIALX_OSL_BINARY_OSLC) - set(OSO_BUILD_PATH ${CMAKE_CURRENT_BINARY_DIR}/DataLibraryBuild/targets/genoslnetwork/osos) - set(MTLX_BUILD_PATH ${CMAKE_CURRENT_BINARY_DIR}/DataLibraryBuild/targets/genoslnetwork) - - set(SENTINEL_FILE ${CMAKE_CURRENT_BINARY_DIR}/buildosos.sentinel) - - add_custom_command( - OUTPUT ${SENTINEL_FILE} - COMMAND touch ${SENTINEL_FILE} - COMMAND cmake -E make_directory ${OSO_BUILD_PATH} - COMMAND cmake -E make_directory ${MTLX_BUILD_PATH} - COMMAND MaterialXGenOsl_LibsToOso - --outputOsoPath ${OSO_BUILD_PATH} - --outputMtlxPath ${MTLX_BUILD_PATH} - --oslCompilerPath ${MATERIALX_OSL_BINARY_OSLC} - --oslIncludePath ${MATERIALX_OSL_INCLUDE_PATH} - --libraryRelativeOsoPath libraries/targets/genoslnetwork/osos - --removeNdPrefix true - DEPENDS ${MATERIALX_DATA_LIBRARY_SOURCE_FILES} MaterialXGenOsl_LibsToOso - ) - - add_custom_target(MaterialXBuild_genoslnetwork_buildOsos ALL DEPENDS ${SENTINEL_FILE}) - add_dependencies(MaterialXBuildData MaterialXBuild_genoslnetwork_buildOsos) - - endif() - - set(DATA_LIBRARY_DIR ${DATA_LIBRARY_BUILD_DIR}) -else() - set(DATA_LIBRARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -endif() - -if(NOT SKBUILD) - install(DIRECTORY ${DATA_LIBRARY_DIR}/ - DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}" - PATTERN "CMakeLists.txt" EXCLUDE) -endif() - -if(MATERIALX_BUILD_PYTHON) - set(MATERIALX_PYTHON_LIBRARIES_PATH "${MATERIALX_PYTHON_FOLDER_NAME}/${MATERIALX_INSTALL_STDLIB_PATH}") - if(SKBUILD) - set(MATERIALX_PYTHON_LIBRARIES_PATH "${SKBUILD_PLATLIB_DIR}/MaterialX/libraries") - endif() - - install(DIRECTORY ${DATA_LIBRARY_DIR}/ - DESTINATION "${MATERIALX_PYTHON_LIBRARIES_PATH}" - PATTERN "CMakeLists.txt" EXCLUDE) -endif() - -set(MATERIALX_DATA_LIBRARY_DIR ${DATA_LIBRARY_DIR} PARENT_SCOPE) +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}" + DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) +endif() + +set(MATERIALX_PYTHON_LIBRARIES_PATH "${MATERIALX_PYTHON_FOLDER_NAME}/${MATERIALX_INSTALL_STDLIB_PATH}") +if(SKBUILD) + set(MATERIALX_PYTHON_LIBRARIES_PATH "${SKBUILD_PLATLIB_DIR}/MaterialX/libraries") +endif() + +if(MATERIALX_BUILD_PYTHON) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ + 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}" + DESTINATION "${MATERIALX_PYTHON_LIBRARIES_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) +endif() diff --git a/MaterialX/libraries/README.md b/MaterialX/libraries/README.md old mode 100644 new mode 100755 index 40842a0..2af1d03 --- a/MaterialX/libraries/README.md +++ b/MaterialX/libraries/README.md @@ -1,79 +1,80 @@ -# MaterialX Data Libraries - -This folder contains the standard data libraries for MaterialX, providing declarations and graph definitions for the MaterialX nodes, and source code for all supported shader generators. - -## Standard Pattern Library -- [stdlib](stdlib) - - [stdlib_defs.mtlx](stdlib/stdlib_defs.mtlx) : Nodedef declarations. - - [stdlib_ng.mtlx](stdlib/stdlib_ng.mtlx) : Nodegraph definitions. - - [genglsl](stdlib/genglsl): GLSL language support. - - [lib](stdlib/genglsl/lib) : Shader utility files. - - [stdlib_genglsl_impl.mtlx](stdlib/genglsl/stdlib_genglsl_impl.mtlx) : Mapping from declarations to implementations. - - [genosl](stdlib/genosl): OSL language support. - - [lib](stdlib/genosl/lib) : Shader utility files. - - [stdlib_genosl_impl.mtlx](stdlib/genosl/stdlib_genosl_impl.mtlx) : Mapping from declarations to implementations. - - [genmdl](stdlib/genmdl): MDL language support. - - [stdlib_genmdl_impl.mtlx](stdlib/genmdl/stdlib_genmdl_impl.mtlx) : Mapping from declarations to implementations. - - Additional MaterialX support libraries for MDL are located in the [source/MaterialXGenMdl/mdl/materialx](../source/MaterialXGenMdl/mdl/materialx) package folder - - [genmsl](stdlib/genmsl): MSL language support. - - [lib](stdlib/genmsl/lib) : Shader utility files. - - [stdlib_genmsl_impl.mtlx](stdlib/genmsl/stdlib_genmsl_impl.mtlx) : Mapping from declarations to implementations. - -## Physically Based Shading Library -- [pbrlib](pbrlib) - - [pbrlib_defs.mtlx](pbrlib/pbrlib_defs.mtlx) : Nodedef declarations. - - [pbrlib_ng.mtlx](pbrlib/pbrlib_ng.mtlx) : Nodegraph definitions. - - [genglsl](pbrlib/genglsl) : GLSL language support - - [lib](pbrlib/genglsl/lib) : Shader utility files. - - [pbrlib_genglsl_impl.mtlx](pbrlib/genglsl/pbrlib_genglsl_impl.mtlx) : Mapping from declarations to implementations. - - [genosl](pbrlib/genosl) : OSL language support - - [lib](pbrlib/genosl/lib) : Shader utility files. - - [pbrlib_genosl_impl.mtlx](pbrlib/genosl/pbrlib_genosl_impl.mtlx) : Mapping from declarations to implementations. - - [genmdl](pbrlib/genmdl) : MDL language support - - [pbrlib_genmdl_impl.mtlx](pbrlib/genmdl/pbrlib_genmdl_impl.mtlx) : Mapping from declarations to implementations. - - [genmsl](pbrlib/genmsl) : MSL language support - - [pbrlib_genmsl_impl.mtlx](pbrlib/genmsl/pbrlib_genmsl_impl.mtlx) : Mapping from declarations to implementations. - -## BxDF Graph Library -- [bxdf](bxdf) - - [standard_surface.mtlx](bxdf/standard_surface.mtlx) : Graph definition of the [Autodesk Standard Surface](https://autodesk.github.io/standard-surface/) shading model. - - [gltf_pbr.mtlx](bxdf/gltf_pbr.mtlx) : Graph definition of the [glTF PBR](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#appendix-b-brdf-implementation) shading model. - - [usd_preview_surface.mtlx](bxdf/usd_preview_surface.mtlx) : Graph definition of the [UsdPreviewSurface](https://openusd.org/release/spec_usdpreviewsurface.html) shading model. - - [lama](bxdf/lama) : Graph definitions of the [MaterialX Lama](https://rmanwiki.pixar.com/display/REN24/MaterialX+Lama) node set. - -## Color Management Library -- MaterialX shader generation natively supports a small set of common spaces for input colors, with all color transforms implemented as language-independent MaterialX graphs.The canonical definitions of these color transforms may be found in the OpenColorIO configuration for [ACES 1.2](https://github.com/colour-science/OpenColorIO-Configs/tree/feature/aces-1.2-config/aces_1.2). - - lin_rec709 - - g18_rec709 - - g22_rec709 - - rec709_display - - acescg (lin_ap1) - - g22_ap1 - - srgb_texture - - lin_adobergb - - adobergb - - srgb_displayp3 - - lin_displayp3 -- [cmlib](cmlib) - - [cmlib_defs.mtlx](cmlib/cmlib_defs.mtlx) : Nodedef declarations. - - [cmlib_ng.mtlx](cmlib/cmlib_ng.mtlx) : Nodegraph definitions. - -## Target Definitions -- Each target implementation requires a target definition for declaration / implementation correspondence to work. -- The [targets](targets) folder contains definition files for the following core targets: - - GLSL : `genglsl` - - OSL : `genosl` - - MDL : `genmdl` - - MSL : `genmsl` -- Any additional target files should be added under this folder and loaded in as required. - -### Target Support -- GLSL target support is for version 4.0 or higher. -- OSL target support is for version 1.12.6 or higher. -- MDL target support is for version 1.6 or higher. -- 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: - - `displacementshader` and `volumeshader` nodes for hardware shading targets (GLSL, MSL). - - `hextiledimage` and `hextilednormalmap` for OSL and MDL. - - `blur` the implementation passes through `in` unmodified in all shading languages. +# MaterialX Data Libraries + +This folder contains the standard data libraries for MaterialX, providing declarations and graph definitions for the MaterialX nodes, and source code for all supported shader generators. + +## Standard Pattern Library +- [stdlib](stdlib) + - [stdlib_defs.mtlx](stdlib/stdlib_defs.mtlx) : Nodedef declarations. + - [stdlib_ng.mtlx](stdlib/stdlib_ng.mtlx) : Nodegraph definitions. + - [genglsl](stdlib/genglsl): GLSL language support. + - [lib](stdlib/genglsl/lib) : Shader utility files. + - [stdlib_genglsl_impl.mtlx](stdlib/genglsl/stdlib_genglsl_impl.mtlx) : Mapping from declarations to implementations. + - [genosl](stdlib/genosl): OSL language support. + - [lib](stdlib/genosl/lib) : Shader utility files. + - [stdlib_genosl_impl.mtlx](stdlib/genosl/stdlib_genosl_impl.mtlx) : Mapping from declarations to implementations. + - [genmdl](stdlib/genmdl): MDL language support. + - [stdlib_genmdl_impl.mtlx](stdlib/genmdl/stdlib_genmdl_impl.mtlx) : Mapping from declarations to implementations. + - Additional MaterialX support libraries for MDL are located in the [source/MaterialXGenMdl/mdl/materialx](../source/MaterialXGenMdl/mdl/materialx) package folder + - [genmsl](stdlib/genmsl): MSL language support. + - [lib](stdlib/genmsl/lib) : Shader utility files. + - [stdlib_genmsl_impl.mtlx](stdlib/genmsl/stdlib_genmsl_impl.mtlx) : Mapping from declarations to implementations. + +## Physically Based Shading Library +- [pbrlib](pbrlib) + - [pbrlib_defs.mtlx](pbrlib/pbrlib_defs.mtlx) : Nodedef declarations. + - [pbrlib_ng.mtlx](pbrlib/pbrlib_ng.mtlx) : Nodegraph definitions. + - [genglsl](pbrlib/genglsl) : GLSL language support + - [lib](pbrlib/genglsl/lib) : Shader utility files. + - [pbrlib_genglsl_impl.mtlx](pbrlib/genglsl/pbrlib_genglsl_impl.mtlx) : Mapping from declarations to implementations. + - [genosl](pbrlib/genosl) : OSL language support + - [lib](pbrlib/genosl/lib) : Shader utility files. + - [pbrlib_genosl_impl.mtlx](pbrlib/genosl/pbrlib_genosl_impl.mtlx) : Mapping from declarations to implementations. + - [genmdl](pbrlib/genmdl) : MDL language support + - [pbrlib_genmdl_impl.mtlx](pbrlib/genmdl/pbrlib_genmdl_impl.mtlx) : Mapping from declarations to implementations. + - [genmsl](pbrlib/genmsl) : MSL language support + - [pbrlib_genmsl_impl.mtlx](pbrlib/genmsl/pbrlib_genmsl_impl.mtlx) : Mapping from declarations to implementations. + +## BxDF Graph Library +- [bxdf](bxdf) + - [standard_surface.mtlx](bxdf/standard_surface.mtlx) : Graph definition of the [Autodesk Standard Surface](https://autodesk.github.io/standard-surface/) shading model. + - [gltf_pbr.mtlx](bxdf/gltf_pbr.mtlx) : Graph definition of the [glTF PBR](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#appendix-b-brdf-implementation) shading model. + - [usd_preview_surface.mtlx](bxdf/usd_preview_surface.mtlx) : Graph definition of the [UsdPreviewSurface](https://openusd.org/release/spec_usdpreviewsurface.html) shading model. + - [lama](bxdf/lama) : Graph definitions of the [MaterialX Lama](https://rmanwiki.pixar.com/display/REN24/MaterialX+Lama) node set. + +## Color Management Library +- MaterialX shader generation natively supports a small set of common spaces for input colors, with all color transforms implemented as language-independent MaterialX graphs.The canonical definitions of these color transforms may be found in the OpenColorIO configuration for [ACES 1.2](https://github.com/colour-science/OpenColorIO-Configs/tree/feature/aces-1.2-config/aces_1.2). + - lin_rec709 + - g18_rec709 + - g22_rec709 + - rec709_display + - acescg (lin_ap1) + - g22_ap1 + - srgb_texture + - lin_adobergb + - adobergb + - srgb_displayp3 + - lin_displayp3 +- [cmlib](cmlib) + - [cmlib_defs.mtlx](cmlib/cmlib_defs.mtlx) : Nodedef declarations. + - [cmlib_ng.mtlx](cmlib/cmlib_ng.mtlx) : Nodegraph definitions. + +## Target Definitions +- Each target implementation requires a target definition for declaration / implementation correspondence to work. +- The [targets](targets) folder contains definition files for the following core targets: + - GLSL : `genglsl` + - OSL : `genosl` + - MDL : `genmdl` + - MSL : `genmsl` +- Any additional target files should be added under this folder and loaded in as required. + +### Target Support +- GLSL target support is for version 4.0 or higher. +- OSL target support is for version 1.9.10 or higher. +- MDL target support is for version 1.7. +- 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/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_default.mtlx b/MaterialX/libraries/bxdf/disney_brdf_2012.mtlx old mode 100644 new mode 100755 similarity index 60% rename from MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_default.mtlx rename to MaterialX/libraries/bxdf/disney_brdf_2012.mtlx index 717d769..4f812fd --- a/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_default.mtlx +++ b/MaterialX/libraries/bxdf/disney_brdf_2012.mtlx @@ -1,21 +1,18 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/disney_brdf_2015.mtlx b/MaterialX/libraries/bxdf/disney_brdf_2015.mtlx new file mode 100755 index 0000000..647544d --- /dev/null +++ b/MaterialX/libraries/bxdf/disney_brdf_2015.mtlx @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/disney_principled.mtlx b/MaterialX/libraries/bxdf/disney_principled.mtlx deleted file mode 100644 index 72394cb..0000000 --- a/MaterialX/libraries/bxdf/disney_principled.mtlx +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/libraries/bxdf/genglsl/gltf_pbr.mtlx b/MaterialX/libraries/bxdf/genglsl/gltf_pbr.mtlx deleted file mode 100644 index c60c566..0000000 --- a/MaterialX/libraries/bxdf/genglsl/gltf_pbr.mtlx +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/libraries/bxdf/genglsl/open_pbr_surface.mtlx b/MaterialX/libraries/bxdf/genglsl/open_pbr_surface.mtlx deleted file mode 100644 index 85d8717..0000000 --- a/MaterialX/libraries/bxdf/genglsl/open_pbr_surface.mtlx +++ /dev/null @@ -1,596 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/libraries/bxdf/genglsl/standard_surface.mtlx b/MaterialX/libraries/bxdf/genglsl/standard_surface.mtlx deleted file mode 100644 index bedae8e..0000000 --- a/MaterialX/libraries/bxdf/genglsl/standard_surface.mtlx +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/libraries/bxdf/genmdl/open_pbr_surface.mtlx b/MaterialX/libraries/bxdf/genmdl/open_pbr_surface.mtlx deleted file mode 100644 index d040812..0000000 --- a/MaterialX/libraries/bxdf/genmdl/open_pbr_surface.mtlx +++ /dev/null @@ -1,593 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/libraries/bxdf/gltf_pbr.mtlx b/MaterialX/libraries/bxdf/gltf_pbr.mtlx old mode 100644 new mode 100755 index 3675bae..d1f9650 --- a/MaterialX/libraries/bxdf/gltf_pbr.mtlx +++ b/MaterialX/libraries/bxdf/gltf_pbr.mtlx @@ -1,816 +1,695 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_add.mtlx b/MaterialX/libraries/bxdf/lama/lama_add.mtlx old mode 100644 new mode 100755 index d589e36..91b3097 --- a/MaterialX/libraries/bxdf/lama/lama_add.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_add.mtlx @@ -1,52 +1,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_conductor.mtlx b/MaterialX/libraries/bxdf/lama/lama_conductor.mtlx old mode 100644 new mode 100755 index d3a8cb7..4e0dcf6 --- a/MaterialX/libraries/bxdf/lama/lama_conductor.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_conductor.mtlx @@ -1,123 +1,123 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_dielectric.mtlx b/MaterialX/libraries/bxdf/lama/lama_dielectric.mtlx old mode 100644 new mode 100755 index 1aa75e5..b6c42f1 --- a/MaterialX/libraries/bxdf/lama/lama_dielectric.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_dielectric.mtlx @@ -1,163 +1,163 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_diffuse.mtlx b/MaterialX/libraries/bxdf/lama/lama_diffuse.mtlx old mode 100644 new mode 100755 index 358c728..8f7315b --- a/MaterialX/libraries/bxdf/lama/lama_diffuse.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_diffuse.mtlx @@ -1,45 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_emission.mtlx b/MaterialX/libraries/bxdf/lama/lama_emission.mtlx old mode 100644 new mode 100755 index 3f73144..4850801 --- a/MaterialX/libraries/bxdf/lama/lama_emission.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_emission.mtlx @@ -1,20 +1,20 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_generalized_schlick.mtlx b/MaterialX/libraries/bxdf/lama/lama_generalized_schlick.mtlx old mode 100644 new mode 100755 index 84fa57c..e101171 --- a/MaterialX/libraries/bxdf/lama/lama_generalized_schlick.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_generalized_schlick.mtlx @@ -1,172 +1,172 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_iridescence.mtlx b/MaterialX/libraries/bxdf/lama/lama_iridescence.mtlx old mode 100644 new mode 100755 index 5383f5f..a01ed65 --- a/MaterialX/libraries/bxdf/lama/lama_iridescence.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_iridescence.mtlx @@ -1,103 +1,103 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_layer.mtlx b/MaterialX/libraries/bxdf/lama/lama_layer.mtlx old mode 100644 new mode 100755 index 921ec36..5c80ea6 --- a/MaterialX/libraries/bxdf/lama/lama_layer.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_layer.mtlx @@ -1,27 +1,27 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_mix.mtlx b/MaterialX/libraries/bxdf/lama/lama_mix.mtlx old mode 100644 new mode 100755 index 69e6ad3..f1e4d74 --- a/MaterialX/libraries/bxdf/lama/lama_mix.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_mix.mtlx @@ -1,41 +1,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_sheen.mtlx b/MaterialX/libraries/bxdf/lama/lama_sheen.mtlx old mode 100644 new mode 100755 index 8accb41..1543a1f --- a/MaterialX/libraries/bxdf/lama/lama_sheen.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_sheen.mtlx @@ -1,41 +1,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_sss.mtlx b/MaterialX/libraries/bxdf/lama/lama_sss.mtlx old mode 100644 new mode 100755 index f09d2da..247dc94 --- a/MaterialX/libraries/bxdf/lama/lama_sss.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_sss.mtlx @@ -1,60 +1,60 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_surface.mtlx b/MaterialX/libraries/bxdf/lama/lama_surface.mtlx old mode 100644 new mode 100755 index b7e84a5..b3537fd --- a/MaterialX/libraries/bxdf/lama/lama_surface.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_surface.mtlx @@ -1,28 +1,28 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/lama/lama_translucent.mtlx b/MaterialX/libraries/bxdf/lama/lama_translucent.mtlx old mode 100644 new mode 100755 index ec3e968..0854664 --- a/MaterialX/libraries/bxdf/lama/lama_translucent.mtlx +++ b/MaterialX/libraries/bxdf/lama/lama_translucent.mtlx @@ -1,22 +1,22 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/open_pbr_surface.mtlx b/MaterialX/libraries/bxdf/open_pbr_surface.mtlx old mode 100644 new mode 100755 index 2728d47..6835daf --- a/MaterialX/libraries/bxdf/open_pbr_surface.mtlx +++ b/MaterialX/libraries/bxdf/open_pbr_surface.mtlx @@ -1,676 +1,676 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/standard_surface.mtlx b/MaterialX/libraries/bxdf/standard_surface.mtlx old mode 100644 new mode 100755 index 4959584..b3c010b --- a/MaterialX/libraries/bxdf/standard_surface.mtlx +++ b/MaterialX/libraries/bxdf/standard_surface.mtlx @@ -1,431 +1,431 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx b/MaterialX/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx old mode 100644 new mode 100755 index f9ca1cd..5198a8c --- a/MaterialX/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx +++ b/MaterialX/libraries/bxdf/translation/open_pbr_to_standard_surface.mtlx @@ -1,362 +1,362 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx b/MaterialX/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx old mode 100644 new mode 100755 index 2db18e9..94cb990 --- a/MaterialX/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx +++ b/MaterialX/libraries/bxdf/translation/standard_surface_to_gltf_pbr.mtlx @@ -1,302 +1,145 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx b/MaterialX/libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx old mode 100644 new mode 100755 index 4edc743..9a7681c --- a/MaterialX/libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx +++ b/MaterialX/libraries/bxdf/translation/standard_surface_to_open_pbr.mtlx @@ -1,309 +1,309 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/translation/standard_surface_to_usd.mtlx b/MaterialX/libraries/bxdf/translation/standard_surface_to_usd.mtlx old mode 100644 new mode 100755 index c92038c..e8171ff --- a/MaterialX/libraries/bxdf/translation/standard_surface_to_usd.mtlx +++ b/MaterialX/libraries/bxdf/translation/standard_surface_to_usd.mtlx @@ -1,128 +1,117 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/bxdf/usd_preview_surface.mtlx b/MaterialX/libraries/bxdf/usd_preview_surface.mtlx old mode 100644 new mode 100755 index 657921e..f62e4aa --- a/MaterialX/libraries/bxdf/usd_preview_surface.mtlx +++ b/MaterialX/libraries/bxdf/usd_preview_surface.mtlx @@ -1,438 +1,408 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/cmlib/cmlib_defs.mtlx b/MaterialX/libraries/cmlib/cmlib_defs.mtlx old mode 100644 new mode 100755 index 0f73109..83f18a3 --- a/MaterialX/libraries/cmlib/cmlib_defs.mtlx +++ b/MaterialX/libraries/cmlib/cmlib_defs.mtlx @@ -1,110 +1,110 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/cmlib/cmlib_ng.mtlx b/MaterialX/libraries/cmlib/cmlib_ng.mtlx old mode 100644 new mode 100755 index 4f37d0a..0031dba --- a/MaterialX/libraries/cmlib/cmlib_ng.mtlx +++ b/MaterialX/libraries/cmlib/cmlib_ng.mtlx @@ -1,390 +1,392 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/lights/genglsl/lights_genglsl_impl.mtlx b/MaterialX/libraries/lights/genglsl/lights_genglsl_impl.mtlx old mode 100644 new mode 100755 index d9c2d03..74e6e15 --- a/MaterialX/libraries/lights/genglsl/lights_genglsl_impl.mtlx +++ b/MaterialX/libraries/lights/genglsl/lights_genglsl_impl.mtlx @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/MaterialX/libraries/lights/genglsl/mx_directional_light.glsl b/MaterialX/libraries/lights/genglsl/mx_directional_light.glsl old mode 100644 new mode 100755 index 634c5fe..5907c79 --- a/MaterialX/libraries/lights/genglsl/mx_directional_light.glsl +++ b/MaterialX/libraries/lights/genglsl/mx_directional_light.glsl @@ -1,5 +1,5 @@ -void mx_directional_light(LightData light, vec3 position, out lightshader result) -{ - result.direction = -light.direction; - result.intensity = light.color * light.intensity; -} +void mx_directional_light(LightData light, vec3 position, out lightshader result) +{ + result.direction = -light.direction; + result.intensity = light.color * light.intensity; +} diff --git a/MaterialX/libraries/lights/genglsl/mx_point_light.glsl b/MaterialX/libraries/lights/genglsl/mx_point_light.glsl old mode 100644 new mode 100755 index c94b222..961b6a7 --- a/MaterialX/libraries/lights/genglsl/mx_point_light.glsl +++ b/MaterialX/libraries/lights/genglsl/mx_point_light.glsl @@ -1,8 +1,8 @@ -void mx_point_light(LightData light, vec3 position, out lightshader result) -{ - result.direction = light.position - position; - float distance = length(result.direction) + M_FLOAT_EPS; - float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS); - result.intensity = light.color * light.intensity / attenuation; - result.direction /= distance; -} +void mx_point_light(LightData light, vec3 position, out lightshader result) +{ + result.direction = light.position - position; + float distance = length(result.direction) + M_FLOAT_EPS; + float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS); + result.intensity = light.color * light.intensity / attenuation; + result.direction /= distance; +} diff --git a/MaterialX/libraries/lights/genglsl/mx_spot_light.glsl b/MaterialX/libraries/lights/genglsl/mx_spot_light.glsl old mode 100644 new mode 100755 index b360784..720442c --- a/MaterialX/libraries/lights/genglsl/mx_spot_light.glsl +++ b/MaterialX/libraries/lights/genglsl/mx_spot_light.glsl @@ -1,13 +1,13 @@ -void mx_spot_light(LightData light, vec3 position, out lightshader result) -{ - result.direction = light.position - position; - float distance = length(result.direction) + M_FLOAT_EPS; - float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS); - result.intensity = light.color * light.intensity / attenuation; - result.direction /= distance; - float low = min(light.inner_angle, light.outer_angle); - float high = light.inner_angle; - float cosDir = dot(result.direction, -light.direction); - float spotAttenuation = smoothstep(low, high, cosDir); - result.intensity *= spotAttenuation; -} +void mx_spot_light(LightData light, vec3 position, out lightshader result) +{ + result.direction = light.position - position; + float distance = length(result.direction) + M_FLOAT_EPS; + float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS); + result.intensity = light.color * light.intensity / attenuation; + result.direction /= distance; + float low = min(light.inner_angle, light.outer_angle); + float high = light.inner_angle; + float cosDir = dot(result.direction, -light.direction); + float spotAttenuation = smoothstep(low, high, cosDir); + result.intensity *= spotAttenuation; +} diff --git a/MaterialX/libraries/lights/genmsl/lights_genmsl_impl.mtlx b/MaterialX/libraries/lights/genmsl/lights_genmsl_impl.mtlx old mode 100644 new mode 100755 index deba242..3e872cf --- a/MaterialX/libraries/lights/genmsl/lights_genmsl_impl.mtlx +++ b/MaterialX/libraries/lights/genmsl/lights_genmsl_impl.mtlx @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/MaterialX/libraries/lights/genmsl/mx_directional_light.metal b/MaterialX/libraries/lights/genmsl/mx_directional_light.metal old mode 100644 new mode 100755 index 8f90b4e..4b2cdbc --- a/MaterialX/libraries/lights/genmsl/mx_directional_light.metal +++ b/MaterialX/libraries/lights/genmsl/mx_directional_light.metal @@ -1,5 +1,5 @@ -void mx_directional_light(LightData light, float3 position, thread lightshader& result) -{ - result.direction = -light.direction; - result.intensity = light.color * light.intensity; -} +void mx_directional_light(LightData light, float3 position, thread lightshader& result) +{ + result.direction = -light.direction; + result.intensity = light.color * light.intensity; +} diff --git a/MaterialX/libraries/lights/genmsl/mx_point_light.metal b/MaterialX/libraries/lights/genmsl/mx_point_light.metal old mode 100644 new mode 100755 index b4d5b12..4da78ca --- a/MaterialX/libraries/lights/genmsl/mx_point_light.metal +++ b/MaterialX/libraries/lights/genmsl/mx_point_light.metal @@ -1,8 +1,8 @@ -void mx_point_light(LightData light, float3 position, thread lightshader& result) -{ - result.direction = light.position - position; - float distance = length(result.direction) + M_FLOAT_EPS; - float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS); - result.intensity = light.color * light.intensity / attenuation; - result.direction /= distance; -} +void mx_point_light(LightData light, float3 position, thread lightshader& result) +{ + result.direction = light.position - position; + float distance = length(result.direction) + M_FLOAT_EPS; + float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS); + result.intensity = light.color * light.intensity / attenuation; + result.direction /= distance; +} diff --git a/MaterialX/libraries/lights/genmsl/mx_spot_light.metal b/MaterialX/libraries/lights/genmsl/mx_spot_light.metal old mode 100644 new mode 100755 index cfcc646..24f2e5d --- a/MaterialX/libraries/lights/genmsl/mx_spot_light.metal +++ b/MaterialX/libraries/lights/genmsl/mx_spot_light.metal @@ -1,13 +1,13 @@ -void mx_spot_light(LightData light, float3 position, thread lightshader& result) -{ - result.direction = light.position - position; - float distance = length(result.direction) + M_FLOAT_EPS; - float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS); - result.intensity = light.color * light.intensity / attenuation; - result.direction /= distance; - float low = min(light.inner_angle, light.outer_angle); - float high = light.inner_angle; - float cosDir = dot(result.direction, -light.direction); - float spotAttenuation = smoothstep(low, high, cosDir); - result.intensity *= spotAttenuation; -} +void mx_spot_light(LightData light, float3 position, thread lightshader& result) +{ + result.direction = light.position - position; + float distance = length(result.direction) + M_FLOAT_EPS; + float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS); + result.intensity = light.color * light.intensity / attenuation; + result.direction /= distance; + float low = min(light.inner_angle, light.outer_angle); + float high = light.inner_angle; + float cosDir = dot(result.direction, -light.direction); + float spotAttenuation = smoothstep(low, high, cosDir); + result.intensity *= spotAttenuation; +} diff --git a/MaterialX/libraries/lights/genslang/lights_genslang_impl.mtlx b/MaterialX/libraries/lights/genslang/lights_genslang_impl.mtlx deleted file mode 100644 index 61fa148..0000000 --- a/MaterialX/libraries/lights/genslang/lights_genslang_impl.mtlx +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/MaterialX/libraries/lights/genslang/mx_directional_light.slang b/MaterialX/libraries/lights/genslang/mx_directional_light.slang deleted file mode 100644 index 5333aa0..0000000 --- a/MaterialX/libraries/lights/genslang/mx_directional_light.slang +++ /dev/null @@ -1,5 +0,0 @@ -void mx_directional_light(LightData light, float3 position, out lightshader result) -{ - result.direction = -light.direction; - result.intensity = light.color * light.intensity; -} diff --git a/MaterialX/libraries/lights/genslang/mx_point_light.slang b/MaterialX/libraries/lights/genslang/mx_point_light.slang deleted file mode 100644 index 53a8a12..0000000 --- a/MaterialX/libraries/lights/genslang/mx_point_light.slang +++ /dev/null @@ -1,8 +0,0 @@ -void mx_point_light(LightData light, float3 position, out lightshader result) -{ - result.direction = light.position - position; - float distance = length(result.direction) + M_FLOAT_EPS; - float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS); - result.intensity = light.color * light.intensity / attenuation; - result.direction /= distance; -} diff --git a/MaterialX/libraries/lights/genslang/mx_spot_light.slang b/MaterialX/libraries/lights/genslang/mx_spot_light.slang deleted file mode 100644 index 22de861..0000000 --- a/MaterialX/libraries/lights/genslang/mx_spot_light.slang +++ /dev/null @@ -1,13 +0,0 @@ -void mx_spot_light(LightData light, float3 position, out lightshader result) -{ - result.direction = light.position - position; - float distance = length(result.direction) + M_FLOAT_EPS; - float attenuation = pow(distance + 1.0, light.decay_rate + M_FLOAT_EPS); - result.intensity = light.color * light.intensity / attenuation; - result.direction /= distance; - float low = min(light.inner_angle, light.outer_angle); - float high = light.inner_angle; - float cosDir = dot(result.direction, -light.direction); - float spotAttenuation = smoothstep(low, high, cosDir); - result.intensity *= spotAttenuation; -} diff --git a/MaterialX/libraries/lights/lights_defs.mtlx b/MaterialX/libraries/lights/lights_defs.mtlx old mode 100644 new mode 100755 index d0a3d49..2a67813 --- a/MaterialX/libraries/lights/lights_defs.mtlx +++ b/MaterialX/libraries/lights/lights_defs.mtlx @@ -1,53 +1,53 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/nprlib/genglsl/nprlib_genglsl_impl.mtlx b/MaterialX/libraries/nprlib/genglsl/nprlib_genglsl_impl.mtlx old mode 100644 new mode 100755 index dd9700b..516c9f3 --- a/MaterialX/libraries/nprlib/genglsl/nprlib_genglsl_impl.mtlx +++ b/MaterialX/libraries/nprlib/genglsl/nprlib_genglsl_impl.mtlx @@ -1,17 +1,17 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/MaterialX/libraries/nprlib/genmdl/nprlib_genmdl_impl.mtlx b/MaterialX/libraries/nprlib/genmdl/nprlib_genmdl_impl.mtlx old mode 100644 new mode 100755 index 105751f..52b20b1 --- a/MaterialX/libraries/nprlib/genmdl/nprlib_genmdl_impl.mtlx +++ b/MaterialX/libraries/nprlib/genmdl/nprlib_genmdl_impl.mtlx @@ -1,17 +1,17 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/MaterialX/libraries/nprlib/genmsl/nprlib_genmsl_impl.mtlx b/MaterialX/libraries/nprlib/genmsl/nprlib_genmsl_impl.mtlx old mode 100644 new mode 100755 index 28e470b..efe6ce2 --- a/MaterialX/libraries/nprlib/genmsl/nprlib_genmsl_impl.mtlx +++ b/MaterialX/libraries/nprlib/genmsl/nprlib_genmsl_impl.mtlx @@ -1,17 +1,17 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/MaterialX/libraries/nprlib/genosl/nprlib_genosl_impl.mtlx b/MaterialX/libraries/nprlib/genosl/nprlib_genosl_impl.mtlx old mode 100644 new mode 100755 index 9b3d361..9857cff --- a/MaterialX/libraries/nprlib/genosl/nprlib_genosl_impl.mtlx +++ b/MaterialX/libraries/nprlib/genosl/nprlib_genosl_impl.mtlx @@ -1,17 +1,17 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/MaterialX/libraries/nprlib/genslang/nprlib_genslang_impl.mtlx b/MaterialX/libraries/nprlib/genslang/nprlib_genslang_impl.mtlx deleted file mode 100644 index 71288b7..0000000 --- a/MaterialX/libraries/nprlib/genslang/nprlib_genslang_impl.mtlx +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - diff --git a/MaterialX/libraries/nprlib/nprlib_defs.mtlx b/MaterialX/libraries/nprlib/nprlib_defs.mtlx old mode 100644 new mode 100755 index bb6d2e8..1749aec --- a/MaterialX/libraries/nprlib/nprlib_defs.mtlx +++ b/MaterialX/libraries/nprlib/nprlib_defs.mtlx @@ -1,55 +1,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/nprlib/nprlib_ng.mtlx b/MaterialX/libraries/nprlib/nprlib_ng.mtlx old mode 100644 new mode 100755 index e0a0d34..aceade4 --- a/MaterialX/libraries/nprlib/nprlib_ng.mtlx +++ b/MaterialX/libraries/nprlib/nprlib_ng.mtlx @@ -1,114 +1,114 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_closure_type.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_closure_type.glsl deleted file mode 100644 index aca19f1..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_closure_type.glsl +++ /dev/null @@ -1,22 +0,0 @@ -// These are defined based on the HwShaderGenerator::ClosureContextType enum -// if that changes - these need to be updated accordingly. - -#define CLOSURE_TYPE_DEFAULT 0 -#define CLOSURE_TYPE_REFLECTION 1 -#define CLOSURE_TYPE_TRANSMISSION 2 -#define CLOSURE_TYPE_INDIRECT 3 -#define CLOSURE_TYPE_EMISSION 4 - -struct ClosureData { - int closureType; - vec3 L; - vec3 V; - vec3 N; - vec3 P; - float occlusion; -}; - -ClosureData makeClosureData(int closureType, vec3 L, vec3 V, vec3 N, vec3 P, float occlusion) -{ - return $closureDataConstructor; -} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl old mode 100644 new mode 100755 index 5918966..00dcd48 --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl @@ -1,69 +1,69 @@ -#include "mx_microfacet_specular.glsl" - -vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd) -{ - // Generate tangent frame. - X = normalize(X - dot(X, N) * N); - vec3 Y = cross(N, X); - mat3 tangentToWorld = mat3(X, Y, N); - - // Transform the view vector to tangent space. - V = vec3(dot(V, X), dot(V, Y), dot(V, N)); - - // Compute derived properties. - float NdotV = clamp(V.z, M_FLOAT_EPS, 1.0); - float avgAlpha = mx_average_alpha(alpha); - float G1V = mx_ggx_smith_G1(NdotV, avgAlpha); - - // Integrate outgoing radiance using filtered importance sampling. - // http://cgg.mff.cuni.cz/~jaroslav/papers/2008-egsr-fis/2008-egsr-fis-final-embedded.pdf - vec3 radiance = vec3(0.0); - int envRadianceSamples = $envRadianceSamples; - for (int i = 0; i < envRadianceSamples; i++) - { - vec2 Xi = mx_spherical_fibonacci(i, envRadianceSamples); - - // Compute the half vector and incoming light direction. - vec3 H = mx_ggx_importance_sample_VNDF(Xi, V, alpha); - vec3 L = fd.refraction ? mx_refraction_solid_sphere(-V, H, fd.ior.x) : -reflect(V, H); - - // Compute dot products for this sample. - float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0); - float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0); - - // Sample the environment light from the given direction. - vec3 Lw = mx_matrix_mul(tangentToWorld, L); - float pdf = mx_ggx_NDF(H, alpha) * G1V / (4.0 * NdotV); - float lod = mx_latlong_compute_lod(Lw, pdf, float($envRadianceMips - 1), envRadianceSamples); - vec3 sampleColor = mx_latlong_map_lookup(Lw, $envMatrix, lod, $envRadiance); - - // Compute the Fresnel term. - vec3 F = mx_compute_fresnel(VdotH, fd); - - // Compute the geometric term. - float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); - - // 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 - // incidentLight = sampleColor * NdotL - // microfacetSpecular = D * F * G / (4 * NdotL * NdotV) - // pdf = D * G1V / (4 * NdotV); - // radiance = incidentLight * microfacetSpecular / pdf - radiance += sampleColor * FG; - } - - // Apply the global component of the geometric term and normalize. - radiance /= G1V * float(envRadianceSamples); - - // Return the final radiance. - return ($envRadianceSamples == 0 ? vec3(0.0) : radiance) * $envLightIntensity; -} - -vec3 mx_environment_irradiance(vec3 N) -{ - vec3 Li = mx_latlong_map_lookup(N, $envMatrix, 0.0, $envIrradiance); - return Li * $envLightIntensity; -} +#include "mx_microfacet_specular.glsl" + +vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd) +{ + // Generate tangent frame. + X = normalize(X - dot(X, N) * N); + vec3 Y = cross(N, X); + mat3 tangentToWorld = mat3(X, Y, N); + + // Transform the view vector to tangent space. + V = vec3(dot(V, X), dot(V, Y), dot(V, N)); + + // Compute derived properties. + float NdotV = clamp(V.z, M_FLOAT_EPS, 1.0); + float avgAlpha = mx_average_alpha(alpha); + float G1V = mx_ggx_smith_G1(NdotV, avgAlpha); + + // Integrate outgoing radiance using filtered importance sampling. + // http://cgg.mff.cuni.cz/~jaroslav/papers/2008-egsr-fis/2008-egsr-fis-final-embedded.pdf + vec3 radiance = vec3(0.0); + int envRadianceSamples = $envRadianceSamples; + for (int i = 0; i < envRadianceSamples; i++) + { + vec2 Xi = mx_spherical_fibonacci(i, envRadianceSamples); + + // Compute the half vector and incoming light direction. + vec3 H = mx_ggx_importance_sample_VNDF(Xi, V, alpha); + vec3 L = fd.refraction ? mx_refraction_solid_sphere(-V, H, fd.ior.x) : -reflect(V, H); + + // Compute dot products for this sample. + float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0); + float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0); + + // Sample the environment light from the given direction. + vec3 Lw = tangentToWorld * L; + float pdf = mx_ggx_NDF(H, alpha) * G1V / (4.0 * NdotV); + float lod = mx_latlong_compute_lod(Lw, pdf, float($envRadianceMips - 1), envRadianceSamples); + vec3 sampleColor = mx_latlong_map_lookup(Lw, $envMatrix, lod, $envRadiance); + + // Compute the Fresnel term. + vec3 F = mx_compute_fresnel(VdotH, fd); + + // Compute the geometric term. + float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); + + // 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 + // incidentLight = sampleColor * NdotL + // microfacetSpecular = D * F * G / (4 * NdotL * NdotV) + // pdf = D * G1V / (4 * NdotV); + // radiance = incidentLight * microfacetSpecular / pdf + radiance += sampleColor * FG; + } + + // Apply the global component of the geometric term and normalize. + radiance /= G1V * float(envRadianceSamples); + + // Return the final radiance. + return radiance * $envLightIntensity; +} + +vec3 mx_environment_irradiance(vec3 N) +{ + vec3 Li = mx_latlong_map_lookup(N, $envMatrix, 0.0, $envIrradiance); + return Li * $envLightIntensity; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_none.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_none.glsl old mode 100644 new mode 100755 index f0a1da5..36bead9 --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_none.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_none.glsl @@ -1,11 +1,11 @@ -#include "mx_microfacet_specular.glsl" - -vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 roughness, int distribution, FresnelData fd) -{ - return vec3(0.0); -} - -vec3 mx_environment_irradiance(vec3 N) -{ - return vec3(0.0); -} +#include "mx_microfacet_specular.glsl" + +vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 roughness, int distribution, FresnelData fd) +{ + return vec3(0.0); +} + +vec3 mx_environment_irradiance(vec3 N) +{ + return vec3(0.0); +} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_prefilter.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_prefilter.glsl old mode 100644 new mode 100755 index 778742c..df7933d --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_prefilter.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_environment_prefilter.glsl @@ -1,30 +1,30 @@ -#include "mx_microfacet_specular.glsl" - -// Return the mip level associated with the given alpha in a prefiltered environment. -float mx_latlong_alpha_to_lod(float alpha) -{ - float lodBias = (alpha < 0.25) ? sqrt(alpha) : 0.5 * alpha + 0.375; - return lodBias * float($envRadianceMips - 1); -} - -vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd) -{ - N = mx_forward_facing_normal(N, V); - vec3 L = fd.refraction ? mx_refraction_solid_sphere(-V, N, fd.ior.x) : -reflect(V, N); - - float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - - float avgAlpha = mx_average_alpha(alpha); - vec3 F = mx_compute_fresnel(NdotV, fd); - float G = mx_ggx_smith_G2(NdotV, NdotV, avgAlpha); - vec3 FG = fd.refraction ? vec3(1.0) - (F * G) : F * G; - - vec3 Li = mx_latlong_map_lookup(L, $envMatrix, mx_latlong_alpha_to_lod(avgAlpha), $envRadiance); - return Li * FG * $envLightIntensity; -} - -vec3 mx_environment_irradiance(vec3 N) -{ - vec3 Li = mx_latlong_map_lookup(N, $envMatrix, 0.0, $envIrradiance); - return Li * $envLightIntensity; -} +#include "mx_microfacet_specular.glsl" + +// Return the mip level associated with the given alpha in a prefiltered environment. +float mx_latlong_alpha_to_lod(float alpha) +{ + float lodBias = (alpha < 0.25) ? sqrt(alpha) : 0.5 * alpha + 0.375; + return lodBias * float($envRadianceMips - 1); +} + +vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd) +{ + N = mx_forward_facing_normal(N, V); + vec3 L = fd.refraction ? mx_refraction_solid_sphere(-V, N, fd.ior.x) : -reflect(V, N); + + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + + float avgAlpha = mx_average_alpha(alpha); + vec3 F = mx_compute_fresnel(NdotV, fd); + float G = mx_ggx_smith_G2(NdotV, NdotV, avgAlpha); + vec3 FG = fd.refraction ? vec3(1.0) - (F * G) : F * G; + + vec3 Li = mx_latlong_map_lookup(L, $envMatrix, mx_latlong_alpha_to_lod(avgAlpha), $envRadiance); + return Li * FG * $envLightIntensity; +} + +vec3 mx_environment_irradiance(vec3 N) +{ + vec3 Li = mx_latlong_map_lookup(N, $envMatrix, 0.0, $envIrradiance); + return Li * $envLightIntensity; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_generate_albedo_table.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_generate_albedo_table.glsl old mode 100644 new mode 100755 index 5d310e9..a32dcc0 --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_generate_albedo_table.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_generate_albedo_table.glsl @@ -1,10 +1,10 @@ -#include "mx_microfacet_sheen.glsl" -#include "mx_microfacet_specular.glsl" - -vec3 mx_generate_dir_albedo_table() -{ - vec2 uv = gl_FragCoord.xy / $albedoTableSize; - vec2 ggxDirAlbedo = mx_ggx_dir_albedo(uv.x, uv.y, vec3(1, 0, 0), vec3(0, 1, 0)).xy; - float sheenDirAlbedo = mx_imageworks_sheen_dir_albedo(uv.x, uv.y); - return vec3(ggxDirAlbedo, sheenDirAlbedo); -} +#include "mx_microfacet_sheen.glsl" +#include "mx_microfacet_specular.glsl" + +vec3 mx_generate_dir_albedo_table() +{ + vec2 uv = gl_FragCoord.xy / $albedoTableSize; + vec2 ggxDirAlbedo = mx_ggx_dir_albedo(uv.x, uv.y, vec3(1, 0, 0), vec3(0, 1, 0)).xy; + float sheenDirAlbedo = mx_imageworks_sheen_dir_albedo(uv.x, uv.y); + return vec3(ggxDirAlbedo, sheenDirAlbedo); +} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl old mode 100644 new mode 100755 index 33b4547..fdaac0d --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_generate_prefilter_env.glsl @@ -1,66 +1,66 @@ -#include "mx_microfacet_specular.glsl" - -// Return the alpha associated with the given mip level in a prefiltered environment. -float mx_latlong_lod_to_alpha(float lod) -{ - float lodBias = lod / float($envRadianceMips - 1); - return (lodBias < 0.5) ? mx_square(lodBias) : 2.0 * (lodBias - 0.375); -} - -// The inverse of mx_latlong_projection. -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 = -mx_cos(latitude) * mx_sin(longitude); - float y = -mx_sin(latitude); - float z = mx_cos(latitude) * mx_cos(longitude); - - return vec3(x, y, z); -} - -vec3 mx_generate_prefilter_env() -{ - // The tangent view vector is aligned with the normal. - vec3 V = vec3(0.0, 0.0, 1.0); - float NdotV = 1.0; - - // Compute derived properties. - vec2 uv = gl_FragCoord.xy * pow(2.0, $envPrefilterMip) / vec2(textureSize($envRadianceSampler2D, 0)); - vec3 worldN = mx_latlong_map_projection_inverse(uv); - mat3 tangentToWorld = mx_orthonormal_basis(worldN); - float alpha = mx_latlong_lod_to_alpha(float($envPrefilterMip)); - float G1V = mx_ggx_smith_G1(NdotV, alpha); - - // Integrate the LD term for the given environment and alpha. - vec3 radiance = vec3(0.0, 0.0, 0.0); - float weight = 0.0; - int envRadianceSamples = 1024; - for (int i = 0; i < envRadianceSamples; i++) - { - vec2 Xi = mx_spherical_fibonacci(i, envRadianceSamples); - - // Compute the half vector and incoming light direction. - vec3 H = mx_ggx_importance_sample_VNDF(Xi, V, vec2(alpha)); - vec3 L = -V + 2.0 * H.z * H; - - // Compute dot products for this sample. - float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0); - - // Compute the geometric term. - float G = mx_ggx_smith_G2(NdotL, NdotV, alpha); - - // Sample the environment light from the given direction. - vec3 Lw = mx_matrix_mul(tangentToWorld, L); - float pdf = mx_ggx_NDF(H, vec2(alpha)) * G1V / (4.0 * NdotV); - float lod = mx_latlong_compute_lod(Lw, pdf, float($envRadianceMips - 1), envRadianceSamples); - vec3 sampleColor = mx_latlong_map_lookup(Lw, $envMatrix, lod, $envRadiance); - - // Add the radiance contribution of this sample. - radiance += G * sampleColor; - weight += G; - } - - return radiance / weight; -} +#include "mx_microfacet_specular.glsl" + +// Return the alpha associated with the given mip level in a prefiltered environment. +float mx_latlong_lod_to_alpha(float lod) +{ + float lodBias = lod / float($envRadianceMips - 1); + return (lodBias < 0.5) ? mx_square(lodBias) : 2.0 * (lodBias - 0.375); +} + +// The inverse of mx_latlong_projection. +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); + + return vec3(x, y, z); +} + +vec3 mx_generate_prefilter_env() +{ + // The tangent view vector is aligned with the normal. + vec3 V = vec3(0.0, 0.0, 1.0); + float NdotV = 1.0; + + // Compute derived properties. + vec2 uv = gl_FragCoord.xy * pow(2.0, $envPrefilterMip) / vec2(textureSize($envRadiance, 0)); + vec3 worldN = mx_latlong_map_projection_inverse(uv); + mat3 tangentToWorld = mx_orthonormal_basis(worldN); + float alpha = mx_latlong_lod_to_alpha(float($envPrefilterMip)); + float G1V = mx_ggx_smith_G1(NdotV, alpha); + + // Integrate the LD term for the given environment and alpha. + vec3 radiance = vec3(0.0, 0.0, 0.0); + float weight = 0.0; + int envRadianceSamples = 1024; + for (int i = 0; i < envRadianceSamples; i++) + { + vec2 Xi = mx_spherical_fibonacci(i, envRadianceSamples); + + // Compute the half vector and incoming light direction. + vec3 H = mx_ggx_importance_sample_VNDF(Xi, V, vec2(alpha)); + vec3 L = -V + 2.0 * H.z * H; + + // Compute dot products for this sample. + float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0); + + // Compute the geometric term. + float G = mx_ggx_smith_G2(NdotL, NdotV, alpha); + + // Sample the environment light from the given direction. + vec3 Lw = tangentToWorld * L; + float pdf = mx_ggx_NDF(H, vec2(alpha)) * G1V / (4.0 * NdotV); + float lod = mx_latlong_compute_lod(Lw, pdf, float($envRadianceMips - 1), envRadianceSamples); + vec3 sampleColor = mx_latlong_map_lookup(Lw, $envMatrix, lod, $envRadiance); + + // Add the radiance contribution of this sample. + radiance += G * sampleColor; + weight += G; + } + + return radiance / weight; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl old mode 100644 new mode 100755 index 05c12e9..e35034f --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet.glsl @@ -1,106 +1,106 @@ -#define M_PI 3.1415926535897932 -#define M_PI_INV (1.0 / M_PI) - -float mx_pow5(float x) -{ - return mx_square(mx_square(x)) * x; -} - -float mx_pow6(float x) -{ - float x2 = mx_square(x); - return mx_square(x2) * x2; -} - -// Standard Schlick Fresnel -float mx_fresnel_schlick(float cosTheta, float F0) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - float x5 = mx_pow5(x); - return F0 + (1.0 - F0) * x5; -} -vec3 mx_fresnel_schlick(float cosTheta, vec3 F0) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - float x5 = mx_pow5(x); - return F0 + (1.0 - F0) * x5; -} - -// Generalized Schlick Fresnel -float mx_fresnel_schlick(float cosTheta, float F0, float F90) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - float x5 = mx_pow5(x); - return mix(F0, F90, x5); -} -vec3 mx_fresnel_schlick(float cosTheta, vec3 F0, vec3 F90) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - float x5 = mx_pow5(x); - return mix(F0, F90, x5); -} - -// Generalized Schlick Fresnel with a variable exponent -float mx_fresnel_schlick(float cosTheta, float F0, float F90, float exponent) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - return mix(F0, F90, pow(x, exponent)); -} -vec3 mx_fresnel_schlick(float cosTheta, vec3 F0, vec3 F90, float exponent) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - return mix(F0, F90, pow(x, exponent)); -} - -// Enforce that the given normal is forward-facing from the specified view direction. -vec3 mx_forward_facing_normal(vec3 N, vec3 V) -{ - return (dot(N, V) < 0.0) ? -N : N; -} - -// https://www.graphics.rwth-aachen.de/publication/2/jgt.pdf -float mx_golden_ratio_sequence(int i) -{ - const float GOLDEN_RATIO = 1.6180339887498948; - return fract((float(i) + 1.0) * GOLDEN_RATIO); -} - -// https://people.irisa.fr/Ricardo.Marques/articles/2013/SF_CGF.pdf -vec2 mx_spherical_fibonacci(int i, int numSamples) -{ - return vec2((float(i) + 0.5) / float(numSamples), mx_golden_ratio_sequence(i)); -} - -// Generate a uniform-weighted sample on the unit hemisphere. -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(mx_cos(phi) * sinTheta, - mx_sin(phi) * sinTheta, - cosTheta); -} - -// Generate a cosine-weighted sample on the unit hemisphere. -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(mx_cos(phi) * sinTheta, - mx_sin(phi) * sinTheta, - cosTheta); -} - -// Construct an orthonormal basis from a unit vector. -// https://graphics.pixar.com/library/OrthonormalB/paper.pdf -mat3 mx_orthonormal_basis(vec3 N) -{ - float sign = (N.z < 0.0) ? -1.0 : 1.0; - float a = -1.0 / (sign + N.z); - float b = N.x * N.y * a; - vec3 X = vec3(1.0 + sign * N.x * N.x * a, sign * b, -sign * N.x); - vec3 Y = vec3(b, sign + N.y * N.y * a, -N.y); - return mat3(X, Y, N); -} +#define M_PI 3.1415926535897932 +#define M_PI_INV (1.0 / M_PI) + +float mx_pow5(float x) +{ + return mx_square(mx_square(x)) * x; +} + +float mx_pow6(float x) +{ + float x2 = mx_square(x); + return mx_square(x2) * x2; +} + +// Standard Schlick Fresnel +float mx_fresnel_schlick(float cosTheta, float F0) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + float x5 = mx_pow5(x); + return F0 + (1.0 - F0) * x5; +} +vec3 mx_fresnel_schlick(float cosTheta, vec3 F0) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + float x5 = mx_pow5(x); + return F0 + (1.0 - F0) * x5; +} + +// Generalized Schlick Fresnel +float mx_fresnel_schlick(float cosTheta, float F0, float F90) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + float x5 = mx_pow5(x); + return mix(F0, F90, x5); +} +vec3 mx_fresnel_schlick(float cosTheta, vec3 F0, vec3 F90) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + float x5 = mx_pow5(x); + return mix(F0, F90, x5); +} + +// Generalized Schlick Fresnel with a variable exponent +float mx_fresnel_schlick(float cosTheta, float F0, float F90, float exponent) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + return mix(F0, F90, pow(x, exponent)); +} +vec3 mx_fresnel_schlick(float cosTheta, vec3 F0, vec3 F90, float exponent) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + return mix(F0, F90, pow(x, exponent)); +} + +// Enforce that the given normal is forward-facing from the specified view direction. +vec3 mx_forward_facing_normal(vec3 N, vec3 V) +{ + return (dot(N, V) < 0.0) ? -N : N; +} + +// https://www.graphics.rwth-aachen.de/publication/2/jgt.pdf +float mx_golden_ratio_sequence(int i) +{ + const float GOLDEN_RATIO = 1.6180339887498948; + return fract((float(i) + 1.0) * GOLDEN_RATIO); +} + +// https://people.irisa.fr/Ricardo.Marques/articles/2013/SF_CGF.pdf +vec2 mx_spherical_fibonacci(int i, int numSamples) +{ + return vec2((float(i) + 0.5) / float(numSamples), mx_golden_ratio_sequence(i)); +} + +// Generate a uniform-weighted sample on the unit hemisphere. +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, + cosTheta); +} + +// Generate a cosine-weighted sample on the unit hemisphere. +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, + cosTheta); +} + +// Construct an orthonormal basis from a unit vector. +// https://graphics.pixar.com/library/OrthonormalB/paper.pdf +mat3 mx_orthonormal_basis(vec3 N) +{ + float sign = (N.z < 0.0) ? -1.0 : 1.0; + float a = -1.0 / (sign + N.z); + float b = N.x * N.y * a; + vec3 X = vec3(1.0 + sign * N.x * N.x * a, sign * b, -sign * N.x); + vec3 Y = vec3(b, sign + N.y * N.y * a, -N.y); + return mat3(X, Y, N); +} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl old mode 100644 new mode 100755 index f26c15d..0eec9e2 --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl @@ -1,199 +1,199 @@ -#include "mx_microfacet.glsl" - -const float FUJII_CONSTANT_1 = 0.5 - 2.0 / (3.0 * M_PI); -const float FUJII_CONSTANT_2 = 2.0 / 3.0 - 28.0 / (15.0 * M_PI); - -// Qualitative Oren-Nayar diffuse with simplified math: -// https://www1.cs.columbia.edu/CAVE/publications/pdfs/Oren_SIGGRAPH94.pdf -float mx_oren_nayar_diffuse(float NdotV, float NdotL, float LdotV, float roughness) -{ - float s = LdotV - NdotL * NdotV; - float stinv = (s > 0.0) ? s / max(NdotL, NdotV) : 0.0; - - float sigma2 = mx_square(roughness); - float A = 1.0 - 0.5 * (sigma2 / (sigma2 + 0.33)); - float B = 0.45 * sigma2 / (sigma2 + 0.09); - - return A + B * stinv; -} - -// Rational quadratic fit to Monte Carlo data for Oren-Nayar directional albedo. -float mx_oren_nayar_diffuse_dir_albedo_analytic(float NdotV, float roughness) -{ - vec2 r = vec2(1.0, 1.0) + - vec2(-0.4297, -0.6076) * roughness + - vec2(-0.7632, -0.4993) * NdotV * roughness + - vec2(1.4385, 2.0315) * mx_square(roughness); - return r.x / r.y; -} - -float mx_oren_nayar_diffuse_dir_albedo_table_lookup(float NdotV, float roughness) -{ -#if DIRECTIONAL_ALBEDO_METHOD == 1 - if (textureSize($albedoTable, 0).x > 1) - { - return texture($albedoTable, vec2(NdotV, roughness)).b; - } -#endif - return 0.0; -} - -float mx_oren_nayar_diffuse_dir_albedo_monte_carlo(float NdotV, float roughness) -{ - NdotV = clamp(NdotV, M_FLOAT_EPS, 1.0); - vec3 V = vec3(sqrt(1.0 - mx_square(NdotV)), 0, NdotV); - - float radiance = 0.0; - const int SAMPLE_COUNT = 64; - for (int i = 0; i < SAMPLE_COUNT; i++) - { - vec2 Xi = mx_spherical_fibonacci(i, SAMPLE_COUNT); - - // Compute the incoming light direction. - vec3 L = mx_uniform_sample_hemisphere(Xi); - - // Compute dot products for this sample. - float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0); - float LdotV = clamp(dot(L, V), M_FLOAT_EPS, 1.0); - - // Compute diffuse reflectance. - float reflectance = mx_oren_nayar_diffuse(NdotV, NdotL, LdotV, roughness); - - // Add the radiance contribution of this sample. - // uniform_pdf = 1 / (2 * PI) - // radiance = (reflectance * NdotL) / (uniform_pdf * PI); - radiance += reflectance * NdotL; - } - - // Apply global components and normalize. - radiance *= 2.0 / float(SAMPLE_COUNT); - - // Return the final directional albedo. - return radiance; -} - -float mx_oren_nayar_diffuse_dir_albedo(float NdotV, float roughness) -{ -#if DIRECTIONAL_ALBEDO_METHOD == 2 - float dirAlbedo = mx_oren_nayar_diffuse_dir_albedo_monte_carlo(NdotV, roughness); -#else - float dirAlbedo = mx_oren_nayar_diffuse_dir_albedo_analytic(NdotV, roughness); -#endif - return clamp(dirAlbedo, 0.0, 1.0); -} - -// Improved Oren-Nayar diffuse from Fujii: -// https://mimosa-pudica.net/improved-oren-nayar.html -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 * (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); -} - -float mx_oren_nayar_fujii_diffuse_avg_albedo(float roughness) -{ - float A = 1.0 / (1.0 + FUJII_CONSTANT_1 * roughness); - return A * (1.0 + FUJII_CONSTANT_2 * roughness); -} - -// Energy-compensated Oren-Nayar diffuse from OpenPBR Surface: -// https://academysoftwarefoundation.github.io/OpenPBR/ -vec3 mx_oren_nayar_compensated_diffuse(float NdotV, float NdotL, float LdotV, float roughness, vec3 color) -{ - float s = LdotV - NdotL * NdotV; - float stinv = (s > 0.0) ? s / max(NdotL, NdotV) : s; - - // Compute the single-scatter lobe. - float A = 1.0 / (1.0 + FUJII_CONSTANT_1 * roughness); - vec3 lobeSingleScatter = color * A * (1.0 + roughness * stinv); - - // Compute the multi-scatter lobe. - float dirAlbedoV = mx_oren_nayar_fujii_diffuse_dir_albedo(NdotV, roughness); - float dirAlbedoL = mx_oren_nayar_fujii_diffuse_dir_albedo(NdotL, roughness); - float avgAlbedo = mx_oren_nayar_fujii_diffuse_avg_albedo(roughness); - vec3 colorMultiScatter = mx_square(color) * avgAlbedo / - (vec3(1.0) - color * max(0.0, 1.0 - avgAlbedo)); - vec3 lobeMultiScatter = colorMultiScatter * - max(M_FLOAT_EPS, 1.0 - dirAlbedoV) * - max(M_FLOAT_EPS, 1.0 - dirAlbedoL) / - max(M_FLOAT_EPS, 1.0 - avgAlbedo); - - // Return the sum. - return lobeSingleScatter + lobeMultiScatter; -} - -vec3 mx_oren_nayar_compensated_diffuse_dir_albedo(float cosTheta, float roughness, vec3 color) -{ - float dirAlbedo = mx_oren_nayar_fujii_diffuse_dir_albedo(cosTheta, roughness); - float avgAlbedo = mx_oren_nayar_fujii_diffuse_avg_albedo(roughness); - vec3 colorMultiScatter = mx_square(color) * avgAlbedo / - (vec3(1.0) - color * max(0.0, 1.0 - avgAlbedo)); - return mix(colorMultiScatter, color, dirAlbedo); -} - -// https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf -// Section 5.3 -float mx_burley_diffuse(float NdotV, float NdotL, float LdotH, float roughness) -{ - float F90 = 0.5 + (2.0 * roughness * mx_square(LdotH)); - float refL = mx_fresnel_schlick(NdotL, 1.0, F90); - float refV = mx_fresnel_schlick(NdotV, 1.0, F90); - return refL * refV; -} - -// Compute the directional albedo component of Burley diffuse for the given -// view angle and roughness. Curve fit provided by Stephen Hill. -float mx_burley_diffuse_dir_albedo(float NdotV, float roughness) -{ - float x = NdotV; - float fit0 = 0.97619 - 0.488095 * mx_pow5(1.0 - x); - float fit1 = 1.55754 + (-2.02221 + (2.56283 - 1.06244 * x) * x) * x; - return mix(fit0, fit1, roughness); -} - -// Evaluate the Burley diffusion profile for the given distance and diffusion shape. -// Based on https://graphics.pixar.com/library/ApproxBSSRDF/ -vec3 mx_burley_diffusion_profile(float dist, vec3 shape) -{ - vec3 num1 = exp(-shape * dist); - vec3 num2 = exp(-shape * dist / 3.0); - float denom = max(dist, M_FLOAT_EPS); - return (num1 + num2) / denom; -} - -// Integrate the Burley diffusion profile over a sphere of the given radius. -// 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 = mx_acos(dot(N, L)); - - // Estimate the Burley diffusion shape from mean free path. - vec3 shape = vec3(1.0) / max(mfp, 0.1); - - // Integrate the profile over the sphere. - vec3 sumD = vec3(0.0); - vec3 sumR = vec3(0.0); - const int SAMPLE_COUNT = 32; - const float SAMPLE_WIDTH = (2.0 * M_PI) / float(SAMPLE_COUNT); - for (int i = 0; i < SAMPLE_COUNT; i++) - { - float x = -M_PI + (float(i) + 0.5) * SAMPLE_WIDTH; - float dist = radius * abs(2.0 * mx_sin(x * 0.5)); - vec3 R = mx_burley_diffusion_profile(dist, shape); - sumD += R * max(mx_cos(theta + x), 0.0); - sumR += R; - } - - return sumD / sumR; -} - -vec3 mx_subsurface_scattering_approx(vec3 N, vec3 L, vec3 P, vec3 albedo, vec3 mfp) -{ - float curvature = length(fwidth(N)) / length(fwidth(P)); - float radius = 1.0 / max(curvature, 0.01); - return albedo * mx_integrate_burley_diffusion(N, L, radius, mfp) / vec3(M_PI); -} +#include "mx_microfacet.glsl" + +const float FUJII_CONSTANT_1 = 0.5 - 2.0 / (3.0 * M_PI); +const float FUJII_CONSTANT_2 = 2.0 / 3.0 - 28.0 / (15.0 * M_PI); + +// Qualitative Oren-Nayar diffuse with simplified math: +// https://www1.cs.columbia.edu/CAVE/publications/pdfs/Oren_SIGGRAPH94.pdf +float mx_oren_nayar_diffuse(float NdotV, float NdotL, float LdotV, float roughness) +{ + float s = LdotV - NdotL * NdotV; + float stinv = (s > 0.0) ? s / max(NdotL, NdotV) : 0.0; + + float sigma2 = mx_square(roughness); + float A = 1.0 - 0.5 * (sigma2 / (sigma2 + 0.33)); + float B = 0.45 * sigma2 / (sigma2 + 0.09); + + return A + B * stinv; +} + +// Rational quadratic fit to Monte Carlo data for Oren-Nayar directional albedo. +float mx_oren_nayar_diffuse_dir_albedo_analytic(float NdotV, float roughness) +{ + vec2 r = vec2(1.0, 1.0) + + vec2(-0.4297, -0.6076) * roughness + + vec2(-0.7632, -0.4993) * NdotV * roughness + + vec2(1.4385, 2.0315) * mx_square(roughness); + return r.x / r.y; +} + +float mx_oren_nayar_diffuse_dir_albedo_table_lookup(float NdotV, float roughness) +{ +#if DIRECTIONAL_ALBEDO_METHOD == 1 + if (textureSize($albedoTable, 0).x > 1) + { + return texture($albedoTable, vec2(NdotV, roughness)).b; + } +#endif + return 0.0; +} + +float mx_oren_nayar_diffuse_dir_albedo_monte_carlo(float NdotV, float roughness) +{ + NdotV = clamp(NdotV, M_FLOAT_EPS, 1.0); + vec3 V = vec3(sqrt(1.0 - mx_square(NdotV)), 0, NdotV); + + float radiance = 0.0; + const int SAMPLE_COUNT = 64; + for (int i = 0; i < SAMPLE_COUNT; i++) + { + vec2 Xi = mx_spherical_fibonacci(i, SAMPLE_COUNT); + + // Compute the incoming light direction. + vec3 L = mx_uniform_sample_hemisphere(Xi); + + // Compute dot products for this sample. + float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0); + float LdotV = clamp(dot(L, V), M_FLOAT_EPS, 1.0); + + // Compute diffuse reflectance. + float reflectance = mx_oren_nayar_diffuse(NdotV, NdotL, LdotV, roughness); + + // Add the radiance contribution of this sample. + // uniform_pdf = 1 / (2 * PI) + // radiance = (reflectance * NdotL) / (uniform_pdf * PI); + radiance += reflectance * NdotL; + } + + // Apply global components and normalize. + radiance *= 2.0 / float(SAMPLE_COUNT); + + // Return the final directional albedo. + return radiance; +} + +float mx_oren_nayar_diffuse_dir_albedo(float NdotV, float roughness) +{ +#if DIRECTIONAL_ALBEDO_METHOD == 2 + float dirAlbedo = mx_oren_nayar_diffuse_dir_albedo_monte_carlo(NdotV, roughness); +#else + float dirAlbedo = mx_oren_nayar_diffuse_dir_albedo_analytic(NdotV, roughness); +#endif + return clamp(dirAlbedo, 0.0, 1.0); +} + +// Improved Oren-Nayar diffuse from Fujii: +// https://mimosa-pudica.net/improved-oren-nayar.html +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) + + 2.0 * ((Si / cosTheta) * (1.0 - Si * Si * Si) - Si) / 3.0; + return A + (B * G * M_PI_INV); +} + +float mx_oren_nayar_fujii_diffuse_avg_albedo(float roughness) +{ + float A = 1.0 / (1.0 + FUJII_CONSTANT_1 * roughness); + return A * (1.0 + FUJII_CONSTANT_2 * roughness); +} + +// Energy-compensated Oren-Nayar diffuse from OpenPBR Surface: +// https://academysoftwarefoundation.github.io/OpenPBR/ +vec3 mx_oren_nayar_compensated_diffuse(float NdotV, float NdotL, float LdotV, float roughness, vec3 color) +{ + float s = LdotV - NdotL * NdotV; + float stinv = (s > 0.0) ? s / max(NdotL, NdotV) : s; + + // Compute the single-scatter lobe. + float A = 1.0 / (1.0 + FUJII_CONSTANT_1 * roughness); + vec3 lobeSingleScatter = color * A * (1.0 + roughness * stinv); + + // Compute the multi-scatter lobe. + float dirAlbedoV = mx_oren_nayar_fujii_diffuse_dir_albedo(NdotV, roughness); + float dirAlbedoL = mx_oren_nayar_fujii_diffuse_dir_albedo(NdotL, roughness); + float avgAlbedo = mx_oren_nayar_fujii_diffuse_avg_albedo(roughness); + vec3 colorMultiScatter = mx_square(color) * avgAlbedo / + (vec3(1.0) - color * max(0.0, 1.0 - avgAlbedo)); + vec3 lobeMultiScatter = colorMultiScatter * + max(M_FLOAT_EPS, 1.0 - dirAlbedoV) * + max(M_FLOAT_EPS, 1.0 - dirAlbedoL) / + max(M_FLOAT_EPS, 1.0 - avgAlbedo); + + // Return the sum. + return lobeSingleScatter + lobeMultiScatter; +} + +vec3 mx_oren_nayar_compensated_diffuse_dir_albedo(float cosTheta, float roughness, vec3 color) +{ + float dirAlbedo = mx_oren_nayar_fujii_diffuse_dir_albedo(cosTheta, roughness); + float avgAlbedo = mx_oren_nayar_fujii_diffuse_avg_albedo(roughness); + vec3 colorMultiScatter = mx_square(color) * avgAlbedo / + (vec3(1.0) - color * max(0.0, 1.0 - avgAlbedo)); + return mix(colorMultiScatter, color, dirAlbedo); +} + +// https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf +// Section 5.3 +float mx_burley_diffuse(float NdotV, float NdotL, float LdotH, float roughness) +{ + float F90 = 0.5 + (2.0 * roughness * mx_square(LdotH)); + float refL = mx_fresnel_schlick(NdotL, 1.0, F90); + float refV = mx_fresnel_schlick(NdotV, 1.0, F90); + return refL * refV; +} + +// Compute the directional albedo component of Burley diffuse for the given +// view angle and roughness. Curve fit provided by Stephen Hill. +float mx_burley_diffuse_dir_albedo(float NdotV, float roughness) +{ + float x = NdotV; + float fit0 = 0.97619 - 0.488095 * mx_pow5(1.0 - x); + float fit1 = 1.55754 + (-2.02221 + (2.56283 - 1.06244 * x) * x) * x; + return mix(fit0, fit1, roughness); +} + +// Evaluate the Burley diffusion profile for the given distance and diffusion shape. +// Based on https://graphics.pixar.com/library/ApproxBSSRDF/ +vec3 mx_burley_diffusion_profile(float dist, vec3 shape) +{ + vec3 num1 = exp(-shape * dist); + vec3 num2 = exp(-shape * dist / 3.0); + float denom = max(dist, M_FLOAT_EPS); + return (num1 + num2) / denom; +} + +// Integrate the Burley diffusion profile over a sphere of the given radius. +// 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)); + + // Estimate the Burley diffusion shape from mean free path. + vec3 shape = vec3(1.0) / max(mfp, 0.1); + + // Integrate the profile over the sphere. + vec3 sumD = vec3(0.0); + vec3 sumR = vec3(0.0); + const int SAMPLE_COUNT = 32; + const float SAMPLE_WIDTH = (2.0 * M_PI) / float(SAMPLE_COUNT); + 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)); + vec3 R = mx_burley_diffusion_profile(dist, shape); + sumD += R * max(cos(theta + x), 0.0); + sumR += R; + } + + return sumD / sumR; +} + +vec3 mx_subsurface_scattering_approx(vec3 N, vec3 L, vec3 P, vec3 albedo, vec3 mfp) +{ + float curvature = length(fwidth(N)) / length(fwidth(P)); + float radius = 1.0 / max(curvature, 0.01); + return albedo * mx_integrate_burley_diffusion(N, L, radius, mfp) / vec3(M_PI); +} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl old mode 100644 new mode 100755 index 8adac72..03d6608 --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl @@ -1,189 +1,189 @@ -#include "mx_microfacet.glsl" - -// https://fpsunflower.github.io/ckulla/data/s2017_pbs_imageworks_sheen.pdf -// Equation 2 -float mx_imageworks_sheen_NDF(float NdotH, float roughness) -{ - float invRoughness = 1.0 / max(roughness, 0.005); - float cos2 = NdotH * NdotH; - float sin2 = 1.0 - cos2; - return (2.0 + invRoughness) * pow(sin2, invRoughness * 0.5) / (2.0 * M_PI); -} - -float mx_imageworks_sheen_brdf(float NdotL, float NdotV, float NdotH, float roughness) -{ - // Microfacet distribution. - float D = mx_imageworks_sheen_NDF(NdotH, roughness); - - // Fresnel and geometry terms are ignored. - float F = 1.0; - float G = 1.0; - - // We use a smoother denominator, as in: - // https://blog.selfshadow.com/publications/s2013-shading-course/rad/s2013_pbs_rad_notes.pdf - return D * F * G / (4.0 * (NdotL + NdotV - NdotL*NdotV)); -} - -// Rational quadratic fit to Monte Carlo data for Imageworks sheen directional albedo. -float mx_imageworks_sheen_dir_albedo_analytic(float NdotV, float roughness) -{ - vec2 r = vec2(13.67300, 1.0) + - vec2(-68.78018, 61.57746) * NdotV + - vec2(799.08825, 442.78211) * roughness + - vec2(-905.00061, 2597.49308) * NdotV * roughness + - vec2(60.28956, 121.81241) * mx_square(NdotV) + - vec2(1086.96473, 3045.55075) * mx_square(roughness); - return r.x / r.y; -} - -float mx_imageworks_sheen_dir_albedo_table_lookup(float NdotV, float roughness) -{ -#if DIRECTIONAL_ALBEDO_METHOD == 1 - if (textureSize($albedoTable, 0).x > 1) - { - return texture($albedoTable, vec2(NdotV, roughness)).b; - } -#endif - return 0.0; -} - -float mx_imageworks_sheen_dir_albedo_monte_carlo(float NdotV, float roughness) -{ - NdotV = clamp(NdotV, M_FLOAT_EPS, 1.0); - vec3 V = vec3(sqrt(1.0f - mx_square(NdotV)), 0, NdotV); - - float radiance = 0.0; - const int SAMPLE_COUNT = 64; - for (int i = 0; i < SAMPLE_COUNT; i++) - { - vec2 Xi = mx_spherical_fibonacci(i, SAMPLE_COUNT); - - // Compute the incoming light direction and half vector. - vec3 L = mx_uniform_sample_hemisphere(Xi); - vec3 H = normalize(L + V); - - // Compute dot products for this sample. - float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0); - float NdotH = clamp(H.z, M_FLOAT_EPS, 1.0); - - // Compute sheen reflectance. - float reflectance = mx_imageworks_sheen_brdf(NdotL, NdotV, NdotH, roughness); - - // Add the radiance contribution of this sample. - // uniform_pdf = 1 / (2 * PI) - // radiance = reflectance * NdotL / uniform_pdf; - radiance += reflectance * NdotL * 2.0 * M_PI; - } - - // Return the final directional albedo. - return radiance / float(SAMPLE_COUNT); -} - -float mx_imageworks_sheen_dir_albedo(float NdotV, float roughness) -{ -#if DIRECTIONAL_ALBEDO_METHOD == 0 - float dirAlbedo = mx_imageworks_sheen_dir_albedo_analytic(NdotV, roughness); -#elif DIRECTIONAL_ALBEDO_METHOD == 1 - float dirAlbedo = mx_imageworks_sheen_dir_albedo_table_lookup(NdotV, roughness); -#else - float dirAlbedo = mx_imageworks_sheen_dir_albedo_monte_carlo(NdotV, roughness); -#endif - return clamp(dirAlbedo, 0.0, 1.0); -} - -// The following functions are adapted from https://github.com/tizian/ltc-sheen. -// "Practical Multiple-Scattering Sheen Using Linearly Transformed Cosines", Zeltner et al. - -// Gaussian fit to directional albedo table. -float mx_zeltner_sheen_dir_albedo(float x, float y) -{ - float s = y*(0.0206607 + 1.58491*y)/(0.0379424 + y*(1.32227 + y)); - float m = y*(-0.193854 + y*(-1.14885 + y*(1.7932 - 0.95943*y*y)))/(0.046391 + y); - float o = y*(0.000654023 + (-0.0207818 + 0.119681*y)*y)/(1.26264 + y*(-1.92021 + y)); - return exp(-0.5*mx_square((x - m)/s))/(s*sqrt(2.0*M_PI)) + o; -} - -// Rational fits to LTC matrix coefficients. -float mx_zeltner_sheen_ltc_aInv(float x, float y) -{ - return (2.58126*x + 0.813703*y)*y/(1.0 + 0.310327*x*x + 2.60994*x*y); -} - -float mx_zeltner_sheen_ltc_bInv(float x, float y) -{ - return sqrt(1.0 - x)*(y - 1.0)*y*y*y/(0.0000254053 + 1.71228*x - 1.71506*x*y + 1.34174*y*y); -} - -// V and N are assumed to be unit vectors. -mat3 mx_orthonormal_basis_ltc(vec3 V, vec3 N, float NdotV) -{ - // Generate a tangent vector in the plane of V and N. - // This required to correctly orient the LTC lobe. - vec3 X = V - N*NdotV; - float lenSqr = dot(X, X); - if (lenSqr > 0.0) - { - X *= mx_inversesqrt(lenSqr); - vec3 Y = cross(N, X); - return mat3(X, Y, N); - } - - // If lenSqr == 0, then V == N, so any orthonormal basis will do. - return mx_orthonormal_basis(N); -} - -// Multiplication by directional albedo is handled by the calling function. -float mx_zeltner_sheen_brdf(vec3 L, vec3 V, vec3 N, float NdotV, float roughness) -{ - mat3 toLTC = transpose(mx_orthonormal_basis_ltc(V, N, NdotV)); - vec3 w = mx_matrix_mul(toLTC, L); - - float aInv = mx_zeltner_sheen_ltc_aInv(NdotV, roughness); - float bInv = mx_zeltner_sheen_ltc_bInv(NdotV, roughness); - - // Transform w to original configuration (clamped cosine). - // |aInv 0 bInv| - // wo = M^-1 . w = | 0 aInv 0| . w - // | 0 0 1| - vec3 wo = vec3(aInv*w.x + bInv*w.z, aInv * w.y, w.z); - float lenSqr = dot(wo, wo); - - // D(w) = Do(M^-1.w / ||M^-1.w||) . |M^-1| / ||M^-1.w||^3 - // = Do(M^-1.w) . |M^-1| / ||M^-1.w||^4 - // = Do(wo) . |M^-1| / dot(wo, wo)^2 - // = Do(wo) . aInv^2 / dot(wo, wo)^2 - // = Do(wo) . (aInv / dot(wo, wo))^2 - return max(wo.z, 0.0) * M_PI_INV * mx_square(aInv / lenSqr); -} - -vec3 mx_zeltner_sheen_importance_sample(vec2 Xi, vec3 V, vec3 N, float roughness, out float pdf) -{ - float NdotV = clamp(dot(N, V), 0.0, 1.0); - roughness = clamp(roughness, 0.01, 1.0); // Clamp to range of original impl. - - vec3 wo = mx_cosine_sample_hemisphere(Xi); - - float aInv = mx_zeltner_sheen_ltc_aInv(NdotV, roughness); - float bInv = mx_zeltner_sheen_ltc_bInv(NdotV, roughness); - - // Transform wo from original configuration (clamped cosine). - // |1/aInv 0 -bInv/aInv| - // w = M . wo = | 0 1/aInv 0| . wo - // | 0 0 1| - vec3 w = vec3(wo.x/aInv - wo.z*bInv/aInv, wo.y / aInv, wo.z); - - float lenSqr = dot(w, w); - w *= mx_inversesqrt(lenSqr); - - // D(w) = Do(wo) . ||M.wo||^3 / |M| - // = Do(wo / ||M.wo||) . ||M.wo||^4 / |M| - // = Do(w) . ||M.wo||^4 / |M| (possible because M doesn't change z component) - // = Do(w) . dot(w, w)^2 * aInv^2 - // = Do(w) . (aInv * dot(w, w))^2 - pdf = max(w.z, 0.0) * M_PI_INV * mx_square(aInv * lenSqr); - - mat3 fromLTC = mx_orthonormal_basis_ltc(V, N, NdotV); - w = mx_matrix_mul(fromLTC, w); - - return w; -} +#include "mx_microfacet.glsl" + +// https://fpsunflower.github.io/ckulla/data/s2017_pbs_imageworks_sheen.pdf +// Equation 2 +float mx_imageworks_sheen_NDF(float NdotH, float roughness) +{ + float invRoughness = 1.0 / max(roughness, 0.005); + float cos2 = NdotH * NdotH; + float sin2 = 1.0 - cos2; + return (2.0 + invRoughness) * pow(sin2, invRoughness * 0.5) / (2.0 * M_PI); +} + +float mx_imageworks_sheen_brdf(float NdotL, float NdotV, float NdotH, float roughness) +{ + // Microfacet distribution. + float D = mx_imageworks_sheen_NDF(NdotH, roughness); + + // Fresnel and geometry terms are ignored. + float F = 1.0; + float G = 1.0; + + // We use a smoother denominator, as in: + // https://blog.selfshadow.com/publications/s2013-shading-course/rad/s2013_pbs_rad_notes.pdf + return D * F * G / (4.0 * (NdotL + NdotV - NdotL*NdotV)); +} + +// Rational quadratic fit to Monte Carlo data for Imageworks sheen directional albedo. +float mx_imageworks_sheen_dir_albedo_analytic(float NdotV, float roughness) +{ + vec2 r = vec2(13.67300, 1.0) + + vec2(-68.78018, 61.57746) * NdotV + + vec2(799.08825, 442.78211) * roughness + + vec2(-905.00061, 2597.49308) * NdotV * roughness + + vec2(60.28956, 121.81241) * mx_square(NdotV) + + vec2(1086.96473, 3045.55075) * mx_square(roughness); + return r.x / r.y; +} + +float mx_imageworks_sheen_dir_albedo_table_lookup(float NdotV, float roughness) +{ +#if DIRECTIONAL_ALBEDO_METHOD == 1 + if (textureSize($albedoTable, 0).x > 1) + { + return texture($albedoTable, vec2(NdotV, roughness)).b; + } +#endif + return 0.0; +} + +float mx_imageworks_sheen_dir_albedo_monte_carlo(float NdotV, float roughness) +{ + NdotV = clamp(NdotV, M_FLOAT_EPS, 1.0); + vec3 V = vec3(sqrt(1.0f - mx_square(NdotV)), 0, NdotV); + + float radiance = 0.0; + const int SAMPLE_COUNT = 64; + for (int i = 0; i < SAMPLE_COUNT; i++) + { + vec2 Xi = mx_spherical_fibonacci(i, SAMPLE_COUNT); + + // Compute the incoming light direction and half vector. + vec3 L = mx_uniform_sample_hemisphere(Xi); + vec3 H = normalize(L + V); + + // Compute dot products for this sample. + float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0); + float NdotH = clamp(H.z, M_FLOAT_EPS, 1.0); + + // Compute sheen reflectance. + float reflectance = mx_imageworks_sheen_brdf(NdotL, NdotV, NdotH, roughness); + + // Add the radiance contribution of this sample. + // uniform_pdf = 1 / (2 * PI) + // radiance = reflectance * NdotL / uniform_pdf; + radiance += reflectance * NdotL * 2.0 * M_PI; + } + + // Return the final directional albedo. + return radiance / float(SAMPLE_COUNT); +} + +float mx_imageworks_sheen_dir_albedo(float NdotV, float roughness) +{ +#if DIRECTIONAL_ALBEDO_METHOD == 0 + float dirAlbedo = mx_imageworks_sheen_dir_albedo_analytic(NdotV, roughness); +#elif DIRECTIONAL_ALBEDO_METHOD == 1 + float dirAlbedo = mx_imageworks_sheen_dir_albedo_table_lookup(NdotV, roughness); +#else + float dirAlbedo = mx_imageworks_sheen_dir_albedo_monte_carlo(NdotV, roughness); +#endif + return clamp(dirAlbedo, 0.0, 1.0); +} + +// The following functions are adapted from https://github.com/tizian/ltc-sheen. +// "Practical Multiple-Scattering Sheen Using Linearly Transformed Cosines", Zeltner et al. + +// Gaussian fit to directional albedo table. +float mx_zeltner_sheen_dir_albedo(float x, float y) +{ + float s = y*(0.0206607 + 1.58491*y)/(0.0379424 + y*(1.32227 + y)); + float m = y*(-0.193854 + y*(-1.14885 + y*(1.7932 - 0.95943*y*y)))/(0.046391 + y); + float o = y*(0.000654023 + (-0.0207818 + 0.119681*y)*y)/(1.26264 + y*(-1.92021 + y)); + return exp(-0.5*mx_square((x - m)/s))/(s*sqrt(2.0*M_PI)) + o; +} + +// Rational fits to LTC matrix coefficients. +float mx_zeltner_sheen_ltc_aInv(float x, float y) +{ + return (2.58126*x + 0.813703*y)*y/(1.0 + 0.310327*x*x + 2.60994*x*y); +} + +float mx_zeltner_sheen_ltc_bInv(float x, float y) +{ + return sqrt(1.0 - x)*(y - 1.0)*y*y*y/(0.0000254053 + 1.71228*x - 1.71506*x*y + 1.34174*y*y); +} + +// V and N are assumed to be unit vectors. +mat3 mx_orthonormal_basis_ltc(vec3 V, vec3 N, float NdotV) +{ + // Generate a tangent vector in the plane of V and N. + // This required to correctly orient the LTC lobe. + vec3 X = V - N*NdotV; + float lenSqr = dot(X, X); + if (lenSqr > 0.0) + { + X *= inversesqrt(lenSqr); + vec3 Y = cross(N, X); + return mat3(X, Y, N); + } + + // If lenSqr == 0, then V == N, so any orthonormal basis will do. + return mx_orthonormal_basis(N); +} + +// Multiplication by directional albedo is handled by the calling function. +float mx_zeltner_sheen_brdf(vec3 L, vec3 V, vec3 N, float NdotV, float roughness) +{ + mat3 toLTC = transpose(mx_orthonormal_basis_ltc(V, N, NdotV)); + vec3 w = toLTC * L; + + float aInv = mx_zeltner_sheen_ltc_aInv(NdotV, roughness); + float bInv = mx_zeltner_sheen_ltc_bInv(NdotV, roughness); + + // Transform w to original configuration (clamped cosine). + // |aInv 0 bInv| + // wo = M^-1 . w = | 0 aInv 0| . w + // | 0 0 1| + vec3 wo = vec3(aInv*w.x + bInv*w.z, aInv * w.y, w.z); + float lenSqr = dot(wo, wo); + + // D(w) = Do(M^-1.w / ||M^-1.w||) . |M^-1| / ||M^-1.w||^3 + // = Do(M^-1.w) . |M^-1| / ||M^-1.w||^4 + // = Do(wo) . |M^-1| / dot(wo, wo)^2 + // = Do(wo) . aInv^2 / dot(wo, wo)^2 + // = Do(wo) . (aInv / dot(wo, wo))^2 + return max(wo.z, 0.0) * M_PI_INV * mx_square(aInv / lenSqr); +} + +vec3 mx_zeltner_sheen_importance_sample(vec2 Xi, vec3 V, vec3 N, float roughness, out float pdf) +{ + float NdotV = clamp(dot(N, V), 0.0, 1.0); + roughness = clamp(roughness, 0.01, 1.0); // Clamp to range of original impl. + + vec3 wo = mx_cosine_sample_hemisphere(Xi); + + float aInv = mx_zeltner_sheen_ltc_aInv(NdotV, roughness); + float bInv = mx_zeltner_sheen_ltc_bInv(NdotV, roughness); + + // Transform wo from original configuration (clamped cosine). + // |1/aInv 0 -bInv/aInv| + // w = M . wo = | 0 1/aInv 0| . wo + // | 0 0 1| + vec3 w = vec3(wo.x/aInv - wo.z*bInv/aInv, wo.y / aInv, wo.z); + + float lenSqr = dot(w, w); + w *= inversesqrt(lenSqr); + + // D(w) = Do(wo) . ||M.wo||^3 / |M| + // = Do(wo / ||M.wo||) . ||M.wo||^4 / |M| + // = Do(w) . ||M.wo||^4 / |M| (possible because M doesn't change z component) + // = Do(w) . dot(w, w)^2 * aInv^2 + // = Do(w) . (aInv * dot(w, w))^2 + pdf = max(w.z, 0.0) * M_PI_INV * mx_square(aInv * lenSqr); + + mat3 fromLTC = mx_orthonormal_basis_ltc(V, N, NdotV); + w = fromLTC * w; + + return w; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl old mode 100644 new mode 100755 index 3143d11..db9e19d --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -1,510 +1,510 @@ -#include "mx_microfacet.glsl" - -const int FRESNEL_MODEL_DIELECTRIC = 0; -const int FRESNEL_MODEL_CONDUCTOR = 1; -const int FRESNEL_MODEL_SCHLICK = 2; - -// Parameters for Fresnel calculations -struct FresnelData -{ - // Fresnel model - int model; - bool airy; - - // Physical Fresnel - vec3 ior; - vec3 extinction; - - // Generalized Schlick Fresnel - vec3 F0; - vec3 F82; - vec3 F90; - float exponent; - - // Thin film - float tf_thickness; - float tf_ior; - - // Refraction - bool refraction; -}; - -// https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf -// Appendix B.2 Equation 13 -float mx_ggx_NDF(vec3 H, vec2 alpha) -{ - vec2 He = H.xy / alpha; - float denom = dot(He, He) + mx_square(H.z); - return 1.0 / (M_PI * alpha.x * alpha.y * mx_square(denom)); -} - -// https://ggx-research.github.io/publication/2023/06/09/publication-ggx.html -vec3 mx_ggx_importance_sample_VNDF(vec2 Xi, vec3 V, vec2 alpha) -{ - // Transform the view direction to the hemisphere configuration. - V = normalize(vec3(V.xy * alpha, V.z)); - - // Sample a spherical cap in (-V.z, 1]. - 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 * mx_cos(phi); - float y = sinTheta * mx_sin(phi); - vec3 c = vec3(x, y, z); - - // Compute the microfacet normal. - vec3 H = c + V; - - // Transform the microfacet normal back to the ellipsoid configuration. - H = normalize(vec3(H.xy * alpha, max(H.z, 0.0))); - - return H; -} - -// https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf -// Equation 34 -float mx_ggx_smith_G1(float cosTheta, float alpha) -{ - float cosTheta2 = mx_square(cosTheta); - float tanTheta2 = (1.0 - cosTheta2) / cosTheta2; - return 2.0 / (1.0 + sqrt(1.0 + mx_square(alpha) * tanTheta2)); -} - -// Height-correlated Smith masking-shadowing -// http://jcgt.org/published/0003/02/03/paper.pdf -// Equations 72 and 99 -float mx_ggx_smith_G2(float NdotL, float NdotV, float alpha) -{ - float alpha2 = mx_square(alpha); - float lambdaL = sqrt(alpha2 + (1.0 - alpha2) * mx_square(NdotL)); - float lambdaV = sqrt(alpha2 + (1.0 - alpha2) * mx_square(NdotV)); - return 2.0 * NdotL * NdotV / (lambdaL * NdotV + lambdaV * NdotL); -} - -// Rational quadratic fit to Monte Carlo data for GGX directional albedo. -vec3 mx_ggx_dir_albedo_analytic(float NdotV, float alpha, vec3 F0, vec3 F90) -{ - float x = NdotV; - float y = alpha; - float x2 = mx_square(x); - float y2 = mx_square(y); - vec4 r = vec4(0.1003, 0.9345, 1.0, 1.0) + - vec4(-0.6303, -2.323, -1.765, 0.2281) * x + - vec4(9.748, 2.229, 8.263, 15.94) * y + - vec4(-2.038, -3.748, 11.53, -55.83) * x * y + - vec4(29.34, 1.424, 28.96, 13.08) * x2 + - vec4(-8.245, -0.7684, -7.507, 41.26) * y2 + - vec4(-26.44, 1.436, -36.11, 54.9) * x2 * y + - vec4(19.99, 0.2913, 15.86, 300.2) * x * y2 + - vec4(-5.448, 0.6286, 33.37, -285.1) * x2 * y2; - vec2 AB = clamp(r.xy / r.zw, 0.0, 1.0); - return F0 * AB.x + F90 * AB.y; -} - -vec3 mx_ggx_dir_albedo_table_lookup(float NdotV, float alpha, vec3 F0, vec3 F90) -{ -#if DIRECTIONAL_ALBEDO_METHOD == 1 - if (textureSize($albedoTable, 0).x > 1) - { - vec2 AB = texture($albedoTable, vec2(NdotV, alpha)).rg; - return F0 * AB.x + F90 * AB.y; - } -#endif - return vec3(0.0); -} - -// https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf -vec3 mx_ggx_dir_albedo_monte_carlo(float NdotV, float alpha, vec3 F0, vec3 F90) -{ - NdotV = clamp(NdotV, M_FLOAT_EPS, 1.0); - vec3 V = vec3(sqrt(1.0 - mx_square(NdotV)), 0, NdotV); - - vec2 AB = vec2(0.0); - const int SAMPLE_COUNT = 64; - for (int i = 0; i < SAMPLE_COUNT; i++) - { - vec2 Xi = mx_spherical_fibonacci(i, SAMPLE_COUNT); - - // Compute the half vector and incoming light direction. - vec3 H = mx_ggx_importance_sample_VNDF(Xi, V, vec2(alpha)); - vec3 L = -reflect(V, H); - - // Compute dot products for this sample. - float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0); - float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0); - - // Compute the Fresnel term. - float Fc = mx_fresnel_schlick(VdotH, 0.0, 1.0); - - // Compute the per-sample geometric term. - // https://hal.inria.fr/hal-00996995v2/document, Algorithm 2 - float G2 = mx_ggx_smith_G2(NdotL, NdotV, alpha); - - // Add the contribution of this sample. - AB += vec2(G2 * (1.0 - Fc), G2 * Fc); - } - - // Apply the global component of the geometric term and normalize. - AB /= mx_ggx_smith_G1(NdotV, alpha) * float(SAMPLE_COUNT); - - // Return the final directional albedo. - return F0 * AB.x + F90 * AB.y; -} - -vec3 mx_ggx_dir_albedo(float NdotV, float alpha, vec3 F0, vec3 F90) -{ -#if DIRECTIONAL_ALBEDO_METHOD == 0 - return mx_ggx_dir_albedo_analytic(NdotV, alpha, F0, F90); -#elif DIRECTIONAL_ALBEDO_METHOD == 1 - return mx_ggx_dir_albedo_table_lookup(NdotV, alpha, F0, F90); -#else - return mx_ggx_dir_albedo_monte_carlo(NdotV, alpha, F0, F90); -#endif -} - -float mx_ggx_dir_albedo(float NdotV, float alpha, float F0, float F90) -{ - return mx_ggx_dir_albedo(NdotV, alpha, vec3(F0), vec3(F90)).x; -} - -// https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf -// Equations 14 and 16 -vec3 mx_ggx_energy_compensation(float NdotV, float alpha, vec3 Fss) -{ - float Ess = mx_ggx_dir_albedo(NdotV, alpha, 1.0, 1.0); - return 1.0 + Fss * (1.0 - Ess) / Ess; -} - -float mx_ggx_energy_compensation(float NdotV, float alpha, float Fss) -{ - return mx_ggx_energy_compensation(NdotV, alpha, vec3(Fss)).x; -} - -// Compute the average of an anisotropic alpha pair. -float mx_average_alpha(vec2 alpha) -{ - return sqrt(alpha.x * alpha.y); -} - -// Convert a real-valued index of refraction to normal-incidence reflectivity. -float mx_ior_to_f0(float ior) -{ - return mx_square((ior - 1.0) / (ior + 1.0)); -} - -// Convert normal-incidence reflectivity to real-valued index of refraction. -float mx_f0_to_ior(float F0) -{ - float sqrtF0 = sqrt(clamp(F0, 0.01, 0.99)); - return (1.0 + sqrtF0) / (1.0 - sqrtF0); -} -vec3 mx_f0_to_ior(vec3 F0) -{ - vec3 sqrtF0 = sqrt(clamp(F0, 0.01, 0.99)); - return (vec3(1.0) + sqrtF0) / (vec3(1.0) - sqrtF0); -} - -// https://renderwonk.com/publications/wp-generalization-adobe/gen-adobe.pdf -vec3 mx_fresnel_hoffman_schlick(float cosTheta, FresnelData fd) -{ - const float COS_THETA_MAX = 1.0 / 7.0; - const float COS_THETA_FACTOR = 1.0 / (COS_THETA_MAX * pow(1.0 - COS_THETA_MAX, 6.0)); - - float x = clamp(cosTheta, 0.0, 1.0); - vec3 a = mix(fd.F0, fd.F90, pow(1.0 - COS_THETA_MAX, fd.exponent)) * (vec3(1.0) - fd.F82) * COS_THETA_FACTOR; - return mix(fd.F0, fd.F90, pow(1.0 - x, fd.exponent)) - a * x * mx_pow6(1.0 - x); -} - -// https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ -float mx_fresnel_dielectric(float cosTheta, float ior) -{ - float c = cosTheta; - float g2 = ior*ior + c*c - 1.0; - if (g2 < 0.0) - { - // Total internal reflection - return 1.0; - } - - float g = sqrt(g2); - return 0.5 * mx_square((g - c) / (g + c)) * - (1.0 + mx_square(((g + c) * c - 1.0) / ((g - c) * c + 1.0))); -} - -// https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ -vec2 mx_fresnel_dielectric_polarized(float cosTheta, float ior) -{ - float cosTheta2 = mx_square(clamp(cosTheta, 0.0, 1.0)); - float sinTheta2 = 1.0 - cosTheta2; - - float t0 = max(ior * ior - sinTheta2, 0.0); - float t1 = t0 + cosTheta2; - float t2 = 2.0 * sqrt(t0) * cosTheta; - float Rs = (t1 - t2) / (t1 + t2); - - float t3 = cosTheta2 * t0 + sinTheta2 * sinTheta2; - float t4 = t2 * sinTheta2; - float Rp = Rs * (t3 - t4) / (t3 + t4); - - return vec2(Rp, Rs); -} - -// https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ -void mx_fresnel_conductor_polarized(float cosTheta, vec3 n, vec3 k, out vec3 Rp, out vec3 Rs) -{ - float cosTheta2 = mx_square(clamp(cosTheta, 0.0, 1.0)); - float sinTheta2 = 1.0 - cosTheta2; - vec3 n2 = n * n; - vec3 k2 = k * k; - - vec3 t0 = n2 - k2 - vec3(sinTheta2); - vec3 a2plusb2 = sqrt(t0 * t0 + 4.0 * n2 * k2); - vec3 t1 = a2plusb2 + vec3(cosTheta2); - vec3 a = sqrt(max(0.5 * (a2plusb2 + t0), 0.0)); - vec3 t2 = 2.0 * a * cosTheta; - Rs = (t1 - t2) / (t1 + t2); - - vec3 t3 = cosTheta2 * a2plusb2 + vec3(sinTheta2 * sinTheta2); - vec3 t4 = t2 * sinTheta2; - Rp = Rs * (t3 - t4) / (t3 + t4); -} - -vec3 mx_fresnel_conductor(float cosTheta, vec3 n, vec3 k) -{ - vec3 Rp, Rs; - mx_fresnel_conductor_polarized(cosTheta, n, k, Rp, Rs); - return 0.5 * (Rp + Rs); -} - -// https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html -void mx_fresnel_conductor_phase_polarized(float cosTheta, float eta1, vec3 eta2, vec3 kappa2, out vec3 phiP, out vec3 phiS) -{ - vec3 k2 = kappa2 / eta2; - vec3 sinThetaSqr = vec3(1.0) - cosTheta * cosTheta; - vec3 A = eta2*eta2*(vec3(1.0)-k2*k2) - eta1*eta1*sinThetaSqr; - vec3 B = sqrt(A*A + mx_square(2.0*eta2*eta2*k2)); - vec3 U = sqrt((A+B)/2.0); - vec3 V = max(vec3(0.0), sqrt((B-A)/2.0)); - - 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 -vec3 mx_eval_sensitivity(float opd, vec3 shift) -{ - // Use Gaussian fits, given by 3 parameters: val, pos and var - float phase = 2.0*M_PI * opd; - 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) * 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; -} - -// A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence -// https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html -vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) -{ - // XYZ to CIE 1931 RGB color space (using neutral E illuminant) - const mat3 XYZ_TO_RGB = mat3(2.3706743, -0.5138850, 0.0052982, -0.9000405, 1.4253036, -0.0146949, -0.4706338, 0.0885814, 1.0093968); - - // Assume vacuum on the outside - float eta1 = 1.0; - float eta2 = max(fd.tf_ior, eta1); - vec3 eta3 = (fd.model == FRESNEL_MODEL_SCHLICK) ? mx_f0_to_ior(fd.F0) : fd.ior; - vec3 kappa3 = (fd.model == FRESNEL_MODEL_SCHLICK) ? vec3(0.0) : fd.extinction; - float cosThetaT = sqrt(1.0 - (1.0 - mx_square(cosTheta)) * mx_square(eta1 / eta2)); - - // First interface - vec2 R12 = mx_fresnel_dielectric_polarized(cosTheta, eta2 / eta1); - if (cosThetaT <= 0.0) - { - // Total internal reflection - R12 = vec2(1.0); - } - vec2 T121 = vec2(1.0) - R12; - - // Second interface - vec3 R23p, R23s; - if (fd.model == FRESNEL_MODEL_SCHLICK) - { - vec3 f = mx_fresnel_hoffman_schlick(cosThetaT, fd); - R23p = 0.5 * f; - R23s = 0.5 * f; - } - else - { - mx_fresnel_conductor_polarized(cosThetaT, eta3 / eta2, kappa3 / eta2, R23p, R23s); - } - - // Phase shift - 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) - { - phi23p = vec3((eta3[0] < eta2) ? M_PI : 0.0, - (eta3[1] < eta2) ? M_PI : 0.0, - (eta3[2] < eta2) ? M_PI : 0.0); - phi23s = phi23p; - } - else - { - mx_fresnel_conductor_phase_polarized(cosThetaT, eta2, eta3, kappa3, phi23p, phi23s); - } - vec3 r123p = max(sqrt(R12.x*R23p), 0.0); - vec3 r123s = max(sqrt(R12.y*R23s), 0.0); - - // Iridescence term - vec3 I = vec3(0.0); - vec3 Cm, Sm; - - // Optical path difference - float distMeters = fd.tf_thickness * 1.0e-9; - float opd = 2.0 * eta2 * cosThetaT * distMeters; - - // Iridescence term using spectral antialiasing for Parallel polarization - - // Reflectance term for m=0 (DC term amplitude) - vec3 Rs = (mx_square(T121.x) * R23p) / (vec3(1.0) - R12.x*R23p); - I += R12.x + Rs; - - // Reflectance term for m>0 (pairs of diracs) - Cm = Rs - T121.x; - for (int m = 1; m <= AIRY_FRESNEL_ITERATIONS; m++) - { - Cm *= r123p; - Sm = 2.0 * mx_eval_sensitivity(float(m) * opd, float(m)*(phi23p+vec3(phi21.x))); - I += Cm*Sm; - } - - // Iridescence term using spectral antialiasing for Perpendicular polarization - - // Reflectance term for m=0 (DC term amplitude) - vec3 Rp = (mx_square(T121.y) * R23s) / (vec3(1.0) - R12.y*R23s); - I += R12.y + Rp; - - // Reflectance term for m>0 (pairs of diracs) - Cm = Rp - T121.y; - for (int m = 1; m <= AIRY_FRESNEL_ITERATIONS; m++) - { - Cm *= r123s; - Sm = 2.0 * mx_eval_sensitivity(float(m) * opd, float(m)*(phi23s+vec3(phi21.y))); - I += Cm*Sm; - } - - // Average parallel and perpendicular polarization - I *= 0.5; - - // Convert back to RGB reflectance - I = clamp(mx_matrix_mul(XYZ_TO_RGB, I), 0.0, 1.0); - - return I; -} - -FresnelData mx_init_fresnel_dielectric(float ior, float tf_thickness, float tf_ior) -{ - FresnelData fd; - fd.model = FRESNEL_MODEL_DIELECTRIC; - fd.airy = tf_thickness > 0.0; - fd.ior = vec3(ior); - fd.extinction = vec3(0.0); - fd.F0 = vec3(0.0); - fd.F82 = vec3(0.0); - fd.F90 = vec3(0.0); - fd.exponent = 0.0; - fd.tf_thickness = tf_thickness; - fd.tf_ior = tf_ior; - fd.refraction = false; - return fd; -} - -FresnelData mx_init_fresnel_conductor(vec3 ior, vec3 extinction, float tf_thickness, float tf_ior) -{ - FresnelData fd; - fd.model = FRESNEL_MODEL_CONDUCTOR; - fd.airy = tf_thickness > 0.0; - fd.ior = ior; - fd.extinction = extinction; - fd.F0 = vec3(0.0); - fd.F82 = vec3(0.0); - fd.F90 = vec3(0.0); - fd.exponent = 0.0; - fd.tf_thickness = tf_thickness; - fd.tf_ior = tf_ior; - fd.refraction = false; - return fd; -} - -FresnelData mx_init_fresnel_schlick(vec3 F0, vec3 F82, vec3 F90, float exponent, float tf_thickness, float tf_ior) -{ - FresnelData fd; - fd.model = FRESNEL_MODEL_SCHLICK; - fd.airy = tf_thickness > 0.0; - fd.ior = vec3(0.0); - fd.extinction = vec3(0.0); - fd.F0 = F0; - fd.F82 = F82; - fd.F90 = F90; - fd.exponent = exponent; - fd.tf_thickness = tf_thickness; - fd.tf_ior = tf_ior; - fd.refraction = false; - return fd; -} - -vec3 mx_compute_fresnel(float cosTheta, FresnelData fd) -{ - if (fd.airy) - { - return mx_fresnel_airy(cosTheta, fd); - } - else if (fd.model == FRESNEL_MODEL_DIELECTRIC) - { - return vec3(mx_fresnel_dielectric(cosTheta, fd.ior.x)); - } - else if (fd.model == FRESNEL_MODEL_CONDUCTOR) - { - return mx_fresnel_conductor(cosTheta, fd.ior, fd.extinction); - } - else - { - return mx_fresnel_hoffman_schlick(cosTheta, fd); - } -} - -// Compute the refraction of a ray through a solid sphere. -vec3 mx_refraction_solid_sphere(vec3 R, vec3 N, float ior) -{ - R = refract(R, N, 1.0 / ior); - vec3 N1 = normalize(R * dot(R, N) - N * 0.5); - return refract(R, N1, ior); -} - -vec2 mx_latlong_projection(vec3 dir) -{ - 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); -} - -vec3 mx_latlong_map_lookup(vec3 dir, mat4 transform, float lod, $texSamplerSignature) -{ - vec3 envDir = normalize(mx_matrix_mul(transform, vec4(dir,0.0)).xyz); - vec2 uv = mx_latlong_projection(envDir); - return textureLod($texSamplerSampler2D, uv, lod).rgb; -} - -// Return the mip level with the appropriate coverage for a filtered importance sample. -// https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch20.html -// Section 20.4 Equation 13 -float mx_latlong_compute_lod(vec3 dir, float pdf, float maxMipLevel, int envSamples) -{ - const float MIP_LEVEL_OFFSET = 1.5; - float effectiveMaxMipLevel = maxMipLevel - MIP_LEVEL_OFFSET; - float distortion = sqrt(1.0 - mx_square(dir.y)); - return max(effectiveMaxMipLevel - 0.5 * log2(float(envSamples) * pdf * distortion), 0.0); -} +#include "mx_microfacet.glsl" + +const int FRESNEL_MODEL_DIELECTRIC = 0; +const int FRESNEL_MODEL_CONDUCTOR = 1; +const int FRESNEL_MODEL_SCHLICK = 2; + +// Parameters for Fresnel calculations +struct FresnelData +{ + // Fresnel model + int model; + bool airy; + + // Physical Fresnel + vec3 ior; + vec3 extinction; + + // Generalized Schlick Fresnel + vec3 F0; + vec3 F82; + vec3 F90; + float exponent; + + // Thin film + float tf_thickness; + float tf_ior; + + // Refraction + bool refraction; +}; + +// https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf +// Appendix B.2 Equation 13 +float mx_ggx_NDF(vec3 H, vec2 alpha) +{ + vec2 He = H.xy / alpha; + float denom = dot(He, He) + mx_square(H.z); + return 1.0 / (M_PI * alpha.x * alpha.y * mx_square(denom)); +} + +// https://ggx-research.github.io/publication/2023/06/09/publication-ggx.html +vec3 mx_ggx_importance_sample_VNDF(vec2 Xi, vec3 V, vec2 alpha) +{ + // Transform the view direction to the hemisphere configuration. + V = normalize(vec3(V.xy * alpha, V.z)); + + // Sample a spherical cap in (-V.z, 1]. + 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); + vec3 c = vec3(x, y, z); + + // Compute the microfacet normal. + vec3 H = c + V; + + // Transform the microfacet normal back to the ellipsoid configuration. + H = normalize(vec3(H.xy * alpha, max(H.z, 0.0))); + + return H; +} + +// https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf +// Equation 34 +float mx_ggx_smith_G1(float cosTheta, float alpha) +{ + float cosTheta2 = mx_square(cosTheta); + float tanTheta2 = (1.0 - cosTheta2) / cosTheta2; + return 2.0 / (1.0 + sqrt(1.0 + mx_square(alpha) * tanTheta2)); +} + +// Height-correlated Smith masking-shadowing +// http://jcgt.org/published/0003/02/03/paper.pdf +// Equations 72 and 99 +float mx_ggx_smith_G2(float NdotL, float NdotV, float alpha) +{ + float alpha2 = mx_square(alpha); + float lambdaL = sqrt(alpha2 + (1.0 - alpha2) * mx_square(NdotL)); + float lambdaV = sqrt(alpha2 + (1.0 - alpha2) * mx_square(NdotV)); + return 2.0 / (lambdaL / NdotL + lambdaV / NdotV); +} + +// Rational quadratic fit to Monte Carlo data for GGX directional albedo. +vec3 mx_ggx_dir_albedo_analytic(float NdotV, float alpha, vec3 F0, vec3 F90) +{ + float x = NdotV; + float y = alpha; + float x2 = mx_square(x); + float y2 = mx_square(y); + vec4 r = vec4(0.1003, 0.9345, 1.0, 1.0) + + vec4(-0.6303, -2.323, -1.765, 0.2281) * x + + vec4(9.748, 2.229, 8.263, 15.94) * y + + vec4(-2.038, -3.748, 11.53, -55.83) * x * y + + vec4(29.34, 1.424, 28.96, 13.08) * x2 + + vec4(-8.245, -0.7684, -7.507, 41.26) * y2 + + vec4(-26.44, 1.436, -36.11, 54.9) * x2 * y + + vec4(19.99, 0.2913, 15.86, 300.2) * x * y2 + + vec4(-5.448, 0.6286, 33.37, -285.1) * x2 * y2; + vec2 AB = clamp(r.xy / r.zw, 0.0, 1.0); + return F0 * AB.x + F90 * AB.y; +} + +vec3 mx_ggx_dir_albedo_table_lookup(float NdotV, float alpha, vec3 F0, vec3 F90) +{ +#if DIRECTIONAL_ALBEDO_METHOD == 1 + if (textureSize($albedoTable, 0).x > 1) + { + vec2 AB = texture($albedoTable, vec2(NdotV, alpha)).rg; + return F0 * AB.x + F90 * AB.y; + } +#endif + return vec3(0.0); +} + +// https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf +vec3 mx_ggx_dir_albedo_monte_carlo(float NdotV, float alpha, vec3 F0, vec3 F90) +{ + NdotV = clamp(NdotV, M_FLOAT_EPS, 1.0); + vec3 V = vec3(sqrt(1.0 - mx_square(NdotV)), 0, NdotV); + + vec2 AB = vec2(0.0); + const int SAMPLE_COUNT = 64; + for (int i = 0; i < SAMPLE_COUNT; i++) + { + vec2 Xi = mx_spherical_fibonacci(i, SAMPLE_COUNT); + + // Compute the half vector and incoming light direction. + vec3 H = mx_ggx_importance_sample_VNDF(Xi, V, vec2(alpha)); + vec3 L = -reflect(V, H); + + // Compute dot products for this sample. + float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0); + float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0); + + // Compute the Fresnel term. + float Fc = mx_fresnel_schlick(VdotH, 0.0, 1.0); + + // Compute the per-sample geometric term. + // https://hal.inria.fr/hal-00996995v2/document, Algorithm 2 + float G2 = mx_ggx_smith_G2(NdotL, NdotV, alpha); + + // Add the contribution of this sample. + AB += vec2(G2 * (1.0 - Fc), G2 * Fc); + } + + // Apply the global component of the geometric term and normalize. + AB /= mx_ggx_smith_G1(NdotV, alpha) * float(SAMPLE_COUNT); + + // Return the final directional albedo. + return F0 * AB.x + F90 * AB.y; +} + +vec3 mx_ggx_dir_albedo(float NdotV, float alpha, vec3 F0, vec3 F90) +{ +#if DIRECTIONAL_ALBEDO_METHOD == 0 + return mx_ggx_dir_albedo_analytic(NdotV, alpha, F0, F90); +#elif DIRECTIONAL_ALBEDO_METHOD == 1 + return mx_ggx_dir_albedo_table_lookup(NdotV, alpha, F0, F90); +#else + return mx_ggx_dir_albedo_monte_carlo(NdotV, alpha, F0, F90); +#endif +} + +float mx_ggx_dir_albedo(float NdotV, float alpha, float F0, float F90) +{ + return mx_ggx_dir_albedo(NdotV, alpha, vec3(F0), vec3(F90)).x; +} + +// https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf +// Equations 14 and 16 +vec3 mx_ggx_energy_compensation(float NdotV, float alpha, vec3 Fss) +{ + float Ess = mx_ggx_dir_albedo(NdotV, alpha, 1.0, 1.0); + return 1.0 + Fss * (1.0 - Ess) / Ess; +} + +float mx_ggx_energy_compensation(float NdotV, float alpha, float Fss) +{ + return mx_ggx_energy_compensation(NdotV, alpha, vec3(Fss)).x; +} + +// Compute the average of an anisotropic alpha pair. +float mx_average_alpha(vec2 alpha) +{ + return sqrt(alpha.x * alpha.y); +} + +// Convert a real-valued index of refraction to normal-incidence reflectivity. +float mx_ior_to_f0(float ior) +{ + return mx_square((ior - 1.0) / (ior + 1.0)); +} + +// Convert normal-incidence reflectivity to real-valued index of refraction. +float mx_f0_to_ior(float F0) +{ + float sqrtF0 = sqrt(clamp(F0, 0.01, 0.99)); + return (1.0 + sqrtF0) / (1.0 - sqrtF0); +} +vec3 mx_f0_to_ior(vec3 F0) +{ + vec3 sqrtF0 = sqrt(clamp(F0, 0.01, 0.99)); + return (vec3(1.0) + sqrtF0) / (vec3(1.0) - sqrtF0); +} + +// https://renderwonk.com/publications/wp-generalization-adobe/gen-adobe.pdf +vec3 mx_fresnel_hoffman_schlick(float cosTheta, FresnelData fd) +{ + const float COS_THETA_MAX = 1.0 / 7.0; + const float COS_THETA_FACTOR = 1.0 / (COS_THETA_MAX * pow(1.0 - COS_THETA_MAX, 6.0)); + + float x = clamp(cosTheta, 0.0, 1.0); + vec3 a = mix(fd.F0, fd.F90, pow(1.0 - COS_THETA_MAX, fd.exponent)) * (vec3(1.0) - fd.F82) * COS_THETA_FACTOR; + return mix(fd.F0, fd.F90, pow(1.0 - x, fd.exponent)) - a * x * mx_pow6(1.0 - x); +} + +// https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ +float mx_fresnel_dielectric(float cosTheta, float ior) +{ + float c = cosTheta; + float g2 = ior*ior + c*c - 1.0; + if (g2 < 0.0) + { + // Total internal reflection + return 1.0; + } + + float g = sqrt(g2); + return 0.5 * mx_square((g - c) / (g + c)) * + (1.0 + mx_square(((g + c) * c - 1.0) / ((g - c) * c + 1.0))); +} + +// https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ +vec2 mx_fresnel_dielectric_polarized(float cosTheta, float ior) +{ + float cosTheta2 = mx_square(clamp(cosTheta, 0.0, 1.0)); + float sinTheta2 = 1.0 - cosTheta2; + + float t0 = max(ior * ior - sinTheta2, 0.0); + float t1 = t0 + cosTheta2; + float t2 = 2.0 * sqrt(t0) * cosTheta; + float Rs = (t1 - t2) / (t1 + t2); + + float t3 = cosTheta2 * t0 + sinTheta2 * sinTheta2; + float t4 = t2 * sinTheta2; + float Rp = Rs * (t3 - t4) / (t3 + t4); + + return vec2(Rp, Rs); +} + +// https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ +void mx_fresnel_conductor_polarized(float cosTheta, vec3 n, vec3 k, out vec3 Rp, out vec3 Rs) +{ + float cosTheta2 = mx_square(clamp(cosTheta, 0.0, 1.0)); + float sinTheta2 = 1.0 - cosTheta2; + vec3 n2 = n * n; + vec3 k2 = k * k; + + vec3 t0 = n2 - k2 - vec3(sinTheta2); + vec3 a2plusb2 = sqrt(t0 * t0 + 4.0 * n2 * k2); + vec3 t1 = a2plusb2 + vec3(cosTheta2); + vec3 a = sqrt(max(0.5 * (a2plusb2 + t0), 0.0)); + vec3 t2 = 2.0 * a * cosTheta; + Rs = (t1 - t2) / (t1 + t2); + + vec3 t3 = cosTheta2 * a2plusb2 + vec3(sinTheta2 * sinTheta2); + vec3 t4 = t2 * sinTheta2; + Rp = Rs * (t3 - t4) / (t3 + t4); +} + +vec3 mx_fresnel_conductor(float cosTheta, vec3 n, vec3 k) +{ + vec3 Rp, Rs; + mx_fresnel_conductor_polarized(cosTheta, n, k, Rp, Rs); + return 0.5 * (Rp + Rs); +} + +// https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html +void mx_fresnel_conductor_phase_polarized(float cosTheta, float eta1, vec3 eta2, vec3 kappa2, out vec3 phiP, out vec3 phiS) +{ + vec3 k2 = kappa2 / eta2; + vec3 sinThetaSqr = vec3(1.0) - cosTheta * cosTheta; + vec3 A = eta2*eta2*(vec3(1.0)-k2*k2) - eta1*eta1*sinThetaSqr; + vec3 B = sqrt(A*A + mx_square(2.0*eta2*eta2*k2)); + 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)); +} + +// https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html +vec3 mx_eval_sensitivity(float opd, vec3 shift) +{ + // Use Gaussian fits, given by 3 parameters: val, pos and var + float phase = 2.0*M_PI * opd; + 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); + return xyz / 1.0685e-7; +} + +// A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence +// https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html +vec3 mx_fresnel_airy(float cosTheta, FresnelData fd) +{ + // XYZ to CIE 1931 RGB color space (using neutral E illuminant) + const mat3 XYZ_TO_RGB = mat3(2.3706743, -0.5138850, 0.0052982, -0.9000405, 1.4253036, -0.0146949, -0.4706338, 0.0885814, 1.0093968); + + // Assume vacuum on the outside + float eta1 = 1.0; + float eta2 = max(fd.tf_ior, eta1); + vec3 eta3 = (fd.model == FRESNEL_MODEL_SCHLICK) ? mx_f0_to_ior(fd.F0) : fd.ior; + vec3 kappa3 = (fd.model == FRESNEL_MODEL_SCHLICK) ? vec3(0.0) : fd.extinction; + float cosThetaT = sqrt(1.0 - (1.0 - mx_square(cosTheta)) * mx_square(eta1 / eta2)); + + // First interface + vec2 R12 = mx_fresnel_dielectric_polarized(cosTheta, eta2 / eta1); + if (cosThetaT <= 0.0) + { + // Total internal reflection + R12 = vec2(1.0); + } + vec2 T121 = vec2(1.0) - R12; + + // Second interface + vec3 R23p, R23s; + if (fd.model == FRESNEL_MODEL_SCHLICK) + { + vec3 f = mx_fresnel_hoffman_schlick(cosThetaT, fd); + R23p = 0.5 * f; + R23s = 0.5 * f; + } + else + { + mx_fresnel_conductor_polarized(cosThetaT, eta3 / eta2, kappa3 / eta2, R23p, R23s); + } + + // Phase shift + float cosB = cos(atan(eta2 / eta1)); + vec2 phi21 = vec2(cosTheta < cosB ? 0.0 : M_PI, M_PI); + vec3 phi23p, phi23s; + if (fd.model == FRESNEL_MODEL_SCHLICK) + { + phi23p = vec3((eta3[0] < eta2) ? M_PI : 0.0, + (eta3[1] < eta2) ? M_PI : 0.0, + (eta3[2] < eta2) ? M_PI : 0.0); + phi23s = phi23p; + } + else + { + mx_fresnel_conductor_phase_polarized(cosThetaT, eta2, eta3, kappa3, phi23p, phi23s); + } + vec3 r123p = max(sqrt(R12.x*R23p), 0.0); + vec3 r123s = max(sqrt(R12.y*R23s), 0.0); + + // Iridescence term + vec3 I = vec3(0.0); + vec3 Cm, Sm; + + // Optical path difference + float distMeters = fd.tf_thickness * 1.0e-9; + float opd = 2.0 * eta2 * cosThetaT * distMeters; + + // Iridescence term using spectral antialiasing for Parallel polarization + + // Reflectance term for m=0 (DC term amplitude) + vec3 Rs = (mx_square(T121.x) * R23p) / (vec3(1.0) - R12.x*R23p); + I += R12.x + Rs; + + // Reflectance term for m>0 (pairs of diracs) + Cm = Rs - T121.x; + for (int m=1; m<=2; m++) + { + Cm *= r123p; + Sm = 2.0 * mx_eval_sensitivity(float(m) * opd, float(m)*(phi23p+vec3(phi21.x))); + I += Cm*Sm; + } + + // Iridescence term using spectral antialiasing for Perpendicular polarization + + // Reflectance term for m=0 (DC term amplitude) + vec3 Rp = (mx_square(T121.y) * R23s) / (vec3(1.0) - R12.y*R23s); + I += R12.y + Rp; + + // Reflectance term for m>0 (pairs of diracs) + Cm = Rp - T121.y; + for (int m=1; m<=2; m++) + { + Cm *= r123s; + Sm = 2.0 * mx_eval_sensitivity(float(m) * opd, float(m)*(phi23s+vec3(phi21.y))); + I += Cm*Sm; + } + + // Average parallel and perpendicular polarization + I *= 0.5; + + // Convert back to RGB reflectance + I = clamp(XYZ_TO_RGB * I, 0.0, 1.0); + + return I; +} + +FresnelData mx_init_fresnel_dielectric(float ior, float tf_thickness, float tf_ior) +{ + FresnelData fd; + fd.model = FRESNEL_MODEL_DIELECTRIC; + fd.airy = tf_thickness > 0.0; + fd.ior = vec3(ior); + fd.extinction = vec3(0.0); + fd.F0 = vec3(0.0); + fd.F82 = vec3(0.0); + fd.F90 = vec3(0.0); + fd.exponent = 0.0; + fd.tf_thickness = tf_thickness; + fd.tf_ior = tf_ior; + fd.refraction = false; + return fd; +} + +FresnelData mx_init_fresnel_conductor(vec3 ior, vec3 extinction, float tf_thickness, float tf_ior) +{ + FresnelData fd; + fd.model = FRESNEL_MODEL_CONDUCTOR; + fd.airy = tf_thickness > 0.0; + fd.ior = ior; + fd.extinction = extinction; + fd.F0 = vec3(0.0); + fd.F82 = vec3(0.0); + fd.F90 = vec3(0.0); + fd.exponent = 0.0; + fd.tf_thickness = tf_thickness; + fd.tf_ior = tf_ior; + fd.refraction = false; + return fd; +} + +FresnelData mx_init_fresnel_schlick(vec3 F0, vec3 F82, vec3 F90, float exponent, float tf_thickness, float tf_ior) +{ + FresnelData fd; + fd.model = FRESNEL_MODEL_SCHLICK; + fd.airy = tf_thickness > 0.0; + fd.ior = vec3(0.0); + fd.extinction = vec3(0.0); + fd.F0 = F0; + fd.F82 = F82; + fd.F90 = F90; + fd.exponent = exponent; + fd.tf_thickness = tf_thickness; + fd.tf_ior = tf_ior; + fd.refraction = false; + return fd; +} + +vec3 mx_compute_fresnel(float cosTheta, FresnelData fd) +{ + if (fd.airy) + { + return mx_fresnel_airy(cosTheta, fd); + } + else if (fd.model == FRESNEL_MODEL_DIELECTRIC) + { + return vec3(mx_fresnel_dielectric(cosTheta, fd.ior.x)); + } + else if (fd.model == FRESNEL_MODEL_CONDUCTOR) + { + return mx_fresnel_conductor(cosTheta, fd.ior, fd.extinction); + } + else + { + return mx_fresnel_hoffman_schlick(cosTheta, fd); + } +} + +// Compute the refraction of a ray through a solid sphere. +vec3 mx_refraction_solid_sphere(vec3 R, vec3 N, float ior) +{ + R = refract(R, N, 1.0 / ior); + vec3 N1 = normalize(R * dot(R, N) - N * 0.5); + return refract(R, N1, 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; + return vec2(longitude, latitude); +} + +vec3 mx_latlong_map_lookup(vec3 dir, mat4 transform, float lod, sampler2D envSampler) +{ + vec3 envDir = normalize((transform * vec4(dir,0.0)).xyz); + vec2 uv = mx_latlong_projection(envDir); + return textureLod(envSampler, uv, lod).rgb; +} + +// Return the mip level with the appropriate coverage for a filtered importance sample. +// https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch20.html +// Section 20.4 Equation 13 +float mx_latlong_compute_lod(vec3 dir, float pdf, float maxMipLevel, int envSamples) +{ + const float MIP_LEVEL_OFFSET = 1.5; + float effectiveMaxMipLevel = maxMipLevel - MIP_LEVEL_OFFSET; + float distortion = sqrt(1.0 - mx_square(dir.y)); + return max(effectiveMaxMipLevel - 0.5 * log2(float(envSamples) * pdf * distortion), 0.0); +} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_shadow.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_shadow.glsl old mode 100644 new mode 100755 index 0a0fdb4..19525cf --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_shadow.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_shadow.glsl @@ -1,23 +1,23 @@ -// https://developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-8-summed-area-variance-shadow-maps -float mx_variance_shadow_occlusion(vec2 moments, float fragmentDepth) -{ - const float MIN_VARIANCE = 0.00001; - - // One-tailed inequality valid if fragmentDepth > moments.x. - float p = (fragmentDepth <= moments.x) ? 1.0 : 0.0; - - // Compute variance. - float variance = moments.y - mx_square(moments.x); - variance = max(variance, MIN_VARIANCE); - - // Compute probabilistic upper bound. - float d = fragmentDepth - moments.x; - float pMax = variance / (variance + mx_square(d)); - return max(p, pMax); -} - -vec2 mx_compute_depth_moments() -{ - float depth = gl_FragCoord.z; - return vec2(depth, mx_square(depth)); -} +// https://developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-8-summed-area-variance-shadow-maps +float mx_variance_shadow_occlusion(vec2 moments, float fragmentDepth) +{ + const float MIN_VARIANCE = 0.00001; + + // One-tailed inequality valid if fragmentDepth > moments.x. + float p = (fragmentDepth <= moments.x) ? 1.0 : 0.0; + + // Compute variance. + float variance = moments.y - mx_square(moments.x); + variance = max(variance, MIN_VARIANCE); + + // Compute probabilistic upper bound. + float d = fragmentDepth - moments.x; + float pMax = variance / (variance + mx_square(d)); + return max(p, pMax); +} + +vec2 mx_compute_depth_moments() +{ + float depth = gl_FragCoord.z; + return vec2(depth, mx_square(depth)); +} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_shadow_platform.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_shadow_platform.glsl deleted file mode 100644 index 8d1c162..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_shadow_platform.glsl +++ /dev/null @@ -1,13 +0,0 @@ - -float mx_shadow_occlusion( - $texSamplerSignature, - mat4 shadow_matrix, - vec3 world_position -) -{ - vec4 shadowCoord4 = mx_matrix_mul(shadow_matrix, vec4(world_position, 1.0)); - vec3 shadowCoord = shadowCoord4.xyz / shadowCoord4.w; - shadowCoord = shadowCoord * 0.5 + 0.5; - vec2 shadowMoments = texture($texSamplerSampler2D, shadowCoord.xy).xy; - return mx_variance_shadow_occlusion(shadowMoments, shadowCoord.z); -} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_transmission_opacity.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_transmission_opacity.glsl old mode 100644 new mode 100755 index 2861d06..4aae395 --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_transmission_opacity.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_transmission_opacity.glsl @@ -1,6 +1,6 @@ -#include "mx_microfacet_specular.glsl" - -vec3 mx_surface_transmission(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd, vec3 tint) -{ - return tint; -} +#include "mx_microfacet_specular.glsl" + +vec3 mx_surface_transmission(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd, vec3 tint) +{ + return tint; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/lib/mx_transmission_refract.glsl b/MaterialX/libraries/pbrlib/genglsl/lib/mx_transmission_refract.glsl old mode 100644 new mode 100755 index 64e496a..fffa42d --- a/MaterialX/libraries/pbrlib/genglsl/lib/mx_transmission_refract.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/lib/mx_transmission_refract.glsl @@ -1,14 +1,14 @@ -#include "mx_microfacet_specular.glsl" - -vec3 mx_surface_transmission(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd, vec3 tint) -{ - // Approximate the appearance of surface transmission as glossy - // environment map refraction, ignoring any scene geometry that might - // be visible through the surface. - fd.refraction = true; - if ($refractionTwoSided) - { - tint = mx_square(tint); - } - return mx_environment_radiance(N, V, X, alpha, distribution, fd) * tint; -} +#include "mx_microfacet_specular.glsl" + +vec3 mx_surface_transmission(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd, vec3 tint) +{ + // Approximate the appearance of surface transmission as glossy + // environment map refraction, ignoring any scene geometry that might + // be visible through the surface. + fd.refraction = true; + if ($refractionTwoSided) + { + tint = mx_square(tint); + } + return mx_environment_radiance(N, V, X, alpha, distribution, fd) * tint; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_add_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_add_bsdf.glsl deleted file mode 100644 index 2fc8b0f..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/mx_add_bsdf.glsl +++ /dev/null @@ -1,14 +0,0 @@ -#include "lib/mx_closure_type.glsl" - -void mx_add_bsdf(ClosureData closureData, BSDF in1, BSDF in2, out BSDF result) -{ - result.response = in1.response + in2.response; - - // We derive the throughput for closure addition as follows: - // throughput_1 = 1 - dir_albedo_1 - // throughput_2 = 1 - dir_albedo_2 - // throughput_sum = 1 - (dir_albedo_1 + dir_albedo_2) - // = 1 - ((1 - throughput_1) + (1 - throughput_2)) - // = throughput_1 + throughput_2 - 1 - result.throughput = max(in1.throughput + in2.throughput - 1.0, 0.0); -} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_add_edf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_add_edf.glsl old mode 100644 new mode 100755 index 23ab46c..0b16023 --- a/MaterialX/libraries/pbrlib/genglsl/mx_add_edf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_add_edf.glsl @@ -1,6 +1,4 @@ -#include "lib/mx_closure_type.glsl" - -void mx_add_edf(ClosureData closureData, EDF in1, EDF in2, out EDF result) -{ - result = in1 + in2; -} +void mx_add_edf(vec3 N, vec3 L, EDF in1, EDF in2, out EDF result) +{ + result = in1 + in2; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_anisotropic_vdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_anisotropic_vdf.glsl old mode 100644 new mode 100755 index fe22c56..fd1e295 --- a/MaterialX/libraries/pbrlib/genglsl/mx_anisotropic_vdf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_anisotropic_vdf.glsl @@ -1,6 +1,4 @@ -#include "lib/mx_closure_type.glsl" - -void mx_anisotropic_vdf(ClosureData closureData, vec3 absorption, vec3 scattering, float anisotropy, inout BSDF bsdf) -{ - // TODO: Add some approximation for volumetric light absorption. -} +void mx_anisotropic_vdf(vec3 absorption, vec3 scattering, float anisotropy, inout BSDF bsdf) +{ + // TODO: Add some approximation for volumetric light absorption. +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_artistic_ior.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_artistic_ior.glsl old mode 100644 new mode 100755 index 9c4e405..4f5305d --- a/MaterialX/libraries/pbrlib/genglsl/mx_artistic_ior.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_artistic_ior.glsl @@ -1,17 +1,17 @@ -void mx_artistic_ior(vec3 reflectivity, vec3 edge_color, out vec3 ior, out vec3 extinction) -{ - // "Artist Friendly Metallic Fresnel", Ole Gulbrandsen, 2014 - // http://jcgt.org/published/0003/04/03/paper.pdf - - vec3 r = clamp(reflectivity, 0.0, 0.99); - vec3 r_sqrt = sqrt(r); - vec3 n_min = (1.0 - r) / (1.0 + r); - vec3 n_max = (1.0 + r_sqrt) / (1.0 - r_sqrt); - ior = mix(n_max, n_min, edge_color); - - vec3 np1 = ior + 1.0; - vec3 nm1 = ior - 1.0; - vec3 k2 = (np1*np1 * r - nm1*nm1) / (1.0 - r); - k2 = max(k2, 0.0); - extinction = sqrt(k2); -} +void mx_artistic_ior(vec3 reflectivity, vec3 edge_color, out vec3 ior, out vec3 extinction) +{ + // "Artist Friendly Metallic Fresnel", Ole Gulbrandsen, 2014 + // http://jcgt.org/published/0003/04/03/paper.pdf + + vec3 r = clamp(reflectivity, 0.0, 0.99); + vec3 r_sqrt = sqrt(r); + vec3 n_min = (1.0 - r) / (1.0 + r); + vec3 n_max = (1.0 + r_sqrt) / (1.0 - r_sqrt); + ior = mix(n_max, n_min, edge_color); + + vec3 np1 = ior + 1.0; + vec3 nm1 = ior - 1.0; + vec3 k2 = (np1*np1 * r - nm1*nm1) / (1.0 - r); + k2 = max(k2, 0.0); + extinction = sqrt(k2); +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_blackbody.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_blackbody.glsl old mode 100644 new mode 100755 index b15de27..047420c --- a/MaterialX/libraries/pbrlib/genglsl/mx_blackbody.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_blackbody.glsl @@ -1,48 +1,48 @@ -/// XYZ to Rec.709 RGB colorspace conversion -const mat3 XYZ_to_RGB = mat3( 3.2406, -0.9689, 0.0557, - -1.5372, 1.8758, -0.2040, - -0.4986, 0.0415, 1.0570); - -void mx_blackbody(float temperatureKelvin, out vec3 colorValue) -{ - float xc, yc; - float t, t2, t3, xc2, xc3; - - // if value outside valid range of approximation clamp to accepted temperature range - temperatureKelvin = clamp(temperatureKelvin, 1667.0, 25000.0); - - t = 1000.0 / temperatureKelvin; - t2 = t * t; - t3 = t * t * t; - - // Cubic spline approximation for Kelvin temperature to sRGB conversion - // (https://en.wikipedia.org/wiki/Planckian_locus#Approximation) - if (temperatureKelvin < 4000.0) { // 1667K <= temperatureKelvin < 4000K - xc = -0.2661239 * t3 - 0.2343580 * t2 + 0.8776956 * t + 0.179910; - } - else { // 4000K <= temperatureKelvin <= 25000K - xc = -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t + 0.240390; - } - xc2 = xc * xc; - xc3 = xc * xc * xc; - - if (temperatureKelvin < 2222.0) { // 1667K <= temperatureKelvin < 2222K - yc = -1.1063814 * xc3 - 1.34811020 * xc2 + 2.18555832 * xc - 0.20219683; - } - else if (temperatureKelvin < 4000.0) { // 2222K <= temperatureKelvin < 4000K - yc = -0.9549476 * xc3 - 1.37418593 * xc2 + 2.09137015 * xc - 0.16748867; - } - else { // 4000K <= temperatureKelvin <= 25000K - yc = 3.0817580 * xc3 - 5.87338670 * xc2 + 3.75112997 * xc - 0.37001483; - } - - if (yc <= 0.0) { // avoid division by zero - colorValue = vec3(1.0); - return; - } - - vec3 XYZ = vec3(xc / yc, 1.0, (1.0 - xc - yc) / yc); - - colorValue = mx_matrix_mul(XYZ_to_RGB, XYZ); - colorValue = max(colorValue, vec3(0.0)); -} +/// XYZ to Rec.709 RGB colorspace conversion +const mat3 XYZ_to_RGB = mat3( 3.2406, -0.9689, 0.0557, + -1.5372, 1.8758, -0.2040, + -0.4986, 0.0415, 1.0570); + +void mx_blackbody(float temperatureKelvin, out vec3 colorValue) +{ + float xc, yc; + float t, t2, t3, xc2, xc3; + + // if value outside valid range of approximation clamp to accepted temperature range + temperatureKelvin = clamp(temperatureKelvin, 1667.0, 25000.0); + + t = 1000.0 / temperatureKelvin; + t2 = t * t; + t3 = t * t * t; + + // Cubic spline approximation for Kelvin temperature to sRGB conversion + // (https://en.wikipedia.org/wiki/Planckian_locus#Approximation) + if (temperatureKelvin < 4000.0) { // 1667K <= temperatureKelvin < 4000K + xc = -0.2661239 * t3 - 0.2343580 * t2 + 0.8776956 * t + 0.179910; + } + else { // 4000K <= temperatureKelvin <= 25000K + xc = -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t + 0.240390; + } + xc2 = xc * xc; + xc3 = xc * xc * xc; + + if (temperatureKelvin < 2222.0) { // 1667K <= temperatureKelvin < 2222K + yc = -1.1063814 * xc3 - 1.34811020 * xc2 + 2.18555832 * xc - 0.20219683; + } + else if (temperatureKelvin < 4000.0) { // 2222K <= temperatureKelvin < 4000K + yc = -0.9549476 * xc3 - 1.37418593 * xc2 + 2.09137015 * xc - 0.16748867; + } + else { // 4000K <= temperatureKelvin <= 25000K + yc = 3.0817580 * xc3 - 5.87338670 * xc2 + 3.75112997 * xc - 0.37001483; + } + + if (yc <= 0.0) { // avoid division by zero + colorValue = vec3(1.0); + return; + } + + vec3 XYZ = vec3(xc / yc, 1.0, (1.0 - xc - yc) / yc); + + colorValue = XYZ_to_RGB * XYZ; + colorValue = max(colorValue, vec3(0.0)); +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl old mode 100644 new mode 100755 index 1399758..64f4b08 --- a/MaterialX/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl @@ -1,33 +1,38 @@ -#include "lib/mx_closure_type.glsl" -#include "lib/mx_microfacet_diffuse.glsl" - -void mx_burley_diffuse_bsdf(ClosureData closureData, float weight, vec3 color, float roughness, vec3 N, inout BSDF bsdf) -{ - bsdf.throughput = vec3(0.0); - - if (weight < M_FLOAT_EPS) - { - return; - } - - vec3 V = closureData.V; - vec3 L = closureData.L; - - N = mx_forward_facing_normal(N, V); - float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - - if (closureData.closureType == CLOSURE_TYPE_REFLECTION) - { - float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0); - float LdotH = clamp(dot(L, normalize(L + V)), M_FLOAT_EPS, 1.0); - - bsdf.response = color * closureData.occlusion * weight * NdotL * M_PI_INV; - bsdf.response *= mx_burley_diffuse(NdotV, NdotL, LdotH, roughness); - } - else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) - { - vec3 Li = mx_environment_irradiance(N) * - mx_burley_diffuse_dir_albedo(NdotV, roughness); - bsdf.response = Li * color * weight; - } -} +#include "lib/mx_microfacet_diffuse.glsl" + +void mx_burley_diffuse_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color, float roughness, vec3 normal, inout BSDF bsdf) +{ + bsdf.throughput = vec3(0.0); + + if (weight < M_FLOAT_EPS) + { + return; + } + + normal = mx_forward_facing_normal(normal, V); + + float NdotV = clamp(dot(normal, V), M_FLOAT_EPS, 1.0); + float NdotL = clamp(dot(normal, L), M_FLOAT_EPS, 1.0); + float LdotH = clamp(dot(L, normalize(L + V)), M_FLOAT_EPS, 1.0); + + bsdf.response = color * occlusion * weight * NdotL * M_PI_INV; + bsdf.response *= mx_burley_diffuse(NdotV, NdotL, LdotH, roughness); +} + +void mx_burley_diffuse_bsdf_indirect(vec3 V, float weight, vec3 color, float roughness, vec3 normal, inout BSDF bsdf) +{ + bsdf.throughput = vec3(0.0); + + if (weight < M_FLOAT_EPS) + { + return; + } + + normal = mx_forward_facing_normal(normal, V); + + float NdotV = clamp(dot(normal, V), M_FLOAT_EPS, 1.0); + + vec3 Li = mx_environment_irradiance(normal) * + mx_burley_diffuse_dir_albedo(NdotV, roughness); + bsdf.response = Li * color * weight; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl deleted file mode 100644 index 5485384..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl +++ /dev/null @@ -1,291 +0,0 @@ -#include "lib/mx_closure_type.glsl" -#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 roughness 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); -} - -void mx_chiang_hair_bsdf(ClosureData closureData, 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 V = closureData.V; - vec3 L = closureData.L; - - N = mx_forward_facing_normal(N, V); - - bsdf.throughput = vec3(0.0); - - if (closureData.closureType == CLOSURE_TYPE_REFLECTION) - { - 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, M_FLOAT_EPS); - 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]; - } - - bsdf.response = F * closureData.occlusion * M_PI_INV; - } - else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) - { - // This indirect term is a *very* rough approximation. - - 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 to match the behavior of mx_environment_radiance. - 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.response = Li * comp * tint; - } -} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl old mode 100644 new mode 100755 index 633f6d0..61ef271 --- a/MaterialX/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl @@ -1,51 +1,60 @@ -#include "lib/mx_closure_type.glsl" -#include "lib/mx_microfacet_specular.glsl" - -void mx_conductor_bsdf(ClosureData closureData, float weight, vec3 ior_n, vec3 ior_k, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, inout BSDF bsdf) -{ - bsdf.throughput = vec3(0.0); - - if (weight < M_FLOAT_EPS) - { - return; - } - - vec3 V = closureData.V; - vec3 L = closureData.L; - - N = mx_forward_facing_normal(N, V); - float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - - FresnelData fd = mx_init_fresnel_conductor(ior_n, ior_k, thinfilm_thickness, thinfilm_ior); - - vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); - float avgAlpha = mx_average_alpha(safeAlpha); - - if (closureData.closureType == CLOSURE_TYPE_REFLECTION) - { - X = normalize(X - dot(X, N) * N); - vec3 Y = cross(N, X); - vec3 H = normalize(L + V); - - float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0); - float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0); - - vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); - - vec3 F = mx_compute_fresnel(VdotH, fd); - float D = mx_ggx_NDF(Ht, safeAlpha); - float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); - - vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - - // Note: NdotL is cancelled out - bsdf.response = D * F * G * comp * closureData.occlusion * weight / (4.0 * NdotV); - } - else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) - { - vec3 F = mx_compute_fresnel(NdotV, fd); - vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, distribution, fd); - bsdf.response = Li * comp * weight; - } -} +#include "lib/mx_microfacet_specular.glsl" + +void mx_conductor_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 ior_n, vec3 ior_k, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, inout BSDF bsdf) +{ + bsdf.throughput = vec3(0.0); + + if (weight < M_FLOAT_EPS) + { + return; + } + + N = mx_forward_facing_normal(N, V); + + X = normalize(X - dot(X, N) * N); + vec3 Y = cross(N, X); + vec3 H = normalize(L + V); + + float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0); + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0); + + vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); + float avgAlpha = mx_average_alpha(safeAlpha); + vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); + + FresnelData fd = mx_init_fresnel_conductor(ior_n, ior_k, thinfilm_thickness, thinfilm_ior); + vec3 F = mx_compute_fresnel(VdotH, fd); + float D = mx_ggx_NDF(Ht, safeAlpha); + float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); + + vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); + + // Note: NdotL is cancelled out + bsdf.response = D * F * G * comp * occlusion * weight / (4.0 * NdotV); +} + +void mx_conductor_bsdf_indirect(vec3 V, float weight, vec3 ior_n, vec3 ior_k, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, inout BSDF bsdf) +{ + bsdf.throughput = vec3(0.0); + + if (weight < M_FLOAT_EPS) + { + return; + } + + N = mx_forward_facing_normal(N, V); + + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + + FresnelData fd = mx_init_fresnel_conductor(ior_n, ior_k, thinfilm_thickness, thinfilm_ior); + vec3 F = mx_compute_fresnel(NdotV, fd); + + vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); + float avgAlpha = mx_average_alpha(safeAlpha); + vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); + + vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, distribution, fd); + + bsdf.response = Li * comp * weight; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl old mode 100644 new mode 100755 index 4c59b21..750eed8 --- a/MaterialX/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl @@ -1,73 +1,92 @@ -#include "lib/mx_closure_type.glsl" -#include "lib/mx_microfacet_specular.glsl" - -void mx_dielectric_bsdf(ClosureData closureData, float weight, vec3 tint, float ior, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) -{ - if (weight < M_FLOAT_EPS) - { - return; - } - if (closureData.closureType != CLOSURE_TYPE_TRANSMISSION && scatter_mode == 1) - { - return; - } - - vec3 V = closureData.V; - vec3 L = closureData.L; - - 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, thinfilm_thickness, thinfilm_ior); - float F0 = mx_ior_to_f0(ior); - - vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); - float avgAlpha = mx_average_alpha(safeAlpha); - vec3 safeTint = max(tint, 0.0); - - if (closureData.closureType == CLOSURE_TYPE_REFLECTION) - { - X = normalize(X - dot(X, N) * N); - vec3 Y = cross(N, X); - vec3 H = normalize(L + V); - - float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0); - float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0); - - vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); - - vec3 F = mx_compute_fresnel(VdotH, fd); - float D = mx_ggx_NDF(Ht, safeAlpha); - float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); - - vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, F0, 1.0) * comp; - bsdf.throughput = 1.0 - dirAlbedo * weight; - - bsdf.response = D * F * G * comp * safeTint * closureData.occlusion * weight / (4.0 * NdotV); - } - else if (closureData.closureType == CLOSURE_TYPE_TRANSMISSION) - { - vec3 F = mx_compute_fresnel(NdotV, fd); - - vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, F0, 1.0) * comp; - bsdf.throughput = 1.0 - dirAlbedo * weight; - - if (scatter_mode != 0) - { - bsdf.response = mx_surface_transmission(N, V, X, safeAlpha, distribution, fd, safeTint) * weight; - } - } - else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) - { - vec3 F = mx_compute_fresnel(NdotV, fd); - - vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, F0, 1.0) * comp; - bsdf.throughput = 1.0 - dirAlbedo * weight; - - vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, distribution, fd); - bsdf.response = Li * safeTint * comp * weight; - } -} +#include "lib/mx_microfacet_specular.glsl" + +void mx_dielectric_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 tint, float ior, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +{ + if (weight < M_FLOAT_EPS) + { + return; + } + + N = mx_forward_facing_normal(N, V); + + X = normalize(X - dot(X, N) * N); + vec3 Y = cross(N, X); + vec3 H = normalize(L + V); + + float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0); + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0); + + vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); + float avgAlpha = mx_average_alpha(safeAlpha); + vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); + + vec3 safeTint = max(tint, 0.0); + FresnelData fd = mx_init_fresnel_dielectric(ior, thinfilm_thickness, thinfilm_ior); + vec3 F = mx_compute_fresnel(VdotH, fd); + float D = mx_ggx_NDF(Ht, safeAlpha); + float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); + + 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; + bsdf.throughput = 1.0 - dirAlbedo * weight; + + // Note: NdotL is cancelled out + bsdf.response = D * F * G * comp * safeTint * occlusion * weight / (4.0 * NdotV); +} + +void mx_dielectric_bsdf_transmission(vec3 V, float weight, vec3 tint, float ior, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +{ + if (weight < M_FLOAT_EPS) + { + return; + } + + N = mx_forward_facing_normal(N, V); + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + + vec3 safeTint = max(tint, 0.0); + FresnelData fd = mx_init_fresnel_dielectric(ior, thinfilm_thickness, thinfilm_ior); + vec3 F = mx_compute_fresnel(NdotV, fd); + + vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); + float avgAlpha = mx_average_alpha(safeAlpha); + + 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; + bsdf.throughput = 1.0 - dirAlbedo * weight; + + if (scatter_mode != 0) + { + bsdf.response = mx_surface_transmission(N, V, X, safeAlpha, distribution, fd, safeTint) * weight; + } +} + +void mx_dielectric_bsdf_indirect(vec3 V, float weight, vec3 tint, float ior, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +{ + if (weight < M_FLOAT_EPS) + { + return; + } + + N = mx_forward_facing_normal(N, V); + + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + + vec3 safeTint = max(tint, 0.0); + FresnelData fd = mx_init_fresnel_dielectric(ior, thinfilm_thickness, thinfilm_ior); + vec3 F = mx_compute_fresnel(NdotV, fd); + + vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); + float avgAlpha = mx_average_alpha(safeAlpha); + + 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; + bsdf.throughput = 1.0 - dirAlbedo * weight; + + vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, distribution, fd); + bsdf.response = Li * safeTint * comp * weight; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_displacement_float.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_displacement_float.glsl old mode 100644 new mode 100755 index 8dcdedb..80f506f --- a/MaterialX/libraries/pbrlib/genglsl/mx_displacement_float.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_displacement_float.glsl @@ -1,5 +1,5 @@ -void mx_displacement_float(float disp, float scale, out displacementshader result) -{ - result.offset = vec3(disp); - result.scale = scale; -} +void mx_displacement_float(float disp, float scale, out displacementshader result) +{ + result.offset = vec3(disp); + result.scale = scale; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_displacement_vector3.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_displacement_vector3.glsl old mode 100644 new mode 100755 index 095e015..9b8c499 --- a/MaterialX/libraries/pbrlib/genglsl/mx_displacement_vector3.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_displacement_vector3.glsl @@ -1,5 +1,5 @@ -void mx_displacement_vector3(vec3 disp, float scale, out displacementshader result) -{ - result.offset = disp; - result.scale = scale; -} +void mx_displacement_vector3(vec3 disp, float scale, out displacementshader result) +{ + result.offset = disp; + result.scale = scale; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl old mode 100644 new mode 100755 index 08c7311..5257d6e --- a/MaterialX/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl @@ -1,80 +1,98 @@ -#include "lib/mx_closure_type.glsl" -#include "lib/mx_microfacet_specular.glsl" - -void mx_generalized_schlick_bsdf(ClosureData closureData, float weight, vec3 color0, vec3 color82, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) -{ - if (weight < M_FLOAT_EPS) - { - return; - } - if (closureData.closureType != CLOSURE_TYPE_TRANSMISSION && scatter_mode == 1) - { - return; - } - - vec3 V = closureData.V; - vec3 L = closureData.L; - - N = mx_forward_facing_normal(N, V); - float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - - vec3 safeColor0 = max(color0, 0.0); - vec3 safeColor82 = max(color82, 0.0); - vec3 safeColor90 = max(color90, 0.0); - FresnelData fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); - - vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); - float avgAlpha = mx_average_alpha(safeAlpha); - - if (closureData.closureType == CLOSURE_TYPE_REFLECTION) - { - X = normalize(X - dot(X, N) * N); - vec3 Y = cross(N, X); - vec3 H = normalize(L + V); - - float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0); - float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0); - - vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); - - vec3 F = mx_compute_fresnel(VdotH, fd); - float D = mx_ggx_NDF(Ht, safeAlpha); - float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); - - vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, safeColor0, safeColor90) * comp; - float avgDirAlbedo = dot(dirAlbedo, vec3(1.0 / 3.0)); - bsdf.throughput = vec3(1.0 - avgDirAlbedo * weight); - - // Note: NdotL is cancelled out - bsdf.response = D * F * G * comp * closureData.occlusion * weight / (4.0 * NdotV); - } - else if (closureData.closureType == CLOSURE_TYPE_TRANSMISSION) - { - vec3 F = mx_compute_fresnel(NdotV, fd); - - vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, safeColor0, safeColor90) * comp; - float avgDirAlbedo = dot(dirAlbedo, vec3(1.0 / 3.0)); - bsdf.throughput = vec3(1.0 - avgDirAlbedo * weight); - - if (scatter_mode != 0) - { - 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, vec3(1.0)) * weight; - } - } - else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) - { - vec3 F = mx_compute_fresnel(NdotV, fd); - - vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, safeColor0, safeColor90) * comp; - float avgDirAlbedo = dot(dirAlbedo, vec3(1.0 / 3.0)); - bsdf.throughput = vec3(1.0 - avgDirAlbedo * weight); - - vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, distribution, fd); - bsdf.response = Li * comp * weight; - } -} +#include "lib/mx_microfacet_specular.glsl" + +void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color0, vec3 color82, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +{ + if (weight < M_FLOAT_EPS) + { + return; + } + + N = mx_forward_facing_normal(N, V); + + X = normalize(X - dot(X, N) * N); + vec3 Y = cross(N, X); + vec3 H = normalize(L + V); + + float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0); + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0); + + vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); + float avgAlpha = mx_average_alpha(safeAlpha); + vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); + + vec3 safeColor0 = max(color0, 0.0); + vec3 safeColor82 = max(color82, 0.0); + vec3 safeColor90 = max(color90, 0.0); + FresnelData fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); + vec3 F = mx_compute_fresnel(VdotH, fd); + float D = mx_ggx_NDF(Ht, safeAlpha); + float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); + + vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); + vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, safeColor0, safeColor90) * comp; + float avgDirAlbedo = dot(dirAlbedo, vec3(1.0 / 3.0)); + bsdf.throughput = vec3(1.0 - avgDirAlbedo * weight); + + // Note: NdotL is cancelled out + bsdf.response = D * F * G * comp * occlusion * weight / (4.0 * NdotV); +} + +void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, vec3 color82, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +{ + if (weight < M_FLOAT_EPS) + { + return; + } + + N = mx_forward_facing_normal(N, V); + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + + vec3 safeColor0 = max(color0, 0.0); + vec3 safeColor82 = max(color82, 0.0); + vec3 safeColor90 = max(color90, 0.0); + FresnelData fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); + vec3 F = mx_compute_fresnel(NdotV, fd); + + vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); + float avgAlpha = mx_average_alpha(safeAlpha); + + vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); + vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, safeColor0, safeColor90) * comp; + float avgDirAlbedo = dot(dirAlbedo, vec3(1.0 / 3.0)); + bsdf.throughput = vec3(1.0 - avgDirAlbedo * weight); + + if (scatter_mode != 0) + { + 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, vec3(1.0)) * weight; + } +} + +void mx_generalized_schlick_bsdf_indirect(vec3 V, float weight, vec3 color0, vec3 color82, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf) +{ + if (weight < M_FLOAT_EPS) + { + return; + } + + N = mx_forward_facing_normal(N, V); + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + + vec3 safeColor0 = max(color0, 0.0); + vec3 safeColor82 = max(color82, 0.0); + vec3 safeColor90 = max(color90, 0.0); + FresnelData fd = mx_init_fresnel_schlick(safeColor0, safeColor82, safeColor90, exponent, thinfilm_thickness, thinfilm_ior); + vec3 F = mx_compute_fresnel(NdotV, fd); + + vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); + float avgAlpha = mx_average_alpha(safeAlpha); + vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); + vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, safeColor0, safeColor90) * comp; + float avgDirAlbedo = dot(dirAlbedo, vec3(1.0 / 3.0)); + bsdf.throughput = vec3(1.0 - avgDirAlbedo * weight); + + vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, distribution, fd); + bsdf.response = Li * comp * weight; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_generalized_schlick_edf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_generalized_schlick_edf.glsl old mode 100644 new mode 100755 index 919dfa0..10ec0ac --- a/MaterialX/libraries/pbrlib/genglsl/mx_generalized_schlick_edf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_generalized_schlick_edf.glsl @@ -1,13 +1,9 @@ -#include "lib/mx_closure_type.glsl" -#include "lib/mx_microfacet.glsl" - -void mx_generalized_schlick_edf(ClosureData closureData, vec3 color0, vec3 color90, float exponent, EDF base, out EDF result) -{ - if (closureData.closureType == CLOSURE_TYPE_EMISSION) - { - vec3 N = mx_forward_facing_normal(closureData.N, closureData.V); - float NdotV = clamp(dot(N, closureData.V), M_FLOAT_EPS, 1.0); - vec3 f = mx_fresnel_schlick(NdotV, color0, color90, exponent); - result = base * f; - } -} +#include "lib/mx_microfacet.glsl" + +void mx_generalized_schlick_edf(vec3 N, vec3 V, vec3 color0, vec3 color90, float exponent, EDF base, out EDF result) +{ + N = mx_forward_facing_normal(N, V); + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + vec3 f = mx_fresnel_schlick(NdotV, color0, color90, exponent); + result = base * f; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_layer_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_layer_bsdf.glsl deleted file mode 100644 index 2200af8..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/mx_layer_bsdf.glsl +++ /dev/null @@ -1,7 +0,0 @@ -#include "lib/mx_closure_type.glsl" - -void mx_layer_bsdf(ClosureData closureData, BSDF top, BSDF base, out BSDF result) -{ - result.response = top.response + base.response * top.throughput; - result.throughput = top.throughput * base.throughput; -} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_layer_vdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_layer_vdf.glsl deleted file mode 100644 index 25a571b..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/mx_layer_vdf.glsl +++ /dev/null @@ -1,7 +0,0 @@ -#include "lib/mx_closure_type.glsl" - -void mx_layer_vdf(ClosureData closureData, BSDF top, BSDF base, out BSDF result) -{ - result.response = top.response + base.response; - result.throughput = top.throughput + base.throughput; -} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_mix_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_mix_bsdf.glsl deleted file mode 100644 index 0ee8b15..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/mx_mix_bsdf.glsl +++ /dev/null @@ -1,7 +0,0 @@ -#include "lib/mx_closure_type.glsl" - -void mx_mix_bsdf(ClosureData closureData, BSDF fg, BSDF bg, float mixValue, out BSDF result) -{ - result.response = mix(bg.response, fg.response, mixValue); - result.throughput = mix(bg.throughput, fg.throughput, mixValue); -} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_mix_edf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_mix_edf.glsl deleted file mode 100644 index 6a81db2..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/mx_mix_edf.glsl +++ /dev/null @@ -1,6 +0,0 @@ -#include "lib/mx_closure_type.glsl" - -void mx_mix_edf(ClosureData closureData, EDF fg, EDF bg, float mixValue, out EDF result) -{ - result = mix(bg, fg, mixValue); -} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_multiply_bsdf_color3.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_multiply_bsdf_color3.glsl deleted file mode 100644 index a817a8b..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/mx_multiply_bsdf_color3.glsl +++ /dev/null @@ -1,8 +0,0 @@ -#include "lib/mx_closure_type.glsl" - -void mx_multiply_bsdf_color3(ClosureData closureData, BSDF in1, vec3 in2, out BSDF result) -{ - vec3 tint = clamp(in2, 0.0, 1.0); - result.response = in1.response * tint; - result.throughput = in1.throughput; -} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_multiply_bsdf_float.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_multiply_bsdf_float.glsl deleted file mode 100644 index c5736a7..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/mx_multiply_bsdf_float.glsl +++ /dev/null @@ -1,8 +0,0 @@ -#include "lib/mx_closure_type.glsl" - -void mx_multiply_bsdf_float(ClosureData closureData, BSDF in1, float in2, out BSDF result) -{ - float weight = clamp(in2, 0.0, 1.0); - result.response = in1.response * weight; - result.throughput = in1.throughput; -} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_multiply_edf_color3.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_multiply_edf_color3.glsl deleted file mode 100644 index 9a95773..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/mx_multiply_edf_color3.glsl +++ /dev/null @@ -1,6 +0,0 @@ -#include "lib/mx_closure_type.glsl" - -void mx_multiply_edf_color3(ClosureData closureData, EDF in1, vec3 in2, out EDF result) -{ - result = in1 * in2; -} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_multiply_edf_float.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_multiply_edf_float.glsl deleted file mode 100644 index 3987958..0000000 --- a/MaterialX/libraries/pbrlib/genglsl/mx_multiply_edf_float.glsl +++ /dev/null @@ -1,6 +0,0 @@ -#include "lib/mx_closure_type.glsl" - -void mx_multiply_edf_float(ClosureData closureData, EDF in1, float in2, out EDF result) -{ - result = in1 * in2; -} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl old mode 100644 new mode 100755 index 173a0ab..f60bcad --- a/MaterialX/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl @@ -1,37 +1,42 @@ -#include "lib/mx_closure_type.glsl" -#include "lib/mx_microfacet_diffuse.glsl" - -void mx_oren_nayar_diffuse_bsdf(ClosureData closureData, float weight, vec3 color, float roughness, vec3 N, bool energy_compensation, inout BSDF bsdf) -{ - bsdf.throughput = vec3(0.0); - - if (weight < M_FLOAT_EPS) - { - return; - } - - vec3 V = closureData.V; - vec3 L = closureData.L; - - N = mx_forward_facing_normal(N, V); - float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - - if (closureData.closureType == CLOSURE_TYPE_REFLECTION) - { - float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0); - float LdotV = clamp(dot(L, V), M_FLOAT_EPS, 1.0); - - vec3 diffuse = energy_compensation ? - mx_oren_nayar_compensated_diffuse(NdotV, NdotL, LdotV, roughness, color) : - mx_oren_nayar_diffuse(NdotV, NdotL, LdotV, roughness) * color; - bsdf.response = diffuse * closureData.occlusion * weight * NdotL * M_PI_INV; - } - else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) - { - vec3 diffuse = energy_compensation ? - mx_oren_nayar_compensated_diffuse_dir_albedo(NdotV, roughness, color) : - mx_oren_nayar_diffuse_dir_albedo(NdotV, roughness) * color; - vec3 Li = mx_environment_irradiance(N); - bsdf.response = Li * diffuse * weight; - } -} +#include "lib/mx_microfacet_diffuse.glsl" + +void mx_oren_nayar_diffuse_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color, float roughness, vec3 normal, bool energy_compensation, inout BSDF bsdf) +{ + bsdf.throughput = vec3(0.0); + + if (weight < M_FLOAT_EPS) + { + return; + } + + normal = mx_forward_facing_normal(normal, V); + + float NdotV = clamp(dot(normal, V), M_FLOAT_EPS, 1.0); + float NdotL = clamp(dot(normal, L), M_FLOAT_EPS, 1.0); + float LdotV = clamp(dot(L, V), M_FLOAT_EPS, 1.0); + + vec3 diffuse = energy_compensation ? + mx_oren_nayar_compensated_diffuse(NdotV, NdotL, LdotV, roughness, color) : + mx_oren_nayar_diffuse(NdotV, NdotL, LdotV, roughness) * color; + bsdf.response = diffuse * occlusion * weight * NdotL * M_PI_INV; +} + +void mx_oren_nayar_diffuse_bsdf_indirect(vec3 V, float weight, vec3 color, float roughness, vec3 normal, bool energy_compensation, inout BSDF bsdf) +{ + bsdf.throughput = vec3(0.0); + + if (weight < M_FLOAT_EPS) + { + return; + } + + normal = mx_forward_facing_normal(normal, V); + + float NdotV = clamp(dot(normal, V), M_FLOAT_EPS, 1.0); + + vec3 diffuse = energy_compensation ? + mx_oren_nayar_compensated_diffuse_dir_albedo(NdotV, roughness, color) : + mx_oren_nayar_diffuse_dir_albedo(NdotV, roughness) * color; + vec3 Li = mx_environment_irradiance(normal); + bsdf.response = Li * diffuse * weight; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_roughness_anisotropy.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_roughness_anisotropy.glsl old mode 100644 new mode 100755 index 39d266e..0e9b868 --- a/MaterialX/libraries/pbrlib/genglsl/mx_roughness_anisotropy.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_roughness_anisotropy.glsl @@ -1,15 +1,15 @@ -void mx_roughness_anisotropy(float roughness, float anisotropy, out vec2 result) -{ - float roughness_sqr = clamp(roughness*roughness, M_FLOAT_EPS, 1.0); - if (anisotropy > 0.0) - { - float aspect = sqrt(1.0 - clamp(anisotropy, 0.0, 0.98)); - result.x = min(roughness_sqr / aspect, 1.0); - result.y = roughness_sqr * aspect; - } - else - { - result.x = roughness_sqr; - result.y = roughness_sqr; - } -} +void mx_roughness_anisotropy(float roughness, float anisotropy, out vec2 result) +{ + float roughness_sqr = clamp(roughness*roughness, M_FLOAT_EPS, 1.0); + if (anisotropy > 0.0) + { + float aspect = sqrt(1.0 - clamp(anisotropy, 0.0, 0.98)); + result.x = min(roughness_sqr / aspect, 1.0); + result.y = roughness_sqr * aspect; + } + else + { + result.x = roughness_sqr; + result.y = roughness_sqr; + } +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_roughness_dual.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_roughness_dual.glsl old mode 100644 new mode 100755 index f4b5383..3d4fdd6 --- a/MaterialX/libraries/pbrlib/genglsl/mx_roughness_dual.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_roughness_dual.glsl @@ -1,9 +1,9 @@ -void mx_roughness_dual(vec2 roughness, out vec2 result) -{ - if (roughness.y < 0.0) - { - roughness.y = roughness.x; - } - result.x = clamp(roughness.x * roughness.x, M_FLOAT_EPS, 1.0); - result.y = clamp(roughness.y * roughness.y, M_FLOAT_EPS, 1.0); -} +void mx_roughness_dual(vec2 roughness, out vec2 result) +{ + if (roughness.y < 0.0) + { + roughness.y = roughness.x; + } + result.x = clamp(roughness.x * roughness.x, M_FLOAT_EPS, 1.0); + result.y = clamp(roughness.y * roughness.y, M_FLOAT_EPS, 1.0); +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_sheen_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_sheen_bsdf.glsl old mode 100644 new mode 100755 index 5b264d9..069ed31 --- a/MaterialX/libraries/pbrlib/genglsl/mx_sheen_bsdf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_sheen_bsdf.glsl @@ -1,61 +1,63 @@ -#include "lib/mx_closure_type.glsl" -#include "lib/mx_microfacet_sheen.glsl" - -void mx_sheen_bsdf(ClosureData closureData, float weight, vec3 color, float roughness, vec3 N, int mode, inout BSDF bsdf) -{ - if (weight < M_FLOAT_EPS) - { - return; - } - - vec3 V = closureData.V; - vec3 L = closureData.L; - - N = mx_forward_facing_normal(N, V); - float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - - if (closureData.closureType == CLOSURE_TYPE_REFLECTION) - { - float dirAlbedo; - if (mode == 0) - { - vec3 H = normalize(L + V); - - float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0); - float NdotH = clamp(dot(N, H), M_FLOAT_EPS, 1.0); - - vec3 fr = color * mx_imageworks_sheen_brdf(NdotL, NdotV, NdotH, roughness); - dirAlbedo = mx_imageworks_sheen_dir_albedo(NdotV, roughness); - - // We need to include NdotL from the light integral here - // as in this case it's not cancelled out by the BRDF denominator. - bsdf.response = fr * NdotL * closureData.occlusion * weight; - } - else - { - roughness = clamp(roughness, 0.01, 1.0); // Clamp to range of original impl. - - vec3 fr = color * mx_zeltner_sheen_brdf(L, V, N, NdotV, roughness); - dirAlbedo = mx_zeltner_sheen_dir_albedo(NdotV, roughness); - bsdf.response = dirAlbedo * fr * closureData.occlusion * weight; - } - bsdf.throughput = vec3(1.0 - dirAlbedo * weight); - } - else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) - { - float dirAlbedo; - if (mode == 0) - { - dirAlbedo = mx_imageworks_sheen_dir_albedo(NdotV, roughness); - } - else - { - roughness = clamp(roughness, 0.01, 1.0); // Clamp to range of original impl. - dirAlbedo = mx_zeltner_sheen_dir_albedo(NdotV, roughness); - } - - vec3 Li = mx_environment_irradiance(N); - bsdf.response = Li * color * dirAlbedo * weight; - bsdf.throughput = vec3(1.0 - dirAlbedo * weight); - } -} +#include "lib/mx_microfacet_sheen.glsl" + +void mx_sheen_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color, float roughness, vec3 N, int mode, inout BSDF bsdf) +{ + if (weight < M_FLOAT_EPS) + { + return; + } + + N = mx_forward_facing_normal(N, V); + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + + if (mode == 0) + { + vec3 H = normalize(L + V); + + float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0); + float NdotH = clamp(dot(N, H), M_FLOAT_EPS, 1.0); + + vec3 fr = color * mx_imageworks_sheen_brdf(NdotL, NdotV, NdotH, roughness); + float dirAlbedo = mx_imageworks_sheen_dir_albedo(NdotV, roughness); + bsdf.throughput = vec3(1.0 - dirAlbedo * weight); + + // We need to include NdotL from the light integral here + // as in this case it's not cancelled out by the BRDF denominator. + bsdf.response = fr * NdotL * occlusion * weight; + } + else + { + roughness = clamp(roughness, 0.01, 1.0); // Clamp to range of original impl. + + vec3 fr = color * mx_zeltner_sheen_brdf(L, V, N, NdotV, roughness); + float dirAlbedo = mx_zeltner_sheen_dir_albedo(NdotV, roughness); + bsdf.throughput = vec3(1.0 - dirAlbedo * weight); + bsdf.response = dirAlbedo * fr * occlusion * weight; + } +} + +void mx_sheen_bsdf_indirect(vec3 V, float weight, vec3 color, float roughness, vec3 N, int mode, inout BSDF bsdf) +{ + if (weight < M_FLOAT_EPS) + { + return; + } + + N = mx_forward_facing_normal(N, V); + float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); + + float dirAlbedo; + if (mode == 0) + { + dirAlbedo = mx_imageworks_sheen_dir_albedo(NdotV, roughness); + } + else + { + roughness = clamp(roughness, 0.01, 1.0); // Clamp to range of original impl. + dirAlbedo = mx_zeltner_sheen_dir_albedo(NdotV, roughness); + } + + vec3 Li = mx_environment_irradiance(N); + bsdf.throughput = vec3(1.0 - dirAlbedo * weight); + bsdf.response = Li * color * dirAlbedo * weight; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_subsurface_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_subsurface_bsdf.glsl old mode 100644 new mode 100755 index 30c96f5..58bf721 --- a/MaterialX/libraries/pbrlib/genglsl/mx_subsurface_bsdf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_subsurface_bsdf.glsl @@ -1,33 +1,34 @@ -#include "lib/mx_closure_type.glsl" -#include "lib/mx_microfacet_diffuse.glsl" - -void mx_subsurface_bsdf(ClosureData closureData, float weight, vec3 color, vec3 radius, float anisotropy, vec3 N, inout BSDF bsdf) -{ - bsdf.throughput = vec3(0.0); - - if (weight < M_FLOAT_EPS) - { - return; - } - - vec3 V = closureData.V; - vec3 L = closureData.L; - vec3 P = closureData.P; - float occlusion = closureData.occlusion; - - N = mx_forward_facing_normal(N, V); - - if (closureData.closureType == CLOSURE_TYPE_REFLECTION) - { - vec3 sss = mx_subsurface_scattering_approx(N, L, P, color, radius); - float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0); - float visibleOcclusion = 1.0 - NdotL * (1.0 - occlusion); - bsdf.response = sss * visibleOcclusion * weight; - } - else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) - { - // For now, we render indirect subsurface as simple indirect diffuse. - vec3 Li = mx_environment_irradiance(N); - bsdf.response = Li * color * weight; - } -} +#include "lib/mx_microfacet_diffuse.glsl" + +void mx_subsurface_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color, vec3 radius, float anisotropy, vec3 normal, inout BSDF bsdf) +{ + bsdf.throughput = vec3(0.0); + + if (weight < M_FLOAT_EPS) + { + return; + } + + normal = mx_forward_facing_normal(normal, V); + + vec3 sss = mx_subsurface_scattering_approx(normal, L, P, color, radius); + float NdotL = clamp(dot(normal, L), M_FLOAT_EPS, 1.0); + float visibleOcclusion = 1.0 - NdotL * (1.0 - occlusion); + bsdf.response = sss * visibleOcclusion * weight; +} + +void mx_subsurface_bsdf_indirect(vec3 V, float weight, vec3 color, vec3 radius, float anisotropy, vec3 normal, inout BSDF bsdf) +{ + bsdf.throughput = vec3(0.0); + + if (weight < M_FLOAT_EPS) + { + return; + } + + normal = mx_forward_facing_normal(normal, V); + + // For now, we render indirect subsurface as simple indirect diffuse. + vec3 Li = mx_environment_irradiance(normal); + bsdf.response = Li * color * weight; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_translucent_bsdf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_translucent_bsdf.glsl old mode 100644 new mode 100755 index a2792f0..8603fd9 --- a/MaterialX/libraries/pbrlib/genglsl/mx_translucent_bsdf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_translucent_bsdf.glsl @@ -1,28 +1,29 @@ -#include "lib/mx_closure_type.glsl" - -void mx_translucent_bsdf(ClosureData closureData, float weight, vec3 color, vec3 N, inout BSDF bsdf) -{ - bsdf.throughput = vec3(0.0); - - if (weight < M_FLOAT_EPS) - { - return; - } - - vec3 V = closureData.V; - vec3 L = closureData.L; - - // Invert normal since we're transmitting light from the other side - N = -N; - - if (closureData.closureType == CLOSURE_TYPE_REFLECTION) - { - float NdotL = clamp(dot(N, L), 0.0, 1.0); - bsdf.response = color * weight * NdotL * M_PI_INV; - } - else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) - { - vec3 Li = mx_environment_irradiance(N); - bsdf.response = Li * color * weight; - } -} +// We fake diffuse transmission by using diffuse reflection from the opposite side. +// So this BTDF is really a BRDF. +void mx_translucent_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color, vec3 normal, inout BSDF bsdf) +{ + bsdf.throughput = vec3(0.0); + + // Invert normal since we're transmitting light from the other side + float NdotL = dot(L, -normal); + if (NdotL <= 0.0 || weight < M_FLOAT_EPS) + { + return; + } + + bsdf.response = color * weight * NdotL * M_PI_INV; +} + +void mx_translucent_bsdf_indirect(vec3 V, float weight, vec3 color, vec3 normal, inout BSDF bsdf) +{ + bsdf.throughput = vec3(0.0); + + if (weight < M_FLOAT_EPS) + { + return; + } + + // Invert normal since we're transmitting light from the other side + vec3 Li = mx_environment_irradiance(-normal); + bsdf.response = Li * color * weight; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/mx_uniform_edf.glsl b/MaterialX/libraries/pbrlib/genglsl/mx_uniform_edf.glsl old mode 100644 new mode 100755 index 8f5f256..14e14cf --- a/MaterialX/libraries/pbrlib/genglsl/mx_uniform_edf.glsl +++ b/MaterialX/libraries/pbrlib/genglsl/mx_uniform_edf.glsl @@ -1,9 +1,4 @@ -#include "lib/mx_closure_type.glsl" - -void mx_uniform_edf(ClosureData closureData, vec3 color, out EDF result) -{ - if (closureData.closureType == CLOSURE_TYPE_EMISSION) - { - result = color; - } -} +void mx_uniform_edf(vec3 N, vec3 L, vec3 color, out EDF result) +{ + result = color; +} diff --git a/MaterialX/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx b/MaterialX/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx old mode 100644 new mode 100755 index f48176e..dbc23fd --- a/MaterialX/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx +++ b/MaterialX/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx @@ -1,89 +1,77 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/MaterialX/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx old mode 100644 new mode 100755 index 86f4694..050baf5 --- a/MaterialX/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx +++ b/MaterialX/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx @@ -1,105 +1,93 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/pbrlib/genmsl/lib/mx_shadow_platform.metal b/MaterialX/libraries/pbrlib/genmsl/lib/mx_shadow_platform.metal deleted file mode 100644 index 12f5531..0000000 --- a/MaterialX/libraries/pbrlib/genmsl/lib/mx_shadow_platform.metal +++ /dev/null @@ -1,13 +0,0 @@ - -float mx_shadow_occlusion( - MetalTexture shadow_map_tex, - float4x4 shadow_matrix, - float3 world_position -) -{ - float4 shadowCoord4 = mx_matrix_mul(shadow_matrix, float4(world_position, 1.0)); - float3 shadowCoord = shadowCoord4.xyz / shadowCoord4.w; - shadowCoord.xy = shadowCoord.xy * 0.5 + 0.5; - float2 shadowMoments = texture(shadow_map_tex, shadowCoord.xy).xy; - return mx_variance_shadow_occlusion(shadowMoments, shadowCoord.z); -} diff --git a/MaterialX/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx b/MaterialX/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx old mode 100644 new mode 100755 index 15b49ef..993ad3a --- a/MaterialX/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx +++ b/MaterialX/libraries/pbrlib/genmsl/pbrlib_genmsl_impl.mtlx @@ -1,10 +1,74 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/pbrlib/genosl/legacy/mx_anisotropic_vdf.osl b/MaterialX/libraries/pbrlib/genosl/legacy/mx_anisotropic_vdf.osl new file mode 100755 index 0000000..6a1643e --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/legacy/mx_anisotropic_vdf.osl @@ -0,0 +1,5 @@ +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/MaterialX/libraries/pbrlib/genosl/legacy/mx_burley_diffuse_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/legacy/mx_burley_diffuse_bsdf.osl new file mode 100755 index 0000000..7b3e3fb --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/legacy/mx_burley_diffuse_bsdf.osl @@ -0,0 +1,6 @@ +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/MaterialX/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl new file mode 100755 index 0000000..854717e --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl @@ -0,0 +1,32 @@ +#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/MaterialX/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl new file mode 100755 index 0000000..f8e203e --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl @@ -0,0 +1,36 @@ +#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/MaterialX/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl new file mode 100755 index 0000000..f462c3d --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl @@ -0,0 +1,38 @@ +#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/MaterialX/libraries/pbrlib/genosl/legacy/mx_oren_nayar_diffuse_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/legacy/mx_oren_nayar_diffuse_bsdf.osl new file mode 100755 index 0000000..158cc87 --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/legacy/mx_oren_nayar_diffuse_bsdf.osl @@ -0,0 +1,5 @@ +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/MaterialX/libraries/pbrlib/genosl/legacy/mx_sheen_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/legacy/mx_sheen_bsdf.osl new file mode 100755 index 0000000..f3e7f01 --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/legacy/mx_sheen_bsdf.osl @@ -0,0 +1,24 @@ +#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/MaterialX/libraries/pbrlib/genosl/legacy/mx_subsurface_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/legacy/mx_subsurface_bsdf.osl new file mode 100755 index 0000000..63412ea --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/legacy/mx_subsurface_bsdf.osl @@ -0,0 +1,6 @@ +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/MaterialX/libraries/pbrlib/genosl/legacy/mx_surface.osl b/MaterialX/libraries/pbrlib/genosl/legacy/mx_surface.osl new file mode 100755 index 0000000..751b086 --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/legacy/mx_surface.osl @@ -0,0 +1,6 @@ +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/MaterialX/libraries/pbrlib/genosl/legacy/mx_translucent_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/legacy/mx_translucent_bsdf.osl new file mode 100755 index 0000000..5a1b2b4 --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/legacy/mx_translucent_bsdf.osl @@ -0,0 +1,5 @@ +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/MaterialX/libraries/pbrlib/genosl/lib/mx_microfacet.osl b/MaterialX/libraries/pbrlib/genosl/lib/mx_microfacet.osl old mode 100644 new mode 100755 index 2c8ff80..b6f2cc5 --- a/MaterialX/libraries/pbrlib/genosl/lib/mx_microfacet.osl +++ b/MaterialX/libraries/pbrlib/genosl/lib/mx_microfacet.osl @@ -1,78 +1,78 @@ -float mx_square(float x) -{ - return x*x; -} - -vector2 mx_square(vector2 x) -{ - return x*x; -} - -vector mx_square(vector x) -{ - return x*x; -} - -vector4 mx_square(vector4 x) -{ - return x*x; -} - -float mx_pow5(float x) -{ - return mx_square(mx_square(x)) * x; -} - -color mx_fresnel_conductor(float cosTheta, vector n, vector k) -{ - float c2 = cosTheta*cosTheta; - vector n2_k2 = n*n + k*k; - vector nc2 = 2.0 * n * cosTheta; - - vector rs_a = n2_k2 + c2; - vector rp_a = n2_k2 * c2 + 1.0; - vector rs = (rs_a - nc2) / (rs_a + nc2); - vector rp = (rp_a - nc2) / (rp_a + nc2); - - return 0.5 * (rs + rp); -} - -// Standard Schlick Fresnel -float mx_fresnel_schlick(float cosTheta, float F0) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - float x5 = mx_pow5(x); - return F0 + (1.0 - F0) * x5; -} -color mx_fresnel_schlick(float cosTheta, color F0) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - float x5 = mx_pow5(x); - return F0 + (1.0 - F0) * x5; -} - -// Generalized Schlick Fresnel -float mx_fresnel_schlick(float cosTheta, float F0, float F90) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - float x5 = mx_pow5(x); - return mix(F0, F90, x5); -} -color mx_fresnel_schlick(float cosTheta, color F0, color F90) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - float x5 = mx_pow5(x); - return mix(F0, F90, x5); -} - -// Generalized Schlick Fresnel with a variable exponent -color mx_fresnel_schlick(float cosTheta, float f0, float f90, float exponent) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - return mix(f0, f90, pow(x, exponent)); -} -color mx_fresnel_schlick(float cosTheta, color f0, color f90, float exponent) -{ - float x = clamp(1.0 - cosTheta, 0.0, 1.0); - return mix(f0, f90, pow(x, exponent)); -} +float mx_square(float x) +{ + return x*x; +} + +vector2 mx_square(vector2 x) +{ + return x*x; +} + +vector mx_square(vector x) +{ + return x*x; +} + +vector4 mx_square(vector4 x) +{ + return x*x; +} + +float mx_pow5(float x) +{ + return mx_square(mx_square(x)) * x; +} + +color mx_fresnel_conductor(float cosTheta, vector n, vector k) +{ + float c2 = cosTheta*cosTheta; + vector n2_k2 = n*n + k*k; + vector nc2 = 2.0 * n * cosTheta; + + vector rs_a = n2_k2 + c2; + vector rp_a = n2_k2 * c2 + 1.0; + vector rs = (rs_a - nc2) / (rs_a + nc2); + vector rp = (rp_a - nc2) / (rp_a + nc2); + + return 0.5 * (rs + rp); +} + +// Standard Schlick Fresnel +float mx_fresnel_schlick(float cosTheta, float F0) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + float x5 = mx_pow5(x); + return F0 + (1.0 - F0) * x5; +} +color mx_fresnel_schlick(float cosTheta, color F0) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + float x5 = mx_pow5(x); + return F0 + (1.0 - F0) * x5; +} + +// Generalized Schlick Fresnel +float mx_fresnel_schlick(float cosTheta, float F0, float F90) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + float x5 = mx_pow5(x); + return mix(F0, F90, x5); +} +color mx_fresnel_schlick(float cosTheta, color F0, color F90) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + float x5 = mx_pow5(x); + return mix(F0, F90, x5); +} + +// Generalized Schlick Fresnel with a variable exponent +color mx_fresnel_schlick(float cosTheta, float f0, float f90, float exponent) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + return mix(f0, f90, pow(x, exponent)); +} +color mx_fresnel_schlick(float cosTheta, color f0, color f90, float exponent) +{ + float x = clamp(1.0 - cosTheta, 0.0, 1.0); + return mix(f0, f90, pow(x, exponent)); +} diff --git a/MaterialX/libraries/pbrlib/genosl/lib/mx_microfacet_sheen.osl b/MaterialX/libraries/pbrlib/genosl/lib/mx_microfacet_sheen.osl new file mode 100755 index 0000000..1dd4f10 --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/lib/mx_microfacet_sheen.osl @@ -0,0 +1,15 @@ +#include "mx_microfacet.osl" + +// Rational curve fit approximation for the directional albedo of Imageworks sheen. +float mx_imageworks_sheen_dir_albedo_analytic(float NdotV, float roughness) +{ + float a = 5.25248 - 7.66024 * NdotV + 14.26377 * roughness; + float b = 1.0 + 30.66449 * NdotV + 32.53420 * roughness; + return a / b; +} + +float mx_imageworks_sheen_dir_albedo(float NdotV, float roughness) +{ + float dirAlbedo = mx_imageworks_sheen_dir_albedo_analytic(NdotV, roughness); + return clamp(dirAlbedo, 0.0, 1.0); +} diff --git a/MaterialX/libraries/pbrlib/genosl/lib/mx_microfacet_specular.osl b/MaterialX/libraries/pbrlib/genosl/lib/mx_microfacet_specular.osl new file mode 100755 index 0000000..9e1f32f --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/lib/mx_microfacet_specular.osl @@ -0,0 +1,68 @@ +#include "mx_microfacet.osl" + +// Compute the average of an anisotropic alpha pair. +float mx_average_alpha(vector2 alpha) +{ + return sqrt(alpha.x * alpha.y); +} + +// Convert a real-valued index of refraction to normal-incidence reflectivity. +float mx_ior_to_f0(float ior) +{ + return mx_square((ior - 1.0) / (ior + 1.0)); +} + +// Convert normal-incidence reflectivity to real-valued index of refraction. +float mx_f0_to_ior(float F0) +{ + float sqrtF0 = sqrt(clamp(F0, 0.01, 0.99)); + return (1.0 + sqrtF0) / (1.0 - sqrtF0); +} + +// Rational quadratic fit to Monte Carlo data for GGX directional albedo. +color mx_ggx_dir_albedo(float NdotV, float alpha, color F0, color F90) +{ + float x = NdotV; + float y = alpha; + float x2 = mx_square(x); + float y2 = mx_square(y); + vector4 r = vector4(0.1003, 0.9345, 1.0, 1.0) + + vector4(-0.6303, -2.323, -1.765, 0.2281) * x + + vector4(9.748, 2.229, 8.263, 15.94) * y + + vector4(-2.038, -3.748, 11.53, -55.83) * x * y + + vector4(29.34, 1.424, 28.96, 13.08) * x2 + + vector4(-8.245, -0.7684, -7.507, 41.26) * y2 + + vector4(-26.44, 1.436, -36.11, 54.9) * x2 * y + + vector4(19.99, 0.2913, 15.86, 300.2) * x * y2 + + vector4(-5.448, 0.6286, 33.37, -285.1) * x2 * y2; + vector2 AB = vector2(r.x, r.y) / vector2(r.z, r.w); + AB.x = clamp(AB.x, 0.0, 1.0); + AB.y = clamp(AB.y, 0.0, 1.0); + return F0 * AB.x + F90 * AB.y; +} + +float mx_ggx_dir_albedo(float NdotV, float alpha, float F0, float F90) +{ + color result = mx_ggx_dir_albedo(NdotV, alpha, color(F0), color(F90)); + return result[0]; +} + +float mx_ggx_dir_albedo(float NdotV, float alpha, float ior) +{ + color result = mx_ggx_dir_albedo(NdotV, alpha, color(mx_ior_to_f0(ior)), color(1.0)); + return result[0]; +} + +// https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf +// Equations 14 and 16 +color mx_ggx_energy_compensation(float NdotV, float alpha, color Fss) +{ + float Ess = mx_ggx_dir_albedo(NdotV, alpha, 1.0, 1.0); + return 1.0 + Fss * (1.0 - Ess) / Ess; +} + +float mx_ggx_energy_compensation(float NdotV, float alpha, float Fss) +{ + color result = mx_ggx_energy_compensation(NdotV, alpha, color(Fss)); + return result[0]; +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl b/MaterialX/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl old mode 100644 new mode 100755 index eb48e72..fa5829f --- a/MaterialX/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl +++ b/MaterialX/libraries/pbrlib/genosl/mx_anisotropic_vdf.osl @@ -1,8 +1,6 @@ -void mx_anisotropic_vdf(color absorption, color scattering, float anisotropy, output VDF vdf) -{ - // 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); -} +void mx_anisotropic_vdf(vector absorption, vector 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; +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_artistic_ior.osl b/MaterialX/libraries/pbrlib/genosl/mx_artistic_ior.osl old mode 100644 new mode 100755 index ca7f1ec..a3b781a --- a/MaterialX/libraries/pbrlib/genosl/mx_artistic_ior.osl +++ b/MaterialX/libraries/pbrlib/genosl/mx_artistic_ior.osl @@ -1,17 +1,17 @@ -void mx_artistic_ior(color reflectivity, color edge_color, output vector ior, output vector extinction) -{ - // "Artist Friendly Metallic Fresnel", Ole Gulbrandsen, 2014 - // http://jcgt.org/published/0003/04/03/paper.pdf - - color r = clamp(reflectivity, 0.0, 0.99); - color r_sqrt = sqrt(r); - color n_min = (1.0 - r) / (1.0 + r); - color n_max = (1.0 + r_sqrt) / (1.0 - r_sqrt); - ior = mix(n_max, n_min, edge_color); - - color np1 = ior + 1.0; - color nm1 = ior - 1.0; - color k2 = (np1*np1 * r - nm1*nm1) / (1.0 - r); - k2 = max(k2, 0.0); - extinction = sqrt(k2); -} +void mx_artistic_ior(color reflectivity, color edge_color, output vector ior, output vector extinction) +{ + // "Artist Friendly Metallic Fresnel", Ole Gulbrandsen, 2014 + // http://jcgt.org/published/0003/04/03/paper.pdf + + color r = clamp(reflectivity, 0.0, 0.99); + color r_sqrt = sqrt(r); + color n_min = (1.0 - r) / (1.0 + r); + color n_max = (1.0 + r_sqrt) / (1.0 - r_sqrt); + ior = mix(n_max, n_min, edge_color); + + color np1 = ior + 1.0; + color nm1 = ior - 1.0; + color k2 = (np1*np1 * r - nm1*nm1) / (1.0 - r); + k2 = max(k2, 0.0); + extinction = sqrt(k2); +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_blackbody.osl b/MaterialX/libraries/pbrlib/genosl/mx_blackbody.osl old mode 100644 new mode 100755 index 9595133..a455ae3 --- a/MaterialX/libraries/pbrlib/genosl/mx_blackbody.osl +++ b/MaterialX/libraries/pbrlib/genosl/mx_blackbody.osl @@ -1,49 +1,49 @@ -void mx_blackbody(float temp, output color color_value) -{ - float xc, yc; - float t, t2, t3, xc2, xc3; - - // if value outside valid range of approximation clamp to accepted temperature range - float temperature = clamp(temp, 1667.0, 25000.0); - - t = 1000.0 / temperature; - t2 = t * t; - t3 = t * t * t; - - // Cubic spline approximation for Kelvin temperature to sRGB conversion - // (https://en.wikipedia.org/wiki/Planckian_locus#Approximation) - if (temperature < 4000.0) { // 1667K <= temperature < 4000K - xc = -0.2661239 * t3 - 0.2343580 * t2 + 0.8776956 * t + 0.179910; - } - else { // 4000K <= temperature <= 25000K - xc = -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t + 0.240390; - } - xc2 = xc * xc; - xc3 = xc * xc * xc; - - if (temperature < 2222.0) { // 1667K <= temperature < 2222K - yc = -1.1063814 * xc3 - 1.34811020 * xc2 + 2.18555832 * xc - 0.20219683; - } - else if (temperature < 4000.0) { // 2222K <= temperature < 4000K - yc = -0.9549476 * xc3 - 1.37418593 * xc2 + 2.09137015 * xc - 0.16748867; - } - else { // 4000K <= temperature <= 25000K - yc = 3.0817580 * xc3 - 5.87338670 * xc2 + 3.75112997 * xc - 0.37001483; - } - - if (yc <= 0.0) { // avoid division by zero - color_value = color(1.0); - return; - } - - vector XYZ = vector(xc / yc, 1.0, (1 - xc - yc) / yc); - - /// XYZ to Rec.709 RGB colorspace conversion - matrix XYZ_to_RGB = matrix( 3.2406, -0.9689, 0.0557, 0.0, - -1.5372, 1.8758, -0.2040, 0.0, - -0.4986, 0.0415, 1.0570, 0.0, - 0.0, 0.0, 0.0, 1.0); - - color_value = transform(XYZ_to_RGB, XYZ); - color_value = max(color_value, vector(0.0)); -} +void mx_blackbody(float temp, output color color_value) +{ + float xc, yc; + float t, t2, t3, xc2, xc3; + + // if value outside valid range of approximation clamp to accepted temperature range + float temperature = clamp(temp, 1667.0, 25000.0); + + t = 1000.0 / temperature; + t2 = t * t; + t3 = t * t * t; + + // Cubic spline approximation for Kelvin temperature to sRGB conversion + // (https://en.wikipedia.org/wiki/Planckian_locus#Approximation) + if (temperature < 4000.0) { // 1667K <= temperature < 4000K + xc = -0.2661239 * t3 - 0.2343580 * t2 + 0.8776956 * t + 0.179910; + } + else { // 4000K <= temperature <= 25000K + xc = -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t + 0.240390; + } + xc2 = xc * xc; + xc3 = xc * xc * xc; + + if (temperature < 2222.0) { // 1667K <= temperature < 2222K + yc = -1.1063814 * xc3 - 1.34811020 * xc2 + 2.18555832 * xc - 0.20219683; + } + else if (temperature < 4000.0) { // 2222K <= temperature < 4000K + yc = -0.9549476 * xc3 - 1.37418593 * xc2 + 2.09137015 * xc - 0.16748867; + } + else { // 4000K <= temperature <= 25000K + yc = 3.0817580 * xc3 - 5.87338670 * xc2 + 3.75112997 * xc - 0.37001483; + } + + if (yc <= 0.0) { // avoid division by zero + color_value = color(1.0); + return; + } + + vector XYZ = vector(xc / yc, 1.0, (1 - xc - yc) / yc); + + /// XYZ to Rec.709 RGB colorspace conversion + matrix XYZ_to_RGB = matrix( 3.2406, -0.9689, 0.0557, 0.0, + -1.5372, 1.8758, -0.2040, 0.0, + -0.4986, 0.0415, 1.0570, 0.0, + 0.0, 0.0, 0.0, 1.0); + + color_value = transform(XYZ_to_RGB, XYZ); + color_value = max(color_value, vector(0.0)); +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_chiang_hair_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/mx_chiang_hair_bsdf.osl deleted file mode 100644 index 8b2bafe..0000000 --- a/MaterialX/libraries/pbrlib/genosl/mx_chiang_hair_bsdf.osl +++ /dev/null @@ -1,12 +0,0 @@ -void mx_chiang_hair_bsdf(color tint_R, color tint_TT, color tint_TRT, float ior, - vector2 roughness_R, vector2 roughness_TT, vector2 roughness_TRT, - float cuticle_angle, vector absorption_coefficient, normal N, vector U, output BSDF bsdf) -{ -#if (OSL_VERSION_MAJOR == 1 && OSL_VERSION_MINOR >= 14) || (OSL_VERSION_MAJOR > 1) - bsdf = chiang_hair_bsdf(N, U, tint_R, tint_TT, tint_TRT, ior, - roughness_R.x, roughness_TT.x, roughness_TRT.x, roughness_R.y, roughness_TT.y, roughness_TRT.y, - cuticle_angle, absorption_coefficient); -#else - bsdf = dielectric_bsdf(N, U, color(1), color(0), 0.1, 0.1, ior, "ggx"); -#endif -} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl b/MaterialX/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl deleted file mode 100644 index 002bdc3..0000000 --- a/MaterialX/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl +++ /dev/null @@ -1,7 +0,0 @@ -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/MaterialX/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl old mode 100644 new mode 100755 index 5d465ea..d57195e --- a/MaterialX/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl +++ b/MaterialX/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl @@ -1,6 +1,15 @@ -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) -{ - color reflection_tint = (scatter_mode == "T") ? color(0.0) : tint; - color transmission_tint = (scatter_mode == "R") ? color(0.0) : tint; - bsdf = weight * dielectric_bsdf(N, U, reflection_tint, transmission_tint, roughness.x, roughness.y, ior, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); -} +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 == "R") + { + bsdf = weight * dielectric_bsdf(N, U, tint, color(0.0), roughness.x, roughness.y, ior, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); + } + else if (scatter_mode == "T") + { + bsdf = weight * dielectric_bsdf(N, U, color(0.0), tint, roughness.x, roughness.y, ior, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); + } + else + { + bsdf = weight * dielectric_bsdf(N, U, tint, tint, roughness.x, roughness.y, ior, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); + } +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_displacement_float.osl b/MaterialX/libraries/pbrlib/genosl/mx_displacement_float.osl new file mode 100755 index 0000000..92d083c --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/mx_displacement_float.osl @@ -0,0 +1,4 @@ +void mx_displacement_float(float displacement, float scale, output displacementshader result) +{ + result = vector(displacement * scale); +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_displacement_vector3.osl b/MaterialX/libraries/pbrlib/genosl/mx_displacement_vector3.osl new file mode 100755 index 0000000..5d4b836 --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/mx_displacement_vector3.osl @@ -0,0 +1,4 @@ +void mx_displacement_vector3(vector displacement, float scale, output displacementshader result) +{ + result = displacement * scale; +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl old mode 100644 new mode 100755 index 9a05300..c7a54a0 --- a/MaterialX/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl +++ b/MaterialX/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl @@ -1,6 +1,15 @@ -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) -{ - color reflection_tint = (scatter_mode == "T") ? color(0.0) : color(1.0); - color transmission_tint = (scatter_mode == "R") ? color(0.0) : color(1.0); - bsdf = weight * generalized_schlick_bsdf(N, U, reflection_tint, transmission_tint, roughness.x, roughness.y, color0, color90, exponent, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); -} +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) +{ + if (scatter_mode == "R") + { + bsdf = weight * generalized_schlick_bsdf(N, U, color(1.0), color(0.0), roughness.x, roughness.y, color0, color90, exponent, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); + } + else if (scatter_mode == "T") + { + bsdf = weight * generalized_schlick_bsdf(N, U, color(0.0), color(1.0), roughness.x, roughness.y, color0, color90, exponent, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); + } + else + { + bsdf = weight * generalized_schlick_bsdf(N, U, color(1.0), color(1.0), roughness.x, roughness.y, color0, color90, exponent, distribution, "thinfilm_thickness", thinfilm_thickness, "thinfilm_ior", thinfilm_ior); + } +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_generalized_schlick_edf.osl b/MaterialX/libraries/pbrlib/genosl/mx_generalized_schlick_edf.osl old mode 100644 new mode 100755 index 84ecdfc..1c23369 --- a/MaterialX/libraries/pbrlib/genosl/mx_generalized_schlick_edf.osl +++ b/MaterialX/libraries/pbrlib/genosl/mx_generalized_schlick_edf.osl @@ -1,8 +1,8 @@ -#include "lib/mx_microfacet.osl" - -void mx_generalized_schlick_edf(color color0, color color90, float exponent, EDF base, output EDF result) -{ - float NdotV = fabs(dot(N,-I)); - color f = mx_fresnel_schlick(NdotV, color0, color90, exponent); - result = base * f; -} +#include "lib/mx_microfacet.osl" + +void mx_generalized_schlick_edf(color color0, color color90, float exponent, EDF base, output EDF result) +{ + float NdotV = fabs(dot(N,-I)); + color f = mx_fresnel_schlick(NdotV, color0, color90, exponent); + result = base * f; +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_roughness_anisotropy.osl b/MaterialX/libraries/pbrlib/genosl/mx_roughness_anisotropy.osl old mode 100644 new mode 100755 index 48b256e..38246d6 --- a/MaterialX/libraries/pbrlib/genosl/mx_roughness_anisotropy.osl +++ b/MaterialX/libraries/pbrlib/genosl/mx_roughness_anisotropy.osl @@ -1,15 +1,15 @@ -void mx_roughness_anisotropy(float roughness, float anisotropy, output vector2 result) -{ - float roughness_sqr = clamp(roughness*roughness, M_FLOAT_EPS, 1.0); - if (anisotropy > 0.0) - { - float aspect = sqrt(1.0 - clamp(anisotropy, 0.0, 0.98)); - result.x = min(roughness_sqr / aspect, 1.0); - result.y = roughness_sqr * aspect; - } - else - { - result.x = roughness_sqr; - result.y = roughness_sqr; - } -} +void mx_roughness_anisotropy(float roughness, float anisotropy, output vector2 result) +{ + float roughness_sqr = clamp(roughness*roughness, M_FLOAT_EPS, 1.0); + if (anisotropy > 0.0) + { + float aspect = sqrt(1.0 - clamp(anisotropy, 0.0, 0.98)); + result.x = min(roughness_sqr / aspect, 1.0); + result.y = roughness_sqr * aspect; + } + else + { + result.x = roughness_sqr; + result.y = roughness_sqr; + } +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_roughness_dual.osl b/MaterialX/libraries/pbrlib/genosl/mx_roughness_dual.osl old mode 100644 new mode 100755 index 6de64c7..532b46f --- a/MaterialX/libraries/pbrlib/genosl/mx_roughness_dual.osl +++ b/MaterialX/libraries/pbrlib/genosl/mx_roughness_dual.osl @@ -1,12 +1,12 @@ -void mx_roughness_dual(vector2 roughness, output vector2 result) -{ - result.x = clamp(roughness.x * roughness.x, M_FLOAT_EPS, 1.0); - if (roughness.y < 0.0) - { - result.y = result.x; - } - else - { - result.y = clamp(roughness.y * roughness.y, M_FLOAT_EPS, 1.0); - } -} +void mx_roughness_dual(vector2 roughness, output vector2 result) +{ + result.x = clamp(roughness.x * roughness.x, M_FLOAT_EPS, 1.0); + if (roughness.y < 0.0) + { + result.y = result.x; + } + else + { + result.y = clamp(roughness.y * roughness.y, M_FLOAT_EPS, 1.0); + } +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_subsurface_bsdf.osl b/MaterialX/libraries/pbrlib/genosl/mx_subsurface_bsdf.osl old mode 100644 new mode 100755 index d0f3f5b..c8e06f4 --- a/MaterialX/libraries/pbrlib/genosl/mx_subsurface_bsdf.osl +++ b/MaterialX/libraries/pbrlib/genosl/mx_subsurface_bsdf.osl @@ -1,8 +1,5 @@ -void mx_subsurface_bsdf(float weight, color albedo, color radius, float anisotropy, normal N, output BSDF bsdf) -{ -#if (OSL_VERSION_MAJOR == 1 && OSL_VERSION_MINOR >= 14) || (OSL_VERSION_MAJOR > 1) - bsdf = weight * subsurface_bssrdf(N, albedo, radius, anisotropy); -#else - bsdf = weight * subsurface_bssrdf(N, albedo, 1.0, radius, anisotropy); -#endif -} +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 = _color * weight * diffuse(N); +} diff --git a/MaterialX/libraries/pbrlib/genosl/mx_surface.osl b/MaterialX/libraries/pbrlib/genosl/mx_surface.osl old mode 100644 new mode 100755 index ac45493..2129b0f --- a/MaterialX/libraries/pbrlib/genosl/mx_surface.osl +++ b/MaterialX/libraries/pbrlib/genosl/mx_surface.osl @@ -1,6 +1,6 @@ -void mx_surface(BSDF bsdf, EDF edf, float opacity, int thin_walled, output surfaceshader result) -{ - result.bsdf = bsdf; - result.edf = edf; - result.opacity = clamp(opacity, 0.0, 1.0); -} +void mx_surface(BSDF bsdf, EDF edf, float opacity, int thin_walled, output surfaceshader result) +{ + result.bsdf = bsdf; + result.edf = edf; + result.opacity = clamp(opacity, 0.0, 1.0); +} diff --git a/MaterialX/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy b/MaterialX/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy new file mode 100755 index 0000000..e5cce0e --- /dev/null +++ b/MaterialX/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx b/MaterialX/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx old mode 100644 new mode 100755 index fe5210f..867dfe5 --- a/MaterialX/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx +++ b/MaterialX/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx @@ -1,86 +1,74 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/pbrlib/genslang/pbrlib_genslang_impl.mtlx b/MaterialX/libraries/pbrlib/genslang/pbrlib_genslang_impl.mtlx deleted file mode 100644 index ad6ce95..0000000 --- a/MaterialX/libraries/pbrlib/genslang/pbrlib_genslang_impl.mtlx +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/MaterialX/libraries/pbrlib/pbrlib_defs.mtlx b/MaterialX/libraries/pbrlib/pbrlib_defs.mtlx old mode 100644 new mode 100755 index 039d78b..29ba449 --- a/MaterialX/libraries/pbrlib/pbrlib_defs.mtlx +++ b/MaterialX/libraries/pbrlib/pbrlib_defs.mtlx @@ -1,462 +1,407 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/pbrlib/pbrlib_ng.mtlx b/MaterialX/libraries/pbrlib/pbrlib_ng.mtlx old mode 100644 new mode 100755 index 8e86786..6d13ef8 --- a/MaterialX/libraries/pbrlib/pbrlib_ng.mtlx +++ b/MaterialX/libraries/pbrlib/pbrlib_ng.mtlx @@ -1,22 +1,22 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/stdlib/genglsl/lib/mx_geometry.glsl b/MaterialX/libraries/stdlib/genglsl/lib/mx_geometry.glsl deleted file mode 100644 index de27655..0000000 --- a/MaterialX/libraries/stdlib/genglsl/lib/mx_geometry.glsl +++ /dev/null @@ -1,41 +0,0 @@ -// Blend 3 normals by blending the gradients -// Morten S. Mikkelsen, Surface Gradient–Based Bump Mapping Framework, Journal of -// Computer Graphics Techniques (JCGT), vol. 9, no. 3, 60–90, 2020 -// http://jcgt.org/published/0009/03/04/ -vec3 mx_normals_to_gradient(vec3 N, vec3 Np) -{ - float d = dot(N, Np); - vec3 g = (d * N - Np) / max(M_FLOAT_EPS, abs(d)); - return g; -} - -vec3 mx_gradient_blend_3_normals(vec3 N, vec3 N1, float N1_weight, vec3 N2, float N2_weight, vec3 N3, float N3_weight) -{ - float w1 = clamp(N1_weight, 0.0, 1.0); - float w2 = clamp(N2_weight, 0.0, 1.0); - float w3 = clamp(N3_weight, 0.0, 1.0); - - vec3 g1 = mx_normals_to_gradient(N, N1); - vec3 g2 = mx_normals_to_gradient(N, N2); - vec3 g3 = mx_normals_to_gradient(N, N3); - - // blend - vec3 gg = w1 * g1 + w2 * g2 + w3 * g3; - - // gradient to normal - return normalize(N - gg); -} - -// This function should be categorized in mx_math.glsl but it causes build errors in MSL -// so adding here for a workaround -mat3 mx_axis_rotation_matrix(vec3 a, float r) -{ - float s = sin(r); - float c = cos(r); - float omc = 1.0 - c; - return mat3( - a.x*a.x*omc + c, a.x*a.y*omc - a.z*s, a.x*a.z*omc + a.y*s, - a.y*a.x*omc + a.z*s, a.y*a.y*omc + c, a.y*a.z*omc - a.x*s, - a.z*a.x*omc - a.y*s, a.z*a.y*omc + a.x*s, a.z*a.z*omc + c - ); -} diff --git a/MaterialX/libraries/stdlib/genglsl/lib/mx_hextile.glsl b/MaterialX/libraries/stdlib/genglsl/lib/mx_hextile.glsl deleted file mode 100644 index d7df048..0000000 --- a/MaterialX/libraries/stdlib/genglsl/lib/mx_hextile.glsl +++ /dev/null @@ -1,139 +0,0 @@ -// https://www.shadertoy.com/view/4djSRW -vec2 mx_hextile_hash(vec2 p) -{ - vec3 p3 = fract(vec3(p.x, p.y, p.x) * vec3(0.1031, 0.1030, 0.0973)); - p3 += dot(p3, vec3(p3.y, p3.z, p3.x) + 33.33); - return fract((vec2(p3.x, p3.x) + vec2(p3.y, p3.z)) * vec2(p3.z, p3.y)); -} - -// Christophe Schlick. “Fast Alternatives to Perlin’s Bias and Gain Functions”. -// In Graphics Gems IV, Morgan Kaufmann, 1994, pages 401–403. -// https://dept-info.labri.fr/~schlick/DOC/gem2.html -float mx_schlick_gain(float x, float r) -{ - float rr = clamp(r, 0.001, 0.999); // to avoid glitch - float a = (1.0 / rr - 2.0) * (1.0 - 2.0 * x); - return (x < 0.5) ? x / (a + 1.0) : (a - x) / (a - 1.0); -} - -struct HextileData -{ - vec2 coords[3]; - vec3 weights; - vec3 rotations; - vec2 ddx[3]; - vec2 ddy[3]; -}; - -// Helper function to compute blend weights with optional falloff -vec3 mx_hextile_compute_blend_weights(vec3 luminance_weights, vec3 tile_weights, float falloff) -{ - vec3 w = luminance_weights * pow(tile_weights, vec3(7.0)); - w /= (w.x + w.y + w.z); - - if (falloff != 0.5) - { - w.x = mx_schlick_gain(w.x, falloff); - w.y = mx_schlick_gain(w.y, falloff); - w.z = mx_schlick_gain(w.z, falloff); - w /= (w.x + w.y + w.z); - } - return w; -} - -// Morten S. Mikkelsen, Practical Real-Time Hex-Tiling, Journal of Computer Graphics -// Techniques (JCGT), vol. 11, no. 2, 77-94, 2022 -// http://jcgt.org/published/0011/03/05/ -HextileData mx_hextile_coord( - vec2 coord, - float rotation, - vec2 rotation_range, - float scale, - vec2 scale_range, - float offset, - vec2 offset_range) -{ - float sqrt3_2 = sqrt(3.0) * 2.0; - - // scale coord to maintain the original fit - vec2 st = coord * sqrt3_2; - - // skew input space into simplex triangle grid - // (1, 0, -tan(30), 2*tan(30)) - mat2 to_skewed = mat2(1.0, 0.0, -0.57735027, 1.15470054); - vec2 st_skewed = mx_matrix_mul(to_skewed, st); - - // barycentric weights - vec2 st_frac = fract(st_skewed); - vec3 temp = vec3(st_frac.x, st_frac.y, 0.0); - temp.z = 1.0 - temp.x - temp.y; - - float s = step(0.0, -temp.z); - float s2 = 2.0 * s - 1.0; - - float w1 = -temp.z * s2; - float w2 = s - temp.y * s2; - float w3 = s - temp.x * s2; - - // vertex IDs - ivec2 base_id = ivec2(floor(st_skewed)); - int si = int(s); - ivec2 id1 = base_id + ivec2(si, si); - ivec2 id2 = base_id + ivec2(si, 1 - si); - ivec2 id3 = base_id + ivec2(1 - si, si); - - // tile center - mat2 inv_skewed = mat2(1.0, 0.0, 0.5, 1.0 / 1.15470054); - vec2 ctr1 = mx_matrix_mul(inv_skewed, vec2(id1) / vec2(sqrt3_2)); - vec2 ctr2 = mx_matrix_mul(inv_skewed, vec2(id2) / vec2(sqrt3_2)); - vec2 ctr3 = mx_matrix_mul(inv_skewed, vec2(id3) / vec2(sqrt3_2)); - - // reuse hash for performance - vec2 seed_offset = vec2(0.12345); // to avoid some zeros - vec2 rand1 = mx_hextile_hash(vec2(id1) + seed_offset); - vec2 rand2 = mx_hextile_hash(vec2(id2) + seed_offset); - vec2 rand3 = mx_hextile_hash(vec2(id3) + seed_offset); - - // randomized rotation matrix - vec2 rr = mx_radians(rotation_range); - vec3 rand_x = vec3(rand1.x, rand2.x, rand3.x); - vec3 rotations = mix(vec3(rr.x), vec3(rr.y), rand_x * rotation); - vec3 sin_r = sin(rotations); - vec3 cos_r = cos(rotations); - mat2 rm1 = mat2(cos_r.x, -sin_r.x, sin_r.x, cos_r.x); - mat2 rm2 = mat2(cos_r.y, -sin_r.y, sin_r.y, cos_r.y); - mat2 rm3 = mat2(cos_r.z, -sin_r.z, sin_r.z, cos_r.z); - - // randomized scale - vec3 rand_y = vec3(rand1.y, rand2.y, rand3.y); - vec3 scales = mix(vec3(1.0), mix(vec3(scale_range.x), vec3(scale_range.y), rand_y), scale); - vec2 scale1 = vec2(scales.x); - vec2 scale2 = vec2(scales.y); - vec2 scale3 = vec2(scales.z); - - // randomized offset - vec2 offset1 = mix(vec2(offset_range.x), vec2(offset_range.y), rand1 * offset); - vec2 offset2 = mix(vec2(offset_range.x), vec2(offset_range.y), rand2 * offset); - vec2 offset3 = mix(vec2(offset_range.x), vec2(offset_range.y), rand3 * offset); - - HextileData tile_data; - tile_data.weights = vec3(w1, w2, w3); - tile_data.rotations = rotations; - - // get coord - tile_data.coords[0] = (mx_matrix_mul((coord - ctr1), rm1) / scale1) + ctr1 + offset1; - tile_data.coords[1] = (mx_matrix_mul((coord - ctr2), rm2) / scale2) + ctr2 + offset2; - tile_data.coords[2] = (mx_matrix_mul((coord - ctr3), rm3) / scale3) + ctr3 + offset3; - - // derivatives - vec2 ddx = dFdx(coord); - vec2 ddy = dFdy(coord); - tile_data.ddx[0] = mx_matrix_mul(ddx, rm1) / scale1; - tile_data.ddx[1] = mx_matrix_mul(ddx, rm2) / scale2; - tile_data.ddx[2] = mx_matrix_mul(ddx, rm3) / scale3; - tile_data.ddy[0] = mx_matrix_mul(ddy, rm1) / scale1; - tile_data.ddy[1] = mx_matrix_mul(ddy, rm2) / scale2; - tile_data.ddy[2] = mx_matrix_mul(ddy, rm3) / scale3; - - return tile_data; -} diff --git a/MaterialX/libraries/stdlib/genglsl/lib/mx_hsv.glsl b/MaterialX/libraries/stdlib/genglsl/lib/mx_hsv.glsl old mode 100644 new mode 100755 index 1fb78b2..832c16e --- a/MaterialX/libraries/stdlib/genglsl/lib/mx_hsv.glsl +++ b/MaterialX/libraries/stdlib/genglsl/lib/mx_hsv.glsl @@ -1,91 +1,91 @@ -/* -Color transform functions. - -These functions are modified versions of the color operators found in Open Shading Language: -github.com/imageworks/OpenShadingLanguage/blob/master/src/liboslexec/opcolor.cpp - -It contains the subset of color operators needed to implement the MaterialX -standard library. The modifications are for conversions from C++ to GLSL. - -Original copyright notice: ------------------------------------------------------------------------- -Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. -All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -* Neither the name of Sony Pictures Imageworks nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------- -*/ - -vec3 mx_hsvtorgb(vec3 hsv) -{ - // Reference for this technique: Foley & van Dam - float h = hsv.x; float s = hsv.y; float v = hsv.z; - if (s < 0.0001f) { - return vec3 (v, v, v); - } else { - h = 6.0f * (h - floor(h)); // expand to [0..6) - int hi = int(trunc(h)); - float f = h - float(hi); - float p = v * (1.0f-s); - float q = v * (1.0f-s*f); - float t = v * (1.0f-s*(1.0f-f)); - if (hi == 0) - return vec3 (v, t, p); - else if (hi == 1) - return vec3 (q, v, p); - else if (hi == 2) - return vec3 (p, v, t); - else if (hi == 3) - return vec3 (p, q, v); - else if (hi == 4) - return vec3 (t, p, v); - return vec3 (v, p, q); - } -} - - -vec3 mx_rgbtohsv(vec3 c) -{ - // See Foley & van Dam - float r = c.x; float g = c.y; float b = c.z; - float mincomp = min (r, min(g, b)); - float maxcomp = max (r, max(g, b)); - float delta = maxcomp - mincomp; // chroma - float h, s, v; - v = maxcomp; - if (maxcomp > 0.0f) - s = delta / maxcomp; - else s = 0.0f; - if (s <= 0.0f) - h = 0.0f; - else { - if (r >= maxcomp) h = (g-b) / delta; - else if (g >= maxcomp) h = 2.0f + (b-r) / delta; - else h = 4.0f + (r-g) / delta; - h *= (1.0f/6.0f); - if (h < 0.0f) - h += 1.0f; - } - return vec3(h, s, v); -} +/* +Color transform functions. + +These funcions are modified versions of the color operators found in Open Shading Language: +github.com/imageworks/OpenShadingLanguage/blob/master/src/liboslexec/opcolor.cpp + +It contains the subset of color operators needed to implement the MaterialX +standard library. The modifications are for conversions from C++ to GLSL. + +Original copyright notice: +------------------------------------------------------------------------ +Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. +All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of Sony Pictures Imageworks nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +------------------------------------------------------------------------ +*/ + +vec3 mx_hsvtorgb(vec3 hsv) +{ + // Reference for this technique: Foley & van Dam + float h = hsv.x; float s = hsv.y; float v = hsv.z; + if (s < 0.0001f) { + return vec3 (v, v, v); + } else { + h = 6.0f * (h - floor(h)); // expand to [0..6) + int hi = int(trunc(h)); + float f = h - float(hi); + float p = v * (1.0f-s); + float q = v * (1.0f-s*f); + float t = v * (1.0f-s*(1.0f-f)); + if (hi == 0) + return vec3 (v, t, p); + else if (hi == 1) + return vec3 (q, v, p); + else if (hi == 2) + return vec3 (p, v, t); + else if (hi == 3) + return vec3 (p, q, v); + else if (hi == 4) + return vec3 (t, p, v); + return vec3 (v, p, q); + } +} + + +vec3 mx_rgbtohsv(vec3 c) +{ + // See Foley & van Dam + float r = c.x; float g = c.y; float b = c.z; + float mincomp = min (r, min(g, b)); + float maxcomp = max (r, max(g, b)); + float delta = maxcomp - mincomp; // chroma + float h, s, v; + v = maxcomp; + if (maxcomp > 0.0f) + s = delta / maxcomp; + else s = 0.0f; + if (s <= 0.0f) + h = 0.0f; + else { + if (r >= maxcomp) h = (g-b) / delta; + else if (g >= maxcomp) h = 2.0f + (b-r) / delta; + else h = 4.0f + (r-g) / delta; + h *= (1.0f/6.0f); + if (h < 0.0f) + h += 1.0f; + } + return vec3(h, s, v); +} diff --git a/MaterialX/libraries/stdlib/genglsl/lib/mx_math.glsl b/MaterialX/libraries/stdlib/genglsl/lib/mx_math.glsl old mode 100644 new mode 100755 index 1f02bd0..769c5a6 --- a/MaterialX/libraries/stdlib/genglsl/lib/mx_math.glsl +++ b/MaterialX/libraries/stdlib/genglsl/lib/mx_math.glsl @@ -1,46 +1,24 @@ -#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 -#define mx_float_bits_to_int floatBitsToInt - -vec2 mx_matrix_mul(vec2 v, mat2 m) { return v * m; } -vec3 mx_matrix_mul(vec3 v, mat3 m) { return v * m; } -vec4 mx_matrix_mul(vec4 v, mat4 m) { return v * m; } -vec2 mx_matrix_mul(mat2 m, vec2 v) { return m * v; } -vec3 mx_matrix_mul(mat3 m, vec3 v) { return m * v; } -vec4 mx_matrix_mul(mat4 m, vec4 v) { return m * v; } -mat2 mx_matrix_mul(mat2 m1, mat2 m2) { return m1 * m2; } -mat3 mx_matrix_mul(mat3 m1, mat3 m2) { return m1 * m2; } -mat4 mx_matrix_mul(mat4 m1, mat4 m2) { return m1 * m2; } - -float mx_square(float x) -{ - return x*x; -} - -vec2 mx_square(vec2 x) -{ - return x*x; -} - -vec3 mx_square(vec3 x) -{ - return x*x; -} - -vec3 mx_srgb_encode(vec3 color) -{ - bvec3 isAbove = greaterThan(color, vec3(0.0031308)); - vec3 linSeg = color * 12.92; - vec3 powSeg = 1.055 * pow(max(color, vec3(0.0)), vec3(1.0 / 2.4)) - 0.055; - return mix(linSeg, powSeg, isAbove); -} +#define M_FLOAT_EPS 1e-8 + +float mx_square(float x) +{ + return x*x; +} + +vec2 mx_square(vec2 x) +{ + return x*x; +} + +vec3 mx_square(vec3 x) +{ + return x*x; +} + +vec3 mx_srgb_encode(vec3 color) +{ + bvec3 isAbove = greaterThan(color, vec3(0.0031308)); + vec3 linSeg = color * 12.92; + vec3 powSeg = 1.055 * pow(max(color, vec3(0.0)), vec3(1.0 / 2.4)) - 0.055; + return mix(linSeg, powSeg, isAbove); +} diff --git a/MaterialX/libraries/stdlib/genglsl/lib/mx_noise.glsl b/MaterialX/libraries/stdlib/genglsl/lib/mx_noise.glsl old mode 100644 new mode 100755 index d837ccc..fafb24d --- a/MaterialX/libraries/stdlib/genglsl/lib/mx_noise.glsl +++ b/MaterialX/libraries/stdlib/genglsl/lib/mx_noise.glsl @@ -1,746 +1,636 @@ -/* -Noise Library. - -This library is a modified version of the noise library found in -Open Shading Language: -github.com/imageworks/OpenShadingLanguage/blob/master/src/include/OSL/oslnoise.h - -It contains the subset of noise types needed to implement the MaterialX -standard library. The modifications are mainly conversions from C++ to GLSL. -Produced results should be identical to the OSL noise functions. - -Original copyright notice: ------------------------------------------------------------------------- -Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. -All Rights Reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -* Neither the name of Sony Pictures Imageworks nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------- -*/ - -float mx_select(bool b, float t, float f) -{ - return b ? t : f; -} - -float mx_negate_if(float val, bool b) -{ - return b ? -val : val; -} - -int mx_floor(float x) -{ - return int(floor(x)); -} - -// return mx_floor as well as the fractional remainder -float mx_floorfrac(float x, out int i) -{ - i = mx_floor(x); - return x - float(i); -} - -float mx_bilerp(float v0, float v1, float v2, float v3, float s, float t) -{ - float s1 = 1.0 - s; - return (1.0 - t) * (v0*s1 + v1*s) + t * (v2*s1 + v3*s); -} -vec3 mx_bilerp(vec3 v0, vec3 v1, vec3 v2, vec3 v3, float s, float t) -{ - float s1 = 1.0 - s; - return (1.0 - t) * (v0*s1 + v1*s) + t * (v2*s1 + v3*s); -} -float mx_trilerp(float v0, float v1, float v2, float v3, float v4, float v5, float v6, float v7, float s, float t, float r) -{ - float s1 = 1.0 - s; - float t1 = 1.0 - t; - float r1 = 1.0 - r; - return (r1*(t1*(v0*s1 + v1*s) + t*(v2*s1 + v3*s)) + - r*(t1*(v4*s1 + v5*s) + t*(v6*s1 + v7*s))); -} -vec3 mx_trilerp(vec3 v0, vec3 v1, vec3 v2, vec3 v3, vec3 v4, vec3 v5, vec3 v6, vec3 v7, float s, float t, float r) -{ - float s1 = 1.0 - s; - float t1 = 1.0 - t; - float r1 = 1.0 - r; - return (r1*(t1*(v0*s1 + v1*s) + t*(v2*s1 + v3*s)) + - r*(t1*(v4*s1 + v5*s) + t*(v6*s1 + v7*s))); -} - -// 2 and 3 dimensional gradient functions - perform a dot product against a -// randomly chosen vector. Note that the gradient vector is not normalized, but -// this only affects the overall "scale" of the result, so we simply account for -// the scale by multiplying in the corresponding "perlin" function. -float mx_gradient_float(uint hash, float x, float y) -{ - // 8 possible directions (+-1,+-2) and (+-2,+-1) - uint h = hash & 7u; - float u = mx_select(h<4u, x, y); - float v = 2.0 * mx_select(h<4u, y, x); - // compute the dot product with (x,y). - return mx_negate_if(u, bool(h&1u)) + mx_negate_if(v, bool(h&2u)); -} -float mx_gradient_float(uint hash, float x, float y, float z) -{ - // use vectors pointing to the edges of the cube - uint h = hash & 15u; - float u = mx_select(h<8u, x, y); - float v = mx_select(h<4u, y, mx_select((h==12u)||(h==14u), x, z)); - return mx_negate_if(u, bool(h&1u)) + mx_negate_if(v, bool(h&2u)); -} -vec3 mx_gradient_vec3(uvec3 hash, float x, float y) -{ - return vec3(mx_gradient_float(hash.x, x, y), mx_gradient_float(hash.y, x, y), mx_gradient_float(hash.z, x, y)); -} -vec3 mx_gradient_vec3(uvec3 hash, float x, float y, float z) -{ - return vec3(mx_gradient_float(hash.x, x, y, z), mx_gradient_float(hash.y, x, y, z), mx_gradient_float(hash.z, x, y, z)); -} -// Scaling factors to normalize the result of gradients above. -// These factors were experimentally calculated to be: -// 2D: 0.6616 -// 3D: 0.9820 -float mx_gradient_scale2d(float v) { return 0.6616 * v; } -float mx_gradient_scale3d(float v) { return 0.9820 * v; } -vec3 mx_gradient_scale2d(vec3 v) { return 0.6616 * v; } -vec3 mx_gradient_scale3d(vec3 v) { return 0.9820 * v; } - -/// Bitwise circular rotation left by k bits (for 32 bit unsigned integers) -uint mx_rotl32(uint x, int k) -{ - return (x<>(32-k)); -} - -void mx_bjmix(inout uint a, inout uint b, inout uint c) -{ - a -= c; a ^= mx_rotl32(c, 4); c += b; - b -= a; b ^= mx_rotl32(a, 6); a += c; - c -= b; c ^= mx_rotl32(b, 8); b += a; - a -= c; a ^= mx_rotl32(c,16); c += b; - b -= a; b ^= mx_rotl32(a,19); a += c; - c -= b; c ^= mx_rotl32(b, 4); b += a; -} - -// Mix up and combine the bits of a, b, and c (doesn't change them, but -// returns a hash of those three original values). -uint mx_bjfinal(uint a, uint b, uint c) -{ - c ^= b; c -= mx_rotl32(b,14); - a ^= c; a -= mx_rotl32(c,11); - b ^= a; b -= mx_rotl32(a,25); - c ^= b; c -= mx_rotl32(b,16); - a ^= c; a -= mx_rotl32(c,4); - b ^= a; b -= mx_rotl32(a,14); - c ^= b; c -= mx_rotl32(b,24); - return c; -} - -// Convert a 32 bit integer into a floating point number in [0,1] -float mx_bits_to_01(uint bits) -{ - return float(bits) / float(uint(0xffffffff)); -} - -float mx_fade(float t) -{ - return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); -} - -uint mx_hash_int(int x) -{ - uint len = 1u; - uint seed = uint(0xdeadbeef) + (len << 2u) + 13u; - return mx_bjfinal(seed+uint(x), seed, seed); -} - -uint mx_hash_int(int x, int y) -{ - uint len = 2u; - uint a, b, c; - a = b = c = uint(0xdeadbeef) + (len << 2u) + 13u; - a += uint(x); - b += uint(y); - return mx_bjfinal(a, b, c); -} - -uint mx_hash_int(int x, int y, int z) -{ - uint len = 3u; - uint a, b, c; - a = b = c = uint(0xdeadbeef) + (len << 2u) + 13u; - a += uint(x); - b += uint(y); - c += uint(z); - return mx_bjfinal(a, b, c); -} - -uint mx_hash_int(int x, int y, int z, int xx) -{ - uint len = 4u; - uint a, b, c; - a = b = c = uint(0xdeadbeef) + (len << 2u) + 13u; - a += uint(x); - b += uint(y); - c += uint(z); - mx_bjmix(a, b, c); - a += uint(xx); - return mx_bjfinal(a, b, c); -} - -uint mx_hash_int(int x, int y, int z, int xx, int yy) -{ - uint len = 5u; - uint a, b, c; - a = b = c = uint(0xdeadbeef) + (len << 2u) + 13u; - a += uint(x); - b += uint(y); - c += uint(z); - mx_bjmix(a, b, c); - a += uint(xx); - b += uint(yy); - return mx_bjfinal(a, b, c); -} - -uvec3 mx_hash_vec3(int x, int y) -{ - uint h = mx_hash_int(x, y); - // we only need the low-order bits to be random, so split out - // the 32 bit result into 3 parts for each channel - uvec3 result; - result.x = (h ) & 0xFFu; - result.y = (h >> 8 ) & 0xFFu; - result.z = (h >> 16) & 0xFFu; - return result; -} - -uvec3 mx_hash_vec3(int x, int y, int z) -{ - uint h = mx_hash_int(x, y, z); - // we only need the low-order bits to be random, so split out - // the 32 bit result into 3 parts for each channel - uvec3 result; - result.x = (h ) & 0xFFu; - result.y = (h >> 8 ) & 0xFFu; - result.z = (h >> 16) & 0xFFu; - return result; -} - -float mx_perlin_noise_float(vec2 p) -{ - int X, Y; - float fx = mx_floorfrac(p.x, X); - float fy = mx_floorfrac(p.y, Y); - float u = mx_fade(fx); - float v = mx_fade(fy); - float result = mx_bilerp( - mx_gradient_float(mx_hash_int(X , Y ), fx , fy ), - mx_gradient_float(mx_hash_int(X+1, Y ), fx-1.0, fy ), - mx_gradient_float(mx_hash_int(X , Y+1), fx , fy-1.0), - mx_gradient_float(mx_hash_int(X+1, Y+1), fx-1.0, fy-1.0), - u, v); - return mx_gradient_scale2d(result); -} - -float mx_perlin_noise_float(vec3 p) -{ - int X, Y, Z; - float fx = mx_floorfrac(p.x, X); - float fy = mx_floorfrac(p.y, Y); - float fz = mx_floorfrac(p.z, Z); - float u = mx_fade(fx); - float v = mx_fade(fy); - float w = mx_fade(fz); - float result = mx_trilerp( - mx_gradient_float(mx_hash_int(X , Y , Z ), fx , fy , fz ), - mx_gradient_float(mx_hash_int(X+1, Y , Z ), fx-1.0, fy , fz ), - mx_gradient_float(mx_hash_int(X , Y+1, Z ), fx , fy-1.0, fz ), - mx_gradient_float(mx_hash_int(X+1, Y+1, Z ), fx-1.0, fy-1.0, fz ), - mx_gradient_float(mx_hash_int(X , Y , Z+1), fx , fy , fz-1.0), - mx_gradient_float(mx_hash_int(X+1, Y , Z+1), fx-1.0, fy , fz-1.0), - mx_gradient_float(mx_hash_int(X , Y+1, Z+1), fx , fy-1.0, fz-1.0), - mx_gradient_float(mx_hash_int(X+1, Y+1, Z+1), fx-1.0, fy-1.0, fz-1.0), - u, v, w); - return mx_gradient_scale3d(result); -} - -vec3 mx_perlin_noise_vec3(vec2 p) -{ - int X, Y; - float fx = mx_floorfrac(p.x, X); - float fy = mx_floorfrac(p.y, Y); - float u = mx_fade(fx); - float v = mx_fade(fy); - vec3 result = mx_bilerp( - mx_gradient_vec3(mx_hash_vec3(X , Y ), fx , fy ), - mx_gradient_vec3(mx_hash_vec3(X+1, Y ), fx-1.0, fy ), - mx_gradient_vec3(mx_hash_vec3(X , Y+1), fx , fy-1.0), - mx_gradient_vec3(mx_hash_vec3(X+1, Y+1), fx-1.0, fy-1.0), - u, v); - return mx_gradient_scale2d(result); -} - -vec3 mx_perlin_noise_vec3(vec3 p) -{ - int X, Y, Z; - float fx = mx_floorfrac(p.x, X); - float fy = mx_floorfrac(p.y, Y); - float fz = mx_floorfrac(p.z, Z); - float u = mx_fade(fx); - float v = mx_fade(fy); - float w = mx_fade(fz); - vec3 result = mx_trilerp( - mx_gradient_vec3(mx_hash_vec3(X , Y , Z ), fx , fy , fz ), - mx_gradient_vec3(mx_hash_vec3(X+1, Y , Z ), fx-1.0, fy , fz ), - mx_gradient_vec3(mx_hash_vec3(X , Y+1, Z ), fx , fy-1.0, fz ), - mx_gradient_vec3(mx_hash_vec3(X+1, Y+1, Z ), fx-1.0, fy-1.0, fz ), - mx_gradient_vec3(mx_hash_vec3(X , Y , Z+1), fx , fy , fz-1.0), - mx_gradient_vec3(mx_hash_vec3(X+1, Y , Z+1), fx-1.0, fy , fz-1.0), - mx_gradient_vec3(mx_hash_vec3(X , Y+1, Z+1), fx , fy-1.0, fz-1.0), - mx_gradient_vec3(mx_hash_vec3(X+1, Y+1, Z+1), fx-1.0, fy-1.0, fz-1.0), - u, v, w); - return mx_gradient_scale3d(result); -} - -float mx_cell_noise_float(float p) -{ - int ix = mx_floor(p); - return mx_bits_to_01(mx_hash_int(ix)); -} - -float mx_cell_noise_float(vec2 p) -{ - int ix = mx_floor(p.x); - int iy = mx_floor(p.y); - return mx_bits_to_01(mx_hash_int(ix, iy)); -} - -float mx_cell_noise_float(vec3 p) -{ - int ix = mx_floor(p.x); - int iy = mx_floor(p.y); - int iz = mx_floor(p.z); - return mx_bits_to_01(mx_hash_int(ix, iy, iz)); -} - -float mx_cell_noise_float(vec4 p) -{ - int ix = mx_floor(p.x); - int iy = mx_floor(p.y); - int iz = mx_floor(p.z); - int iw = mx_floor(p.w); - return mx_bits_to_01(mx_hash_int(ix, iy, iz, iw)); -} - -vec3 mx_cell_noise_vec3(float p) -{ - int ix = mx_floor(p); - return vec3( - mx_bits_to_01(mx_hash_int(ix, 0)), - mx_bits_to_01(mx_hash_int(ix, 1)), - mx_bits_to_01(mx_hash_int(ix, 2)) - ); -} - -vec3 mx_cell_noise_vec3(vec2 p) -{ - int ix = mx_floor(p.x); - int iy = mx_floor(p.y); - return vec3( - mx_bits_to_01(mx_hash_int(ix, iy, 0)), - mx_bits_to_01(mx_hash_int(ix, iy, 1)), - mx_bits_to_01(mx_hash_int(ix, iy, 2)) - ); -} - -vec3 mx_cell_noise_vec3(vec3 p) -{ - int ix = mx_floor(p.x); - int iy = mx_floor(p.y); - int iz = mx_floor(p.z); - return vec3( - mx_bits_to_01(mx_hash_int(ix, iy, iz, 0)), - mx_bits_to_01(mx_hash_int(ix, iy, iz, 1)), - mx_bits_to_01(mx_hash_int(ix, iy, iz, 2)) - ); -} - -vec3 mx_cell_noise_vec3(vec4 p) -{ - int ix = mx_floor(p.x); - int iy = mx_floor(p.y); - int iz = mx_floor(p.z); - int iw = mx_floor(p.w); - return vec3( - mx_bits_to_01(mx_hash_int(ix, iy, iz, iw, 0)), - mx_bits_to_01(mx_hash_int(ix, iy, iz, iw, 1)), - mx_bits_to_01(mx_hash_int(ix, iy, iz, iw, 2)) - ); -} - -float mx_fractal2d_noise_float(vec2 p, int octaves, float lacunarity, float diminish) -{ - float result = 0.0; - float amplitude = 1.0; - for (int i = 0; i < octaves; ++i) - { - result += amplitude * mx_perlin_noise_float(p); - amplitude *= diminish; - p *= lacunarity; - } - return result; -} - -vec3 mx_fractal2d_noise_vec3(vec2 p, int octaves, float lacunarity, float diminish) -{ - vec3 result = vec3(0.0); - float amplitude = 1.0; - for (int i = 0; i < octaves; ++i) - { - result += amplitude * mx_perlin_noise_vec3(p); - amplitude *= diminish; - p *= lacunarity; - } - return result; -} - -vec2 mx_fractal2d_noise_vec2(vec2 p, int octaves, float lacunarity, float diminish) -{ - return vec2(mx_fractal2d_noise_float(p, octaves, lacunarity, diminish), - mx_fractal2d_noise_float(p+vec2(19, 193), octaves, lacunarity, diminish)); -} - -vec4 mx_fractal2d_noise_vec4(vec2 p, int octaves, float lacunarity, float diminish) -{ - vec3 c = mx_fractal2d_noise_vec3(p, octaves, lacunarity, diminish); - float f = mx_fractal2d_noise_float(p+vec2(19, 193), octaves, lacunarity, diminish); - return vec4(c, f); -} - -float mx_fractal3d_noise_float(vec3 p, int octaves, float lacunarity, float diminish) -{ - float result = 0.0; - float amplitude = 1.0; - for (int i = 0; i < octaves; ++i) - { - result += amplitude * mx_perlin_noise_float(p); - amplitude *= diminish; - p *= lacunarity; - } - return result; -} - -vec3 mx_fractal3d_noise_vec3(vec3 p, int octaves, float lacunarity, float diminish) -{ - vec3 result = vec3(0.0); - float amplitude = 1.0; - for (int i = 0; i < octaves; ++i) - { - result += amplitude * mx_perlin_noise_vec3(p); - amplitude *= diminish; - p *= lacunarity; - } - return result; -} - -vec2 mx_fractal3d_noise_vec2(vec3 p, int octaves, float lacunarity, float diminish) -{ - return vec2(mx_fractal3d_noise_float(p, octaves, lacunarity, diminish), - mx_fractal3d_noise_float(p+vec3(19, 193, 17), octaves, lacunarity, diminish)); -} - -vec4 mx_fractal3d_noise_vec4(vec3 p, int octaves, float lacunarity, float diminish) -{ - vec3 c = mx_fractal3d_noise_vec3(p, octaves, lacunarity, diminish); - float f = mx_fractal3d_noise_float(p+vec3(19, 193, 17), octaves, lacunarity, diminish); - return vec4(c, f); -} - -vec2 mx_worley_cell_position(int x, int y, int xoff, int yoff, float jitter) -{ - vec3 tmp = mx_cell_noise_vec3(vec2(x+xoff, y+yoff)); - vec2 off = vec2(tmp.x, tmp.y); - - off -= 0.5f; - off *= jitter; - off += 0.5f; - - return vec2(float(x), float(y)) + off; -} - -vec3 mx_worley_cell_position(int x, int y, int z, int xoff, int yoff, int zoff, float jitter) -{ - vec3 off = mx_cell_noise_vec3(vec3(x+xoff, y+yoff, z+zoff)); - - off -= 0.5f; - off *= jitter; - off += 0.5f; - - return vec3(float(x), float(y), float(z)) + off; -} - -float mx_worley_distance(vec2 p, int x, int y, int xoff, int yoff, float jitter, int metric) -{ - vec2 cellpos = mx_worley_cell_position(x, y, xoff, yoff, jitter); - vec2 diff = cellpos - p; - if (metric == 2) - return abs(diff.x) + abs(diff.y); // Manhattan distance - if (metric == 3) - return max(abs(diff.x), abs(diff.y)); // Chebyshev distance - // Either Euclidean or Distance^2 - return dot(diff, diff); -} - -float mx_worley_distance(vec3 p, int x, int y, int z, int xoff, int yoff, int zoff, float jitter, int metric) -{ - vec3 cellpos = mx_worley_cell_position(x, y, z, xoff, yoff, zoff, jitter); - vec3 diff = cellpos - p; - if (metric == 2) - return abs(diff.x) + abs(diff.y) + abs(diff.z); // Manhattan distance - if (metric == 3) - return max(max(abs(diff.x), abs(diff.y)), abs(diff.z)); // Chebyshev distance - // Either Euclidean or Distance^2 - return dot(diff, diff); -} - -float mx_worley_noise_float(vec2 p, float jitter, int style, int metric) -{ - int X, Y; - float dist; - vec2 localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); - float sqdist = 1e6f; // Some big number for jitter > 1 (not all GPUs may be IEEE) - vec2 minpos = vec2(0,0); - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); - vec2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; - if(dist < sqdist) - { - sqdist = dist; - minpos = cellpos; - } - } - } - if (style == 1) - return mx_cell_noise_float(minpos + p); - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} - -vec2 mx_worley_noise_vec2(vec2 p, float jitter, int style, int metric) -{ - int X, Y; - vec2 localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); - vec2 sqdist = vec2(1e6f, 1e6f); - vec2 minpos = vec2(0,0); - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); - vec2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; - if (dist < sqdist.x) - { - sqdist.y = sqdist.x; - sqdist.x = dist; - minpos = cellpos; - } - else if (dist < sqdist.y) - { - sqdist.y = dist; - } - } - } - if (style == 1) - { - vec3 tmp = mx_cell_noise_vec3(minpos + p); - return vec2(tmp.x,tmp.y); - } - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} - -vec3 mx_worley_noise_vec3(vec2 p, float jitter, int style, int metric) -{ - int X, Y; - vec2 localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); - vec3 sqdist = vec3(1e6f, 1e6f, 1e6f); - vec2 minpos = vec2(0,0); - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); - vec2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; - if (dist < sqdist.x) - { - sqdist.z = sqdist.y; - sqdist.y = sqdist.x; - sqdist.x = dist; - minpos = cellpos; - } - else if (dist < sqdist.y) - { - sqdist.z = sqdist.y; - sqdist.y = dist; - } - else if (dist < sqdist.z) - { - sqdist.z = dist; - } - } - } - if (style == 1) - return mx_cell_noise_vec3(minpos + p); - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} - -float mx_worley_noise_float(vec3 p, float jitter, int style, int metric) -{ - int X, Y, Z; - vec3 localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); - float sqdist = 1e6f; - vec3 minpos = vec3(0,0,0); - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - for (int z = -1; z <= 1; ++z) - { - float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); - vec3 cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; - if(dist < sqdist) - { - sqdist = dist; - minpos = cellpos; - } - } - } - } - if (style == 1) - return mx_cell_noise_float(minpos + p); - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} - -vec2 mx_worley_noise_vec2(vec3 p, float jitter, int style, int metric) -{ - int X, Y, Z; - vec3 localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); - vec2 sqdist = vec2(1e6f, 1e6f); - vec3 minpos = vec3(0,0,0); - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - for (int z = -1; z <= 1; ++z) - { - float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); - vec3 cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; - if (dist < sqdist.x) - { - sqdist.y = sqdist.x; - sqdist.x = dist; - minpos = cellpos; - } - else if (dist < sqdist.y) - { - sqdist.y = dist; - } - } - } - } - if (style == 1) - { - vec3 tmp = mx_cell_noise_vec3(minpos + p); - return vec2(tmp.x,tmp.y); - } - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} - -vec3 mx_worley_noise_vec3(vec3 p, float jitter, int style, int metric) -{ - int X, Y, Z; - vec3 localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); - vec3 sqdist = vec3(1e6f, 1e6f, 1e6f); - vec3 minpos = vec3(0,0,0); - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - for (int z = -1; z <= 1; ++z) - { - float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); - vec3 cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; - if (dist < sqdist.x) - { - sqdist.z = sqdist.y; - sqdist.y = sqdist.x; - sqdist.x = dist; - minpos = cellpos; - } - else if (dist < sqdist.y) - { - sqdist.z = sqdist.y; - sqdist.y = dist; - } - else if (dist < sqdist.z) - { - sqdist.z = dist; - } - } - } - } - if (style == 1) - return mx_cell_noise_vec3(minpos + p); - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} +/* +Noise Library. + +This library is a modified version of the noise library found in +Open Shading Language: +github.com/imageworks/OpenShadingLanguage/blob/master/src/include/OSL/oslnoise.h + +It contains the subset of noise types needed to implement the MaterialX +standard library. The modifications are mainly conversions from C++ to GLSL. +Produced results should be identical to the OSL noise functions. + +Original copyright notice: +------------------------------------------------------------------------ +Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. +All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of Sony Pictures Imageworks nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +------------------------------------------------------------------------ +*/ + +float mx_select(bool b, float t, float f) +{ + return b ? t : f; +} + +float mx_negate_if(float val, bool b) +{ + return b ? -val : val; +} + +int mx_floor(float x) +{ + return int(floor(x)); +} + +// return mx_floor as well as the fractional remainder +float mx_floorfrac(float x, out int i) +{ + i = mx_floor(x); + return x - float(i); +} + +float mx_bilerp(float v0, float v1, float v2, float v3, float s, float t) +{ + float s1 = 1.0 - s; + return (1.0 - t) * (v0*s1 + v1*s) + t * (v2*s1 + v3*s); +} +vec3 mx_bilerp(vec3 v0, vec3 v1, vec3 v2, vec3 v3, float s, float t) +{ + float s1 = 1.0 - s; + return (1.0 - t) * (v0*s1 + v1*s) + t * (v2*s1 + v3*s); +} +float mx_trilerp(float v0, float v1, float v2, float v3, float v4, float v5, float v6, float v7, float s, float t, float r) +{ + float s1 = 1.0 - s; + float t1 = 1.0 - t; + float r1 = 1.0 - r; + return (r1*(t1*(v0*s1 + v1*s) + t*(v2*s1 + v3*s)) + + r*(t1*(v4*s1 + v5*s) + t*(v6*s1 + v7*s))); +} +vec3 mx_trilerp(vec3 v0, vec3 v1, vec3 v2, vec3 v3, vec3 v4, vec3 v5, vec3 v6, vec3 v7, float s, float t, float r) +{ + float s1 = 1.0 - s; + float t1 = 1.0 - t; + float r1 = 1.0 - r; + return (r1*(t1*(v0*s1 + v1*s) + t*(v2*s1 + v3*s)) + + r*(t1*(v4*s1 + v5*s) + t*(v6*s1 + v7*s))); +} + +// 2 and 3 dimensional gradient functions - perform a dot product against a +// randomly chosen vector. Note that the gradient vector is not normalized, but +// this only affects the overal "scale" of the result, so we simply account for +// the scale by multiplying in the corresponding "perlin" function. +float mx_gradient_float(uint hash, float x, float y) +{ + // 8 possible directions (+-1,+-2) and (+-2,+-1) + uint h = hash & 7u; + float u = mx_select(h<4u, x, y); + float v = 2.0 * mx_select(h<4u, y, x); + // compute the dot product with (x,y). + return mx_negate_if(u, bool(h&1u)) + mx_negate_if(v, bool(h&2u)); +} +float mx_gradient_float(uint hash, float x, float y, float z) +{ + // use vectors pointing to the edges of the cube + uint h = hash & 15u; + float u = mx_select(h<8u, x, y); + float v = mx_select(h<4u, y, mx_select((h==12u)||(h==14u), x, z)); + return mx_negate_if(u, bool(h&1u)) + mx_negate_if(v, bool(h&2u)); +} +vec3 mx_gradient_vec3(uvec3 hash, float x, float y) +{ + return vec3(mx_gradient_float(hash.x, x, y), mx_gradient_float(hash.y, x, y), mx_gradient_float(hash.z, x, y)); +} +vec3 mx_gradient_vec3(uvec3 hash, float x, float y, float z) +{ + return vec3(mx_gradient_float(hash.x, x, y, z), mx_gradient_float(hash.y, x, y, z), mx_gradient_float(hash.z, x, y, z)); +} +// Scaling factors to normalize the result of gradients above. +// These factors were experimentally calculated to be: +// 2D: 0.6616 +// 3D: 0.9820 +float mx_gradient_scale2d(float v) { return 0.6616 * v; } +float mx_gradient_scale3d(float v) { return 0.9820 * v; } +vec3 mx_gradient_scale2d(vec3 v) { return 0.6616 * v; } +vec3 mx_gradient_scale3d(vec3 v) { return 0.9820 * v; } + +/// Bitwise circular rotation left by k bits (for 32 bit unsigned integers) +uint mx_rotl32(uint x, int k) +{ + return (x<>(32-k)); +} + +void mx_bjmix(inout uint a, inout uint b, inout uint c) +{ + a -= c; a ^= mx_rotl32(c, 4); c += b; + b -= a; b ^= mx_rotl32(a, 6); a += c; + c -= b; c ^= mx_rotl32(b, 8); b += a; + a -= c; a ^= mx_rotl32(c,16); c += b; + b -= a; b ^= mx_rotl32(a,19); a += c; + c -= b; c ^= mx_rotl32(b, 4); b += a; +} + +// Mix up and combine the bits of a, b, and c (doesn't change them, but +// returns a hash of those three original values). +uint mx_bjfinal(uint a, uint b, uint c) +{ + c ^= b; c -= mx_rotl32(b,14); + a ^= c; a -= mx_rotl32(c,11); + b ^= a; b -= mx_rotl32(a,25); + c ^= b; c -= mx_rotl32(b,16); + a ^= c; a -= mx_rotl32(c,4); + b ^= a; b -= mx_rotl32(a,14); + c ^= b; c -= mx_rotl32(b,24); + return c; +} + +// Convert a 32 bit integer into a floating point number in [0,1] +float mx_bits_to_01(uint bits) +{ + return float(bits) / float(uint(0xffffffff)); +} + +float mx_fade(float t) +{ + return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); +} + +uint mx_hash_int(int x) +{ + uint len = 1u; + uint seed = uint(0xdeadbeef) + (len << 2u) + 13u; + return mx_bjfinal(seed+uint(x), seed, seed); +} + +uint mx_hash_int(int x, int y) +{ + uint len = 2u; + uint a, b, c; + a = b = c = uint(0xdeadbeef) + (len << 2u) + 13u; + a += uint(x); + b += uint(y); + return mx_bjfinal(a, b, c); +} + +uint mx_hash_int(int x, int y, int z) +{ + uint len = 3u; + uint a, b, c; + a = b = c = uint(0xdeadbeef) + (len << 2u) + 13u; + a += uint(x); + b += uint(y); + c += uint(z); + return mx_bjfinal(a, b, c); +} + +uint mx_hash_int(int x, int y, int z, int xx) +{ + uint len = 4u; + uint a, b, c; + a = b = c = uint(0xdeadbeef) + (len << 2u) + 13u; + a += uint(x); + b += uint(y); + c += uint(z); + mx_bjmix(a, b, c); + a += uint(xx); + return mx_bjfinal(a, b, c); +} + +uint mx_hash_int(int x, int y, int z, int xx, int yy) +{ + uint len = 5u; + uint a, b, c; + a = b = c = uint(0xdeadbeef) + (len << 2u) + 13u; + a += uint(x); + b += uint(y); + c += uint(z); + mx_bjmix(a, b, c); + a += uint(xx); + b += uint(yy); + return mx_bjfinal(a, b, c); +} + +uvec3 mx_hash_vec3(int x, int y) +{ + uint h = mx_hash_int(x, y); + // we only need the low-order bits to be random, so split out + // the 32 bit result into 3 parts for each channel + uvec3 result; + result.x = (h ) & 0xFFu; + result.y = (h >> 8 ) & 0xFFu; + result.z = (h >> 16) & 0xFFu; + return result; +} + +uvec3 mx_hash_vec3(int x, int y, int z) +{ + uint h = mx_hash_int(x, y, z); + // we only need the low-order bits to be random, so split out + // the 32 bit result into 3 parts for each channel + uvec3 result; + result.x = (h ) & 0xFFu; + result.y = (h >> 8 ) & 0xFFu; + result.z = (h >> 16) & 0xFFu; + return result; +} + +float mx_perlin_noise_float(vec2 p) +{ + int X, Y; + float fx = mx_floorfrac(p.x, X); + float fy = mx_floorfrac(p.y, Y); + float u = mx_fade(fx); + float v = mx_fade(fy); + float result = mx_bilerp( + mx_gradient_float(mx_hash_int(X , Y ), fx , fy ), + mx_gradient_float(mx_hash_int(X+1, Y ), fx-1.0, fy ), + mx_gradient_float(mx_hash_int(X , Y+1), fx , fy-1.0), + mx_gradient_float(mx_hash_int(X+1, Y+1), fx-1.0, fy-1.0), + u, v); + return mx_gradient_scale2d(result); +} + +float mx_perlin_noise_float(vec3 p) +{ + int X, Y, Z; + float fx = mx_floorfrac(p.x, X); + float fy = mx_floorfrac(p.y, Y); + float fz = mx_floorfrac(p.z, Z); + float u = mx_fade(fx); + float v = mx_fade(fy); + float w = mx_fade(fz); + float result = mx_trilerp( + mx_gradient_float(mx_hash_int(X , Y , Z ), fx , fy , fz ), + mx_gradient_float(mx_hash_int(X+1, Y , Z ), fx-1.0, fy , fz ), + mx_gradient_float(mx_hash_int(X , Y+1, Z ), fx , fy-1.0, fz ), + mx_gradient_float(mx_hash_int(X+1, Y+1, Z ), fx-1.0, fy-1.0, fz ), + mx_gradient_float(mx_hash_int(X , Y , Z+1), fx , fy , fz-1.0), + mx_gradient_float(mx_hash_int(X+1, Y , Z+1), fx-1.0, fy , fz-1.0), + mx_gradient_float(mx_hash_int(X , Y+1, Z+1), fx , fy-1.0, fz-1.0), + mx_gradient_float(mx_hash_int(X+1, Y+1, Z+1), fx-1.0, fy-1.0, fz-1.0), + u, v, w); + return mx_gradient_scale3d(result); +} + +vec3 mx_perlin_noise_vec3(vec2 p) +{ + int X, Y; + float fx = mx_floorfrac(p.x, X); + float fy = mx_floorfrac(p.y, Y); + float u = mx_fade(fx); + float v = mx_fade(fy); + vec3 result = mx_bilerp( + mx_gradient_vec3(mx_hash_vec3(X , Y ), fx , fy ), + mx_gradient_vec3(mx_hash_vec3(X+1, Y ), fx-1.0, fy ), + mx_gradient_vec3(mx_hash_vec3(X , Y+1), fx , fy-1.0), + mx_gradient_vec3(mx_hash_vec3(X+1, Y+1), fx-1.0, fy-1.0), + u, v); + return mx_gradient_scale2d(result); +} + +vec3 mx_perlin_noise_vec3(vec3 p) +{ + int X, Y, Z; + float fx = mx_floorfrac(p.x, X); + float fy = mx_floorfrac(p.y, Y); + float fz = mx_floorfrac(p.z, Z); + float u = mx_fade(fx); + float v = mx_fade(fy); + float w = mx_fade(fz); + vec3 result = mx_trilerp( + mx_gradient_vec3(mx_hash_vec3(X , Y , Z ), fx , fy , fz ), + mx_gradient_vec3(mx_hash_vec3(X+1, Y , Z ), fx-1.0, fy , fz ), + mx_gradient_vec3(mx_hash_vec3(X , Y+1, Z ), fx , fy-1.0, fz ), + mx_gradient_vec3(mx_hash_vec3(X+1, Y+1, Z ), fx-1.0, fy-1.0, fz ), + mx_gradient_vec3(mx_hash_vec3(X , Y , Z+1), fx , fy , fz-1.0), + mx_gradient_vec3(mx_hash_vec3(X+1, Y , Z+1), fx-1.0, fy , fz-1.0), + mx_gradient_vec3(mx_hash_vec3(X , Y+1, Z+1), fx , fy-1.0, fz-1.0), + mx_gradient_vec3(mx_hash_vec3(X+1, Y+1, Z+1), fx-1.0, fy-1.0, fz-1.0), + u, v, w); + return mx_gradient_scale3d(result); +} + +float mx_cell_noise_float(float p) +{ + int ix = mx_floor(p); + return mx_bits_to_01(mx_hash_int(ix)); +} + +float mx_cell_noise_float(vec2 p) +{ + int ix = mx_floor(p.x); + int iy = mx_floor(p.y); + return mx_bits_to_01(mx_hash_int(ix, iy)); +} + +float mx_cell_noise_float(vec3 p) +{ + int ix = mx_floor(p.x); + int iy = mx_floor(p.y); + int iz = mx_floor(p.z); + return mx_bits_to_01(mx_hash_int(ix, iy, iz)); +} + +float mx_cell_noise_float(vec4 p) +{ + int ix = mx_floor(p.x); + int iy = mx_floor(p.y); + int iz = mx_floor(p.z); + int iw = mx_floor(p.w); + return mx_bits_to_01(mx_hash_int(ix, iy, iz, iw)); +} + +vec3 mx_cell_noise_vec3(float p) +{ + int ix = mx_floor(p); + return vec3( + mx_bits_to_01(mx_hash_int(ix, 0)), + mx_bits_to_01(mx_hash_int(ix, 1)), + mx_bits_to_01(mx_hash_int(ix, 2)) + ); +} + +vec3 mx_cell_noise_vec3(vec2 p) +{ + int ix = mx_floor(p.x); + int iy = mx_floor(p.y); + return vec3( + mx_bits_to_01(mx_hash_int(ix, iy, 0)), + mx_bits_to_01(mx_hash_int(ix, iy, 1)), + mx_bits_to_01(mx_hash_int(ix, iy, 2)) + ); +} + +vec3 mx_cell_noise_vec3(vec3 p) +{ + int ix = mx_floor(p.x); + int iy = mx_floor(p.y); + int iz = mx_floor(p.z); + return vec3( + mx_bits_to_01(mx_hash_int(ix, iy, iz, 0)), + mx_bits_to_01(mx_hash_int(ix, iy, iz, 1)), + mx_bits_to_01(mx_hash_int(ix, iy, iz, 2)) + ); +} + +vec3 mx_cell_noise_vec3(vec4 p) +{ + int ix = mx_floor(p.x); + int iy = mx_floor(p.y); + int iz = mx_floor(p.z); + int iw = mx_floor(p.w); + return vec3( + mx_bits_to_01(mx_hash_int(ix, iy, iz, iw, 0)), + mx_bits_to_01(mx_hash_int(ix, iy, iz, iw, 1)), + mx_bits_to_01(mx_hash_int(ix, iy, iz, iw, 2)) + ); +} + +float mx_fractal_noise_float(vec3 p, int octaves, float lacunarity, float diminish) +{ + float result = 0.0; + float amplitude = 1.0; + for (int i = 0; i < octaves; ++i) + { + result += amplitude * mx_perlin_noise_float(p); + amplitude *= diminish; + p *= lacunarity; + } + return result; +} + +vec3 mx_fractal_noise_vec3(vec3 p, int octaves, float lacunarity, float diminish) +{ + vec3 result = vec3(0.0); + float amplitude = 1.0; + for (int i = 0; i < octaves; ++i) + { + result += amplitude * mx_perlin_noise_vec3(p); + amplitude *= diminish; + p *= lacunarity; + } + return result; +} + +vec2 mx_fractal_noise_vec2(vec3 p, int octaves, float lacunarity, float diminish) +{ + return vec2(mx_fractal_noise_float(p, octaves, lacunarity, diminish), + mx_fractal_noise_float(p+vec3(19, 193, 17), octaves, lacunarity, diminish)); +} + +vec4 mx_fractal_noise_vec4(vec3 p, int octaves, float lacunarity, float diminish) +{ + vec3 c = mx_fractal_noise_vec3(p, octaves, lacunarity, diminish); + float f = mx_fractal_noise_float(p+vec3(19, 193, 17), octaves, lacunarity, diminish); + return vec4(c, f); +} + +float mx_worley_distance(vec2 p, int x, int y, int xoff, int yoff, float jitter, int metric) +{ + vec3 tmp = mx_cell_noise_vec3(vec2(x+xoff, y+yoff)); + vec2 off = vec2(tmp.x, tmp.y); + + off -= 0.5f; + off *= jitter; + off += 0.5f; + + vec2 cellpos = vec2(float(x), float(y)) + off; + vec2 diff = cellpos - p; + if (metric == 2) + return abs(diff.x) + abs(diff.y); // Manhattan distance + if (metric == 3) + return max(abs(diff.x), abs(diff.y)); // Chebyshev distance + // Either Euclidian or Distance^2 + return dot(diff, diff); +} + +float mx_worley_distance(vec3 p, int x, int y, int z, int xoff, int yoff, int zoff, float jitter, int metric) +{ + vec3 off = mx_cell_noise_vec3(vec3(x+xoff, y+yoff, z+zoff)); + + off -= 0.5f; + off *= jitter; + off += 0.5f; + + vec3 cellpos = vec3(float(x), float(y), float(z)) + off; + vec3 diff = cellpos - p; + if (metric == 2) + return abs(diff.x) + abs(diff.y) + abs(diff.z); // Manhattan distance + if (metric == 3) + return max(max(abs(diff.x), abs(diff.y)), abs(diff.z)); // Chebyshev distance + // Either Euclidian or Distance^2 + return dot(diff, diff); +} + +float mx_worley_noise_float(vec2 p, float jitter, int metric) +{ + int X, Y; + vec2 localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); + float sqdist = 1e6f; // Some big number for jitter > 1 (not all GPUs may be IEEE) + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); + sqdist = min(sqdist, dist); + } + } + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; +} + +vec2 mx_worley_noise_vec2(vec2 p, float jitter, int metric) +{ + int X, Y; + vec2 localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); + vec2 sqdist = vec2(1e6f, 1e6f); + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); + if (dist < sqdist.x) + { + sqdist.y = sqdist.x; + sqdist.x = dist; + } + else if (dist < sqdist.y) + { + sqdist.y = dist; + } + } + } + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; +} + +vec3 mx_worley_noise_vec3(vec2 p, float jitter, int metric) +{ + int X, Y; + vec2 localpos = vec2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); + vec3 sqdist = vec3(1e6f, 1e6f, 1e6f); + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); + if (dist < sqdist.x) + { + sqdist.z = sqdist.y; + sqdist.y = sqdist.x; + sqdist.x = dist; + } + else if (dist < sqdist.y) + { + sqdist.z = sqdist.y; + sqdist.y = dist; + } + else if (dist < sqdist.z) + { + sqdist.z = dist; + } + } + } + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; +} + +float mx_worley_noise_float(vec3 p, float jitter, int metric) +{ + int X, Y, Z; + vec3 localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); + float sqdist = 1e6f; + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + for (int z = -1; z <= 1; ++z) + { + float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); + sqdist = min(sqdist, dist); + } + } + } + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; +} + +vec2 mx_worley_noise_vec2(vec3 p, float jitter, int metric) +{ + int X, Y, Z; + vec3 localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); + vec2 sqdist = vec2(1e6f, 1e6f); + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + for (int z = -1; z <= 1; ++z) + { + float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); + if (dist < sqdist.x) + { + sqdist.y = sqdist.x; + sqdist.x = dist; + } + else if (dist < sqdist.y) + { + sqdist.y = dist; + } + } + } + } + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; +} + +vec3 mx_worley_noise_vec3(vec3 p, float jitter, int metric) +{ + int X, Y, Z; + vec3 localpos = vec3(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); + vec3 sqdist = vec3(1e6f, 1e6f, 1e6f); + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + for (int z = -1; z <= 1; ++z) + { + float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); + if (dist < sqdist.x) + { + sqdist.z = sqdist.y; + sqdist.y = sqdist.x; + sqdist.x = dist; + } + else if (dist < sqdist.y) + { + sqdist.z = sqdist.y; + sqdist.y = dist; + } + else if (dist < sqdist.z) + { + sqdist.z = dist; + } + } + } + } + if (metric == 0) + sqdist = sqrt(sqdist); + return sqdist; +} diff --git a/MaterialX/libraries/stdlib/genglsl/lib/mx_sampling.glsl b/MaterialX/libraries/stdlib/genglsl/lib/mx_sampling.glsl new file mode 100755 index 0000000..b78205b --- /dev/null +++ b/MaterialX/libraries/stdlib/genglsl/lib/mx_sampling.glsl @@ -0,0 +1,91 @@ +// Restrict to 7x7 kernel size for performance reasons +#define MX_MAX_SAMPLE_COUNT 49 +// Size of all weights for all levels (including level 1) +#define MX_WEIGHT_ARRAY_SIZE 84 + +// +// Function to compute the sample size relative to a texture coordinate +// +vec2 mx_compute_sample_size_uv(vec2 uv, float filterSize, float filterOffset) +{ + vec2 derivUVx = dFdx(uv) * 0.5f; + vec2 derivUVy = dFdy(uv) * 0.5f; + float derivX = abs(derivUVx.x) + abs(derivUVy.x); + float derivY = abs(derivUVx.y) + abs(derivUVy.y); + float sampleSizeU = 2.0f * filterSize * derivX + filterOffset; + if (sampleSizeU < 1.0E-05f) + sampleSizeU = 1.0E-05f; + float sampleSizeV = 2.0f * filterSize * derivY + filterOffset; + if (sampleSizeV < 1.0E-05f) + sampleSizeV = 1.0E-05f; + return vec2(sampleSizeU, sampleSizeV); +} + +// +// Compute a normal mapped to 0..1 space based on a set of input +// samples using a Sobel filter. +// +vec3 mx_normal_from_samples_sobel(float S[9], 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 = max(_scale, M_FLOAT_EPS) * sqrt(max(1.0 - nx * nx - ny * ny, M_FLOAT_EPS)); + vec3 norm = normalize(vec3(nx, ny, nz)); + return (norm + 1.0) * 0.5; +} + +// +// Apply filter for float samples S, using weights W. +// sampleCount should be a square of a odd number in the range { 1, 3, 5, 7 } +// +float mx_convolution_float(float S[MX_MAX_SAMPLE_COUNT], float W[MX_WEIGHT_ARRAY_SIZE], int offset, int sampleCount) +{ + float result = 0.0; + for (int i = 0; i < sampleCount; i++) + { + result += S[i]*W[i+offset]; + } + return result; +} + +// +// Apply filter for vec2 samples S, using weights W. +// sampleCount should be a square of a odd number in the range { 1, 3, 5, 7 } +// +vec2 mx_convolution_vec2(vec2 S[MX_MAX_SAMPLE_COUNT], float W[MX_WEIGHT_ARRAY_SIZE], int offset, int sampleCount) +{ + vec2 result = vec2(0.0); + for (int i=0; i= high) - result = 1.0; - else if (val <= low) - result = 0.0; - else - result = smoothstep(low, high, val); -} +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/MaterialX/libraries/stdlib/genglsl/mx_splitlr_float.glsl b/MaterialX/libraries/stdlib/genglsl/mx_splitlr_float.glsl old mode 100644 new mode 100755 index 7331c48..3ccba94 --- a/MaterialX/libraries/stdlib/genglsl/mx_splitlr_float.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_splitlr_float.glsl @@ -1,6 +1,6 @@ -#include "mx_aastep.glsl" - -void mx_splitlr_float(float valuel, float valuer, float center, vec2 texcoord, out float result) -{ - result = mix(valuel, valuer, mx_aastep(center, texcoord.x)); -} +#include "mx_aastep.glsl" + +void mx_splitlr_float(float valuel, float valuer, float center, vec2 texcoord, out float result) +{ + result = mix(valuel, valuer, mx_aastep(center, texcoord.x)); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector2.glsl b/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector2.glsl old mode 100644 new mode 100755 index 820ac09..fdae214 --- a/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector2.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector2.glsl @@ -1,6 +1,6 @@ -#include "mx_aastep.glsl" - -void mx_splitlr_vector2(vec2 valuel, vec2 valuer, float center, vec2 texcoord, out vec2 result) -{ - result = mix(valuel, valuer, mx_aastep(center, texcoord.x)); -} +#include "mx_aastep.glsl" + +void mx_splitlr_vector2(vec2 valuel, vec2 valuer, float center, vec2 texcoord, out vec2 result) +{ + result = mix(valuel, valuer, mx_aastep(center, texcoord.x)); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector3.glsl b/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector3.glsl old mode 100644 new mode 100755 index 7ac28b4..0159f27 --- a/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector3.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector3.glsl @@ -1,6 +1,6 @@ -#include "mx_aastep.glsl" - -void mx_splitlr_vector3(vec3 valuel, vec3 valuer, float center, vec2 texcoord, out vec3 result) -{ - result = mix(valuel, valuer, mx_aastep(center, texcoord.x)); -} +#include "mx_aastep.glsl" + +void mx_splitlr_vector3(vec3 valuel, vec3 valuer, float center, vec2 texcoord, out vec3 result) +{ + result = mix(valuel, valuer, mx_aastep(center, texcoord.x)); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector4.glsl b/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector4.glsl old mode 100644 new mode 100755 index 7edc726..715767c --- a/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector4.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_splitlr_vector4.glsl @@ -1,6 +1,6 @@ -#include "mx_aastep.glsl" - -void mx_splitlr_vector4(vec4 valuel, vec4 valuer, float center, vec2 texcoord, out vec4 result) -{ - result = mix(valuel, valuer, mx_aastep(center, texcoord.x)); -} +#include "mx_aastep.glsl" + +void mx_splitlr_vector4(vec4 valuel, vec4 valuer, float center, vec2 texcoord, out vec4 result) +{ + result = mix(valuel, valuer, mx_aastep(center, texcoord.x)); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_splittb_float.glsl b/MaterialX/libraries/stdlib/genglsl/mx_splittb_float.glsl old mode 100644 new mode 100755 index 0f68a46..f0eea7c --- a/MaterialX/libraries/stdlib/genglsl/mx_splittb_float.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_splittb_float.glsl @@ -1,6 +1,6 @@ -#include "mx_aastep.glsl" - -void mx_splittb_float(float valuet, float valueb, float center, vec2 texcoord, out float result) -{ - result = mix(valueb, valuet, mx_aastep(center, texcoord.y)); -} +#include "mx_aastep.glsl" + +void mx_splittb_float(float valuet, float valueb, float center, vec2 texcoord, out float result) +{ + result = mix(valuet, valueb, mx_aastep(center, texcoord.y)); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector2.glsl b/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector2.glsl old mode 100644 new mode 100755 index 76ac4da..79c8654 --- a/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector2.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector2.glsl @@ -1,6 +1,6 @@ -#include "mx_aastep.glsl" - -void mx_splittb_vector2(vec2 valuet, vec2 valueb, float center, vec2 texcoord, out vec2 result) -{ - result = mix(valueb, valuet, mx_aastep(center, texcoord.y)); -} +#include "mx_aastep.glsl" + +void mx_splittb_vector2(vec2 valuet, vec2 valueb, float center, vec2 texcoord, out vec2 result) +{ + result = mix(valuet, valueb, mx_aastep(center, texcoord.y)); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector3.glsl b/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector3.glsl old mode 100644 new mode 100755 index cf13f32..1f40045 --- a/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector3.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector3.glsl @@ -1,6 +1,6 @@ -#include "mx_aastep.glsl" - -void mx_splittb_vector3(vec3 valuet, vec3 valueb, float center, vec2 texcoord, out vec3 result) -{ - result = mix(valueb, valuet, mx_aastep(center, texcoord.y)); -} +#include "mx_aastep.glsl" + +void mx_splittb_vector3(vec3 valuet, vec3 valueb, float center, vec2 texcoord, out vec3 result) +{ + result = mix(valuet, valueb, mx_aastep(center, texcoord.y)); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector4.glsl b/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector4.glsl old mode 100644 new mode 100755 index 13f5fb9..88e140f --- a/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector4.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_splittb_vector4.glsl @@ -1,6 +1,6 @@ -#include "mx_aastep.glsl" - -void mx_splittb_vector4(vec4 valuet, vec4 valueb, float center, vec2 texcoord, out vec4 result) -{ - result = mix(valueb, valuet, mx_aastep(center, texcoord.y)); -} +#include "mx_aastep.glsl" + +void mx_splittb_vector4(vec4 valuet, vec4 valueb, float center, vec2 texcoord, out vec4 result) +{ + result = mix(valuet, valueb, mx_aastep(center, texcoord.y)); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_surface_unlit.glsl b/MaterialX/libraries/stdlib/genglsl/mx_surface_unlit.glsl deleted file mode 100644 index 6adeee6..0000000 --- a/MaterialX/libraries/stdlib/genglsl/mx_surface_unlit.glsl +++ /dev/null @@ -1,6 +0,0 @@ - -void mx_surface_unlit(float emission, vec3 emission_color, float transmission, vec3 transmission_color, float opacity, out surfaceshader result) -{ - result.color = emission * emission_color * opacity; - result.transparency = mix(vec3(1.0), transmission * transmission_color, opacity); -} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_transformmatrix_vector2M3.glsl b/MaterialX/libraries/stdlib/genglsl/mx_transformmatrix_vector2M3.glsl old mode 100644 new mode 100755 index 277e33f..0d5b06f --- a/MaterialX/libraries/stdlib/genglsl/mx_transformmatrix_vector2M3.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_transformmatrix_vector2M3.glsl @@ -1,5 +1,5 @@ -void mx_transformmatrix_vector2M3(vec2 val, mat3 transform, out vec2 result) -{ - vec3 res = mx_matrix_mul(transform, vec3(val, 1.0)); - result = res.xy; -} +void mx_transformmatrix_vector2M3(vec2 val, mat3 transform, out vec2 result) +{ + vec3 res = transform * vec3(val, 1.0); + result = res.xy; +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_transformmatrix_vector3M4.glsl b/MaterialX/libraries/stdlib/genglsl/mx_transformmatrix_vector3M4.glsl old mode 100644 new mode 100755 index 3a5b64a..1284b9b --- a/MaterialX/libraries/stdlib/genglsl/mx_transformmatrix_vector3M4.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_transformmatrix_vector3M4.glsl @@ -1,5 +1,5 @@ -void mx_transformmatrix_vector3M4(vec3 val, mat4 transform, out vec3 result) -{ - vec4 res = mx_matrix_mul(transform, vec4(val, 1.0)); - result = res.xyz; -} +void mx_transformmatrix_vector3M4(vec3 val, mat4 transform, out vec3 result) +{ + vec4 res = transform * vec4(val, 1.0); + result = res.xyz; +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_unpremult_color4.glsl b/MaterialX/libraries/stdlib/genglsl/mx_unpremult_color4.glsl old mode 100644 new mode 100755 index c4503b4..b018b7d --- a/MaterialX/libraries/stdlib/genglsl/mx_unpremult_color4.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_unpremult_color4.glsl @@ -1,4 +1,4 @@ -void mx_unpremult_color4(vec4 _in, out vec4 result) -{ - result = vec4(_in.rgb / _in.a, _in.a); -} +void mx_unpremult_color4(vec4 _in, out vec4 result) +{ + result = vec4(_in.rgb / _in.a, _in.a); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_float.glsl b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_float.glsl old mode 100644 new mode 100755 index a69bc80..4e0ecf8 --- a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_float.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_float.glsl @@ -1,6 +1,6 @@ -#include "lib/mx_noise.glsl" - -void mx_worleynoise2d_float(vec2 texcoord, float jitter, int style, out float result) -{ - result = mx_worley_noise_float(texcoord, jitter, style, 0); -} +#include "lib/mx_noise.glsl" + +void mx_worleynoise2d_float(vec2 texcoord, float jitter, out float result) +{ + result = mx_worley_noise_float(texcoord, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_vector2.glsl b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_vector2.glsl old mode 100644 new mode 100755 index fca38ef..c243653 --- a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_vector2.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_vector2.glsl @@ -1,6 +1,6 @@ -#include "lib/mx_noise.glsl" - -void mx_worleynoise2d_vector2(vec2 texcoord, float jitter, int style, out vec2 result) -{ - result = mx_worley_noise_vec2(texcoord, jitter, style, 0); -} +#include "lib/mx_noise.glsl" + +void mx_worleynoise2d_vector2(vec2 texcoord, float jitter, out vec2 result) +{ + result = mx_worley_noise_vec2(texcoord, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_vector3.glsl b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_vector3.glsl old mode 100644 new mode 100755 index 2aff692..f058af8 --- a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_vector3.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise2d_vector3.glsl @@ -1,6 +1,6 @@ -#include "lib/mx_noise.glsl" - -void mx_worleynoise2d_vector3(vec2 texcoord, float jitter, int style, out vec3 result) -{ - result = mx_worley_noise_vec3(texcoord, jitter, style, 0); -} +#include "lib/mx_noise.glsl" + +void mx_worleynoise2d_vector3(vec2 texcoord, float jitter, out vec3 result) +{ + result = mx_worley_noise_vec3(texcoord, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_float.glsl b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_float.glsl old mode 100644 new mode 100755 index ad43dee..fed1312 --- a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_float.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_float.glsl @@ -1,6 +1,6 @@ -#include "lib/mx_noise.glsl" - -void mx_worleynoise3d_float(vec3 position, float jitter, int style, out float result) -{ - result = mx_worley_noise_float(position, jitter, style, 0); -} +#include "lib/mx_noise.glsl" + +void mx_worleynoise3d_float(vec3 position, float jitter, out float result) +{ + result = mx_worley_noise_float(position, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_vector2.glsl b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_vector2.glsl old mode 100644 new mode 100755 index c124d3a..e972c8c --- a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_vector2.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_vector2.glsl @@ -1,6 +1,6 @@ -#include "lib/mx_noise.glsl" - -void mx_worleynoise3d_vector2(vec3 position, float jitter, int style, out vec2 result) -{ - result = mx_worley_noise_vec2(position, jitter, style, 0); -} +#include "lib/mx_noise.glsl" + +void mx_worleynoise3d_vector2(vec3 position, float jitter, out vec2 result) +{ + result = mx_worley_noise_vec2(position, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_vector3.glsl b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_vector3.glsl old mode 100644 new mode 100755 index b960862..7d41263 --- a/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_vector3.glsl +++ b/MaterialX/libraries/stdlib/genglsl/mx_worleynoise3d_vector3.glsl @@ -1,6 +1,6 @@ -#include "lib/mx_noise.glsl" - -void mx_worleynoise3d_vector3(vec3 position, float jitter, int style, out vec3 result) -{ - result = mx_worley_noise_vec3(position, jitter, style, 0); -} +#include "lib/mx_noise.glsl" + +void mx_worleynoise3d_vector3(vec3 position, float jitter, out vec3 result) +{ + result = mx_worley_noise_vec3(position, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/MaterialX/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx old mode 100644 new mode 100755 index 2b28119..6f72e8e --- a/MaterialX/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/MaterialX/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -1,760 +1,744 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/MaterialX/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx old mode 100644 new mode 100755 index 24e0587..6724777 --- a/MaterialX/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/MaterialX/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -1,775 +1,758 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/stdlib/genmsl/lib/mx_math.metal b/MaterialX/libraries/stdlib/genmsl/lib/mx_math.metal old mode 100644 new mode 100755 index a93a3d5..665906c --- a/MaterialX/libraries/stdlib/genmsl/lib/mx_math.metal +++ b/MaterialX/libraries/stdlib/genmsl/lib/mx_math.metal @@ -1,145 +1,110 @@ -#define M_FLOAT_EPS 1e-8 - -#define mx_sin metal::sin -#define mx_cos metal::cos -#define mx_tan metal::tan -#define mx_asin metal::asin -#define mx_acos metal::acos -#define mx_float_bits_to_int as_type - -float2 mx_matrix_mul(float2 v, float2x2 m) { return v * m; } -float3 mx_matrix_mul(float3 v, float3x3 m) { return v * m; } -float4 mx_matrix_mul(float4 v, float4x4 m) { return v * m; } -float2 mx_matrix_mul(float2x2 m, float2 v) { return m * v; } -float3 mx_matrix_mul(float3x3 m, float3 v) { return m * v; } -float4 mx_matrix_mul(float4x4 m, float4 v) { return m * v; } -float2x2 mx_matrix_mul(float2x2 m1, float2x2 m2) { return m1 * m2; } -float3x3 mx_matrix_mul(float3x3 m1, float3x3 m2) { return m1 * m2; } -float4x4 mx_matrix_mul(float4x4 m1, float4x4 m2) { return m1 * m2; } - -float mx_square(float x) -{ - return x*x; -} - -float2 mx_square(float2 x) -{ - return x*x; -} - -float3 mx_square(float3 x) -{ - return x*x; -} - -float mx_inversesqrt(float x) -{ - return metal::rsqrt(x); -} - -template -T1 mx_mod(T1 x, T2 y) -{ - return x - y * floor(x/y); -} - -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]; - float n31 = m[0][2], n32 = m[1][2], n33 = m[2][2]; - - float det = metal::determinant(m); - float idet = 1.0f / det; - - float3x3 ret; - - ret[0][0] = idet * (n22 * n33 - n32 * n23); - ret[1][0] = idet * (n32 * n13 - n12 * n33); - ret[2][0] = idet * (n12 * n23 - n22 * n13); - - ret[0][1] = idet * (n31 * n23 - n21 * n33); - ret[1][1] = idet * (n11 * n33 - n31 * n13); - ret[2][1] = idet * (n21 * n13 - n11 * n23); - - ret[0][2] = idet * (n21 * n32 - n31 * n22); - ret[1][2] = idet * (n31 * n12 - n11 * n32); - ret[2][2] = idet * (n11 * n22 - n21 * n12); - - return ret; -} - -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]; - float n31 = m[0][2], n32 = m[1][2], n33 = m[2][2], n34 = m[3][2]; - float n41 = m[0][3], n42 = m[1][3], n43 = m[2][3], n44 = m[3][3]; - - float t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44; - float t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44; - float t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44; - float t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; - - float det = metal::determinant(m); - float idet = 1.0f / det; - - float4x4 ret; - - ret[0][0] = t11 * idet; - ret[0][1] = (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * idet; - ret[0][2] = (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * idet; - ret[0][3] = (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * idet; - - ret[1][0] = t12 * idet; - ret[1][1] = (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * idet; - ret[1][2] = (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * idet; - ret[1][3] = (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * idet; - - ret[2][0] = t13 * idet; - ret[2][1] = (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * idet; - ret[2][2] = (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * idet; - ret[2][3] = (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * idet; - - ret[3][0] = t14 * idet; - ret[3][1] = (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * idet; - ret[3][2] = (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * idet; - ret[3][3] = (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * idet; - - return ret; -} - -float mx_atan(float y_over_x) -{ - return metal::atan(y_over_x); -} - -float mx_atan(float y, float x) -{ - return metal::atan2(y, x); -} - -float2 mx_atan(float2 y, float2 x) -{ - return metal::atan2(y, x); -} - -float3 mx_atan(float3 y, float3 x) -{ - return metal::atan2(y, x); -} - -float4 mx_atan(float4 y, float4 x) -{ - return metal::atan2(y, x); -} - -float mx_radians(float degree) -{ - return (degree * M_PI_F / 180.0f); -} - -float2 mx_radians(float2 degree) -{ - return (degree * M_PI_F / 180.0f); -} +#define M_FLOAT_EPS 1e-8 + +float mx_square(float x) +{ + return x*x; +} + +vec2 mx_square(vec2 x) +{ + return x*x; +} + +vec3 mx_square(vec3 x) +{ + return x*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) +{ + 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]; + float n31 = m[0][2], n32 = m[1][2], n33 = m[2][2]; + + float det = determinant(m); + float idet = 1.0f / det; + + float3x3 ret; + + ret[0][0] = idet * (n22 * n33 - n32 * n23); + ret[1][0] = idet * (n32 * n13 - n12 * n33); + ret[2][0] = idet * (n12 * n23 - n22 * n13); + + ret[0][1] = idet * (n31 * n23 - n21 * n33); + ret[1][1] = idet * (n11 * n33 - n31 * n13); + ret[2][1] = idet * (n21 * n13 - n11 * n23); + + ret[0][2] = idet * (n21 * n32 - n31 * n22); + ret[1][2] = idet * (n31 * n12 - n11 * n32); + ret[2][2] = idet * (n11 * n22 - n21 * n12); + + return ret; +} + +float4x4 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]; + float n31 = m[0][2], n32 = m[1][2], n33 = m[2][2], n34 = m[3][2]; + float n41 = m[0][3], n42 = m[1][3], n43 = m[2][3], n44 = m[3][3]; + + float t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44; + float t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44; + float t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44; + float t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; + + float det = determinant(m); + float idet = 1.0f / det; + + float4x4 ret; + + ret[0][0] = t11 * idet; + ret[0][1] = (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * idet; + ret[0][2] = (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * idet; + ret[0][3] = (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * idet; + + ret[1][0] = t12 * idet; + ret[1][1] = (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * idet; + ret[1][2] = (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * idet; + ret[1][3] = (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * idet; + + ret[2][0] = t13 * idet; + ret[2][1] = (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * idet; + ret[2][2] = (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * idet; + ret[2][3] = (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * idet; + + ret[3][0] = t14 * idet; + ret[3][1] = (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * idet; + ret[3][2] = (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * idet; + ret[3][3] = (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * idet; + + return ret; +} + +template +T atan(T y_over_x) { return ::atan(y_over_x); } + +template +T atan(T y, T x) { return ::atan2(y, x); } + +template +T inversesqrt(T x) { return ::rsqrt(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)) + +#endif diff --git a/MaterialX/libraries/stdlib/genmsl/lib/mx_matscalaroperators.metal b/MaterialX/libraries/stdlib/genmsl/lib/mx_matscalaroperators.metal old mode 100644 new mode 100755 index 2b32a45..eabe0ee --- a/MaterialX/libraries/stdlib/genmsl/lib/mx_matscalaroperators.metal +++ b/MaterialX/libraries/stdlib/genmsl/lib/mx_matscalaroperators.metal @@ -1,55 +1,55 @@ -float3x3 operator+(float3x3 a, float b) -{ - return a + float3x3(b,b,b,b,b,b,b,b,b); -} - -float4x4 operator+(float4x4 a, float b) -{ - return a + float4x4(b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b); -} - -float3x3 operator-(float3x3 a, float b) -{ - return a - float3x3(b,b,b,b,b,b,b,b,b); -} - -float4x4 operator-(float4x4 a, float b) -{ - return a - float4x4(b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b); -} - -float3x3 operator/(float3x3 a, float3x3 b) -{ - for(int i = 0; i < 3; ++i) - for(int j = 0; j < 3; ++j) - a[i][j] /= b[i][j]; - - return a; -} - -float4x4 operator/(float4x4 a, float4x4 b) -{ - for(int i = 0; i < 4; ++i) - for(int j = 0; j < 4; ++j) - a[i][j] /= b[i][j]; - - return a; -} - -float3x3 operator/(float3x3 a, float b) -{ - for(int i = 0; i < 3; ++i) - for(int j = 0; j < 3; ++j) - a[i][j] /= b; - - return a; -} - -float4x4 operator/(float4x4 a, float b) -{ - for(int i = 0; i < 4; ++i) - for(int j = 0; j < 4; ++j) - a[i][j] /= b; - - return a; -} +float3x3 operator+(float3x3 a, float b) +{ + return a + float3x3(b,b,b,b,b,b,b,b,b); +} + +float4x4 operator+(float4x4 a, float b) +{ + return a + float4x4(b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b); +} + +float3x3 operator-(float3x3 a, float b) +{ + return a - float3x3(b,b,b,b,b,b,b,b,b); +} + +float4x4 operator-(float4x4 a, float b) +{ + return a - float4x4(b,b,b,b,b,b,b,b,b,b,b,b,b,b,b,b); +} + +float3x3 operator/(float3x3 a, float3x3 b) +{ + for(int i = 0; i < 3; ++i) + for(int j = 0; j < 3; ++j) + a[i][j] /= b[i][j]; + + return a; +} + +float4x4 operator/(float4x4 a, float4x4 b) +{ + for(int i = 0; i < 4; ++i) + for(int j = 0; j < 4; ++j) + a[i][j] /= b[i][j]; + + return a; +} + +float3x3 operator/(float3x3 a, float b) +{ + for(int i = 0; i < 3; ++i) + for(int j = 0; j < 3; ++j) + a[i][j] /= b; + + return a; +} + +float4x4 operator/(float4x4 a, float b) +{ + for(int i = 0; i < 4; ++i) + for(int j = 0; j < 4; ++j) + a[i][j] /= b; + + return a; +} diff --git a/MaterialX/libraries/stdlib/genmsl/lib/mx_sampling.metal b/MaterialX/libraries/stdlib/genmsl/lib/mx_sampling.metal new file mode 100755 index 0000000..74635eb --- /dev/null +++ b/MaterialX/libraries/stdlib/genmsl/lib/mx_sampling.metal @@ -0,0 +1,91 @@ +// Restrict to 7x7 kernel size for performance reasons +#define MX_MAX_SAMPLE_COUNT 49 +// Size of all weights for all levels (including level 1) +#define MX_WEIGHT_ARRAY_SIZE 84 + +// +// Function to compute the sample size relative to a texture coordinate +// +vec2 mx_compute_sample_size_uv(vec2 uv, float filterSize, float filterOffset) +{ + vec2 derivUVx = dFdx(uv) * 0.5f; + vec2 derivUVy = dFdy(uv) * 0.5f; + float derivX = abs(derivUVx.x) + abs(derivUVy.x); + float derivY = abs(derivUVx.y) + abs(derivUVy.y); + float sampleSizeU = 2.0f * filterSize * derivX + filterOffset; + if (sampleSizeU < 1.0E-05f) + sampleSizeU = 1.0E-05f; + float sampleSizeV = 2.0f * filterSize * derivY + filterOffset; + if (sampleSizeV < 1.0E-05f) + sampleSizeV = 1.0E-05f; + return vec2(sampleSizeU, sampleSizeV); +} + +// +// Compute a normal mapped to 0..1 space based on a set of input +// samples using a Sobel filter. +// +vec3 mx_normal_from_samples_sobel(constant float S[9], 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 = max(_scale, M_FLOAT_EPS) * sqrt(max(1.0 - nx * nx - ny * ny, M_FLOAT_EPS)); + vec3 norm = normalize(vec3(nx, ny, nz)); + return (norm + 1.0) * 0.5; +} + +// +// Apply filter for float samples S, using weights W. +// sampleCount should be a square of a odd number in the range { 1, 3, 5, 7 } +// +float mx_convolution_float(float S[MX_MAX_SAMPLE_COUNT], constant float W[MX_WEIGHT_ARRAY_SIZE], int offset, int sampleCount) +{ + float result = 0.0; + for (int i = 0; i < sampleCount; i++) + { + result += S[i]*W[i+offset]; + } + return result; +} + +// +// Apply filter for vec2 samples S, using weights W. +// sampleCount should be a square of a odd number in the range { 1, 3, 5, 7 } +// +vec2 mx_convolution_vec2(vec2 S[MX_MAX_SAMPLE_COUNT], constant float W[MX_WEIGHT_ARRAY_SIZE], int offset, int sampleCount) +{ + vec2 result = vec2(0.0); + for (int i=0; i tex; - sampler s; - - // needed for Storm - 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(); } -}; - -float4 texture(MetalTexture mtlTex, float2 uv) -{ - return mtlTex.tex.sample(mtlTex.s, uv); -} - -float4 textureLod(MetalTexture mtlTex, float2 uv, float lod) -{ - return mtlTex.tex.sample(mtlTex.s, uv, level(lod)); -} - -float4 textureGrad(MetalTexture mtlTex, float2 uv, float2 dx, float2 dy) -{ - return mtlTex.tex.sample(mtlTex.s, uv, gradient2d(dx, dy)); -} - -int2 textureSize(MetalTexture mtlTex, int mipLevel) -{ - return int2(mtlTex.tex.get_width(), mtlTex.tex.get_height()); -} +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); +} + +float4 textureLod(MetalTexture mtlTex, float2 uv, float lod) +{ + return mtlTex.tex.sample(mtlTex.s, uv, level(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(); +} diff --git a/MaterialX/libraries/stdlib/genmsl/mx_burn_color3.metal b/MaterialX/libraries/stdlib/genmsl/mx_burn_color3.metal new file mode 100755 index 0000000..98718a8 --- /dev/null +++ b/MaterialX/libraries/stdlib/genmsl/mx_burn_color3.metal @@ -0,0 +1,9 @@ +#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/MaterialX/libraries/stdlib/genmsl/mx_burn_color4.metal b/MaterialX/libraries/stdlib/genmsl/mx_burn_color4.metal new file mode 100755 index 0000000..959c4b1 --- /dev/null +++ b/MaterialX/libraries/stdlib/genmsl/mx_burn_color4.metal @@ -0,0 +1,10 @@ +#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/MaterialX/libraries/stdlib/genmsl/mx_burn_float.metal b/MaterialX/libraries/stdlib/genmsl/mx_burn_float.metal new file mode 100755 index 0000000..52c2cc4 --- /dev/null +++ b/MaterialX/libraries/stdlib/genmsl/mx_burn_float.metal @@ -0,0 +1,9 @@ +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/MaterialX/libraries/stdlib/genmsl/mx_dodge_color3.metal b/MaterialX/libraries/stdlib/genmsl/mx_dodge_color3.metal new file mode 100755 index 0000000..547e9b0 --- /dev/null +++ b/MaterialX/libraries/stdlib/genmsl/mx_dodge_color3.metal @@ -0,0 +1,9 @@ +#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/MaterialX/libraries/stdlib/genmsl/mx_dodge_color4.metal b/MaterialX/libraries/stdlib/genmsl/mx_dodge_color4.metal new file mode 100755 index 0000000..9f748c1 --- /dev/null +++ b/MaterialX/libraries/stdlib/genmsl/mx_dodge_color4.metal @@ -0,0 +1,10 @@ +#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/MaterialX/libraries/stdlib/genmsl/mx_dodge_float.metal b/MaterialX/libraries/stdlib/genmsl/mx_dodge_float.metal new file mode 100755 index 0000000..042a91d --- /dev/null +++ b/MaterialX/libraries/stdlib/genmsl/mx_dodge_float.metal @@ -0,0 +1,9 @@ +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/MaterialX/libraries/stdlib/genmsl/mx_normalmap.metal b/MaterialX/libraries/stdlib/genmsl/mx_normalmap.metal new file mode 100755 index 0000000..d57d906 --- /dev/null +++ b/MaterialX/libraries/stdlib/genmsl/mx_normalmap.metal @@ -0,0 +1,13 @@ +void mx_normalmap_vector2(vec3 value, vec2 normal_scale, vec3 N, vec3 T, vec3 B, out vec3 result) +{ + value = all(value == vec3(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, float normal_scale, vec3 N, vec3 T, vec3 B, out vec3 result) +{ + mx_normalmap_vector2(value, vec2(normal_scale), N, T, B, result); +} diff --git a/MaterialX/libraries/stdlib/genmsl/mx_smoothstep_float.metal b/MaterialX/libraries/stdlib/genmsl/mx_smoothstep_float.metal new file mode 100755 index 0000000..f5053f3 --- /dev/null +++ b/MaterialX/libraries/stdlib/genmsl/mx_smoothstep_float.metal @@ -0,0 +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) + result = 1.0; + else + result = smoothstep(low, high, val); +} diff --git a/MaterialX/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/MaterialX/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx old mode 100644 new mode 100755 index 4daa0b8..0f4289f --- a/MaterialX/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/MaterialX/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -1,149 +1,744 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/stdlib/genosl/include/color4.h b/MaterialX/libraries/stdlib/genosl/include/color4.h old mode 100644 new mode 100755 index 8fbdca4..a2eedc6 --- a/MaterialX/libraries/stdlib/genosl/include/color4.h +++ b/MaterialX/libraries/stdlib/genosl/include/color4.h @@ -1,332 +1,343 @@ -// Copyright Contributors to the Open Shading Language project. -// SPDX-License-Identifier: BSD-3-Clause -// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage - -#pragma once -#define COLOR4_H - - -// color4 is a color + alpha -struct color4 -{ - color rgb; - float a; -}; - - - -// -// For color4, define math operators to match color -// - -color4 __operator__neg__(color4 a) -{ - return color4(-a.rgb, -a.a); -} - -color4 __operator__add__(color4 a, color4 b) -{ - return color4(a.rgb + b.rgb, a.a + b.a); -} - -color4 __operator__add__(color4 a, int b) -{ - return a + color4(color(b), b); -} - -color4 __operator__add__(color4 a, float b) -{ - return a + color4(color(b), b); -} - -color4 __operator__add__(int a, color4 b) -{ - return color4(color(a), a) + b; -} - -color4 __operator__add__(float a, color4 b) -{ - return color4(color(a), a) + b; -} - -color4 __operator__sub__(color4 a, color4 b) -{ - return color4(a.rgb - b.rgb, a.a - b.a); -} - -color4 __operator__sub__(color4 a, int b) -{ - return a - color4(color(b), b); -} - -color4 __operator__sub__(color4 a, float b) -{ - return a - color4(color(b), b); -} - -color4 __operator__sub__(int a, color4 b) -{ - return color4(color(a), a) - b; -} - -color4 __operator__sub__(float a, color4 b) -{ - return color4(color(a), a) - b; -} - -color4 __operator__mul__(color4 a, color4 b) -{ - return color4(a.rgb * b.rgb, a.a * b.a); -} - -color4 __operator__mul__(color4 a, int b) -{ - return a * color4(color(b), b); -} - -color4 __operator__mul__(color4 a, float b) -{ - return a * color4(color(b), b); -} - -color4 __operator__mul__(int a, color4 b) -{ - return color4(color(a), a) * b; -} - -color4 __operator__mul__(float a, color4 b) -{ - return color4(color(a), a) * b; -} - -color4 __operator__div__(color4 a, color4 b) -{ - return color4(a.rgb / b.rgb, a.a / b.a); -} - -color4 __operator__div__(color4 a, int b) -{ - float b_inv = 1.0 / float(b); - return a * color4(color(b_inv), b_inv); -} - -color4 __operator__div__(color4 a, float b) -{ - float b_inv = 1.0 / b; - return a * color4(color(b_inv), b_inv); -} - -color4 __operator_div__(int a, color4 b) -{ - return color4(color(a), a) / b; -} - -color4 __operator__div__(float a, color4 b) -{ - return color4(color(a), a) / b; -} - -int __operator__eq__(color4 a, color4 b) -{ - return (a.rgb == b.rgb) && (a.a == b.a); -} - -int __operator__neq__(color4 a, color4 b) -{ - return (a.rgb != b.rgb) || (a.a != b.a); -} - - - -// -// For color4, define most of the stdosl functions to match color -// - -color4 abs(color4 a) -{ - return color4(abs(a.rgb), abs(a.a)); -} - -color4 ceil(color4 a) -{ - return color4(ceil(a.rgb), ceil(a.a)); -} - -color4 round(color4 a) -{ - return color4(round(a.rgb), round(a.a)); -} - -color4 floor(color4 a) -{ - return color4(floor(a.rgb), floor(a.a)); -} - -color4 sqrt(color4 a) -{ - return color4(sqrt(a.rgb), sqrt(a.a)); -} - -color4 exp(color4 a) -{ - return color4(exp(a.rgb), exp(a.a)); -} - -color4 log(color4 a) -{ - return color4(log(a.rgb), log(a.a)); -} - -color4 log2(color4 a) -{ - return color4(log2(a.rgb), log2(a.a)); -} - -color4 mix(color4 a, color4 b, float x ) -{ - return color4(mix(a.rgb, b.rgb, x), - mix(a.a, b.a, x)); -} - -color4 mix(color4 a, color4 b, color4 x ) -{ - return color4(mix(a.rgb, b.rgb, x.rgb), - mix(a.a, b.a, x.a)); -} - -color4 smoothstep(color4 edge0, color4 edge1, color4 c) -{ - return color4(smoothstep(edge0.rgb, edge1.rgb, c.rgb), - smoothstep(edge0.a, edge1.a, c.a)); -} - -color4 smoothstep(float edge0, float edge1, color4 c) -{ - return smoothstep(color4(color(edge0), edge0), color4(color(edge1), edge1), c); -} - -color4 clamp(color4 c, color4 minval, color4 maxval) -{ - return color4(clamp(c.rgb, minval.rgb, maxval.rgb), - clamp(c.a, minval.a, maxval.a)); -} - -color4 clamp(color4 c, float minval, float maxval) -{ - return clamp(c, color4(color(minval), minval), color4(color(maxval), maxval)); -} - -color4 max(color4 a, color4 b) -{ - return color4(max(a.rgb, b.rgb), - max(a.a, b.a)); -} - -color4 max(color4 a, float b) -{ - return color4(max(a.rgb, b), - max(a.a, b)); -} - -color4 min(color4 a, color4 b) -{ - return color4(min(a.rgb, b.rgb), - min(a.a, b.a)); -} - -color4 min(color4 a, float b) -{ - return color4(min(a.rgb, b), - min(a.a, b)); -} - -color4 mod(color4 a, color4 b) -{ - return color4(mod(a.rgb, b.rgb), - mod(a.a, b.a)); -} - -color4 mod(color4 a, float b) -{ - return mod(a, color4(color(b), b)); -} - -color4 fmod(color4 a, color4 b) -{ - return color4(fmod(a.rgb, b.rgb), - fmod(a.a, b.a)); -} - -color4 fmod(color4 a, int b) -{ - return fmod(a, color4(color(b), b)); -} - -color4 fmod(color4 a, float b) -{ - return fmod(a, color4(color(b), b)); -} - -color4 pow(color4 base, color4 power) -{ - return color4(pow(base.rgb, power.rgb), pow(base.a, power.a)); -} - -color4 pow(color4 base, float power) -{ - return pow(base, color4(color(power), power)); -} - -color4 sign(color4 a) -{ - return color4(sign(a.rgb), - sign(a.a)); -} - -color4 sin(color4 a) -{ - return color4(sin(a.rgb), - sin(a.a)); -} - -color4 cos(color4 a) -{ - return color4(cos(a.rgb), - cos(a.a)); -} - -color4 tan(color4 a) -{ - return color4(tan(a.rgb), - tan(a.a)); -} - -color4 asin(color4 a) -{ - return color4(asin(a.rgb), - asin(a.a)); -} - -color4 acos(color4 a) -{ - return color4(acos(a.rgb), - acos(a.a)); -} - -color4 atan2(color4 a, float f) -{ - return color4(atan2(a.rgb, f), - atan2(a.a, f)); -} - -color4 atan2(color4 a, color4 b) -{ - return color4(atan2(a.rgb, b.rgb), - atan2(a.a, b.a)); -} - - -color4 transformc (string fromspace, string tospace, color4 C) -{ - return color4 (transformc (fromspace, tospace, C.rgb), C.a); -} +// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al. +// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE + +#pragma once +#define COLOR4_H + + +// color4 is a color + alpha +struct color4 +{ + color rgb; + float a; +}; + + + +// +// For color4, define math operators to match color +// + +color4 __operator__neg__(color4 a) +{ + return color4(-a.rgb, -a.a); +} + +color4 __operator__add__(color4 a, color4 b) +{ + return color4(a.rgb + b.rgb, a.a + b.a); +} + +color4 __operator__add__(color4 a, int b) +{ + return a + color4(color(b), b); +} + +color4 __operator__add__(color4 a, float b) +{ + return a + color4(color(b), b); +} + +color4 __operator__add__(int a, color4 b) +{ + return color4(color(a), a) + b; +} + +color4 __operator__add__(float a, color4 b) +{ + return color4(color(a), a) + b; +} + +color4 __operator__sub__(color4 a, color4 b) +{ + return color4(a.rgb - b.rgb, a.a - b.a); +} + +color4 __operator__sub__(color4 a, int b) +{ + return a - color4(color(b), b); +} + +color4 __operator__sub__(color4 a, float b) +{ + return a - color4(color(b), b); +} + +color4 __operator__sub__(int a, color4 b) +{ + return color4(color(a), a) - b; +} + +color4 __operator__sub__(float a, color4 b) +{ + return color4(color(a), a) - b; +} + +color4 __operator__mul__(color4 a, color4 b) +{ + return color4(a.rgb * b.rgb, a.a * b.a); +} + +color4 __operator__mul__(color4 a, int b) +{ + return a * color4(color(b), b); +} + +color4 __operator__mul__(color4 a, float b) +{ + return a * color4(color(b), b); +} + +color4 __operator__mul__(int a, color4 b) +{ + return color4(color(a), a) * b; +} + +color4 __operator__mul__(float a, color4 b) +{ + return color4(color(a), a) * b; +} + +color4 __operator__div__(color4 a, color4 b) +{ + return color4(a.rgb / b.rgb, a.a / b.a); +} + +color4 __operator__div__(color4 a, int b) +{ + float b_inv = 1.0/b; + return a * color4(color(b_inv), b_inv); +} + +color4 __operator__div__(color4 a, float b) +{ + float b_inv = 1.0/b; + return a * color4(color(b_inv), b_inv); +} + +color4 __operator_div__(int a, color4 b) +{ + return color4(color(a), a) / b; +} + +color4 __operator__div__(float a, color4 b) +{ + return color4(color(a), a) / b; +} + +int __operator__eq__(color4 a, color4 b) +{ + return (a.rgb == b.rgb) && (a.a == b.a); +} + +int __operator__ne__(color4 a, color4 b) +{ + return (a.rgb != b.rgb) || (a.a != b.a); +} + + + +// +// For color4, define most of the stdosl functions to match color +// + +color4 abs(color4 a) +{ + return color4(abs(a.rgb), abs(a.a)); +} + +color4 ceil(color4 a) +{ + return color4(ceil(a.rgb), ceil(a.a)); +} + +color4 round(color4 a) +{ + return color4(round(a.rgb), round(a.a)); +} + +color4 floor(color4 a) +{ + return color4(floor(a.rgb), floor(a.a)); +} + +color4 sqrt(color4 a) +{ + return color4(sqrt(a.rgb), sqrt(a.a)); +} + +color4 exp(color4 a) +{ + return color4(exp(a.rgb), exp(a.a)); +} + +color4 log(color4 a) +{ + return color4(log(a.rgb), log(a.a)); +} + +color4 log2(color4 a) +{ + return color4(log2(a.rgb), log2(a.a)); +} + +color4 mix(color4 a, color4 b, float x ) +{ + return color4(mix(a.rgb, b.rgb, x), + mix(a.a, b.a, x)); +} + +color4 mix(color4 a, color4 b, color4 x ) +{ + return color4(mix(a.rgb, b.rgb, x.rgb), + mix(a.a, b.a, x.a)); +} + +float dot(color4 a, color b) +{ + return dot(a.rgb, b); +} + +color4 smoothstep(color4 edge0, color4 edge1, color4 c) +{ + return color4(smoothstep(edge0.rgb, edge1.rgb, c.rgb), + smoothstep(edge0.a, edge1.a, c.a)); +} + +color4 smoothstep(float edge0, float edge1, color4 c) +{ + return smoothstep(color4(color(edge0), edge0), color4(color(edge1), edge1), c); +} + +color4 clamp(color4 c, color4 minval, color4 maxval) +{ + return color4(clamp(c.rgb, minval.rgb, maxval.rgb), + clamp(c.a, minval.a, maxval.a)); +} + +color4 clamp(color4 c, float minval, float maxval) +{ + return clamp(c, color4(color(minval), minval), color4(color(maxval), maxval)); +} + +color4 max(color4 a, color4 b) +{ + return color4(max(a.rgb, b.rgb), + max(a.a, b.a)); +} + +color4 max(color4 a, float b) +{ + return color4(max(a.rgb, b), + max(a.a, b)); +} + +color4 min(color4 a, color4 b) +{ + return color4(min(a.rgb, b.rgb), + min(a.a, b.a)); +} + +color4 min(color4 a, float b) +{ + return color4(min(a.rgb, b), + min(a.a, b)); +} + +color4 mod(color4 a, color4 b) +{ + return color4(mod(a.rgb, b.rgb), + mod(a.a, b.a)); +} + +color4 mod(color4 a, int b) +{ + return mod(a, color4(color(b), b)); +} + +color4 mod(color4 a, float b) +{ + return mod(a, color4(color(b), b)); +} + +color4 fmod(color4 a, color4 b) +{ + return color4(fmod(a.rgb, b.rgb), + fmod(a.a, b.a)); +} + +color4 fmod(color4 a, int b) +{ + return fmod(a, color4(color(b), b)); +} + +color4 fmod(color4 a, float b) +{ + return fmod(a, color4(color(b), b)); +} + +color4 pow(color4 base, color4 power) +{ + return color4(pow(base.rgb, power.rgb), + pow(base.a, power.a)); +} + +color4 pow(color4 base, float power) +{ + return color4(pow(base.rgb, power), + pow(base.a, power)); +} + +color4 sign(color4 a) +{ + return color4(sign(a.rgb), + sign(a.a)); +} + +color4 sin(color4 a) +{ + return color4(sin(a.rgb), + sin(a.a)); +} + +color4 cos(color4 a) +{ + return color4(cos(a.rgb), + cos(a.a)); +} + +color4 tan(color4 a) +{ + return color4(tan(a.rgb), + tan(a.a)); +} + +color4 asin(color4 a) +{ + return color4(asin(a.rgb), + asin(a.a)); +} + +color4 acos(color4 a) +{ + return color4(acos(a.rgb), + acos(a.a)); +} + +color4 atan2(color4 a, float f) +{ + return color4(atan2(a.rgb, f), + atan2(a.a, f)); +} + +color4 atan2(color4 a, color4 b) +{ + return color4(atan2(a.rgb, b.rgb), + atan2(a.a, b.a)); +} + + +color4 transformc (string fromspace, string tospace, color4 C) +{ + return color4 (transformc (fromspace, tospace, C.rgb), C.a); +} diff --git a/MaterialX/libraries/stdlib/genosl/include/matrix33.h b/MaterialX/libraries/stdlib/genosl/include/matrix33.h old mode 100644 new mode 100755 index e14dc28..5bf62f9 --- a/MaterialX/libraries/stdlib/genosl/include/matrix33.h +++ b/MaterialX/libraries/stdlib/genosl/include/matrix33.h @@ -1,161 +1,165 @@ -// Copyright Contributors to the Open Shading Language project. -// SPDX-License-Identifier: BSD-3-Clause -// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage - - -#pragma once -#define MATRIX33_H - - -struct matrix33 -{ - matrix m; -}; - -int isValidAs33(matrix m44) -{ - return m44[0][3] == 0 && - m44[1][3] == 0 && - m44[2][3] == 0 && - m44[3][0] == 0 && - m44[3][1] == 0 && - m44[3][2] == 0 && - m44[3][3] == 1; -} - -matrix matrix33To44 (matrix33 m33) -{ - return m33.m; -} - -// Convert an arbitrary m44 to m33 by removing the translation -//QUESTION: should we check if it's valid to represent the 4x4 as a 3x3? -matrix33 matrix44To33 (matrix m44) -{ - matrix33 m33; - m33.m = m44; - m33.m[0][3] = 0; - m33.m[1][3] = 0; - m33.m[2][3] = 0; - m33.m[3][0] = 0; - m33.m[3][1] = 0; - m33.m[3][2] = 0; - m33.m[3][3] = 1; - - return m33; -} - -matrix33 __operator__neg__(matrix33 a) -{ - matrix33 m33; - m33.m = -a.m; - return m33; -} - - -matrix33 __operator__mul__(int a, matrix33 b) -{ - matrix33 m33; - m33.m = a * b.m; - return m33; -} - -matrix33 __operator__mul__(float a, matrix33 b) -{ - matrix33 m33; - m33.m = a * b.m; - return m33; -} - -matrix33 __operator__mul__(matrix33 a, int b) -{ - matrix33 m33; - m33.m = a.m * b; - return m33; -} - -matrix33 __operator__mul__(matrix33 a, float b) -{ - matrix33 m33; - m33.m = a.m * b; - return m33; -} - -matrix33 __operator__mul__(matrix33 a, matrix33 b) -{ - matrix33 m33; - m33.m = a.m * b.m; - return m33; -} - -matrix33 __operator__div__(int a, matrix33 b) -{ - matrix33 m33; - m33.m = a / b.m; - return m33; -} - -matrix33 __operator__div__(float a, matrix33 b) -{ - matrix33 m33; - m33.m = a / b.m; - return m33; -} - -matrix33 __operator__div__(matrix33 a, int b) -{ - matrix33 m33; - m33.m = a.m / b; - return m33; -} - -matrix33 __operator__div__(matrix33 a, float b) -{ - matrix33 m33; - m33.m = a.m / b; - return m33; -} - -matrix33 __operator__div__(matrix33 a, matrix33 b) -{ - matrix33 m33; - m33.m = a.m / b.m; - return m33; -} - -int __operator__eq__(matrix33 a, matrix33 b) -{ - return a.m == b.m; -} - -int __operator__ne__(matrix33 a, matrix33 b) -{ - return a.m != b.m; -} - -float determinant (matrix33 a) -{ - return determinant(a.m); -} - -matrix33 transpose(matrix33 a) -{ - matrix33 m33; - m33.m = transpose(a.m); - return m33; -} - -point transform(matrix33 a, point b) -{ - return transform(a.m, b); -} - -vector transform(matrix33 a, vector b) -{ - return transform(a.m, b); -} - -normal transform(matrix33 a, normal b) -{ - return transform(a.m, b); -} +// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al. +// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE +// +// MaterialX specification (c) 2017 Lucasfilm Ltd. +// http://www.materialx.org/ + +#pragma once +#define MATRIX33_H + + +struct matrix33 +{ + matrix m; +}; + +int isValidAs33(matrix m44) +{ + return m44[0][3] == 0 && + m44[1][3] == 0 && + m44[2][3] == 0 && + m44[3][0] == 0 && + m44[3][1] == 0 && + m44[3][2] == 0 && + m44[3][3] == 1; +} + +matrix matrix33To44 (matrix33 m33) +{ + return m33.m; +} + +// Convert an arbitrary m44 to m33 by removing the translation +//QUESTION: should we check if it's valid to represent the 4x4 as a 3x3? +matrix33 matrix44To33 (matrix m44) +{ + matrix33 m33; + m33.m = m44; + m33.m[0][3] = 0; + m33.m[1][3] = 0; + m33.m[2][3] = 0; + m33.m[3][0] = 0; + m33.m[3][1] = 0; + m33.m[3][2] = 0; + m33.m[3][3] = 1; + + return m33; +} + +matrix33 __operator__neg__(matrix33 a) +{ + matrix33 m33; + m33.m = -a.m; + return m33; +} + + +matrix33 __operator__mul__(int a, matrix33 b) +{ + matrix33 m33; + m33.m = a * b.m; + return m33; +} + +matrix33 __operator__mul__(float a, matrix33 b) +{ + matrix33 m33; + m33.m = a * b.m; + return m33; +} + +matrix33 __operator__mul__(matrix33 a, int b) +{ + matrix33 m33; + m33.m = a.m * b; + return m33; +} + +matrix33 __operator__mul__(matrix33 a, float b) +{ + matrix33 m33; + m33.m = a.m * b; + return m33; +} + +matrix33 __operator__mul__(matrix33 a, matrix33 b) +{ + matrix33 m33; + m33.m = a.m * b.m; + return m33; +} + +matrix33 __operator__div__(int a, matrix33 b) +{ + matrix33 m33; + m33.m = a / b.m; + return m33; +} + +matrix33 __operator__div__(float a, matrix33 b) +{ + matrix33 m33; + m33.m = a / b.m; + return m33; +} + +matrix33 __operator__div__(matrix33 a, int b) +{ + matrix33 m33; + m33.m = a.m / b; + return m33; +} + +matrix33 __operator__div__(matrix33 a, float b) +{ + matrix33 m33; + m33.m = a.m / b; + return m33; +} + +matrix33 __operator__div__(matrix33 a, matrix33 b) +{ + matrix33 m33; + m33.m = a.m / b.m; + return m33; +} + +int __operator__eq__(matrix33 a, matrix33 b) +{ + return a.m == b.m; +} + +int __operator__ne__(matrix33 a, matrix33 b) +{ + return a.m != b.m; +} + +float determinant (matrix33 a) +{ + return determinant(a.m); +} + +matrix33 transpose(matrix33 a) +{ + matrix33 m33; + m33.m = transpose(a.m); + return m33; +} + +point transform(matrix33 a, point b) +{ + return transform(a.m, b); +} + +vector transform(matrix33 a, vector b) +{ + return transform(a.m, b); +} + +normal transform(matrix33 a, normal b) +{ + return transform(a.m, b); +} + + + diff --git a/MaterialX/libraries/stdlib/genosl/include/mx_funcs.h b/MaterialX/libraries/stdlib/genosl/include/mx_funcs.h old mode 100644 new mode 100755 index e1c4e11..5d3e99e --- a/MaterialX/libraries/stdlib/genosl/include/mx_funcs.h +++ b/MaterialX/libraries/stdlib/genosl/include/mx_funcs.h @@ -1,724 +1,564 @@ -// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al. -// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE -// -// MaterialX specification (c) 2017 Lucasfilm Ltd. -// http://www.materialx.org/ - -#pragma once - -#include "color4.h" -#include "vector2.h" -#include "vector4.h" -#include "matrix33.h" - -// -// Support functions for OSL implementations of the MaterialX nodes. -// - -float mx_ternary(int expr, float v1, float v2) { if (expr) return v1; else return v2; } -int mx_ternary(int expr, int v1, int v2) { if (expr) return v1; else return v2; } -color mx_ternary(int expr, color v1, color v2) { if (expr) return v1; else return v2; } -color4 mx_ternary(int expr, color4 v1, color4 v2) { if (expr) return v1; else return v2; } -vector mx_ternary(int expr, vector v1, vector v2) { if (expr) return v1; else return v2; } -vector2 mx_ternary(int expr, vector2 v1, vector2 v2) { if (expr) return v1; else return v2; } -vector4 mx_ternary(int expr, vector4 v1, vector4 v2) { if (expr) return v1; else return v2; } -matrix mx_ternary(int expr, matrix v1, matrix v2) { if (expr) return v1; else return v2; } -matrix33 mx_ternary(int expr, matrix33 v1, matrix33 v2) { if (expr) return v1; else return v2; } - - -matrix33 mx_add(matrix33 a, matrix33 b) -{ - return matrix33(matrix( - a.m[0][0]+b.m[0][0], a.m[0][1]+b.m[0][1], a.m[0][2]+b.m[0][2], 0.0, - a.m[1][0]+b.m[1][0], a.m[1][1]+b.m[1][1], a.m[1][2]+b.m[1][2], 0.0, - a.m[2][0]+b.m[2][0], a.m[2][1]+b.m[2][1], a.m[2][2]+b.m[2][2], 0.0, - 0.0, 0.0, 0.0, 1.0)); -} - -matrix33 mx_add(matrix33 a, float b) -{ - return matrix33(matrix( - a.m[0][0]+b, a.m[0][1]+b, a.m[0][2]+b, 0.0, - a.m[1][0]+b, a.m[1][1]+b, a.m[1][2]+b, 0.0, - a.m[2][0]+b, a.m[2][1]+b, a.m[2][2]+b, 0.0, - 0.0, 0.0, 0.0, 1.0)); -} - -matrix mx_add(matrix a, matrix b) -{ - return matrix( - a[0][0]+b[0][0], a[0][1]+b[0][1], a[0][2]+b[0][2], a[0][3]+b[0][3], - a[1][0]+b[1][0], a[1][1]+b[1][1], a[1][2]+b[1][2], a[1][3]+b[1][3], - a[2][0]+b[2][0], a[2][1]+b[2][1], a[2][2]+b[2][2], a[2][3]+b[2][3], - a[3][0]+b[3][0], a[3][1]+b[3][1], a[3][2]+b[3][2], a[3][3]+b[3][3]); -} - -matrix mx_add(matrix a, float b) -{ - return matrix( - a[0][0]+b, a[0][1]+b, a[0][2]+b, a[0][3]+b, - a[1][0]+b, a[1][1]+b, a[1][2]+b, a[1][3]+b, - a[2][0]+b, a[2][1]+b, a[2][2]+b, a[2][3]+b, - a[3][0]+b, a[3][1]+b, a[3][2]+b, a[3][3]+b); -} - - -matrix33 mx_subtract(matrix33 a, matrix33 b) -{ - return matrix33(matrix( - a.m[0][0]-b.m[0][0], a.m[0][1]-b.m[0][1], a.m[0][2]-b.m[0][2], 0.0, - a.m[1][0]-b.m[1][0], a.m[1][1]-b.m[1][1], a.m[1][2]-b.m[1][2], 0.0, - a.m[2][0]-b.m[2][0], a.m[2][1]-b.m[2][1], a.m[2][2]-b.m[2][2], 0.0, - 0.0, 0.0, 0.0, 1.0)); -} - -matrix33 mx_subtract(matrix33 a, float b) -{ - return matrix33(matrix( - a.m[0][0]-b, a.m[0][1]-b, a.m[0][2]-b, 0.0, - a.m[1][0]-b, a.m[1][1]-b, a.m[1][2]-b, 0.0, - a.m[2][0]-b, a.m[2][1]-b, a.m[2][2]-b, 0.0, - 0.0, 0.0, 0.0, 1.0)); -} - -matrix mx_subtract(matrix a, matrix b) -{ - return matrix( - a[0][0]-b[0][0], a[0][1]-b[0][1], a[0][2]-b[0][2], a[0][3]-b[0][3], - a[1][0]-b[1][0], a[1][1]-b[1][1], a[1][2]-b[1][2], a[1][3]-b[1][3], - a[2][0]-b[2][0], a[2][1]-b[2][1], a[2][2]-b[2][2], a[2][3]-b[2][3], - a[3][0]-b[3][0], a[3][1]-b[3][1], a[3][2]-b[3][2], a[3][3]-b[3][3]); -} - -matrix mx_subtract(matrix a, float b) -{ - return matrix( - a[0][0]-b, a[0][1]-b, a[0][2]-b, a[0][3]-b, - a[1][0]-b, a[1][1]-b, a[1][2]-b, a[1][3]-b, - a[2][0]-b, a[2][1]-b, a[2][2]-b, a[2][3]-b, - a[3][0]-b, a[3][1]-b, a[3][2]-b, a[3][3]-b); -} - - -float mx_extract(color in, int index) -{ - return in[index]; -} - -float mx_extract(color4 in, int index) -{ - if (index == 0) return in.rgb.r; - else if (index == 1) return in.rgb.g; - else if (index == 2) return in.rgb.b; - else return in.a; -} - -float mx_extract(vector2 in, int index) -{ - if (index == 0) return in.x; - else return in.y; -} - -float mx_extract(vector in, int index) -{ - return in[index]; -} - -float mx_extract(vector4 in, int index) -{ - if (index == 0) return in.x; - else if (index == 1) return in.y; - else if (index == 2) return in.z; - else return in.w; -} - - -float mx_remap(float in, float inLow, float inHigh, float outLow, float outHigh, int doClamp) -{ - float x = (in - inLow)/(inHigh-inLow); - if (doClamp == 1) { - x = clamp(x, 0, 1); - } - return outLow + (outHigh - outLow) * x; -} - -color mx_remap(color in, color inLow, color inHigh, color outLow, color outHigh, int doClamp) -{ - color x = (in - inLow) / (inHigh - inLow); - if (doClamp == 1) { - x = clamp(x, 0, 1); - } - return outLow + (outHigh - outLow) * x; -} - -color mx_remap(color in, float inLow, float inHigh, float outLow, float outHigh, int doClamp) -{ - color x = (in - inLow) / (inHigh - inLow); - if (doClamp == 1) { - x = clamp(x, 0, 1); - } - return outLow + (outHigh - outLow) * x; -} - -color4 mx_remap(color4 c, color4 inLow, color4 inHigh, color4 outLow, color4 outHigh, int doClamp) -{ - return color4(mx_remap(c.rgb, inLow.rgb, inHigh.rgb, outLow.rgb, outHigh.rgb, doClamp), - mx_remap(c.a, inLow.a, inHigh.a, outLow.a, outHigh.a, doClamp)); -} - -color4 mx_remap(color4 c, float inLow, float inHigh, float outLow, float outHigh, int doClamp) -{ - color4 c4_inLow = color4(color(inLow), inLow); - color4 c4_inHigh = color4(color(inHigh), inHigh); - color4 c4_outLow = color4(color(outLow), outLow); - color4 c4_outHigh = color4(color(outHigh), outHigh); - return mx_remap(c, c4_inLow, c4_inHigh, c4_outLow, c4_outHigh, doClamp); -} - -vector2 mx_remap(vector2 in, vector2 inLow, vector2 inHigh, vector2 outLow, vector2 outHigh, int doClamp) -{ - return vector2(mx_remap(in.x, inLow.x, inHigh.x, outLow.x, outHigh.x, doClamp), - mx_remap(in.y, inLow.y, inHigh.y, outLow.y, outHigh.y, doClamp)); -} - -vector2 mx_remap(vector2 in, float inLow, float inHigh, float outLow, float outHigh, int doClamp) -{ - return vector2(mx_remap(in.x, inLow, inHigh, outLow, outHigh, doClamp), - mx_remap(in.y, inLow, inHigh, outLow, outHigh, doClamp)); -} - -vector4 mx_remap(vector4 in, vector4 inLow, vector4 inHigh, vector4 outLow, vector4 outHigh, int doClamp) -{ - return vector4(mx_remap(in.x, inLow.x, inHigh.x, outLow.x, outHigh.x, doClamp), - mx_remap(in.y, inLow.y, inHigh.y, outLow.y, outHigh.y, doClamp), - mx_remap(in.z, inLow.z, inHigh.z, outLow.z, outHigh.z, doClamp), - mx_remap(in.w, inLow.w, inHigh.w, outLow.w, outHigh.w, doClamp)); -} - -vector4 mx_remap(vector4 in, float inLow, float inHigh, float outLow, float outHigh, int doClamp) -{ - return vector4(mx_remap(in.x, inLow, inHigh, outLow, outHigh, doClamp), - mx_remap(in.y, inLow, inHigh, outLow, outHigh, doClamp), - mx_remap(in.z, inLow, inHigh, outLow, outHigh, doClamp), - mx_remap(in.w, inLow, inHigh, outLow, outHigh, doClamp)); -} - - -float mx_contrast(float in, float amount, float pivot) -{ - float out = in - pivot; - out *= amount; - out += pivot; - return out; -} - -color mx_contrast(color in, color amount, color pivot) -{ - color out = in - pivot; - out *= amount; - out += pivot; - return out; -} - -color mx_contrast(color in, float amount, float pivot) -{ - color out = in - pivot; - out *= amount; - out += pivot; - return out; -} - -color4 mx_contrast(color4 c, color4 amount, color4 pivot) -{ - return color4(mx_contrast(c.rgb, amount.rgb, pivot.rgb), - mx_contrast(c.a, amount.a, pivot.a)); -} - -color4 mx_contrast(color4 c, float amount, float pivot) -{ - return mx_contrast(c, color4(color(amount), amount), color4(color(pivot), pivot)); -} - -vector2 mx_contrast(vector2 in, vector2 amount, vector2 pivot) -{ - return vector2 (mx_contrast(in.x, amount.x, pivot.x), - mx_contrast(in.y, amount.y, pivot.y)); -} - -vector2 mx_contrast(vector2 in, float amount, float pivot) -{ - return mx_contrast(in, vector2(amount, amount), vector2(pivot, pivot)); -} - -vector4 mx_contrast(vector4 in, vector4 amount, vector4 pivot) -{ - return vector4(mx_contrast(in.x, amount.x, pivot.x), - mx_contrast(in.y, amount.y, pivot.y), - mx_contrast(in.z, amount.z, pivot.z), - mx_contrast(in.w, amount.w, pivot.w)); -} - -vector4 mx_contrast(vector4 in, float amount, float pivot) -{ - return vector4(mx_contrast(in.x, amount, pivot), - mx_contrast(in.y, amount, pivot), - mx_contrast(in.z, amount, pivot), - mx_contrast(in.w, amount, pivot)); -} - - -vector2 mx_noise(string noisetype, float x, float y) -{ - color cnoise = (color) noise(noisetype, x, y); - return vector2 (cnoise[0], cnoise[1]); -} - -color4 mx_noise(string noisetype, float x, float y) -{ - color cnoise = (color) noise(noisetype, x, y); - float fnoise = (float) noise(noisetype, x + 19, y + 73); - return color4 (cnoise, fnoise); -} - -vector4 mx_noise(string noisetype, float x, float y) -{ - color cnoise = (color) noise(noisetype, x, y); - float fnoise = (float) noise(noisetype, x + 19, y + 73); - return vector4 (cnoise[0], cnoise[1], cnoise[2], fnoise); -} - -vector2 mx_noise(string noisetype, point position) -{ - color cnoise = (color) noise(noisetype, position); - return vector2 (cnoise[0], cnoise[1]); -} - -color4 mx_noise(string noisetype, point position) -{ - color cnoise = (color) noise(noisetype, position); - float fnoise = (float) noise(noisetype, position+vector(19,73,29)); - return color4 (cnoise, fnoise); -} - -vector4 mx_noise(string noisetype, point position) -{ - color cnoise = (color) noise(noisetype, position); - float fnoise = (float) noise(noisetype, position+vector(19,73,29)); - return vector4 (cnoise[0], cnoise[1], cnoise[2], fnoise); -} - -float mx_fbm(float x, float y, int octaves, float lacunarity, float diminish, string noisetype) -{ - float out = 0; - float amp = 1.0; - float xx = x; - float yy = y; - - for (int i = 0; i < octaves; i += 1) { - out += amp * noise(noisetype, xx, yy); - amp *= diminish; - xx *= lacunarity; - yy *= lacunarity; - } - return out; -} - -color mx_fbm(float x, float y, int octaves, float lacunarity, float diminish, string noisetype) -{ - color out = 0; - float amp = 1.0; - float xx = x; - float yy = y; - - for (int i = 0; i < octaves; i += 1) { - out += amp * (color)noise(noisetype, xx, yy); - amp *= diminish; - xx *= lacunarity; - yy *= lacunarity; - } - return out; -} - -vector2 mx_fbm(float x, float y, int octaves, float lacunarity, float diminish, string noisetype) -{ - return vector2((float) mx_fbm(x, y, octaves, lacunarity, diminish, noisetype), - (float) mx_fbm(x+19, y+193, octaves, lacunarity, diminish, noisetype)); -} - -color4 mx_fbm(float x, float y, int octaves, float lacunarity, float diminish, string noisetype) -{ - color c = (color) mx_fbm(x, y, octaves, lacunarity, diminish, noisetype); - float f = (float) mx_fbm(x+19, y+193, octaves, lacunarity, diminish, noisetype); - return color4 (c, f); -} - -vector4 mx_fbm(float x, float y, int octaves, float lacunarity, float diminish, string noisetype) -{ - color c = (color) mx_fbm(x, y, octaves, lacunarity, diminish, noisetype); - float f = (float) mx_fbm(x+19, y+193, octaves, lacunarity, diminish, noisetype); - return vector4 (c[0], c[1], c[2], f); -} - -float mx_fbm(point position, int octaves, float lacunarity, float diminish, string noisetype) -{ - float out = 0; - float amp = 1.0; - point p = position; - - for (int i = 0; i < octaves; i += 1) { - out += amp * noise(noisetype, p); - amp *= diminish; - p *= lacunarity; - } - return out; -} - -color mx_fbm(point position, int octaves, float lacunarity, float diminish, string noisetype) -{ - color out = 0; - float amp = 1.0; - point p = position; - - for (int i = 0; i < octaves; i += 1) { - out += amp * (color)noise(noisetype, p); - amp *= diminish; - p *= lacunarity; - } - return out; -} - -vector2 mx_fbm(point position, int octaves, float lacunarity, float diminish, string noisetype) -{ - return vector2((float) mx_fbm(position, octaves, lacunarity, diminish, noisetype), - (float) mx_fbm(position+point(19, 193, 17), octaves, lacunarity, diminish, noisetype)); -} - -color4 mx_fbm(point position, int octaves, float lacunarity, float diminish, string noisetype) -{ - color c = (color) mx_fbm(position, octaves, lacunarity, diminish, noisetype); - float f = (float) mx_fbm(position+point(19, 193, 17), octaves, lacunarity, diminish, noisetype); - return color4 (c, f); -} - -vector4 mx_fbm(point position, int octaves, float lacunarity, float diminish, string noisetype) -{ - color c = (color) mx_fbm(position, octaves, lacunarity, diminish, noisetype); - float f = (float) mx_fbm(position+point(19, 193, 17), octaves, lacunarity, diminish, noisetype); - return vector4 (c[0], c[1], c[2], f); -} - -vector2 mx_worley_cell_position(int x, int y, int xoff, int yoff, float jitter) -{ - vector tmp = cellnoise(x+xoff, y+yoff); - vector2 off = vector2(tmp.x, tmp.y); - off -= 0.5; - off *= jitter; - off += 0.5; - return vector2(x, y) + off; -} - -vector mx_worley_cell_position(int x, int y, int z, int xoff, int yoff, int zoff, float jitter) -{ - vector off = cellnoise(vector(x+xoff, y+yoff, z+zoff)); - off -= 0.5; - off *= jitter; - off += 0.5; - return vector(x,y,z) + off; -} - -float mx_worley_distance(vector2 p, int x, int y, int X, int Y, float jitter, int metric) -{ - vector2 cellpos = mx_worley_cell_position(x,y,X,Y,jitter); - vector2 diff = cellpos - p; - - if (metric == 2) - return abs(diff.x) + abs(diff.y); // Manhattan distance - if (metric == 3) - return max(abs(diff.x), abs(diff.y)); // Chebyshev distance - return diff.x*diff.x + diff.y*diff.y; // Euclidean or distance^2 -} - -float mx_worley_distance(vector p, int x, int y, int z, int X, int Y, int Z, float jitter, int metric) -{ - vector cellpos = mx_worley_cell_position(x,y,z,X,Y,Z,jitter); - vector diff = cellpos - p; - if (metric == 2) - return abs(diff[0]) + abs(diff[1]); // Manhattan distance - if (metric == 3) - return max(abs(diff[0]), abs(diff[1])); // Chebyshev distance - return dot(diff, diff); // Eucldean or distance^2 -} - -void mx_sort_distance(float dist, output vector2 result) -{ - if (dist < result.x) - { - result.y = result.x; - result.x = dist; - } - else if (dist < result.y) - { - result.y = dist; - } -} - -void mx_sort_distance(float dist, output vector result) -{ - if (dist < result[0]) - { - result[2] = result[1]; - result[1] = result[0]; - result[0] = dist; - } - else if (dist < result[1]) - { - result[2] = result[1]; - result[1] = dist; - } - else if (dist < result[2]) - { - result[2] = dist; - } -} - -// return floor as well as the fractional remainder -float mx_floorfrac(float x, output int i) -{ - i = (int)floor(x); - return x - float(i); -} - -float mx_worley_noise_float(vector2 p, float jitter, int style, int metric) -{ - int X, Y; - float sqdist = 1e6; - vector2 localpos = vector2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); - vector2 minpos = vector2(0.0, 0.0); - - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); - vector2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; - if (dist < sqdist) - { - sqdist = dist; - minpos = cellpos; - } - } - } - if (style == 1) - { - vector2 tmpP = minpos + p; - return cellnoise(tmpP.x, tmpP.y); - } - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} - -vector2 mx_worley_noise_vector2(vector2 p, float jitter, int style, int metric) -{ - int X, Y; - vector2 sqdist = vector2(1e6, 1e6); - vector2 localpos = vector2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); - vector2 minpos = vector2(0.0, 0.0); - - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); - vector2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; - if (dist < sqdist.x) - { - sqdist.y = sqdist.x; - sqdist.x = dist; - minpos = cellpos; - } - else if (dist < sqdist.y) - { - sqdist.y = dist; - } - } - } - - if (style == 1) - { - vector2 tmpP = minpos + p; - vector tmp = cellnoise(tmpP.x, tmpP.y); - return vector2(tmp.x, tmp.y); - } - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} - -vector mx_worley_noise_vector3(vector2 p, float jitter, int style, int metric) -{ - int X, Y; - vector sqdist = vector(1e6, 1e6, 1e6); - vector2 localpos = vector2(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y)); - vector2 minpos = vector2(0.0, 0.0); - - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - float dist = mx_worley_distance(localpos, x, y, X, Y, jitter, metric); - vector2 cellpos = mx_worley_cell_position(x, y, X, Y, jitter) - localpos; - if (dist < sqdist.x) - { - sqdist.z = sqdist.y; - sqdist.y = sqdist.x; - sqdist.x = dist; - minpos = cellpos; - } - else if (dist < sqdist.y) - { - sqdist.z = sqdist.y; - sqdist.y = dist; - } - else if (dist < sqdist.z) - { - sqdist.z = dist; - } - } - } - if (style == 1) - { - vector2 tmpP = minpos + p; - return cellnoise(tmpP.x, tmpP.y); - } - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} - -float mx_worley_noise_float(vector p, float jitter, int style, int metric) -{ - int X, Y, Z; - vector seed = p; - float sqdist = 1e6; - vector localpos = vector(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); - vector minpos = vector(0.0, 0.0, 0.0); - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - for (int z = -1; z <= 1; ++z) - { - float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); - vector cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; - if(dist < sqdist) - { - sqdist = dist; - minpos = cellpos; - } - } - } - } - if (style == 1) - return cellnoise(minpos + p); - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} - -vector2 mx_worley_noise_vector2(vector p, float jitter, int style, int metric) -{ - int X, Y, Z; - vector2 sqdist = vector2(1e6, 1e6); - vector localpos = vector(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); - vector minpos = vector(0.0, 0.0, 0.0); - - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - for (int z = -1; z <= 1; ++z) - { - float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); - vector cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; - if (dist < sqdist.x) - { - sqdist.y = sqdist.x; - sqdist.x = dist; - minpos = cellpos; - } - else if (dist < sqdist.y) - { - sqdist.y = dist; - } - } - } - } - if (style == 1) - { - vector tmp = cellnoise(minpos + p); - return vector2(tmp.x,tmp.y); - } - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} - -vector mx_worley_noise_vector3(vector p, float jitter, int style, int metric) -{ - int X, Y, Z; - vector sqdist = 1e6; - vector localpos = vector(mx_floorfrac(p.x, X), mx_floorfrac(p.y, Y), mx_floorfrac(p.z, Z)); - vector minpos = vector(0.0, 0.0, 0.0); - - for (int x = -1; x <= 1; ++x) - { - for (int y = -1; y <= 1; ++y) - { - for (int z = -1; z <= 1; ++z) - { - float dist = mx_worley_distance(localpos, x, y, z, X, Y, Z, jitter, metric); - vector cellpos = mx_worley_cell_position(x, y, z, X, Y, Z, jitter) - localpos; - if (dist < sqdist.x) - { - sqdist.z = sqdist.y; - sqdist.y = sqdist.x; - sqdist.x = dist; - minpos = cellpos; - } - else if (dist < sqdist.y) - { - sqdist.z = sqdist.y; - sqdist.y = dist; - } - else if (dist < sqdist.z) - { - sqdist.z = dist; - } - } - } - } - if (style == 1) - return cellnoise(minpos + p); - else - { - if (metric == 0) - sqdist = sqrt(sqdist); - return sqdist; - } -} +// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al. +// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE +// +// MaterialX specification (c) 2017 Lucasfilm Ltd. +// http://www.materialx.org/ + +#pragma once + +#include "color4.h" +#include "vector2.h" +#include "vector4.h" +#include "matrix33.h" + +// +// Support functions for OSL implementations of the MaterialX nodes. +// + +float mx_ternary(int expr, float v1, float v2) { if (expr) return v1; else return v2; } +int mx_ternary(int expr, int v1, int v2) { if (expr) return v1; else return v2; } +color mx_ternary(int expr, color v1, color v2) { if (expr) return v1; else return v2; } +color4 mx_ternary(int expr, color4 v1, color4 v2) { if (expr) return v1; else return v2; } +vector mx_ternary(int expr, vector v1, vector v2) { if (expr) return v1; else return v2; } +vector2 mx_ternary(int expr, vector2 v1, vector2 v2) { if (expr) return v1; else return v2; } +vector4 mx_ternary(int expr, vector4 v1, vector4 v2) { if (expr) return v1; else return v2; } +matrix mx_ternary(int expr, matrix v1, matrix v2) { if (expr) return v1; else return v2; } +matrix33 mx_ternary(int expr, matrix33 v1, matrix33 v2) { if (expr) return v1; else return v2; } + + +matrix33 mx_add(matrix33 a, matrix33 b) +{ + return matrix33(matrix( + a.m[0][0]+b.m[0][0], a.m[0][1]+b.m[0][1], a.m[0][2]+b.m[0][2], 0.0, + a.m[1][0]+b.m[1][0], a.m[1][1]+b.m[1][1], a.m[1][2]+b.m[1][2], 0.0, + a.m[2][0]+b.m[2][0], a.m[2][1]+b.m[2][1], a.m[2][2]+b.m[2][2], 0.0, + 0.0, 0.0, 0.0, 1.0)); +} + +matrix33 mx_add(matrix33 a, float b) +{ + return matrix33(matrix( + a.m[0][0]+b, a.m[0][1]+b, a.m[0][2]+b, 0.0, + a.m[1][0]+b, a.m[1][1]+b, a.m[1][2]+b, 0.0, + a.m[2][0]+b, a.m[2][1]+b, a.m[2][2]+b, 0.0, + 0.0, 0.0, 0.0, 1.0)); +} + +matrix mx_add(matrix a, matrix b) +{ + return matrix( + a[0][0]+b[0][0], a[0][1]+b[0][1], a[0][2]+b[0][2], a[0][3]+b[0][3], + a[1][0]+b[1][0], a[1][1]+b[1][1], a[1][2]+b[1][2], a[1][3]+b[1][3], + a[2][0]+b[2][0], a[2][1]+b[2][1], a[2][2]+b[2][2], a[2][3]+b[2][3], + a[3][0]+b[3][0], a[3][1]+b[3][1], a[3][2]+b[3][2], a[3][3]+b[3][3]); +} + +matrix mx_add(matrix a, float b) +{ + return matrix( + a[0][0]+b, a[0][1]+b, a[0][2]+b, a[0][3]+b, + a[1][0]+b, a[1][1]+b, a[1][2]+b, a[1][3]+b, + a[2][0]+b, a[2][1]+b, a[2][2]+b, a[2][3]+b, + a[3][0]+b, a[3][1]+b, a[3][2]+b, a[3][3]+b); +} + + +matrix33 mx_subtract(matrix33 a, matrix33 b) +{ + return matrix33(matrix( + a.m[0][0]-b.m[0][0], a.m[0][1]-b.m[0][1], a.m[0][2]-b.m[0][2], 0.0, + a.m[1][0]-b.m[1][0], a.m[1][1]-b.m[1][1], a.m[1][2]-b.m[1][2], 0.0, + a.m[2][0]-b.m[2][0], a.m[2][1]-b.m[2][1], a.m[2][2]-b.m[2][2], 0.0, + 0.0, 0.0, 0.0, 1.0)); +} + +matrix33 mx_subtract(matrix33 a, float b) +{ + return matrix33(matrix( + a.m[0][0]-b, a.m[0][1]-b, a.m[0][2]-b, 0.0, + a.m[1][0]-b, a.m[1][1]-b, a.m[1][2]-b, 0.0, + a.m[2][0]-b, a.m[2][1]-b, a.m[2][2]-b, 0.0, + 0.0, 0.0, 0.0, 1.0)); +} + +matrix mx_subtract(matrix a, matrix b) +{ + return matrix( + a[0][0]-b[0][0], a[0][1]-b[0][1], a[0][2]-b[0][2], a[0][3]-b[0][3], + a[1][0]-b[1][0], a[1][1]-b[1][1], a[1][2]-b[1][2], a[1][3]-b[1][3], + a[2][0]-b[2][0], a[2][1]-b[2][1], a[2][2]-b[2][2], a[2][3]-b[2][3], + a[3][0]-b[3][0], a[3][1]-b[3][1], a[3][2]-b[3][2], a[3][3]-b[3][3]); +} + +matrix mx_subtract(matrix a, float b) +{ + return matrix( + a[0][0]-b, a[0][1]-b, a[0][2]-b, a[0][3]-b, + a[1][0]-b, a[1][1]-b, a[1][2]-b, a[1][3]-b, + a[2][0]-b, a[2][1]-b, a[2][2]-b, a[2][3]-b, + a[3][0]-b, a[3][1]-b, a[3][2]-b, a[3][3]-b); +} + + +float mx_extract(color in, int index) +{ + return in[index]; +} + +float mx_extract(color4 in, int index) +{ + if (index == 0) return in.rgb.r; + else if (index == 1) return in.rgb.g; + else if (index == 2) return in.rgb.b; + else return in.a; +} + +float mx_extract(vector2 in, int index) +{ + if (index == 0) return in.x; + else return in.y; +} + +float mx_extract(vector in, int index) +{ + return in[index]; +} + +float mx_extract(vector4 in, int index) +{ + if (index == 0) return in.x; + else if (index == 1) return in.y; + else if (index == 2) return in.z; + else return in.w; +} + + +float mx_remap(float in, float inLow, float inHigh, float outLow, float outHigh, int doClamp) +{ + float x = (in - inLow)/(inHigh-inLow); + if (doClamp == 1) { + x = clamp(x, 0, 1); + } + return outLow + (outHigh - outLow) * x; +} + +color mx_remap(color in, color inLow, color inHigh, color outLow, color outHigh, int doClamp) +{ + color x = (in - inLow) / (inHigh - inLow); + if (doClamp == 1) { + x = clamp(x, 0, 1); + } + return outLow + (outHigh - outLow) * x; +} + +color mx_remap(color in, float inLow, float inHigh, float outLow, float outHigh, int doClamp) +{ + color x = (in - inLow) / (inHigh - inLow); + if (doClamp == 1) { + x = clamp(x, 0, 1); + } + return outLow + (outHigh - outLow) * x; +} + +color4 mx_remap(color4 c, color4 inLow, color4 inHigh, color4 outLow, color4 outHigh, int doClamp) +{ + return color4(mx_remap(c.rgb, inLow.rgb, inHigh.rgb, outLow.rgb, outHigh.rgb, doClamp), + mx_remap(c.a, inLow.a, inHigh.a, outLow.a, outHigh.a, doClamp)); +} + +color4 mx_remap(color4 c, float inLow, float inHigh, float outLow, float outHigh, int doClamp) +{ + color4 c4_inLow = color4(color(inLow), inLow); + color4 c4_inHigh = color4(color(inHigh), inHigh); + color4 c4_outLow = color4(color(outLow), outLow); + color4 c4_outHigh = color4(color(outHigh), outHigh); + return mx_remap(c, c4_inLow, c4_inHigh, c4_outLow, c4_outHigh, doClamp); +} + +vector2 mx_remap(vector2 in, vector2 inLow, vector2 inHigh, vector2 outLow, vector2 outHigh, int doClamp) +{ + return vector2(mx_remap(in.x, inLow.x, inHigh.x, outLow.x, outHigh.x, doClamp), + mx_remap(in.y, inLow.y, inHigh.y, outLow.y, outHigh.y, doClamp)); +} + +vector2 mx_remap(vector2 in, float inLow, float inHigh, float outLow, float outHigh, int doClamp) +{ + return vector2(mx_remap(in.x, inLow, inHigh, outLow, outHigh, doClamp), + mx_remap(in.y, inLow, inHigh, outLow, outHigh, doClamp)); +} + +vector4 mx_remap(vector4 in, vector4 inLow, vector4 inHigh, vector4 outLow, vector4 outHigh, int doClamp) +{ + return vector4(mx_remap(in.x, inLow.x, inHigh.x, outLow.x, outHigh.x, doClamp), + mx_remap(in.y, inLow.y, inHigh.y, outLow.y, outHigh.y, doClamp), + mx_remap(in.z, inLow.z, inHigh.z, outLow.z, outHigh.z, doClamp), + mx_remap(in.w, inLow.w, inHigh.w, outLow.w, outHigh.w, doClamp)); +} + +vector4 mx_remap(vector4 in, float inLow, float inHigh, float outLow, float outHigh, int doClamp) +{ + return vector4(mx_remap(in.x, inLow, inHigh, outLow, outHigh, doClamp), + mx_remap(in.y, inLow, inHigh, outLow, outHigh, doClamp), + mx_remap(in.z, inLow, inHigh, outLow, outHigh, doClamp), + mx_remap(in.w, inLow, inHigh, outLow, outHigh, doClamp)); +} + + +float mx_contrast(float in, float amount, float pivot) +{ + float out = in - pivot; + out *= amount; + out += pivot; + return out; +} + +color mx_contrast(color in, color amount, color pivot) +{ + color out = in - pivot; + out *= amount; + out += pivot; + return out; +} + +color mx_contrast(color in, float amount, float pivot) +{ + color out = in - pivot; + out *= amount; + out += pivot; + return out; +} + +color4 mx_contrast(color4 c, color4 amount, color4 pivot) +{ + return color4(mx_contrast(c.rgb, amount.rgb, pivot.rgb), + mx_contrast(c.a, amount.a, pivot.a)); +} + +color4 mx_contrast(color4 c, float amount, float pivot) +{ + return mx_contrast(c, color4(color(amount), amount), color4(color(pivot), pivot)); +} + +vector2 mx_contrast(vector2 in, vector2 amount, vector2 pivot) +{ + return vector2 (mx_contrast(in.x, amount.x, pivot.x), + mx_contrast(in.y, amount.y, pivot.y)); +} + +vector2 mx_contrast(vector2 in, float amount, float pivot) +{ + return mx_contrast(in, vector2(amount, amount), vector2(pivot, pivot)); +} + +vector4 mx_contrast(vector4 in, vector4 amount, vector4 pivot) +{ + return vector4(mx_contrast(in.x, amount.x, pivot.x), + mx_contrast(in.y, amount.y, pivot.y), + mx_contrast(in.z, amount.z, pivot.z), + mx_contrast(in.w, amount.w, pivot.w)); +} + +vector4 mx_contrast(vector4 in, float amount, float pivot) +{ + return vector4(mx_contrast(in.x, amount, pivot), + mx_contrast(in.y, amount, pivot), + mx_contrast(in.z, amount, pivot), + mx_contrast(in.w, amount, pivot)); +} + + +vector2 mx_noise(string noisetype, float x, float y) +{ + color cnoise = (color) noise(noisetype, x, y); + return vector2 (cnoise[0], cnoise[1]); +} + +color4 mx_noise(string noisetype, float x, float y) +{ + color cnoise = (color) noise(noisetype, x, y); + float fnoise = (float) noise(noisetype, x + 19, y + 73); + return color4 (cnoise, fnoise); +} + +vector4 mx_noise(string noisetype, float x, float y) +{ + color cnoise = (color) noise(noisetype, x, y); + float fnoise = (float) noise(noisetype, x + 19, y + 73); + return vector4 (cnoise[0], cnoise[1], cnoise[2], fnoise); +} + +vector2 mx_noise(string noisetype, point position) +{ + color cnoise = (color) noise(noisetype, position); + return vector2 (cnoise[0], cnoise[1]); +} + +color4 mx_noise(string noisetype, point position) +{ + color cnoise = (color) noise(noisetype, position); + float fnoise = (float) noise(noisetype, position+vector(19,73,29)); + return color4 (cnoise, fnoise); +} + +vector4 mx_noise(string noisetype, point position) +{ + color cnoise = (color) noise(noisetype, position); + float fnoise = (float) noise(noisetype, position+vector(19,73,29)); + return vector4 (cnoise[0], cnoise[1], cnoise[2], fnoise); +} + + +float mx_fbm(point position, int octaves, float lacunarity, float diminish, string noisetype) +{ + float out = 0; + float amp = 1.0; + point p = position; + + for (int i = 0; i < octaves; i += 1) { + out += amp * noise(noisetype, p); + amp *= diminish; + p *= lacunarity; + } + return out; +} + +color mx_fbm(point position, int octaves, float lacunarity, float diminish, string noisetype) +{ + color out = 0; + float amp = 1.0; + point p = position; + + for (int i = 0; i < octaves; i += 1) { + out += amp * (color)noise(noisetype, p); + amp *= diminish; + p *= lacunarity; + } + return out; +} + +vector2 mx_fbm(point position, int octaves, float lacunarity, float diminish, string noisetype) +{ + return vector2((float) mx_fbm(position, octaves, lacunarity, diminish, noisetype), + (float) mx_fbm(position+point(19, 193, 17), octaves, lacunarity, diminish, noisetype)); +} + +color4 mx_fbm(point position, int octaves, float lacunarity, float diminish, string noisetype) +{ + color c = (color) mx_fbm(position, octaves, lacunarity, diminish, noisetype); + float f = (float) mx_fbm(position+point(19, 193, 17), octaves, lacunarity, diminish, noisetype); + return color4 (c, f); +} + +vector4 mx_fbm(point position, int octaves, float lacunarity, float diminish, string noisetype) +{ + color c = (color) mx_fbm(position, octaves, lacunarity, diminish, noisetype); + float f = (float) mx_fbm(position+point(19, 193, 17), octaves, lacunarity, diminish, noisetype); + return vector4 (c[0], c[1], c[2], f); +} + + +void mx_split_float(output float x, output int ix) +{ + ix = int(floor(x)); + x -= ix; +} + +float mx_worley_distance(vector2 p, int x, int y, int X, int Y, float jitter, int metric) +{ + vector o = cellnoise(x+X, y+Y); + o = (o - .5)*jitter + .5; + float cposx = x + o[0]; + float cposy = y + o[1]; + float diffx = cposx - p.x; + float diffy = cposy - p.y; + + if (metric == 2) + return abs(diffx) + abs(diffy); // Manhattan distance + if (metric == 3) + return max(abs(diffx), abs(diffy)); // Chebyshev distance + return diffx*diffx + diffy*diffy; // Euclidean or distance^2 +} + +float mx_worley_distance(vector p, int x, int y, int z, int X, int Y, int Z, float jitter, int metric) +{ + vector o = cellnoise(vector(x+X, y+Y, z+Z)); + o = (o - .5)*jitter + .5; + vector cpos = vector(x, y, z) + o; + vector diff = cpos - p; + + if (metric == 2) + return abs(diff[0]) + abs(diff[1]); // Manhattan distance + if (metric == 3) + return max(abs(diff[0]), abs(diff[1])); // Chebyshev distance + return dot(diff, diff); // Eucldean or distance^2 +} + +void mx_sort_distance(float dist, output vector2 result) +{ + if (dist < result.x) + { + result.y = result.x; + result.x = dist; + } + else if (dist < result.y) + { + result.y = dist; + } +} + +void mx_sort_distance(float dist, output vector result) +{ + if (dist < result[0]) + { + result[2] = result[1]; + result[1] = result[0]; + result[0] = dist; + } + else if (dist < result[1]) + { + result[2] = result[1]; + result[1] = dist; + } + else if (dist < result[2]) + { + result[2] = dist; + } +} + +float mx_worley_noise_float(vector2 p, float jitter, int metric) +{ + int X, Y; + vector2 seed = p; + float result = 1e6; + + mx_split_float(seed.x, X); + mx_split_float(seed.y, Y); + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + float d = mx_worley_distance(seed, x, y, X, Y, jitter, metric); + result = min(result, d); + } + } + if (metric == 0) + result = sqrt(result); + return result; +} + +vector2 mx_worley_noise_vector2(vector2 p, float jitter, int metric) +{ + int X, Y; + vector2 seed = p; + vector2 result = vector2(1e6, 1e6); + + mx_split_float(seed.x, X); + mx_split_float(seed.y, Y); + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + float d = mx_worley_distance(seed, x, y, X, Y, jitter, metric); + mx_sort_distance(d, result); + } + } + if (metric == 0) + result = sqrt(result); + return result; +} + +vector mx_worley_noise_vector3(vector2 p, float jitter, int metric) +{ + int X, Y; + vector2 seed = p; + vector result = vector(1e6, 1e6, 1e6); + + mx_split_float(seed.x, X); + mx_split_float(seed.y, Y); + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + float d = mx_worley_distance(seed, x, y, X, Y, jitter, metric); + mx_sort_distance(d, result); + } + } + if (metric == 0) + result = sqrt(result); + return result; +} + +float mx_worley_noise_float(vector p, float jitter, int metric) +{ + int X, Y, Z; + vector seed = p; + float result = 1e6; + + mx_split_float(seed[0], X); + mx_split_float(seed[1], Y); + mx_split_float(seed[2], Z); + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + for (int z = -1; z <= 1; ++z) + { + float d = mx_worley_distance(seed, x, y, z, X, Y, Z, jitter, metric); + result = min(result, d); + } + } + } + if (metric == 0) + result = sqrt(result); + return result; +} + +vector2 mx_worley_noise_vector2(vector p, float jitter, int metric) +{ + int X, Y, Z; + vector seed = p; + vector2 result = vector2(1e6, 1e6); + + mx_split_float(seed[0], X); + mx_split_float(seed[1], Y); + mx_split_float(seed[2], Z); + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + for (int z = -1; z <= 1; ++z) + { + float d = mx_worley_distance(seed, x, y, z, X, Y, Z, jitter, metric); + mx_sort_distance(d, result); + } + } + } + if (metric == 0) + result = sqrt(result); + return result; +} + +vector mx_worley_noise_vector3(vector p, float jitter, int metric) +{ + int X, Y, Z; + vector result = 1e6; + vector seed = p; + + mx_split_float(seed[0], X); + mx_split_float(seed[1], Y); + mx_split_float(seed[2], Z); + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + for (int z = -1; z <= 1; ++z) + { + float d = mx_worley_distance(seed, x, y, z, X, Y, Z, jitter, metric); + mx_sort_distance(d, result); + } + } + } + if (metric == 0) + result = sqrt(result); + return result; +} diff --git a/MaterialX/libraries/stdlib/genosl/include/vector2.h b/MaterialX/libraries/stdlib/genosl/include/vector2.h old mode 100644 new mode 100755 index 54a7db0..e76d56a --- a/MaterialX/libraries/stdlib/genosl/include/vector2.h +++ b/MaterialX/libraries/stdlib/genosl/include/vector2.h @@ -1,333 +1,336 @@ -// Copyright Contributors to the Open Shading Language project. -// SPDX-License-Identifier: BSD-3-Clause -// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage - -#pragma once -#define VECTOR2_H - -// vector2 is a 2D vector -struct vector2 -{ - float x; - float y; -}; - - - -// -// For vector2, define math operators to match vector -// - -vector2 __operator__neg__(vector2 a) -{ - return vector2(-a.x, -a.y); -} - -vector2 __operator__add__(vector2 a, vector2 b) -{ - return vector2(a.x + b.x, a.y + b.y); -} - -vector2 __operator__add__(vector2 a, int b) -{ - return a + vector2(b, b); -} - -vector2 __operator__add__(vector2 a, float b) -{ - return a + vector2(b, b); -} - -vector2 __operator__add__(int a, vector2 b) -{ - return vector2(a, a) + b; -} - -vector2 __operator__add__(float a, vector2 b) -{ - return vector2(a, a) + b; -} - -vector2 __operator__sub__(vector2 a, vector2 b) -{ - return vector2(a.x - b.x, a.y - b.y); -} - -vector2 __operator__sub__(vector2 a, int b) -{ - return a - vector2(b, b); -} - -vector2 __operator__sub__(vector2 a, float b) -{ - return a - vector2(b, b); -} - -vector2 __operator__sub__(int a, vector2 b) -{ - return vector2(a, a) - b; -} - -vector2 __operator__sub__(float a, vector2 b) -{ - return vector2(a, a) - b; -} - -vector2 __operator__mul__(vector2 a, vector2 b) -{ - return vector2(a.x * b.x, a.y * b.y); -} - -vector2 __operator__mul__(vector2 a, int b) -{ - return a * vector2(b, b); -} - -vector2 __operator__mul__(vector2 a, float b) -{ - return a * vector2(b, b); -} - -vector2 __operator__mul__(int a, vector2 b) -{ - return b * vector2(a, a); -} - -vector2 __operator__mul__(float a, vector2 b) -{ - return b * vector2(a, a); -} - -vector2 __operator__div__(vector2 a, vector2 b) -{ - return vector2(a.x / b.x, a.y / b.y); -} - -vector2 __operator__div__(vector2 a, int b) -{ - float b_inv = 1.0 / float(b); - return a * vector2(b_inv, b_inv); -} - -vector2 __operator__div__(vector2 a, float b) -{ - float b_inv = 1.0 / b; - return a * vector2(b_inv, b_inv); -} - -vector2 __operator__div__(int a, vector2 b) -{ - return vector2(a, a) / b; -} - -vector2 __operator__div__(float a, vector2 b) -{ - return vector2(a, a) / b; -} - -int __operator__eq__(vector2 a, vector2 b) -{ - return (a.x == b.x) && (a.y == b.y); -} - -int __operator__neq__(vector2 a, vector2 b) -{ - return (a.x != b.x) || (a.y != b.y); -} - - - - -// -// For vector2, define most of the stdosl functions to match vector -// - -vector2 abs(vector2 a) -{ - return vector2 (abs(a.x), abs(a.y)); -} - -vector2 ceil(vector2 a) -{ - return vector2 (ceil(a.x), ceil(a.y)); -} - -vector2 round(vector2 a) -{ - return vector2 (round(a.x), round(a.y)); -} - -vector2 floor(vector2 a) -{ - return vector2 (floor(a.x), floor(a.y)); -} - -vector2 sqrt(vector2 a) -{ - return vector2 (sqrt(a.x), sqrt(a.y)); -} - -vector2 exp(vector2 a) -{ - return vector2 (exp(a.x), exp(a.y)); -} - -vector2 log(vector2 a) -{ - return vector2 (log(a.x), log(a.y)); -} - -vector2 log2(vector2 a) -{ - return vector2 (log2(a.x), log2(a.y)); -} - -vector2 mix(vector2 a, vector2 b, float x ) -{ - return vector2 (mix(a.x, b.x, x), mix(a.y, b.y, x)); -} - -vector2 mix(vector2 a, vector2 b, vector2 x ) -{ - return vector2 (mix(a.x, b.x, x.x), mix(a.y, b.y, x.y)); -} - -float dot(vector2 a, vector2 b) -{ - return (a.x * b.x + a.y * b.y); -} - -float length (vector2 a) -{ - return hypot (a.x, a.y); -} - -vector2 smoothstep(vector2 low, vector2 high, vector2 in) -{ - return vector2 (smoothstep(low.x, high.x, in.x), - smoothstep(low.y, high.y, in.y)); -} - -vector2 smoothstep(float low, float high, vector2 in) -{ - return vector2 (smoothstep(low, high, in.x), - smoothstep(low, high, in.y)); -} - -vector2 clamp(vector2 in, vector2 low, vector2 high) -{ - return vector2 (clamp(in.x, low.x, high.x), - clamp(in.y, low.y, high.y)); -} - -vector2 clamp(vector2 in, float low, float high) -{ - return clamp(in, vector2(low, low), vector2(high, high)); -} - -vector2 max(vector2 a, vector2 b) -{ - return vector2 (max(a.x, b.x), - max(a.y, b.y)); -} - -vector2 min(vector2 a, vector2 b) -{ - return vector2 (min(a.x, b.x), - min(a.y, b.y)); -} - -vector2 min(vector2 a, float b) -{ - return min(a, vector2(b, b)); -} - -vector2 max(vector2 a, float b) -{ - return max(a, vector2(b, b)); -} - -vector2 normalize(vector2 a) -{ - return a / length(a); -} - -vector2 mod(vector2 a, vector2 b) -{ - return vector2(mod(a.x, b.x), - mod(a.y, b.y)); -} - -vector2 mod(vector2 a, float b) -{ - return mod(a, vector2(b, b)); -} - -vector2 fmod(vector2 a, vector2 b) -{ - return vector2 (fmod(a.x, b.x), - fmod(a.y, b.y)); -} - -vector2 fmod(vector2 a, float b) -{ - return fmod(a, vector2(b, b)); -} - -vector2 pow(vector2 in, vector2 amount) -{ - return vector2(pow(in.x, amount.x), pow(in.y, amount.y)); -} - -vector2 pow(vector2 in, float amount) -{ - return pow(in, vector2(amount, amount)); -} - -vector2 sign(vector2 a) -{ - return vector2(sign(a.x), - sign(a.y)); -} - -vector2 sin(vector2 a) -{ - return vector2(sin(a.x), - sin(a.y)); -} - -vector2 cos(vector2 a) -{ - return vector2(cos(a.x), - cos(a.y)); -} - -vector2 tan(vector2 a) -{ - return vector2(tan(a.x), - tan(a.y)); -} - -vector2 asin(vector2 a) -{ - return vector2(asin(a.x), - asin(a.y)); -} - -vector2 acos(vector2 a) -{ - return vector2(acos(a.x), - acos(a.y)); -} - -vector2 atan2(vector2 a, float f) -{ - return vector2(atan2(a.x, f), - atan2(a.y, f)); -} - -vector2 atan2(vector2 a, vector2 b) -{ - return vector2(atan2(a.x, b.x), - atan2(a.y, b.y)); -} +// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al. +// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE + +#pragma once +#define VECTOR2_H + +// vector2 is a 2D vector +struct vector2 +{ + float x; + float y; +}; + + + +// +// For vector2, define math operators to match vector +// + +vector2 __operator__neg__(vector2 a) +{ + return vector2(-a.x, -a.y); +} + +vector2 __operator__add__(vector2 a, vector2 b) +{ + return vector2(a.x + b.x, a.y + b.y); +} + +vector2 __operator__add__(vector2 a, int b) +{ + return a + vector2(b, b); +} + +vector2 __operator__add__(vector2 a, float b) +{ + return a + vector2(b, b); +} + +vector2 __operator__add__(int a, vector2 b) +{ + return vector2(a, a) + b; +} + +vector2 __operator__add__(float a, vector2 b) +{ + return vector2(a, a) + b; +} + +vector2 __operator__sub__(vector2 a, vector2 b) +{ + return vector2(a.x - b.x, a.y - b.y); +} + +vector2 __operator__sub__(vector2 a, int b) +{ + return a - vector2(b, b); +} + +vector2 __operator__sub__(vector2 a, float b) +{ + return a - vector2(b, b); +} + +vector2 __operator__sub__(int a, vector2 b) +{ + return vector2(a, a) - b; +} + +vector2 __operator__sub__(float a, vector2 b) +{ + return vector2(a, a) - b; +} + +vector2 __operator__mul__(vector2 a, vector2 b) +{ + return vector2(a.x * b.x, a.y * b.y); +} + +vector2 __operator__mul__(vector2 a, int b) +{ + return a * vector2(b, b); +} + +vector2 __operator__mul__(vector2 a, float b) +{ + return a * vector2(b, b); +} + +vector2 __operator__mul__(int a, vector2 b) +{ + return b * vector2(a, a); +} + +vector2 __operator__mul__(float a, vector2 b) +{ + return b * vector2(a, a); +} + +vector2 __operator__div__(vector2 a, vector2 b) +{ + return vector2(a.x / b.x, a.y / b.y); +} + +vector2 __operator__div__(vector2 a, int b) +{ + float b_inv = 1.0/b; + return a * vector2(b_inv, b_inv); +} + +vector2 __operator__div__(vector2 a, float b) +{ + float b_inv = 1.0/b; + return a * vector2(b_inv, b_inv); +} + +vector2 __operator__div__(int a, vector2 b) +{ + return vector2(a, a) / b; +} + +vector2 __operator__div__(float a, vector2 b) +{ + return vector2(a, a) / b; +} + +int __operator__eq__(vector2 a, vector2 b) +{ + return (a.x == b.x) && (a.y == b.y); +} + +int __operator__ne__(vector2 a, vector2 b) +{ + return (a.x != b.x) || (a.y != b.y); +} + + + + +// +// For vector2, define most of the stdosl functions to match vector +// + +vector2 abs(vector2 a) +{ + return vector2 (abs(a.x), abs(a.y)); +} + +vector2 ceil(vector2 a) +{ + return vector2 (ceil(a.x), ceil(a.y)); +} + +vector2 round(vector2 a) +{ + return vector2 (round(a.x), round(a.y)); +} + +vector2 floor(vector2 a) +{ + return vector2 (floor(a.x), floor(a.y)); +} + +vector2 sqrt(vector2 a) +{ + return vector2 (sqrt(a.x), sqrt(a.y)); +} + +vector2 exp(vector2 a) +{ + return vector2 (exp(a.x), exp(a.y)); +} + +vector2 log(vector2 a) +{ + return vector2 (log(a.x), log(a.y)); +} + +vector2 log2(vector2 a) +{ + return vector2 (log2(a.x), log2(a.y)); +} + +vector2 mix(vector2 a, vector2 b, float x ) +{ + return vector2 (mix(a.x, b.x, x), mix(a.y, b.y, x)); +} + +vector2 mix(vector2 a, vector2 b, vector2 x ) +{ + return vector2 (mix(a.x, b.x, x.x), mix(a.y, b.y, x.y)); +} + +float dot(vector2 a, vector2 b) +{ + return (a.x * b.x + a.y * b.y); +} + +float length (vector2 a) +{ + return hypot (a.x, a.y); +} + +vector2 smoothstep(vector2 low, vector2 high, vector2 in) +{ + return vector2 (smoothstep(low.x, high.x, in.x), + smoothstep(low.y, high.y, in.y)); +} + +vector2 smoothstep(float low, float high, vector2 in) +{ + return vector2 (smoothstep(low, high, in.x), + smoothstep(low, high, in.y)); +} + +vector2 clamp(vector2 in, vector2 low, vector2 high) +{ + return vector2 (clamp(in.x, low.x, high.x), + clamp(in.y, low.y, high.y)); +} + +vector2 clamp(vector2 in, float low, float high) +{ + return clamp(in, vector2(low, low), vector2(high, high)); +} + +vector2 max(vector2 a, vector2 b) +{ + return vector2 (max(a.x, b.x), + max(a.y, b.y)); +} + +vector2 max(vector2 a, float b) +{ + return max(a, vector2(b, b)); +} + +vector2 normalize(vector2 a) +{ + return a / length(a); +} + +vector2 min(vector2 a, vector2 b) +{ + return vector2 (min(a.x, a.x), + min(b.y, b.y)); +} + +vector2 min(vector2 a, float b) +{ + return min(a, vector2(b, b)); +} + +vector2 mod(vector2 a, vector2 b) +{ + return vector2(mod(a.x, b.x), + mod(a.y, b.y)); +} + +vector2 mod(vector2 a, float b) +{ + return mod(a, vector2(b, b)); +} + +vector2 fmod(vector2 a, vector2 b) +{ + return vector2 (fmod(a.x, b.x), + fmod(a.y, b.y)); +} + +vector2 fmod(vector2 a, float b) +{ + return fmod(a, vector2(b, b)); +} + +vector2 pow(vector2 in, vector2 amount) +{ + return vector2(pow(in.x, amount.x), + pow(in.y, amount.y)); +} + +vector2 pow(vector2 in, float amount) +{ + return vector2(pow(in.x, amount), + pow(in.y, amount)); +} + +vector2 sign(vector2 a) +{ + return vector2(sign(a.x), + sign(a.y)); +} + +vector2 sin(vector2 a) +{ + return vector2(sin(a.x), + sin(a.y)); +} + +vector2 cos(vector2 a) +{ + return vector2(cos(a.x), + cos(a.y)); +} + +vector2 tan(vector2 a) +{ + return vector2(tan(a.x), + tan(a.y)); +} + +vector2 asin(vector2 a) +{ + return vector2(asin(a.x), + asin(a.y)); +} + +vector2 acos(vector2 a) +{ + return vector2(acos(a.x), + acos(a.y)); +} + +vector2 atan2(vector2 a, float f) +{ + return vector2(atan2(a.x, f), + atan2(a.y, f)); +} + +vector2 atan2(vector2 a, vector2 b) +{ + return vector2(atan2(a.x, b.x), + atan2(a.y, b.y)); +} + + diff --git a/MaterialX/libraries/stdlib/genosl/include/vector4.h b/MaterialX/libraries/stdlib/genosl/include/vector4.h old mode 100644 new mode 100755 index 2ad650a..1796761 --- a/MaterialX/libraries/stdlib/genosl/include/vector4.h +++ b/MaterialX/libraries/stdlib/genosl/include/vector4.h @@ -1,424 +1,423 @@ -// Copyright Contributors to the Open Shading Language project. -// SPDX-License-Identifier: BSD-3-Clause -// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage - -#pragma once -#define VECTOR4_H - - -// vector4 is a 4D vector -struct vector4 -{ - float x; - float y; - float z; - float w; -}; - - - -// -// For vector4, define math operators to match vector -// - -vector4 __operator__neg__(vector4 a) -{ - return vector4(-a.x, -a.y, -a.z, -a.w); -} - -vector4 __operator__add__(vector4 a, vector4 b) -{ - return vector4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); -} - -vector4 __operator__add__(vector4 a, int b) -{ - return a + vector4(b, b, b, b); -} - -vector4 __operator__add__(vector4 a, float b) -{ - return a + vector4(b, b, b, b); -} - -vector4 __operator__add__(int a, vector4 b) -{ - return vector4(a, a, a, a) + b; -} - -vector4 __operator__add__(float a, vector4 b) -{ - return vector4(a, a, a, a) + b; -} - -vector4 __operator__sub__(vector4 a, vector4 b) -{ - return vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); -} - -vector4 __operator__sub__(vector4 a, int b) -{ - return a - vector4(b, b, b, b); -} - -vector4 __operator__sub__(vector4 a, float b) -{ - return a - vector4(b, b, b, b); -} - -vector4 __operator__sub__(int a, vector4 b) -{ - return vector4(a, a, a, a) - b; -} - -vector4 __operator__sub__(float a, vector4 b) -{ - return vector4(a, a, a, a) - b; -} - -vector4 __operator__mul__(vector4 a, vector4 b) -{ - return vector4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); -} - -vector4 __operator__mul__(vector4 a, int b) -{ - return a * vector4(b, b, b, b); -} - -vector4 __operator__mul__(vector4 a, float b) -{ - return a * vector4(b, b, b, b); -} - -vector4 __operator__mul__(int a, vector4 b) -{ - return vector4(a, a, a, a) * b; -} - -vector4 __operator__mul__(float a, vector4 b) -{ - return vector4(a, a, a, a) * b; -} - -vector4 __operator__div__(vector4 a, vector4 b) -{ - return vector4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); -} - -vector4 __operator__div__(vector4 a, int b) -{ - float b_inv = 1.0 / float(b); - return a * vector4(b_inv, b_inv, b_inv, b_inv); -} - -vector4 __operator__div__(vector4 a, float b) -{ - float b_inv = 1.0 / b; - return a * vector4(b_inv, b_inv, b_inv, b_inv); -} - -vector4 __operator__div__(int a, vector4 b) -{ - return vector4(a, a, a, a) / b; -} - -vector4 __operator__div__(float a, vector4 b) -{ - return vector4(a, a, a, a) / b; -} - -int __operator__eq__(vector4 a, vector4 b) -{ - return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); -} - -int __operator__neq__(vector4 a, vector4 b) -{ - return (a.x != b.x) || (a.y != b.y) || (a.z != b.z) || (a.w != b.w); -} - - - - -// -// For vector4, define most of the stdosl functions to match vector -// - -vector4 abs(vector4 in) -{ - return vector4 (abs(in.x), - abs(in.y), - abs(in.z), - abs(in.w)); -} - -vector4 ceil(vector4 in) -{ - return vector4 (ceil(in.x), - ceil(in.y), - ceil(in.z), - ceil(in.w)); -} - -vector4 round(vector4 in) -{ - return vector4 (round(in.x), - round(in.y), - round(in.z), - round(in.w)); -} - -vector4 floor(vector4 in) -{ - return vector4 (floor(in.x), - floor(in.y), - floor(in.z), - floor(in.w)); -} - -vector4 sqrt(vector4 in) -{ - return vector4 (sqrt(in.x), - sqrt(in.y), - sqrt(in.z), - sqrt(in.w)); -} - -vector4 exp(vector4 in) -{ - return vector4 (exp(in.x), - exp(in.y), - exp(in.z), - exp(in.w)); -} - -vector4 log(vector4 in) -{ - return vector4 (log(in.x), - log(in.y), - log(in.z), - log(in.w)); -} - -vector4 log2(vector4 in) -{ - return vector4 (log2(in.x), - log2(in.y), - log2(in.z), - log2(in.w)); -} - -vector4 mix(vector4 value1, vector4 value2, float x ) -{ - return vector4 (mix( value1.x, value2.x, x), - mix( value1.y, value2.y, x), - mix( value1.z, value2.z, x), - mix( value1.w, value2.w, x)); -} - -vector4 mix(vector4 value1, vector4 value2, vector4 x ) -{ - return vector4 (mix( value1.x, value2.x, x.x), - mix( value1.y, value2.y, x.y), - mix( value1.z, value2.z, x.z), - mix( value1.w, value2.w, x.w)); -} - -vector vec4ToVec3(vector4 v) -{ - return vector(v.x, v.y, v.z) / v.w; -} - -float dot(vector4 a, vector4 b) -{ - return ((a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w)); -} - -float length (vector4 a) -{ - return sqrt (a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w); -} - -vector4 smoothstep(vector4 low, vector4 high, vector4 in) -{ - return vector4 (smoothstep(low.x, high.x, in.x), - smoothstep(low.y, high.y, in.y), - smoothstep(low.z, high.z, in.z), - smoothstep(low.w, high.w, in.w)); -} - -vector4 smoothstep(float low, float high, vector4 in) -{ - return vector4 (smoothstep(low, high, in.x), - smoothstep(low, high, in.y), - smoothstep(low, high, in.z), - smoothstep(low, high, in.w)); -} - -vector4 clamp(vector4 in, vector4 low, vector4 high) -{ - return vector4 (clamp(in.x, low.x, high.x), - clamp(in.y, low.y, high.y), - clamp(in.z, low.z, high.z), - clamp(in.w, low.w, high.w)); -} - -vector4 clamp(vector4 in, float low, float high) -{ - return vector4 (clamp(in.x, low, high), - clamp(in.y, low, high), - clamp(in.z, low, high), - clamp(in.w, low, high)); -} - -vector4 max(vector4 a, vector4 b) -{ - return vector4 (max(a.x, b.x), - max(a.y, b.y), - max(a.z, b.z), - max(a.w, b.w)); -} - -vector4 max(vector4 a, float b) -{ - return max(a, vector4(b, b, b, b)); -} - -vector4 min(vector4 a, vector4 b) -{ - return vector4 (min(a.x, b.x), - min(a.y, b.y), - min(a.z, b.z), - min(a.w, b.w)); -} - -vector4 min(vector4 a, float b) -{ - return min(a, vector4(b, b, b, b)); -} - -vector4 normalize(vector4 a) -{ - return a / length(a); -} - -vector4 mod(vector4 a, vector4 b) -{ - return vector4(mod(a.x, b.x), - mod(a.y, b.y), - mod(a.z, b.z), - mod(a.w, b.w)); -} - -vector4 mod(vector4 a, float b) -{ - return mod(a, vector4(b, b, b, b)); -} - -vector4 fmod(vector4 a, vector4 b) -{ - return vector4 (fmod(a.x, b.x), - fmod(a.y, b.y), - fmod(a.z, b.z), - fmod(a.w, b.w)); -} - -vector4 fmod(vector4 a, float b) -{ - return fmod(a, vector4(b, b, b, b)); -} - -vector4 pow(vector4 in, vector4 amount) -{ - return vector4 (pow(in.x, amount.x), - pow(in.y, amount.y), - pow(in.z, amount.z), - pow(in.w, amount.w)); -} - -vector4 pow(vector4 in, float amount) -{ - return vector4 (pow(in.x, amount), - pow(in.y, amount), - pow(in.z, amount), - pow(in.w, amount)); -} - -vector4 sign(vector4 a) -{ - return vector4(sign(a.x), - sign(a.y), - sign(a.z), - sign(a.w)); -} - -vector4 sin(vector4 a) -{ - return vector4(sin(a.x), - sin(a.y), - sin(a.z), - sin(a.w)); -} - -vector4 cos(vector4 a) -{ - return vector4(cos(a.x), - cos(a.y), - cos(a.z), - cos(a.w)); -} - -vector4 tan(vector4 a) -{ - return vector4(tan(a.x), - tan(a.y), - tan(a.z), - tan(a.w)); -} - -vector4 asin(vector4 a) -{ - return vector4(asin(a.x), - asin(a.y), - asin(a.z), - asin(a.w)); -} - -vector4 acos(vector4 a) -{ - return vector4(acos(a.x), - acos(a.y), - acos(a.z), - acos(a.w)); -} - -vector4 atan2(vector4 a, float f) -{ - return vector4(atan2(a.x, f), - atan2(a.y, f), - atan2(a.z, f), - atan2(a.w, f)); -} - -vector4 atan2(vector4 a, vector4 b) -{ - return vector4(atan2(a.x, b.x), - atan2(a.y, b.y), - atan2(a.z, b.z), - atan2(a.w, b.w)); -} - - -vector4 transform (matrix M, vector4 p) -{ - return vector4 (M[0][0]*p.x + M[1][0]*p.y + M[2][0]*p.z + M[3][0]*p.w, - M[0][1]*p.x + M[1][1]*p.y + M[2][1]*p.z + M[3][1]*p.w, - M[0][2]*p.x + M[1][2]*p.y + M[2][2]*p.z + M[3][2]*p.w, - M[0][3]*p.x + M[1][3]*p.y + M[2][3]*p.z + M[3][3]*p.w); -} - -vector4 transform (string fromspace, string tospace, vector4 p) -{ - return transform (matrix(fromspace,tospace), p); -} +// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al. +// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE + +#pragma once +#define VECTOR4_H + + +// vector4 is a 4D vector +struct vector4 +{ + float x; + float y; + float z; + float w; +}; + + + +// +// For vector4, define math operators to match vector +// + +vector4 __operator__neg__(vector4 a) +{ + return vector4(-a.x, -a.y, -a.z, -a.w); +} + +vector4 __operator__add__(vector4 a, vector4 b) +{ + return vector4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); +} + +vector4 __operator__add__(vector4 a, int b) +{ + return a + vector4(b, b, b, b); +} + +vector4 __operator__add__(vector4 a, float b) +{ + return a + vector4(b, b, b, b); +} + +vector4 __operator__add__(int a, vector4 b) +{ + return vector4(a, a, a, a) + b; +} + +vector4 __operator__add__(float a, vector4 b) +{ + return vector4(a, a, a, a) + b; +} + +vector4 __operator__sub__(vector4 a, vector4 b) +{ + return vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); +} + +vector4 __operator__sub__(vector4 a, int b) +{ + return a - vector4(b, b, b, b); +} + +vector4 __operator__sub__(vector4 a, float b) +{ + return a - vector4(b, b, b, b); +} + +vector4 __operator__sub__(int a, vector4 b) +{ + return vector4(a, a, a, a) - b; +} + +vector4 __operator__sub__(float a, vector4 b) +{ + return vector4(a, a, a, a) - b; +} + +vector4 __operator__mul__(vector4 a, vector4 b) +{ + return vector4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); +} + +vector4 __operator__mul__(vector4 a, int b) +{ + return a * vector4(b, b, b, b); +} + +vector4 __operator__mul__(vector4 a, float b) +{ + return a * vector4(b, b, b, b); +} + +vector4 __operator__mul__(int a, vector4 b) +{ + return vector4(a, a, a, a) * b; +} + +vector4 __operator__mul__(float a, vector4 b) +{ + return vector4(a, a, a, a) * b; +} + +vector4 __operator__div__(vector4 a, vector4 b) +{ + return vector4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); +} + +vector4 __operator__div__(vector4 a, int b) +{ + float b_inv = 1.0/b; + return a * vector4(b_inv, b_inv, b_inv, b_inv); +} + +vector4 __operator__div__(vector4 a, float b) +{ + float b_inv = 1.0/b; + return a * vector4(b_inv, b_inv, b_inv, b_inv); +} + +vector4 __operator__div__(int a, vector4 b) +{ + return vector4(a, a, a, a) / b; +} + +vector4 __operator__div__(float a, vector4 b) +{ + return vector4(a, a, a, a) / b; +} + +int __operator__eq__(vector4 a, vector4 b) +{ + return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); +} + +int __operator__ne__(vector4 a, vector4 b) +{ + return (a.x != b.x) || (a.y != b.y) || (a.z != b.z) || (a.w != b.w); +} + + + + +// +// For vector4, define most of the stdosl functions to match vector +// + +vector4 abs(vector4 in) +{ + return vector4 (abs(in.x), + abs(in.y), + abs(in.z), + abs(in.w)); +} + +vector4 ceil(vector4 in) +{ + return vector4 (ceil(in.x), + ceil(in.y), + ceil(in.z), + ceil(in.w)); +} + +vector4 round(vector4 in) +{ + return vector4 (round(in.x), + round(in.y), + round(in.z), + round(in.w)); +} + +vector4 floor(vector4 in) +{ + return vector4 (floor(in.x), + floor(in.y), + floor(in.z), + floor(in.w)); +} + +vector4 sqrt(vector4 in) +{ + return vector4 (sqrt(in.x), + sqrt(in.y), + sqrt(in.z), + sqrt(in.w)); +} + +vector4 exp(vector4 in) +{ + return vector4 (exp(in.x), + exp(in.y), + exp(in.z), + exp(in.w)); +} + +vector4 log(vector4 in) +{ + return vector4 (log(in.x), + log(in.y), + log(in.z), + log(in.w)); +} + +vector4 log2(vector4 in) +{ + return vector4 (log2(in.x), + log2(in.y), + log2(in.z), + log2(in.w)); +} + +vector4 mix(vector4 value1, vector4 value2, float x ) +{ + return vector4 (mix( value1.x, value2.x, x), + mix( value1.y, value2.y, x), + mix( value1.z, value2.z, x), + mix( value1.w, value2.w, x)); +} + +vector4 mix(vector4 value1, vector4 value2, vector4 x ) +{ + return vector4 (mix( value1.x, value2.x, x.x), + mix( value1.y, value2.y, x.y), + mix( value1.z, value2.z, x.z), + mix( value1.w, value2.w, x.w)); +} + +vector vec4ToVec3(vector4 v) +{ + return vector(v.x, v.y, v.z) / v.w; +} + +float dot(vector4 a, vector4 b) +{ + return ((a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w)); +} + +float length (vector4 a) +{ + return sqrt (a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w); +} + +vector4 smoothstep(vector4 low, vector4 high, vector4 in) +{ + return vector4 (smoothstep(low.x, high.x, in.x), + smoothstep(low.y, high.y, in.y), + smoothstep(low.z, high.z, in.z), + smoothstep(low.w, high.w, in.w)); +} + +vector4 smoothstep(float low, float high, vector4 in) +{ + return vector4 (smoothstep(low, high, in.x), + smoothstep(low, high, in.y), + smoothstep(low, high, in.z), + smoothstep(low, high, in.w)); +} + +vector4 clamp(vector4 in, vector4 low, vector4 high) +{ + return vector4 (clamp(in.x, low.x, high.x), + clamp(in.y, low.y, high.y), + clamp(in.z, low.z, high.z), + clamp(in.w, low.w, high.w)); +} + +vector4 clamp(vector4 in, float low, float high) +{ + return vector4 (clamp(in.x, low, high), + clamp(in.y, low, high), + clamp(in.z, low, high), + clamp(in.w, low, high)); +} + +vector4 max(vector4 a, vector4 b) +{ + return vector4 (max(a.x, b.x), + max(a.y, b.y), + max(a.z, b.z), + max(a.w, b.w)); +} + +vector4 max(vector4 a, float b) +{ + return max(a, vector4(b, b, b, b)); +} + +vector4 normalize(vector4 a) +{ + return a / length(a); +} + +vector4 min(vector4 a, vector4 b) +{ + return vector4 (min(a.x, b.x), + min(a.y, b.y), + min(a.z, b.z), + min(a.w, b.w)); +} + +vector4 min(vector4 a, float b) +{ + return min(a, vector4(b, b, b, b)); +} + +vector4 mod(vector4 a, vector4 b) +{ + return vector4(mod(a.x, b.x), + mod(a.y, b.y), + mod(a.z, b.z), + mod(a.w, b.w)); +} + +vector4 mod(vector4 a, float b) +{ + return mod(a, vector4(b, b, b, b)); +} + +vector4 fmod(vector4 a, vector4 b) +{ + return vector4 (fmod(a.x, b.x), + fmod(a.y, b.y), + fmod(a.z, b.z), + fmod(a.w, b.w)); +} + +vector4 fmod(vector4 a, float b) +{ + return fmod(a, vector4(b, b, b, b)); +} + +vector4 pow(vector4 in, vector4 amount) +{ + return vector4 (pow(in.x, amount.x), + pow(in.y, amount.y), + pow(in.z, amount.z), + pow(in.w, amount.w)); +} + +vector4 pow(vector4 in, float amount) +{ + return vector4 (pow(in.x, amount), + pow(in.y, amount), + pow(in.z, amount), + pow(in.w, amount)); +} + +vector4 sign(vector4 a) +{ + return vector4(sign(a.x), + sign(a.y), + sign(a.z), + sign(a.w)); +} + +vector4 sin(vector4 a) +{ + return vector4(sin(a.x), + sin(a.y), + sin(a.z), + sin(a.w)); +} + +vector4 cos(vector4 a) +{ + return vector4(cos(a.x), + cos(a.y), + cos(a.z), + cos(a.w)); +} + +vector4 tan(vector4 a) +{ + return vector4(tan(a.x), + tan(a.y), + tan(a.z), + tan(a.w)); +} + +vector4 asin(vector4 a) +{ + return vector4(asin(a.x), + asin(a.y), + asin(a.z), + asin(a.w)); +} + +vector4 acos(vector4 a) +{ + return vector4(acos(a.x), + acos(a.y), + acos(a.z), + acos(a.w)); +} + +vector4 atan2(vector4 a, float f) +{ + return vector4(atan2(a.x, f), + atan2(a.y, f), + atan2(a.z, f), + atan2(a.w, f)); +} + +vector4 atan2(vector4 a, vector4 b) +{ + return vector4(atan2(a.x, b.x), + atan2(a.y, b.y), + atan2(a.z, b.z), + atan2(a.w, b.w)); +} + + +vector4 transform (matrix M, vector4 p) +{ + return vector4 (M[0][0]*p.x + M[1][0]*p.y + M[2][0]*p.z + M[3][0]*p.w, + M[0][1]*p.x + M[1][1]*p.y + M[2][1]*p.z + M[3][1]*p.w, + M[0][2]*p.x + M[1][2]*p.y + M[2][2]*p.z + M[3][2]*p.w, + M[0][3]*p.x + M[1][3]*p.y + M[2][3]*p.z + M[3][3]*p.w); +} + +vector4 transform (string fromspace, string tospace, vector4 p) +{ + return transform (matrix(fromspace,tospace), p); +} diff --git a/MaterialX/libraries/stdlib/genosl/lib/mx_sampling.osl b/MaterialX/libraries/stdlib/genosl/lib/mx_sampling.osl new file mode 100755 index 0000000..de4f966 --- /dev/null +++ b/MaterialX/libraries/stdlib/genosl/lib/mx_sampling.osl @@ -0,0 +1,150 @@ +// Restrict to 7x7 kernel size for performance reasons +#define MX_MAX_SAMPLE_COUNT 49 +// Size of all weights for all levels (including level 1) +#define MX_WEIGHT_ARRAY_SIZE 84 + +// +// Function to compute the sample size relative to a texture coordinate +// +vector2 mx_compute_sample_size_uv(vector2 uv, float filterSize, float filterOffset) +{ + vector derivUVx = Dx(vector(uv.x, uv.y, 0.0)) * 0.5; + vector derivUVy = Dy(vector(uv.x, uv.y, 0.0)) * 0.5; + float derivX = abs(derivUVx[0]) + abs(derivUVy[0]); + float derivY = abs(derivUVx[1]) + abs(derivUVy[1]); + float sampleSizeU = filterSize * derivX + filterOffset; + if (sampleSizeU < 1.0E-05) + sampleSizeU = 1.0E-05; + float sampleSizeV = filterSize * derivY + filterOffset; + if (sampleSizeV < 1.0E-05) + sampleSizeV = 1.0E-05; + return vector2(sampleSizeU, sampleSizeV); +} + +// Kernel weights for box filter +void mx_get_box_weights(output float W[MX_MAX_SAMPLE_COUNT], int filterSize) +{ + int sampleCount = filterSize*filterSize; + float value = 1.0 / float(sampleCount); + for (int i=0; i= 7) + { + W[0] = 0.000036; W[1] = 0.000363; W[2] = 0.001446; W[3] = 0.002291; W[4] = 0.001446; W[5] = 0.000363; W[6] = 0.000036; + W[7] = 0.000363; W[8] = 0.003676; W[9] = 0.014662; W[10] = 0.023226; W[11] = 0.014662; W[12] = 0.003676; W[13] = 0.000363; + W[14] = 0.001446; W[15] = 0.014662; W[16] = 0.058488; W[17] = 0.092651; W[18] = 0.058488; W[19] = 0.014662; W[20] = 0.001446; + W[21] = 0.002291; W[22] = 0.023226; W[23] = 0.092651; W[24] = 0.146768; W[25] = 0.092651; W[26] = 0.023226; W[27] = 0.002291; + W[28] = 0.001446; W[29] = 0.014662; W[30] = 0.058488; W[31] = 0.092651; W[32] = 0.058488; W[33] = 0.014662; W[34] = 0.001446; + W[35] = 0.000363; W[36] = 0.003676; W[37] = 0.014662; W[38] = 0.023226; W[39] = 0.014662; W[40] = 0.003676; W[41] = 0.000363; + W[42] = 0.000036; W[43] = 0.000363; W[44] = 0.001446; W[45] = 0.002291; W[46] = 0.001446; W[47] = 0.000363; W[48] = 0.000036; + } + else if (filterSize >= 5) + { + W[0] = 0.003765; W[1] = 0.015019; W[2] = 0.023792; W[3] = 0.015019; W[4] = 0.003765; + W[5] = 0.015019; W[6] = 0.059912; W[7] = 0.094907; W[8] = 0.059912; W[9] = 0.015019; + W[10] = 0.023792; W[11] = 0.094907; W[12] = 0.150342; W[13] = 0.094907; W[14] = 0.023792; + W[15] = 0.015019; W[16] = 0.059912; W[17] = 0.094907; W[18] = 0.059912; W[19] = 0.015019; + W[20] = 0.003765; W[21] = 0.015019; W[22] = 0.023792; W[23] = 0.015019; W[24] = 0.003765; + } + else if (filterSize >= 3) + { + W[0] = 0.0625; W[1] = 0.125; W[2] = 0.0625; + W[3] = 0.125; W[4] = 0.25; W[5] = 0.125; + W[6] = 0.0625; W[7] = 0.125; W[8] = 0.0625; + } + else + { + W[0] = 1.0; + } +} + +// +// Apply filter for float samples S, using weights W. +// sampleCount should be a square of a odd number in the range { 1, 3, 5, 7 } +// +float mx_convolution_float(float S[MX_MAX_SAMPLE_COUNT], float W[MX_WEIGHT_ARRAY_SIZE], int offset, int sampleCount) +{ + float result = 0.0; + for (int i = 0; i < sampleCount; i++) + { + result += S[i]*W[i+offset]; + } + return result; +} + +// +// Apply filter for vector2 samples S, using weights W. +// sampleCount should be a square of a odd number in the range { 1, 3, 5, 7 } +// +vector2 mx_convolution_vector2(vector2 S[MX_MAX_SAMPLE_COUNT], float W[MX_WEIGHT_ARRAY_SIZE], int offset, int sampleCount) +{ + vector2 result = vector2(0.0, 0.0); + for (int i=0; i1.0)) || - (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) - { - out = default_value; - return; - } - - color missingColor = default_value; - vector2 st = mx_transform_uv(texcoord); - out = texture(file.filename, st.x, st.y, - "subimage", layer, "interp", filtertype, - "missingcolor", missingColor, - "swrap", uaddressmode, "twrap", vaddressmode -#if (OSL_VERSION_MAJOR == 1 && OSL_VERSION_MINOR >= 14) || (OSL_VERSION_MAJOR > 1) - , "colorspace", file.colorspace -#endif - ); -} +#include "lib/$fileTransformUv" + +void mx_image_color3(textureresource file, string layer, color default_value, vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, string framerange, int frameoffset, string frameendaction, output color out) +{ + if (file.filename == "" || + (uaddressmode == "constant" && (texcoord.x<0.0 || texcoord.x>1.0)) || + (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) + { + out = default_value; + return; + } + + color missingColor = default_value; + vector2 st = mx_transform_uv(texcoord); + out = texture(file.filename, st.x, st.y, "subimage", layer, "missingcolor", missingColor, "swrap", uaddressmode, "twrap", vaddressmode, "colorspace", file.colorspace); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_image_color4.osl b/MaterialX/libraries/stdlib/genosl/mx_image_color4.osl old mode 100644 new mode 100755 index 73bf978..bec5443 --- a/MaterialX/libraries/stdlib/genosl/mx_image_color4.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_image_color4.osl @@ -1,27 +1,21 @@ -#include "lib/$fileTransformUv" - -void mx_image_color4(textureresource file, string layer, color4 default_value, vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, string framerange, int frameoffset, string frameendaction, output color4 out) -{ - if (file.filename == "" || - (uaddressmode == "constant" && (texcoord.x<0.0 || texcoord.x>1.0)) || - (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) - { - out = default_value; - return; - } - - color missingColor = default_value.rgb; - float missingAlpha = default_value.a; - vector2 st = mx_transform_uv(texcoord); - float alpha; - color rgb = texture(file.filename, st.x, st.y, "alpha", alpha, - "subimage", layer, "interp", filtertype, - "missingcolor", missingColor, "missingalpha", missingAlpha, - "swrap", uaddressmode, "twrap", vaddressmode -#if (OSL_VERSION_MAJOR == 1 && OSL_VERSION_MINOR >= 14) || (OSL_VERSION_MAJOR > 1) - , "colorspace", file.colorspace -#endif - ); - - out = color4(rgb, alpha); -} +#include "lib/$fileTransformUv" + +void mx_image_color4(textureresource file, string layer, color4 default_value, vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, string framerange, int frameoffset, string frameendaction, output color4 out) +{ + if (file.filename == "" || + (uaddressmode == "constant" && (texcoord.x<0.0 || texcoord.x>1.0)) || + (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) + { + out = default_value; + return; + } + + color missingColor = default_value.rgb; + float missingAlpha = default_value.a; + vector2 st = mx_transform_uv(texcoord); + float alpha; + color rgb = texture(file.filename, st.x, st.y, "alpha", alpha, "subimage", layer, + "missingcolor", missingColor, "missingalpha", missingAlpha, "swrap", uaddressmode, "twrap", vaddressmode, "colorspace", file.colorspace); + + out = color4(rgb, alpha); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_image_float.osl b/MaterialX/libraries/stdlib/genosl/mx_image_float.osl old mode 100644 new mode 100755 index 2cdbb9f..a1dae21 --- a/MaterialX/libraries/stdlib/genosl/mx_image_float.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_image_float.osl @@ -1,20 +1,17 @@ -#include "lib/$fileTransformUv" - -void mx_image_float(textureresource file, string layer, float default_value, vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, string framerange, int frameoffset, string frameendaction, output float out) -{ - if (file.filename == "" || - (uaddressmode == "constant" && (texcoord.x<0.0 || texcoord.x>1.0)) || - (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) - { - out = default_value; - return; - } - - color missingColor = color(default_value); - vector2 st = mx_transform_uv(texcoord); - color rgb = texture(file.filename, st.x, st.y, - "subimage", layer, "interp", filtertype, - "missingcolor", missingColor, - "swrap", uaddressmode, "twrap", vaddressmode); - out = rgb[0]; -} +#include "lib/$fileTransformUv" + +void mx_image_float(textureresource file, string layer, float default_value, vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, string framerange, int frameoffset, string frameendaction, output float out) +{ + if (file.filename == "" || + (uaddressmode == "constant" && (texcoord.x<0.0 || texcoord.x>1.0)) || + (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) + { + out = default_value; + return; + } + + color missingColor = color(default_value); + vector2 st = mx_transform_uv(texcoord); + color rgb = texture(file.filename, st.x, st.y, "subimage", layer, "missingcolor", missingColor, "swrap", uaddressmode, "twrap", vaddressmode); + out = rgb[0]; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_image_vector2.osl b/MaterialX/libraries/stdlib/genosl/mx_image_vector2.osl old mode 100644 new mode 100755 index 67c1ae2..31a78a1 --- a/MaterialX/libraries/stdlib/genosl/mx_image_vector2.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_image_vector2.osl @@ -1,21 +1,18 @@ -#include "lib/$fileTransformUv" - -void mx_image_vector2(textureresource file, string layer, vector2 default_value, vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, string framerange, int frameoffset, string frameendaction, output vector2 out) -{ - if (file.filename == "" || - (uaddressmode == "constant" && (texcoord.x<0.0 || texcoord.x>1.0)) || - (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) - { - out = default_value; - return; - } - - color missingColor = color(default_value.x, default_value.y, 0.0); - vector2 st = mx_transform_uv(texcoord); - color rgb = texture(file.filename, st.x, st.y, - "subimage", layer, "interp", filtertype, - "missingcolor", missingColor, - "swrap", uaddressmode, "twrap", vaddressmode); - out.x = rgb[0]; - out.y = rgb[1]; -} +#include "lib/$fileTransformUv" + +void mx_image_vector2(textureresource file, string layer, vector2 default_value, vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, string framerange, int frameoffset, string frameendaction, output vector2 out) +{ + if (file.filename == "" || + (uaddressmode == "constant" && (texcoord.x<0.0 || texcoord.x>1.0)) || + (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) + { + out = default_value; + return; + } + + color missingColor = color(default_value.x, default_value.y, 0.0); + vector2 st = mx_transform_uv(texcoord); + color rgb = texture(file.filename, st.x, st.y, "subimage", layer, "missingcolor", missingColor, "swrap", uaddressmode, "twrap", vaddressmode); + out.x = rgb[0]; + out.y = rgb[1]; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_image_vector3.osl b/MaterialX/libraries/stdlib/genosl/mx_image_vector3.osl old mode 100644 new mode 100755 index 63f363e..ba3846d --- a/MaterialX/libraries/stdlib/genosl/mx_image_vector3.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_image_vector3.osl @@ -1,19 +1,16 @@ -#include "lib/$fileTransformUv" - -void mx_image_vector3(textureresource file, string layer, vector default_value, vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, string framerange, int frameoffset, string frameendaction, output vector out) -{ - if (file.filename == "" || - (uaddressmode == "constant" && (texcoord.x<0.0 || texcoord.x>1.0)) || - (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) - { - out = default_value; - return; - } - - color missingColor = default_value; - vector2 st = mx_transform_uv(texcoord); - out = texture(file.filename, st.x, st.y, - "subimage", layer, "interp", filtertype, - "missingcolor", missingColor, - "swrap", uaddressmode, "twrap", vaddressmode); -} +#include "lib/$fileTransformUv" + +void mx_image_vector3(textureresource file, string layer, vector default_value, vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, string framerange, int frameoffset, string frameendaction, output vector out) +{ + if (file.filename == "" || + (uaddressmode == "constant" && (texcoord.x<0.0 || texcoord.x>1.0)) || + (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) + { + out = default_value; + return; + } + + color missingColor = default_value; + vector2 st = mx_transform_uv(texcoord); + out = texture(file.filename, st.x, st.y, "subimage", layer, "missingcolor", missingColor, "swrap", uaddressmode, "twrap", vaddressmode); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_image_vector4.osl b/MaterialX/libraries/stdlib/genosl/mx_image_vector4.osl old mode 100644 new mode 100755 index eba820a..c083b4c --- a/MaterialX/libraries/stdlib/genosl/mx_image_vector4.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_image_vector4.osl @@ -1,23 +1,21 @@ -#include "lib/$fileTransformUv" - -void mx_image_vector4(textureresource file, string layer, vector4 default_value, vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, string framerange, int frameoffset, string frameendaction, output vector4 out) -{ - if (file.filename == "" || - (uaddressmode == "constant" && (texcoord.x<0.0 || texcoord.x>1.0)) || - (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) - { - out = default_value; - return; - } - - color missingColor = color(default_value.x, default_value.y, default_value.z); - float missingAlpha = default_value.w; - vector2 st = mx_transform_uv(texcoord); - float alpha; - color rgb = texture(file.filename, st.x, st.y, "alpha", alpha, - "subimage", layer, "interp", filtertype, - "missingcolor", missingColor, "missingalpha", missingAlpha, - "swrap", uaddressmode, "twrap", vaddressmode); - - out = vector4(rgb[0], rgb[1], rgb[2], alpha); -} +#include "lib/$fileTransformUv" + +void mx_image_vector4(textureresource file, string layer, vector4 default_value, vector2 texcoord, string uaddressmode, string vaddressmode, string filtertype, string framerange, int frameoffset, string frameendaction, output vector4 out) +{ + if (file.filename == "" || + (uaddressmode == "constant" && (texcoord.x<0.0 || texcoord.x>1.0)) || + (vaddressmode == "constant" && (texcoord.y<0.0 || texcoord.y>1.0))) + { + out = default_value; + return; + } + + color missingColor = color(default_value.x, default_value.y, default_value.z); + float missingAlpha = default_value.w; + vector2 st = mx_transform_uv(texcoord); + float alpha; + color rgb = texture(file.filename, st.x, st.y, "alpha", alpha, "subimage", layer, + "missingcolor", missingColor, "missingalpha", missingAlpha, "swrap", uaddressmode, "twrap", vaddressmode); + + out = vector4(rgb[0], rgb[1], rgb[2], alpha); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_luminance_color3.osl b/MaterialX/libraries/stdlib/genosl/mx_luminance_color3.osl old mode 100644 new mode 100755 index 8db9712..7de37a9 --- a/MaterialX/libraries/stdlib/genosl/mx_luminance_color3.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_luminance_color3.osl @@ -1,4 +1,4 @@ -void mx_luminance_color3(color in, color lumacoeffs, output color result) -{ - result = dot(in, lumacoeffs); -} +void mx_luminance_color3(color in, color lumacoeffs, output color result) +{ + result = dot(in, lumacoeffs); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_luminance_color4.osl b/MaterialX/libraries/stdlib/genosl/mx_luminance_color4.osl old mode 100644 new mode 100755 index bee2298..f74339c --- a/MaterialX/libraries/stdlib/genosl/mx_luminance_color4.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_luminance_color4.osl @@ -1,4 +1,4 @@ -void mx_luminance_color4(color4 in, color lumacoeffs, output color4 result) -{ - result = color4(dot(in.rgb, lumacoeffs), in.a); -} +void mx_luminance_color4(color4 in, color lumacoeffs, output color4 result) +{ + result = color4(dot(in.rgb, lumacoeffs), in.a); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_mix_surfaceshader.osl b/MaterialX/libraries/stdlib/genosl/mx_mix_surfaceshader.osl old mode 100644 new mode 100755 index f6a9ea6..08c0884 --- a/MaterialX/libraries/stdlib/genosl/mx_mix_surfaceshader.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_mix_surfaceshader.osl @@ -1,6 +1,6 @@ -void mx_mix_surfaceshader(surfaceshader fg, surfaceshader bg, float w, output surfaceshader result) -{ - result.bsdf = mix(bg.bsdf, fg.bsdf, w); - result.edf = mix(bg.edf, fg.edf, w); - result.opacity = mix(bg.opacity, fg.opacity, w); -} +void mx_mix_surfaceshader(surfaceshader fg, surfaceshader bg, float w, output surfaceshader result) +{ + result.bsdf = mix(bg.bsdf, fg.bsdf, w); + result.edf = mix(bg.edf, fg.edf, w); + result.opacity = mix(bg.opacity, fg.opacity, w); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_noise2d_float.osl b/MaterialX/libraries/stdlib/genosl/mx_noise2d_float.osl old mode 100644 new mode 100755 index 2af1bd4..7251300 --- a/MaterialX/libraries/stdlib/genosl/mx_noise2d_float.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_noise2d_float.osl @@ -1,5 +1,5 @@ -void mx_noise2d_float(float amplitude, float pivot, vector2 texcoord, output float result) -{ - float value = noise("snoise", texcoord.x, texcoord.y); - result = value * amplitude + pivot; -} +void mx_noise2d_float(float amplitude, float pivot, vector2 texcoord, output float result) +{ + float value = noise("snoise", texcoord.x, texcoord.y); + result = value * amplitude + pivot; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector2.osl b/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector2.osl old mode 100644 new mode 100755 index 1dff4f3..216df02 --- a/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector2.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector2.osl @@ -1,5 +1,5 @@ -void mx_noise2d_vector2(vector2 amplitude, float pivot, vector2 texcoord, output vector2 result) -{ - vector2 value = mx_noise("snoise", texcoord.x, texcoord.y); - result = value * amplitude + pivot; -} +void mx_noise2d_vector2(vector2 amplitude, float pivot, vector2 texcoord, output vector2 result) +{ + vector2 value = mx_noise("snoise", texcoord.x, texcoord.y); + result = value * amplitude + pivot; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector3.osl b/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector3.osl old mode 100644 new mode 100755 index 06d10cc..28aae78 --- a/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector3.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector3.osl @@ -1,5 +1,5 @@ -void mx_noise2d_vector3(vector amplitude, float pivot, vector2 texcoord, output vector result) -{ - vector value = noise("snoise", texcoord.x, texcoord.y); - result = value * amplitude + pivot; -} +void mx_noise2d_vector3(vector amplitude, float pivot, vector2 texcoord, output vector result) +{ + vector value = noise("snoise", texcoord.x, texcoord.y); + result = value * amplitude + pivot; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector4.osl b/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector4.osl old mode 100644 new mode 100755 index 6aac0ea..ca68177 --- a/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector4.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_noise2d_vector4.osl @@ -1,5 +1,5 @@ -void mx_noise2d_vector4(vector4 amplitude, float pivot, vector2 texcoord, output vector4 result) -{ - vector4 value = mx_noise("snoise", texcoord.x, texcoord.y); - result = value * amplitude + pivot; -} +void mx_noise2d_vector4(vector4 amplitude, float pivot, vector2 texcoord, output vector4 result) +{ + vector4 value = mx_noise("snoise", texcoord.x, texcoord.y); + result = value * amplitude + pivot; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_noise3d_float.osl b/MaterialX/libraries/stdlib/genosl/mx_noise3d_float.osl old mode 100644 new mode 100755 index 23c5985..089aa57 --- a/MaterialX/libraries/stdlib/genosl/mx_noise3d_float.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_noise3d_float.osl @@ -1,5 +1,5 @@ -void mx_noise3d_float(float amplitude, float pivot, vector position, output float result) -{ - float value = noise("snoise", position); - result = value * amplitude + pivot; -} +void mx_noise3d_float(float amplitude, float pivot, vector position, output float result) +{ + float value = noise("snoise", position); + result = value * amplitude + pivot; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector2.osl b/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector2.osl old mode 100644 new mode 100755 index 216502a..b7543c5 --- a/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector2.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector2.osl @@ -1,5 +1,5 @@ -void mx_noise3d_vector2(vector2 amplitude, float pivot, vector position, output vector2 result) -{ - vector2 value = mx_noise("snoise", position); - result = value * amplitude + pivot; -} +void mx_noise3d_vector2(vector2 amplitude, float pivot, vector position, output vector2 result) +{ + vector2 value = mx_noise("snoise", position); + result = value * amplitude + pivot; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector3.osl b/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector3.osl old mode 100644 new mode 100755 index cc6b241..3423fce --- a/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector3.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector3.osl @@ -1,5 +1,5 @@ -void mx_noise3d_vector3(vector amplitude, float pivot, vector position, output vector result) -{ - vector value = noise("snoise", position); - result = value * amplitude + pivot; -} +void mx_noise3d_vector3(vector amplitude, float pivot, vector position, output vector result) +{ + vector value = noise("snoise", position); + result = value * amplitude + pivot; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector4.osl b/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector4.osl old mode 100644 new mode 100755 index 10c96b4..5a9186a --- a/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector4.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_noise3d_vector4.osl @@ -1,5 +1,5 @@ -void mx_noise3d_vector4(vector4 amplitude, float pivot, vector position, output vector4 result) -{ - vector4 value = mx_noise("snoise", position); - result = value * amplitude + pivot; -} +void mx_noise3d_vector4(vector4 amplitude, float pivot, vector position, output vector4 result) +{ + vector4 value = mx_noise("snoise", position); + result = value * amplitude + pivot; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_normalmap.osl b/MaterialX/libraries/stdlib/genosl/mx_normalmap.osl old mode 100644 new mode 100755 index 1057eb6..f44c9c6 --- a/MaterialX/libraries/stdlib/genosl/mx_normalmap.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_normalmap.osl @@ -1,24 +1,19 @@ -void mx_normalmap_vector2(vector value, vector2 normal_scale, vector N, vector T, vector B, output vector result) -{ - if (value == vector(0.0)) - { - result = N; - } - else - { - // The OSL backend uses dPdu and dPdv for tangents and bitangents, but these vectors are not - // guaranteed to be orthonormal. - // - // Orthogonalize the tangent frame using Gram-Schmidt, unlike in the other backends. - // - vector v = value * 2.0 - 1.0; - vector Tn = normalize(T - dot(T, N) * N); - vector Bn = normalize(B - dot(B, N) * N - dot(B, Tn) * Tn); - result = normalize(Tn * v[0] * normal_scale.x + Bn * v[1] * normal_scale.y + N * v[2]); - } -} - -void mx_normalmap_float(vector value, float normal_scale, vector N, vector T, vector B, output vector result) -{ - mx_normalmap_vector2(value, vector2(normal_scale, normal_scale), N, T, B, result); -} +void mx_normalmap_vector2(vector value, vector2 normal_scale, vector N, vector T, vector B, output vector result) +{ + vector decodedValue; + if (value == vector(0.0)) + { + decodedValue = vector(0.0, 0.0, 1.0); + } + else + { + 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, float normal_scale, vector N, vector T, vector B, output vector result) +{ + mx_normalmap_vector2(value, vector2(normal_scale, normal_scale), N, T, B, result); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_premult_color4.osl b/MaterialX/libraries/stdlib/genosl/mx_premult_color4.osl old mode 100644 new mode 100755 index 8e57e13..7f80d6f --- a/MaterialX/libraries/stdlib/genosl/mx_premult_color4.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_premult_color4.osl @@ -1,4 +1,4 @@ -void mx_premult_color4(color4 in, output color4 result) -{ - result = color4(in.rgb * in.a, in.a); -} +void mx_premult_color4(color4 in, output color4 result) +{ + result = color4(in.rgb * in.a, in.a); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_rgbtohsv_color3.osl b/MaterialX/libraries/stdlib/genosl/mx_rgbtohsv_color3.osl old mode 100644 new mode 100755 index 7315ead..e6c3be3 --- a/MaterialX/libraries/stdlib/genosl/mx_rgbtohsv_color3.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_rgbtohsv_color3.osl @@ -1,4 +1,4 @@ -void mx_rgbtohsv_color3(vector _in, output vector result) -{ - result = transformc("rgb","hsv", _in); -} +void mx_rgbtohsv_color3(vector _in, output vector result) +{ + result = transformc("rgb","hsv", _in); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_rgbtohsv_color4.osl b/MaterialX/libraries/stdlib/genosl/mx_rgbtohsv_color4.osl old mode 100644 new mode 100755 index 92edec0..c776c8b --- a/MaterialX/libraries/stdlib/genosl/mx_rgbtohsv_color4.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_rgbtohsv_color4.osl @@ -1,4 +1,4 @@ -void mx_rgbtohsv_color4(color4 _in, output color4 result) -{ - result = color4(transformc("rgb","hsv", _in.rgb), 1.0); -} +void mx_rgbtohsv_color4(color4 _in, output color4 result) +{ + result = color4(transformc("rgb","hsv", _in.rgb), 1.0); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_rotate_vector2.osl b/MaterialX/libraries/stdlib/genosl/mx_rotate_vector2.osl old mode 100644 new mode 100755 index 7ac3dbf..bb0a983 --- a/MaterialX/libraries/stdlib/genosl/mx_rotate_vector2.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_rotate_vector2.osl @@ -1,7 +1,7 @@ -void mx_rotate_vector2(vector2 _in, float amount, output vector2 result) -{ - float rotationRadians = radians(amount); - float sa = sin(rotationRadians); - float ca = cos(rotationRadians); - result = vector2(ca*_in.x + sa*_in.y, -sa*_in.x + ca*_in.y); -} +void mx_rotate_vector2(vector2 _in, float amount, output vector2 result) +{ + float rotationRadians = radians(amount); + float sa = sin(rotationRadians); + float ca = cos(rotationRadians); + result = vector2(ca*_in.x + sa*_in.y, -sa*_in.x + ca*_in.y); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_rotate_vector3.osl b/MaterialX/libraries/stdlib/genosl/mx_rotate_vector3.osl old mode 100644 new mode 100755 index d036fe6..b61301d --- a/MaterialX/libraries/stdlib/genosl/mx_rotate_vector3.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_rotate_vector3.osl @@ -1,20 +1,20 @@ -matrix rotationMatrix(vector axis, float angle) -{ - vector nAxis = normalize(axis); - float s = sin(angle); - float c = cos(angle); - float oc = 1.0 - c; - - return matrix(oc * nAxis[0] * nAxis[0] + c, oc * nAxis[0] * nAxis[1] - nAxis[2] * s, oc * nAxis[2] * nAxis[0] + nAxis[1] * s, 0.0, - oc * nAxis[0] * nAxis[1] + nAxis[2] * s, oc * nAxis[1] * nAxis[1] + c, oc * nAxis[1] * nAxis[2] - nAxis[0] * s, 0.0, - oc * nAxis[2] * nAxis[0] - nAxis[1] * s, oc * nAxis[1] * nAxis[2] + nAxis[0] * s, oc * nAxis[2] * nAxis[2] + c, 0.0, - 0.0, 0.0, 0.0, 1.0); -} - -void mx_rotate_vector3(vector _in, float amount, vector axis, output vector result) -{ - float rotationRadians = radians(amount); - matrix m = rotationMatrix(axis, rotationRadians); - vector4 trans = transform(m, vector4(_in[0], _in[1], _in[2], 1.0)); - result = vector(trans.x, trans.y, trans.z); -} +matrix rotationMatrix(vector axis, float angle) +{ + vector nAxis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + + return matrix(oc * nAxis[0] * nAxis[0] + c, oc * nAxis[0] * nAxis[1] - nAxis[2] * s, oc * nAxis[2] * nAxis[0] + nAxis[1] * s, 0.0, + oc * nAxis[0] * nAxis[1] + nAxis[2] * s, oc * nAxis[1] * nAxis[1] + c, oc * nAxis[1] * nAxis[2] - nAxis[0] * s, 0.0, + oc * nAxis[2] * nAxis[0] - nAxis[1] * s, oc * nAxis[1] * nAxis[2] + nAxis[0] * s, oc * nAxis[2] * nAxis[2] + c, 0.0, + 0.0, 0.0, 0.0, 1.0); +} + +void mx_rotate_vector3(vector _in, float amount, vector axis, output vector result) +{ + float rotationRadians = radians(amount); + matrix m = rotationMatrix(axis, rotationRadians); + vector4 trans = transform(m, vector4(_in[0], _in[1], _in[2], 1.0)); + result = vector(trans.x, trans.y, trans.z); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_set_ci.osl b/MaterialX/libraries/stdlib/genosl/mx_set_ci.osl deleted file mode 100644 index 0ed1a05..0000000 --- a/MaterialX/libraries/stdlib/genosl/mx_set_ci.osl +++ /dev/null @@ -1,70 +0,0 @@ -void mx_set_ci ( - int output_type, - - // the per-type inputs must be named with "input_" - // the of these inputs defines their corresponding output_type value. - // this is dynamically derived in the shader generation code by - // inspecting the order of the inputs in the node definition - surfaceshader input_surfaceshader, - MATERIAL input_material, - BSDF input_BSDF, - EDF input_EDF, - float input_float, - color input_color3, - color4 input_color4, - vector2 input_vector2, - vector input_vector3, - vector4 input_vector4, - int input_integer, - int input_boolean, - matrix input_matrix33, - matrix input_matrix44, - displacementshader input_displacementshader, - - output closure color out_ci -) -{ - color c = 0; - float a = 1; - - if (output_type == 0) { - float opacity_weight = clamp(input_surfaceshader.opacity, 0.0, 1.0); - out_ci = (input_surfaceshader.bsdf + input_surfaceshader.edf) * opacity_weight + transparent() * (1.0 - opacity_weight); - } else if (output_type == 1) { - out_ci = input_material; - } else if (output_type == 2) { - out_ci = input_BSDF; - } else if (output_type == 3) { - out_ci = input_EDF; - } else { - if (output_type == 4) { - c = input_float; - } else if (output_type == 5) { - c = input_color3; - } else if (output_type == 6) { - c = input_color4.rgb; - a = input_color4.a; - } else if (output_type == 7) { - c = color(input_vector2.x, input_vector2.y, 0); - } else if (output_type == 8) { - c = color(input_vector3); - } else if (output_type == 9) { - c = color(input_vector4.x, input_vector4.y, input_vector4.z); - a = input_vector4.w; - } else if (output_type == 10) { - c = color(input_integer); - } else if (output_type == 11) { - c = color(input_boolean); - } else if (output_type == 12) { - c = color(input_matrix33[0][0], input_matrix33[1][1], input_matrix33[2][2]); - } else if (output_type == 13) { - c = color(input_matrix44[0][0], input_matrix44[1][1], input_matrix44[2][2]); - a = input_matrix44[4][4]; - } else if (output_type == 14) { - c = color(input_displacementshader); - } - out_ci = c * a * emission() + (1-a) * transparent(); - } - - Ci = out_ci; -} diff --git a/MaterialX/libraries/stdlib/genosl/mx_surface_unlit.osl b/MaterialX/libraries/stdlib/genosl/mx_surface_unlit.osl old mode 100644 new mode 100755 index b870ef2..17edd2f --- a/MaterialX/libraries/stdlib/genosl/mx_surface_unlit.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_surface_unlit.osl @@ -1,7 +1,7 @@ -void mx_surface_unlit(float emission_weight, color emission_color, float transmission_weight, color transmission_color, float opacity, output surfaceshader result) -{ - float trans = clamp(transmission_weight, 0.0, 1.0); - result.bsdf = trans * transmission_color * transparent(); - result.edf = (1.0 - trans) * emission_weight * emission_color * emission(); - result.opacity = clamp(opacity, 0.0, 1.0); -} +void mx_surface_unlit(float emission_weight, color emission_color, float transmission_weight, color transmission_color, float opacity, output surfaceshader result) +{ + float trans = clamp(transmission_weight, 0.0, 1.0); + result.bsdf = trans * transmission_color * transparent(); + result.edf = (1.0 - trans) * emission_weight * emission_color * emission(); + result.opacity = clamp(opacity, 0.0, 1.0); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_surfacematerial.osl b/MaterialX/libraries/stdlib/genosl/mx_surfacematerial.osl deleted file mode 100644 index ca68960..0000000 --- a/MaterialX/libraries/stdlib/genosl/mx_surfacematerial.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_surfacematerial(surfaceshader surface, surfaceshader back, displacementshader disp, output MATERIAL result) -{ - float opacity_weight = clamp(surface.opacity, 0.0, 1.0); - result = (surface.bsdf + surface.edf) * opacity_weight + transparent() * (1.0 - opacity_weight); -} diff --git a/MaterialX/libraries/stdlib/genosl/mx_time_float.osl b/MaterialX/libraries/stdlib/genosl/mx_time_float.osl old mode 100644 new mode 100755 index 511cc18..5464f69 --- a/MaterialX/libraries/stdlib/genosl/mx_time_float.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_time_float.osl @@ -1,6 +1,6 @@ -void mx_time_float(float fps, output float result) -{ - // Use the standard default value if the attribute is not present. - result = 0.0; - getattribute("time", result); -} +void mx_time_float(float fps, output float result) +{ + float frame; + getattribute("frame", frame); + result = frame / fps; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_transformmatrix_vector2M3.osl b/MaterialX/libraries/stdlib/genosl/mx_transformmatrix_vector2M3.osl old mode 100644 new mode 100755 index fe1937b..1601e16 --- a/MaterialX/libraries/stdlib/genosl/mx_transformmatrix_vector2M3.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_transformmatrix_vector2M3.osl @@ -1,6 +1,6 @@ -void mx_transformmatrix_vector2M3(vector2 val, matrix m, output vector2 result) -{ - point res = transform(m, point(val.x, val.y, 1.0)); - result.x = res[0]; - result.y = res[1]; -} +void mx_transformmatrix_vector2M3(vector2 val, matrix m, output vector2 result) +{ + point res = transform(m, point(val.x, val.y, 1.0)); + result.x = res[0]; + result.y = res[1]; +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_unpremult_color4.osl b/MaterialX/libraries/stdlib/genosl/mx_unpremult_color4.osl old mode 100644 new mode 100755 index 55d074c..32533ab --- a/MaterialX/libraries/stdlib/genosl/mx_unpremult_color4.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_unpremult_color4.osl @@ -1,4 +1,4 @@ -void mx_unpremult_color4(color4 in, output color4 result) -{ - result = color4(in.rgb / in.a, in.a); -} +void mx_unpremult_color4(color4 in, output color4 result) +{ + result = color4(in.rgb / in.a, in.a); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_float.osl b/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_float.osl old mode 100644 new mode 100755 index 1b98e31..2e970fa --- a/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_float.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_float.osl @@ -1,4 +1,4 @@ -void mx_worleynoise2d_float(vector2 texcoord, float jitter, int style, output float result) -{ - result = mx_worley_noise_float(texcoord, jitter, style, 0); -} +void mx_worleynoise2d_float(vector2 texcoord, float jitter, output float result) +{ + result = mx_worley_noise_float(texcoord, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl b/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl old mode 100644 new mode 100755 index 6d6be62..eb62417 --- a/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_vector2.osl @@ -1,4 +1,4 @@ -void mx_worleynoise2d_vector2(vector2 texcoord, float jitter, int style, output vector2 result) -{ - result = mx_worley_noise_vector2(texcoord, jitter, style, 0); -} +void mx_worleynoise2d_vector2(vector2 texcoord, float jitter, output vector2 result) +{ + result = mx_worley_noise_vector2(texcoord, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl b/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl old mode 100644 new mode 100755 index 00ae3a5..b06329b --- a/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_worleynoise2d_vector3.osl @@ -1,4 +1,4 @@ -void mx_worleynoise2d_vector3(vector2 texcoord, float jitter, int style, output vector result) -{ - result = mx_worley_noise_vector3(texcoord, jitter, style, 0); -} +void mx_worleynoise2d_vector3(vector2 texcoord, float jitter, output vector result) +{ + result = mx_worley_noise_vector3(texcoord, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_float.osl b/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_float.osl old mode 100644 new mode 100755 index 0386075..f5a9284 --- a/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_float.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_float.osl @@ -1,4 +1,4 @@ -void mx_worleynoise3d_float(vector position, float jitter, int style, output float result) -{ - result = mx_worley_noise_float(position, jitter, style, 0); -} +void mx_worleynoise3d_float(vector position, float jitter, output float result) +{ + result = mx_worley_noise_float(position, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl b/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl old mode 100644 new mode 100755 index 314dde0..1cdce20 --- a/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_vector2.osl @@ -1,4 +1,4 @@ -void mx_worleynoise3d_vector2(vector position, float jitter, int style, output vector2 result) -{ - result = mx_worley_noise_vector2(position, jitter, style, 0); -} +void mx_worleynoise3d_vector2(vector position, float jitter, output vector2 result) +{ + result = mx_worley_noise_vector2(position, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl b/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl old mode 100644 new mode 100755 index 5cfce19..50103e1 --- a/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl +++ b/MaterialX/libraries/stdlib/genosl/mx_worleynoise3d_vector3.osl @@ -1,4 +1,4 @@ -void mx_worleynoise3d_vector3(vector position, float jitter, int style, output vector result) -{ - result = mx_worley_noise_vector3(position, jitter, style, 0); -} +void mx_worleynoise3d_vector3(vector position, float jitter, output vector result) +{ + result = mx_worley_noise_vector3(position, jitter, 0); +} diff --git a/MaterialX/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx b/MaterialX/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx old mode 100644 new mode 100755 index b909c5e..2b66326 --- a/MaterialX/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx +++ b/MaterialX/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx @@ -1,776 +1,748 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/stdlib/genslang/lib/mx_math.slang b/MaterialX/libraries/stdlib/genslang/lib/mx_math.slang deleted file mode 100644 index f54ac60..0000000 --- a/MaterialX/libraries/stdlib/genslang/lib/mx_math.slang +++ /dev/null @@ -1,161 +0,0 @@ -#define M_FLOAT_EPS 1e-8 - -#define mx_inversesqrt rsqrt -#define mx_sin sin -#define mx_cos cos -#define mx_tan tan -#define mx_asin asin -#define mx_acos acos -#define mx_radians radians -#define mx_float_bits_to_int asint - -/// The GLSL we are piggybacking on has all its matrices transposed compared to Slang and the MaterialX spec. -/// (The matrices are defined like mat3(1, 2, 3, 4, 5, 6, 7, 8, 9) where the spec says it should be row-major order, but GLSL creates it as col-major) -/// So when GLSL code says "mul(M, v)" it means "v * transpose(M)", and since in Slang the matrices are stored -/// in row-major order, we need to reverse the order of multiplication to get the same result. -float2 mx_matrix_mul(float2 v, float2x2 m) { return mul(m, v); } -float3 mx_matrix_mul(float3 v, float3x3 m) { return mul(m, v); } -float4 mx_matrix_mul(float4 v, float4x4 m) { return mul(m, v); } -float2 mx_matrix_mul(float2x2 m, float2 v) { return mul(v, m); } -float3 mx_matrix_mul(float3x3 m, float3 v) { return mul(v, m); } -float4 mx_matrix_mul(float4x4 m, float4 v) { return mul(v, m); } -float2x2 mx_matrix_mul(float2x2 m1, float2x2 m2) { return mul(m2, m1); } -float3x3 mx_matrix_mul(float3x3 m1, float3x3 m2) { return mul(m2, m1); } -float4x4 mx_matrix_mul(float4x4 m1, float4x4 m2) { return mul(m2, m1); } - -float mx_square(float x) -{ - return x*x; -} - -float2 mx_square(float2 x) -{ - return x*x; -} - -float3 mx_square(float3 x) -{ - return x*x; -} - -float3 mx_srgb_encode(float3 color) -{ - bool3 isAbove = (color > float3(0.0031308)); - float3 linSeg = color * 12.92; - float3 powSeg = 1.055 * pow(max(color, float3(0.0)), float3(1.0 / 2.4)) - 0.055; - return select(isAbove, powSeg, linSeg); -} - -/// Library assumes GLSL style mod (result has the sign of y), so cannot use fmod -float mx_mod(float a, float b) { return (a - b * floor(a / b)); } -float2 mx_mod(float2 a, float2 b) { return (a - b * floor(a / b)); } -float3 mx_mod(float3 a, float3 b) { return (a - b * floor(a / b)); } -float4 mx_mod(float4 a, float4 b) { return (a - b * floor(a / b)); } -float2 mx_mod(float2 a, float b) { return (a - b * floor(a / b)); } -float3 mx_mod(float3 a, float b) { return (a - b * floor(a / b)); } -float4 mx_mod(float4 a, float b) { return (a - b * floor(a / b)); } - -/// The float3x3 and float4x4 inverse are taken from the Slang's SGL library -/// https://github.com/shader-slang/sgl/ -/// Specifically the matrix_math.h -/// https://github.com/shader-slang/sgl/blob/main/src/sgl/math/matrix_math.h -float3x3 mx_inverse(float3x3 m) -{ - float one_over_det = 1.f / determinant(m); - - float3x3 result; - result[0][0] = +(m[1][1] * m[2][2] - m[1][2] * m[2][1]) * one_over_det; - result[0][1] = -(m[0][1] * m[2][2] - m[0][2] * m[2][1]) * one_over_det; - result[0][2] = +(m[0][1] * m[1][2] - m[0][2] * m[1][1]) * one_over_det; - result[1][0] = -(m[1][0] * m[2][2] - m[1][2] * m[2][0]) * one_over_det; - result[1][1] = +(m[0][0] * m[2][2] - m[0][2] * m[2][0]) * one_over_det; - result[1][2] = -(m[0][0] * m[1][2] - m[0][2] * m[1][0]) * one_over_det; - result[2][0] = +(m[1][0] * m[2][1] - m[1][1] * m[2][0]) * one_over_det; - result[2][1] = -(m[0][0] * m[2][1] - m[0][1] * m[2][0]) * one_over_det; - result[2][2] = +(m[0][0] * m[1][1] - m[0][1] * m[1][0]) * one_over_det; - return result; -} - -float4x4 mx_inverse(float4x4 m) -{ - float c00 = m[2][2] * m[3][3] - m[2][3] * m[3][2]; - float c02 = m[2][1] * m[3][3] - m[2][3] * m[3][1]; - float c03 = m[2][1] * m[3][2] - m[2][2] * m[3][1]; - - float c04 = m[1][2] * m[3][3] - m[1][3] * m[3][2]; - float c06 = m[1][1] * m[3][3] - m[1][3] * m[3][1]; - float c07 = m[1][1] * m[3][2] - m[1][2] * m[3][1]; - - float c08 = m[1][2] * m[2][3] - m[1][3] * m[2][2]; - float c10 = m[1][1] * m[2][3] - m[1][3] * m[2][1]; - float c11 = m[1][1] * m[2][2] - m[1][2] * m[2][1]; - - float c12 = m[0][2] * m[3][3] - m[0][3] * m[3][2]; - float c14 = m[0][1] * m[3][3] - m[0][3] * m[3][1]; - float c15 = m[0][1] * m[3][2] - m[0][2] * m[3][1]; - - float c16 = m[0][2] * m[2][3] - m[0][3] * m[2][2]; - float c18 = m[0][1] * m[2][3] - m[0][3] * m[2][1]; - float c19 = m[0][1] * m[2][2] - m[0][2] * m[2][1]; - - float c20 = m[0][2] * m[1][3] - m[0][3] * m[1][2]; - float c22 = m[0][1] * m[1][3] - m[0][3] * m[1][1]; - float c23 = m[0][1] * m[1][2] - m[0][2] * m[1][1]; - - float4 fac0 = float4(c00, c00, c02, c03); - float4 fac1 = float4(c04, c04, c06, c07); - float4 fac2 = float4(c08, c08, c10, c11); - float4 fac3 = float4(c12, c12, c14, c15); - float4 fac4 = float4(c16, c16, c18, c19); - float4 fac5 = float4(c20, c20, c22, c23); - - float4 vec0 = float4(m[0][1], m[0][0], m[0][0], m[0][0]); - float4 vec1 = float4(m[1][1], m[1][0], m[1][0], m[1][0]); - float4 vec2 = float4(m[2][1], m[2][0], m[2][0], m[2][0]); - float4 vec3 = float4(m[3][1], m[3][0], m[3][0], m[3][0]); - - float4 inv0 = float4(vec1 * fac0 - vec2 * fac1 + vec3 * fac2); - float4 inv1 = float4(vec0 * fac0 - vec2 * fac3 + vec3 * fac4); - float4 inv2 = float4(vec0 * fac1 - vec1 * fac3 + vec3 * fac5); - float4 inv3 = float4(vec0 * fac2 - vec1 * fac4 + vec2 * fac5); - - float4 sign_a = float4(+1, -1, +1, -1); - float4 sign_b = float4(-1, +1, -1, +1); - // make matrix from columns - float4x4 inverse = transpose(float4x4(inv0 * sign_a, inv1 * sign_b, inv2 * sign_a, inv3 * sign_b)); - - float4 row0 = float4(inverse[0][0], inverse[0][1], inverse[0][2], inverse[0][3]); - float4 col0 = float4(inverse[0][0], inverse[1][0], inverse[2][0], inverse[3][0]); - - float4 dot0 = float4(col0 * row0); - float dot1 = (dot0.x + dot0.y) + (dot0.z + dot0.w); - - float one_over_det = 1.f / dot1; - - return inverse * one_over_det; -} - -float mx_atan(float y_over_x) -{ - return atan(y_over_x); -} - -float mx_atan(float y, float x) -{ - return atan2(y, x); -} - -float2 mx_atan(float2 y, float2 x) -{ - return atan2(y, x); -} - -float3 mx_atan(float3 y, float3 x) -{ - return atan2(y, x); -} - -float4 mx_atan(float4 y, float4 x) -{ - return atan2(y, x); -} diff --git a/MaterialX/libraries/stdlib/genslang/lib/mx_texture.slang b/MaterialX/libraries/stdlib/genslang/lib/mx_texture.slang deleted file mode 100644 index 80e3a4c..0000000 --- a/MaterialX/libraries/stdlib/genslang/lib/mx_texture.slang +++ /dev/null @@ -1,47 +0,0 @@ -struct SamplerTexture2D -{ - Texture2D tex; - SamplerState sampler; - - // needed for Storm - int get_width(int mipLevel = 0) - { - uint width, height, numberOfLevels; - tex.GetDimensions(mipLevel, width, height, numberOfLevels); - return width; - } - - int get_height(int mipLevel = 0) - { - uint width, height, numberOfLevels; - tex.GetDimensions(mipLevel, width, height, numberOfLevels); - return height; - } - - int get_num_mip_levels() - { - uint width, height, numberOfLevels; - tex.GetDimensions(0, width, height, numberOfLevels); - return numberOfLevels; - } -} - -float4 textureLod(SamplerTexture2D tex, float2 uv, float lod) -{ - return tex.tex.SampleLevel(tex.sampler, uv, lod); -} - -float4 texture(SamplerTexture2D tex, float2 uv) -{ - return tex.tex.Sample(tex.sampler, uv); -} - -float4 textureGrad(SamplerTexture2D tex, float2 uv, float2 ddx_, float2 ddy_) -{ - return tex.tex.SampleGrad(tex.sampler, uv, ddx_, ddy_); -} - -int2 textureSize(SamplerTexture2D tex, int mipLevel) -{ - return int2(tex.get_width(mipLevel), tex.get_height(mipLevel)); -} diff --git a/MaterialX/libraries/stdlib/genslang/stdlib_genslang_impl.mtlx b/MaterialX/libraries/stdlib/genslang/stdlib_genslang_impl.mtlx deleted file mode 100644 index 9dc9f6d..0000000 --- a/MaterialX/libraries/stdlib/genslang/stdlib_genslang_impl.mtlx +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/libraries/stdlib/stdlib_defs.mtlx b/MaterialX/libraries/stdlib/stdlib_defs.mtlx old mode 100644 new mode 100755 index 058f93d..69d9c1e --- a/MaterialX/libraries/stdlib/stdlib_defs.mtlx +++ b/MaterialX/libraries/stdlib/stdlib_defs.mtlx @@ -1,5111 +1,4897 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/stdlib/stdlib_ng.mtlx b/MaterialX/libraries/stdlib/stdlib_ng.mtlx old mode 100644 new mode 100755 index db57c6e..470d34c --- a/MaterialX/libraries/stdlib/stdlib_ng.mtlx +++ b/MaterialX/libraries/stdlib/stdlib_ng.mtlx @@ -1,6424 +1,6009 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/libraries/targets/essl.mtlx b/MaterialX/libraries/targets/essl.mtlx old mode 100644 new mode 100755 index 03a1b5b..fca8efb --- a/MaterialX/libraries/targets/essl.mtlx +++ b/MaterialX/libraries/targets/essl.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/MaterialX/libraries/targets/genglsl.mtlx b/MaterialX/libraries/targets/genglsl.mtlx old mode 100644 new mode 100755 index 820a43c..ccd8d4f --- a/MaterialX/libraries/targets/genglsl.mtlx +++ b/MaterialX/libraries/targets/genglsl.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/MaterialX/libraries/targets/genmdl.mtlx b/MaterialX/libraries/targets/genmdl.mtlx old mode 100644 new mode 100755 index 91ac5ff..ed9f7bd --- a/MaterialX/libraries/targets/genmdl.mtlx +++ b/MaterialX/libraries/targets/genmdl.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/MaterialX/libraries/targets/genmsl.mtlx b/MaterialX/libraries/targets/genmsl.mtlx old mode 100644 new mode 100755 index 0ad09cc..870d0f4 --- a/MaterialX/libraries/targets/genmsl.mtlx +++ b/MaterialX/libraries/targets/genmsl.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/MaterialX/libraries/targets/genosl.mtlx b/MaterialX/libraries/targets/genosl.mtlx old mode 100644 new mode 100755 index cae914f..e5bea03 --- a/MaterialX/libraries/targets/genosl.mtlx +++ b/MaterialX/libraries/targets/genosl.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/MaterialX/libraries/targets/genoslnetwork.mtlx b/MaterialX/libraries/targets/genoslnetwork.mtlx deleted file mode 100644 index 1141c04..0000000 --- a/MaterialX/libraries/targets/genoslnetwork.mtlx +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - diff --git a/MaterialX/libraries/targets/genslangl.mtlx b/MaterialX/libraries/targets/genslangl.mtlx deleted file mode 100644 index e687982..0000000 --- a/MaterialX/libraries/targets/genslangl.mtlx +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - diff --git a/MaterialX/python/CMakeLists.txt b/MaterialX/python/CMakeLists.txt old mode 100644 new mode 100755 index f0b6de0..4b9141f --- a/MaterialX/python/CMakeLists.txt +++ b/MaterialX/python/CMakeLists.txt @@ -1,18 +1,25 @@ -if(NOT SKBUILD) - install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/MaterialX" DESTINATION "python" MESSAGE_NEVER) - install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Scripts" DESTINATION "python" MESSAGE_NEVER) -endif() - -if(SKBUILD) - install( - DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Scripts/" - DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}/_scripts" - PATTERN "README.md" EXCLUDE - ) -endif() - -if(MATERIALX_INSTALL_PYTHON AND PYTHON_EXECUTABLE AND NOT SKBUILD) - set(SETUP_PY "${CMAKE_INSTALL_PREFIX}/python/setup.py") - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in" "${SETUP_PY}") - install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip install . WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/python)") -endif() +if(NOT SKBUILD) + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/MaterialX" DESTINATION "python" MESSAGE_NEVER) + install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Scripts" DESTINATION "python" MESSAGE_NEVER) +endif() + +if(SKBUILD) + install( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Scripts/" + DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}/_scripts" + PATTERN "README.md" EXCLUDE + ) +endif() + +if(MATERIALX_PYTHON_OCIO_DIR) + if(NOT EXISTS "${MATERIALX_PYTHON_OCIO_DIR}/config.ocio") + message(WARNING "No file named config.ocio was found in the given OCIO directory.") + endif() + install(DIRECTORY "${MATERIALX_PYTHON_OCIO_DIR}/" DESTINATION "${MATERIALX_PYTHON_FOLDER_NAME}/config/" MESSAGE_NEVER) +endif() + +if(MATERIALX_INSTALL_PYTHON AND PYTHON_EXECUTABLE AND NOT SKBUILD) + set(SETUP_PY "${CMAKE_INSTALL_PREFIX}/python/setup.py") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in" "${SETUP_PY}") + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} install clean --all)") +endif() diff --git a/MaterialX/python/MaterialX/MANIFEST.in b/MaterialX/python/MaterialX/MANIFEST.in old mode 100644 new mode 100755 index 576179d..32f406b --- a/MaterialX/python/MaterialX/MANIFEST.in +++ b/MaterialX/python/MaterialX/MANIFEST.in @@ -1 +1 @@ -recursive-include libraries +recursive-include libraries diff --git a/MaterialX/python/MaterialX/__init__.py b/MaterialX/python/MaterialX/__init__.py old mode 100644 new mode 100755 index 05348b0..f9b72da --- a/MaterialX/python/MaterialX/__init__.py +++ b/MaterialX/python/MaterialX/__init__.py @@ -1,24 +1,9 @@ -# Python 3.8+ on Windows: DLL search paths for dependent -# shared libraries -# Refs.: -# - https://github.com/python/cpython/issues/80266 -# - https://docs.python.org/3.8/library/os.html#os.add_dll_directory -import os -import sys -if sys.platform == "win32" and sys.version_info >= (3, 8): - import importlib.metadata - try: - importlib.metadata.version('MaterialX') - except importlib.metadata.PackageNotFoundError: - # On a non-pip installation, this file is in %INSTALLDIR%\python\MaterialX - # We need to add %INSTALLDIR%\bin to the DLL path. - mxdir = os.path.dirname(__file__) - pydir = os.path.split(mxdir)[0] - installdir = os.path.split(pydir)[0] - bindir = os.path.join(installdir, "bin") - if os.path.exists(bindir): - os.add_dll_directory(bindir) - -from .main import * - -__version__ = getVersionString() +from .main import * +from .colorspace import * + +try: + from .legacy import * +except ImportError: + pass + +__version__ = getVersionString() diff --git a/MaterialX/python/MaterialX/_scripts/README.md b/MaterialX/python/MaterialX/_scripts/README.md old mode 100644 new mode 100755 index 8041cb5..32786b6 --- a/MaterialX/python/MaterialX/_scripts/README.md +++ b/MaterialX/python/MaterialX/_scripts/README.md @@ -1,2 +1,2 @@ -This directory is empty built it's used when packaging the Python library. -the files in ../../Scripts will be copied inside. +This directory is empty buit it's used when packaging the Python library. +the files in ../../Scripts will be copied inside. diff --git a/MaterialX/python/MaterialX/_scripts/__init__.py b/MaterialX/python/MaterialX/_scripts/__init__.py old mode 100644 new mode 100755 index 1217aef..d74d173 --- a/MaterialX/python/MaterialX/_scripts/__init__.py +++ b/MaterialX/python/MaterialX/_scripts/__init__.py @@ -1 +1 @@ -# Only required for entry-points. +# Only required for entry-points. diff --git a/MaterialX/python/MaterialX/colorspace.py b/MaterialX/python/MaterialX/colorspace.py new file mode 100755 index 0000000..5fc236c --- /dev/null +++ b/MaterialX/python/MaterialX/colorspace.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +''' +Native Python wrappers for PyMaterialX and PyOpenColorIO, providing helper +functions for transforming MaterialX colors between OpenColorIO color spaces. + +By default, the OpenColorIO configuration packaged with MaterialX Python will +be used, but clients may instead pass their own custom configurations to these +methods. +''' + +import os + +from .PyMaterialXCore import * + + +#-------------------------------------------------------------------------------- +_defaultConfig = None +_defaultConfigFilename = 'config/config.ocio' +_validateDefaultConfig = False + + +#-------------------------------------------------------------------------------- +def getColorSpaces(cms = 'ocio', config = None): + """Return a list containing the names of all supported color spaces. + By default, the OCIO color management system and default MaterialX + config are used.""" + + if cms != 'ocio': + raise ValueError('Color management system is unrecognized: ' + cms) + if config is None: + config = getDefaultOCIOConfig() + + return [cs.getName() for cs in config.getColorSpaces()] + +def transformColor(color, sourceColorSpace, destColorSpace, cms = 'ocio', config = None): + """Given a MaterialX color and the names of two supported color spaces, + transform the color from the source to the destination color space. + By default, the OCIO color management system and default MaterialX + config are used.""" + + if cms != 'ocio': + raise ValueError('Color management system is unrecognized: ' + cms) + if config is None: + config = getDefaultOCIOConfig() + + newColor = color + processor = config.getProcessor(str(sourceColorSpace), str(destColorSpace)) + if isinstance(newColor, Color3): + newColor = Color3(processor.applyRGB(newColor)) + elif isinstance(newColor, Color4): + newColor = Color4(processor.applyRGBA(newColor)) + + return newColor + +def getDefaultOCIOConfig(): + """Return the default OCIO config packaged with this Python library. + Raises ImportError if the PyOpenColorIO module cannot be imported.""" + global _defaultConfig + + if _defaultConfig is None: + import PyOpenColorIO + scriptDir = os.path.dirname(os.path.abspath(__file__)) + configFilename = os.path.join(scriptDir, _defaultConfigFilename) + _defaultConfig = PyOpenColorIO.Config.CreateFromFile(configFilename) + if _validateDefaultConfig: + _defaultConfig.sanityCheck() + + return _defaultConfig diff --git a/MaterialX/python/MaterialX/datatype.py b/MaterialX/python/MaterialX/datatype.py old mode 100644 new mode 100755 index bc9e667..db1f382 --- a/MaterialX/python/MaterialX/datatype.py +++ b/MaterialX/python/MaterialX/datatype.py @@ -1,98 +1,98 @@ -#!/usr/bin/env python -''' -Native Python helper functions for MaterialX data types. -''' - -import sys - -from .PyMaterialXCore import * - - -#-------------------------------------------------------------------------------- -_typeToName = { int : 'integer', - float : 'float', - bool : 'boolean', - Color3 : 'color3', - Color4 : 'color4', - Vector2 : 'vector2', - Vector3 : 'vector3', - Vector4 : 'vector4', - Matrix33 : 'matrix33', - Matrix44 : 'matrix44', - str : 'string' } - -if sys.version_info[0] < 3: - _typeToName[long] = 'integer' - _typeToName[unicode] = 'string' -else: - _typeToName[bytes] = 'string' - - -#-------------------------------------------------------------------------------- -def getTypeString(value): - """Return the MaterialX type string associated with the given Python value - If the type of the given Python value is not recognized by MaterialX, - then None is returned. - - Examples: - getTypeString(1.0) -> 'float' - getTypeString(mx.Color3(1)) -> 'color3'""" - - valueType = type(value) - if valueType in _typeToName: - return _typeToName[valueType] - if valueType in (tuple, list): - if len(value): - elemType = type(value[0]) - if elemType in _typeToName: - return _typeToName[elemType] + 'array' - return 'stringarray' - return None - -def getValueString(value): - """Return the MaterialX value string associated with the given Python value - If the type of the given Python value is not recognized by MaterialX, - then None is returned - - Examples: - getValueString(0.1) -> '0.1' - getValueString(mx.Color3(0.1, 0.2, 0.3)) -> '0.1, 0.2, 0.3'""" - - typeString = getTypeString(value) - if not typeString: - return None - method = globals()['TypedValue_' + typeString].createValue - return method(value).getValueString() - -def createValueFromStrings(valueString, typeString): - """Convert a MaterialX value and type strings to the corresponding - Python value. If the given conversion cannot be performed, then None - is returned. - - Examples: - createValueFromStrings('0.1', 'float') -> 0.1 - createValueFromStrings('0.1, 0.2, 0.3', 'color3') -> mx.Color3(0.1, 0.2, 0.3)""" - - valueObj = Value.createValueFromStrings(valueString, typeString) - if not valueObj: - return None - return valueObj.getData() - - -def isColorType(t): - "Return True if the given type is a MaterialX color." - return t in (Color3, Color4) - -def isColorValue(value): - "Return True if the given value is a MaterialX color." - return isColorType(type(value)) - -def stringToBoolean(value): - "Return boolean value found in a string. Throws and exception if a boolean value could not be parsed" - if isinstance(value, bool): - return value - if value.lower() in ('yes', 'true', 't', '1'): - return True - elif value.lower() in ('no', 'false', 'f', '0'): - return False - raise TypeError('Boolean value expected.') +#!/usr/bin/env python +''' +Native Python helper functions for MaterialX data types. +''' + +import sys + +from .PyMaterialXCore import * + + +#-------------------------------------------------------------------------------- +_typeToName = { int : 'integer', + float : 'float', + bool : 'boolean', + Color3 : 'color3', + Color4 : 'color4', + Vector2 : 'vector2', + Vector3 : 'vector3', + Vector4 : 'vector4', + Matrix33 : 'matrix33', + Matrix44 : 'matrix44', + str : 'string' } + +if sys.version_info[0] < 3: + _typeToName[long] = 'integer' + _typeToName[unicode] = 'string' +else: + _typeToName[bytes] = 'string' + + +#-------------------------------------------------------------------------------- +def getTypeString(value): + """Return the MaterialX type string associated with the given Python value + If the type of the given Python value is not recognized by MaterialX, + then None is returned. + + Examples: + getTypeString(1.0) -> 'float' + getTypeString(mx.Color3(1)) -> 'color3'""" + + valueType = type(value) + if valueType in _typeToName: + return _typeToName[valueType] + if valueType in (tuple, list): + if len(value): + elemType = type(value[0]) + if elemType in _typeToName: + return _typeToName[elemType] + 'array' + return 'stringarray' + return None + +def getValueString(value): + """Return the MaterialX value string associated with the given Python value + If the type of the given Python value is not recognized by MaterialX, + then None is returned + + Examples: + getValueString(0.1) -> '0.1' + getValueString(mx.Color3(0.1, 0.2, 0.3)) -> '0.1, 0.2, 0.3'""" + + typeString = getTypeString(value) + if not typeString: + return None + method = globals()['TypedValue_' + typeString].createValue + return method(value).getValueString() + +def createValueFromStrings(valueString, typeString): + """Convert a MaterialX value and type strings to the corresponding + Python value. If the given conversion cannot be performed, then None + is returned. + + Examples: + createValueFromStrings('0.1', 'float') -> 0.1 + createValueFromStrings('0.1, 0.2, 0.3', 'color3') -> mx.Color3(0.1, 0.2, 0.3)""" + + valueObj = Value.createValueFromStrings(valueString, typeString) + if not valueObj: + return None + return valueObj.getData() + + +def isColorType(t): + "Return True if the given type is a MaterialX color." + return t in (Color3, Color4) + +def isColorValue(value): + "Return True if the given value is a MaterialX color." + return isColorType(type(value)) + +def stringToBoolean(value): + "Return boolean value found in a string. Throws and exception if a boolean value could not be parsed" + if isinstance(value, bool): + return value + if value.lower() in ('yes', 'true', 't', '1'): + return True + elif value.lower() in ('no', 'false', 'f', '0'): + return False + raise TypeError('Boolean value expected.') diff --git a/MaterialX/python/MaterialX/main.py b/MaterialX/python/MaterialX/main.py old mode 100644 new mode 100755 index c20899a..3b67bb2 --- a/MaterialX/python/MaterialX/main.py +++ b/MaterialX/python/MaterialX/main.py @@ -1,311 +1,311 @@ -#!/usr/bin/env python -''' -Native Python wrappers for PyMaterialX, providing a more Pythonic interface -for Elements and Values. -''' - -import warnings - -from .PyMaterialXCore import * -from .PyMaterialXFormat import * -from .datatype import * -import os - -# -# Element -# - -def _isA(self, elementClass, category = ''): - """Return True if this element is an instance of the given subclass. - If a category string is specified, then both subclass and category - matches are required.""" - if not isinstance(self, elementClass): - return False - if category and self.getCategory() != category: - return False - return True - -def _addChild(self, elementClass, name, typeString = ''): - "Add a child element of the given subclass, name, and optional type string." - method = getattr(self.__class__, "_addChild" + elementClass.__name__) - return method(self, name, typeString) - -def _getChild(self, name): - "Return the child element, if any, with the given name." - if (name == None): - return None - return self._getChild(name) - -def _getChildOfType(self, elementClass, name): - "Return the child element, if any, with the given name and subclass." - method = getattr(self.__class__, "_getChildOfType" + elementClass.__name__) - return method(self, name) - -def _getChildrenOfType(self, elementClass): - """Return a list of all child elements that are instances of the given type. - The returned list maintains the order in which children were added.""" - method = getattr(self.__class__, "_getChildrenOfType" + elementClass.__name__) - return method(self) - -def _removeChildOfType(self, elementClass, name): - "Remove the typed child element, if any, with the given name." - method = getattr(self.__class__, "_removeChildOfType" + elementClass.__name__) - method(self, name) - -Element.isA = _isA -Element.addChild = _addChild -Element.getChild = _getChild -Element.getChildOfType = _getChildOfType -Element.getChildrenOfType = _getChildrenOfType -Element.removeChildOfType = _removeChildOfType - - -# -# ValueElement -# - -def _setValue(self, value, typeString = ''): - "Set the typed value of an element." - method = getattr(self.__class__, "_setValue" + getTypeString(value)) - method(self, value, typeString) - -def _getValue(self): - "Return the typed value of an element." - value = self._getValue() - return value.getData() if value else None - -def _getDefaultValue(self): - """Return the default value for this element.""" - value = self._getDefaultValue() - return value.getData() if value else None - -ValueElement.setValue = _setValue -ValueElement.getValue = _getValue -ValueElement.getDefaultValue = _getDefaultValue - - -# -# InterfaceElement -# - -def _setInputValue(self, name, value, typeString = ''): - """Set the typed value of an input by its name, creating a child element - to hold the input if needed.""" - method = getattr(self.__class__, "_setInputValue" + getTypeString(value)) - return method(self, name, value, typeString) - -def _getInputValue(self, name, target = ''): - """Return the typed value of an input by its name, taking both the - calling element and its declaration into account. If the given - input is not found, then None is returned.""" - value = self._getInputValue(name, target) - return value.getData() if value else None - -def _addParameter(self, name): - """(Deprecated) Add a Parameter to this interface.""" - warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) - return self.addInput(name) - -def _getParameters(self): - """(Deprecated) Return a vector of all Parameter elements.""" - warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) - return list() - -def _getActiveParameters(self): - """(Deprecated) Return a vector of all parameters belonging to this interface, taking inheritance into account.""" - warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) - return list() - -def _setParameterValue(self, name, value, typeString = ''): - """(Deprecated) Set the typed value of a parameter by its name.""" - warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) - -def _getParameterValue(self, name, target = ''): - """(Deprecated) Return the typed value of a parameter by its name.""" - warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) - return None - -def _getParameterValueString(self, name): - """(Deprecated) Return the value string of a parameter by its name.""" - warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) - return "" - -def _addBindInput(self, name, type = DEFAULT_TYPE_STRING): - """(Deprecated) Add a BindInput to this shader reference.""" - warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) - return self.addInput(name, type) - -def _getBindInputs(self): - """(Deprecated) Return a vector of all BindInput elements in this shader reference.""" - warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) - return self.getInputs() - -def _addBindParam(self, name, type = DEFAULT_TYPE_STRING): - """(Deprecated) Add a BindParam to this shader reference.""" - warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) - return self.addInput(name, type) - -def _getBindParams(self): - """(Deprecated) Return a vector of all BindParam elements in this shader reference.""" - warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) - return list() - -def _getBindTokens(self): - """(Deprecated) Return a vector of all BindToken elements in this shader reference.""" - warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) - return list() - -InterfaceElement.setInputValue = _setInputValue -InterfaceElement.getInputValue = _getInputValue -InterfaceElement.addParameter = _addParameter -InterfaceElement.getParameters = _getParameters -InterfaceElement.getActiveParameters = _getActiveParameters -InterfaceElement.setParameterValue = _setParameterValue -InterfaceElement.getParameterValue = _getParameterValue -InterfaceElement.getParameterValueString = _getParameterValueString -InterfaceElement.addBindInput = _addBindInput -InterfaceElement.getBindInputs = _getBindInputs -InterfaceElement.addBindParam = _addBindParam -InterfaceElement.getBindParams = _getBindParams -InterfaceElement.getBindTokens = _getBindTokens - - -# -# Node -# - -def _getReferencedNodeDef(self): - "(Deprecated) Return the first NodeDef that declares this node." - warnings.warn("This function is deprecated; call Node.getNodeDef instead.", DeprecationWarning, stacklevel = 2) - return self.getNodeDef() - -def _addShaderRef(self, name, nodeName): - "(Deprecated) Add a shader reference to this material element." - warnings.warn("This function is deprecated; material elements have been replaced with material nodes in 1.38.", DeprecationWarning, stacklevel = 2) - return self.getParent().addNode(nodeName, name) - -def _getShaderRefs(self): - """(Deprecated) Return a vector of all shader references in this material element.""" - warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) - return getShaderNodes(self) - -def _getActiveShaderRefs(self): - """(Deprecated) Return a vector of all shader references in this material element, taking material inheritance into account.""" - warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) - return getShaderNodes(self) - -Node.getReferencedNodeDef = _getReferencedNodeDef -Node.addShaderRef = _addShaderRef -Node.getShaderRefs = _getShaderRefs -Node.getActiveShaderRefs = _getActiveShaderRefs - - -# -# PropertySet -# - -def _setPropertyValue(self, name, value, typeString = ''): - """Set the typed value of a property by its name, creating a child element - to hold the property if needed.""" - method = getattr(self.__class__, "_setPropertyValue" + getTypeString(value)) - return method(self, name, value, typeString) - -def _getPropertyValue(self, name, target = ''): - """Return the typed value of a property by its name. If the given property - is not found, then None is returned.""" - value = self._getPropertyValue(name) - return value.getData() if value else None - -PropertySet.setPropertyValue = _setPropertyValue -PropertySet.getPropertyValue = _getPropertyValue - - -# -# GeomInfo -# - -def _setGeomPropValue(self, name, value, typeString = ''): - """Set the value of a geomprop by its name, creating a child element - to hold the geomprop if needed.""" - method = getattr(self.__class__, "_setGeomPropValue" + getTypeString(value)) - return method(self, name, value, typeString) - -def _addGeomAttr(self, name): - "(Deprecated) Add a geomprop to this element." - warnings.warn("This function is deprecated; call GeomInfo.addGeomProp() instead", DeprecationWarning, stacklevel = 2) - return self.addGeomProp(name) - -def _setGeomAttrValue(self, name, value, typeString = ''): - "(Deprecated) Set the value of a geomattr by its name." - warnings.warn("This function is deprecated; call GeomInfo.setGeomPropValue() instead", DeprecationWarning, stacklevel = 2) - return self.setGeomPropValue(name, value, typeString) - -GeomInfo.setGeomPropValue = _setGeomPropValue -GeomInfo.addGeomAttr = _addGeomAttr -GeomInfo.setGeomAttrValue = _setGeomAttrValue - - -# -# Document -# - -def _addMaterial(self, name): - """(Deprecated) Add a material element to the document.""" - warnings.warn("This function is deprecated; call Document.addMaterialNode() instead.", DeprecationWarning, stacklevel = 2) - return self.addMaterialNode(name) - -def _getMaterials(self): - """(Deprecated) Return a vector of all materials in the document.""" - warnings.warn("This function is deprecated; call Document.getMaterialNodes() instead.", DeprecationWarning, stacklevel = 2) - return self.getMaterialNodes() - -Document.addMaterial = _addMaterial -Document.getMaterials = _getMaterials - - -# -# Value -# - -def _typeToName(t): - "(Deprecated) Return the MaterialX type string associated with the given Python type." - warnings.warn("This function is deprecated; call MaterialX.getTypeString instead.", DeprecationWarning, stacklevel = 2) - return getTypeString(t()) - -def _valueToString(value): - "(Deprecated) Convert a Python value to its corresponding MaterialX value string." - warnings.warn("This function is deprecated; call MaterialX.getValueString instead.", DeprecationWarning, stacklevel = 2) - return getValueString(value) - -def _stringToValue(string, t): - "(Deprecated) Convert a MaterialX value string and Python type to the corresponding Python value." - warnings.warn("This function is deprecated; call MaterialX.createValueFromStrings instead.", DeprecationWarning, stacklevel = 2) - return createValueFromStrings(string, getTypeString(t())) - -typeToName = _typeToName -valueToString = _valueToString -stringToValue = _stringToValue - - -# -# XmlIo -# - -readFromXmlFile = readFromXmlFileBase - - -# -# Default Data Paths -# - -def getDefaultDataSearchPath(): - """ - Return the default data search path. - """ - return FileSearchPath(os.path.dirname(__file__)) - -def getDefaultDataLibraryFolders(): - """ - Return list of default data library folders - """ - return [ 'libraries' ] +#!/usr/bin/env python +''' +Native Python wrappers for PyMaterialX, providing a more Pythonic interface +for Elements and Values. +''' + +import warnings + +from .PyMaterialXCore import * +from .PyMaterialXFormat import * +from .datatype import * +import os + +# +# Element +# + +def _isA(self, elementClass, category = ''): + """Return True if this element is an instance of the given subclass. + If a category string is specified, then both subclass and category + matches are required.""" + if not isinstance(self, elementClass): + return False + if category and self.getCategory() != category: + return False + return True + +def _addChild(self, elementClass, name, typeString = ''): + "Add a child element of the given subclass, name, and optional type string." + method = getattr(self.__class__, "_addChild" + elementClass.__name__) + return method(self, name, typeString) + +def _getChild(self, name): + "Return the child element, if any, with the given name." + if (name == None): + return None + return self._getChild(name) + +def _getChildOfType(self, elementClass, name): + "Return the child element, if any, with the given name and subclass." + method = getattr(self.__class__, "_getChildOfType" + elementClass.__name__) + return method(self, name) + +def _getChildrenOfType(self, elementClass): + """Return a list of all child elements that are instances of the given type. + The returned list maintains the order in which children were added.""" + method = getattr(self.__class__, "_getChildrenOfType" + elementClass.__name__) + return method(self) + +def _removeChildOfType(self, elementClass, name): + "Remove the typed child element, if any, with the given name." + method = getattr(self.__class__, "_removeChildOfType" + elementClass.__name__) + method(self, name) + +Element.isA = _isA +Element.addChild = _addChild +Element.getChild = _getChild +Element.getChildOfType = _getChildOfType +Element.getChildrenOfType = _getChildrenOfType +Element.removeChildOfType = _removeChildOfType + + +# +# ValueElement +# + +def _setValue(self, value, typeString = ''): + "Set the typed value of an element." + method = getattr(self.__class__, "_setValue" + getTypeString(value)) + method(self, value, typeString) + +def _getValue(self): + "Return the typed value of an element." + value = self._getValue() + return value.getData() if value else None + +def _getDefaultValue(self): + """Return the default value for this element.""" + value = self._getDefaultValue() + return value.getData() if value else None + +ValueElement.setValue = _setValue +ValueElement.getValue = _getValue +ValueElement.getDefaultValue = _getDefaultValue + + +# +# InterfaceElement +# + +def _setInputValue(self, name, value, typeString = ''): + """Set the typed value of an input by its name, creating a child element + to hold the input if needed.""" + method = getattr(self.__class__, "_setInputValue" + getTypeString(value)) + return method(self, name, value, typeString) + +def _getInputValue(self, name, target = ''): + """Return the typed value of an input by its name, taking both the + calling element and its declaration into account. If the given + input is not found, then None is returned.""" + value = self._getInputValue(name, target) + return value.getData() if value else None + +def _addParameter(self, name): + """(Deprecated) Add a Parameter to this interface.""" + warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) + return self.addInput(name) + +def _getParameters(self): + """(Deprecated) Return a vector of all Parameter elements.""" + warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) + return list() + +def _getActiveParameters(self): + """(Deprecated) Return a vector of all parameters belonging to this interface, taking inheritance into account.""" + warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) + return list() + +def _setParameterValue(self, name, value, typeString = ''): + """(Deprecated) Set the typed value of a parameter by its name.""" + warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) + +def _getParameterValue(self, name, target = ''): + """(Deprecated) Return the typed value of a parameter by its name.""" + warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) + return None + +def _getParameterValueString(self, name): + """(Deprecated) Return the value string of a parameter by its name.""" + warnings.warn("This function is deprecated; parameters have been replaced with uniform inputs in 1.38.", DeprecationWarning, stacklevel = 2) + return "" + +def _addBindInput(self, name, type = DEFAULT_TYPE_STRING): + """(Deprecated) Add a BindInput to this shader reference.""" + warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) + return self.addInput(name, type) + +def _getBindInputs(self): + """(Deprecated) Return a vector of all BindInput elements in this shader reference.""" + warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) + return self.getInputs() + +def _addBindParam(self, name, type = DEFAULT_TYPE_STRING): + """(Deprecated) Add a BindParam to this shader reference.""" + warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) + return self.addInput(name, type) + +def _getBindParams(self): + """(Deprecated) Return a vector of all BindParam elements in this shader reference.""" + warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) + return list() + +def _getBindTokens(self): + """(Deprecated) Return a vector of all BindToken elements in this shader reference.""" + warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) + return list() + +InterfaceElement.setInputValue = _setInputValue +InterfaceElement.getInputValue = _getInputValue +InterfaceElement.addParameter = _addParameter +InterfaceElement.getParameters = _getParameters +InterfaceElement.getActiveParameters = _getActiveParameters +InterfaceElement.setParameterValue = _setParameterValue +InterfaceElement.getParameterValue = _getParameterValue +InterfaceElement.getParameterValueString = _getParameterValueString +InterfaceElement.addBindInput = _addBindInput +InterfaceElement.getBindInputs = _getBindInputs +InterfaceElement.addBindParam = _addBindParam +InterfaceElement.getBindParams = _getBindParams +InterfaceElement.getBindTokens = _getBindTokens + + +# +# Node +# + +def _getReferencedNodeDef(self): + "(Deprecated) Return the first NodeDef that declares this node." + warnings.warn("This function is deprecated; call Node.getNodeDef instead.", DeprecationWarning, stacklevel = 2) + return self.getNodeDef() + +def _addShaderRef(self, name, nodeName): + "(Deprecated) Add a shader reference to this material element." + warnings.warn("This function is deprecated; material elements have been replaced with material nodes in 1.38.", DeprecationWarning, stacklevel = 2) + return self.getParent().addNode(nodeName, name) + +def _getShaderRefs(self): + """(Deprecated) Return a vector of all shader references in this material element.""" + warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) + return getShaderNodes(self) + +def _getActiveShaderRefs(self): + """(Deprecated) Return a vector of all shader references in this material element, taking material inheritance into account.""" + warnings.warn("This function is deprecated; shader references have been replaced with shader nodes in 1.38.", DeprecationWarning, stacklevel = 2) + return getShaderNodes(self) + +Node.getReferencedNodeDef = _getReferencedNodeDef +Node.addShaderRef = _addShaderRef +Node.getShaderRefs = _getShaderRefs +Node.getActiveShaderRefs = _getActiveShaderRefs + + +# +# PropertySet +# + +def _setPropertyValue(self, name, value, typeString = ''): + """Set the typed value of a property by its name, creating a child element + to hold the property if needed.""" + method = getattr(self.__class__, "_setPropertyValue" + getTypeString(value)) + return method(self, name, value, typeString) + +def _getPropertyValue(self, name, target = ''): + """Return the typed value of a property by its name. If the given property + is not found, then None is returned.""" + value = self._getPropertyValue(name) + return value.getData() if value else None + +PropertySet.setPropertyValue = _setPropertyValue +PropertySet.getPropertyValue = _getPropertyValue + + +# +# GeomInfo +# + +def _setGeomPropValue(self, name, value, typeString = ''): + """Set the value of a geomprop by its name, creating a child element + to hold the geomprop if needed.""" + method = getattr(self.__class__, "_setGeomPropValue" + getTypeString(value)) + return method(self, name, value, typeString) + +def _addGeomAttr(self, name): + "(Deprecated) Add a geomprop to this element." + warnings.warn("This function is deprecated; call GeomInfo.addGeomProp() instead", DeprecationWarning, stacklevel = 2) + return self.addGeomProp(name) + +def _setGeomAttrValue(self, name, value, typeString = ''): + "(Deprecated) Set the value of a geomattr by its name." + warnings.warn("This function is deprecated; call GeomInfo.setGeomPropValue() instead", DeprecationWarning, stacklevel = 2) + return self.setGeomPropValue(name, value, typeString) + +GeomInfo.setGeomPropValue = _setGeomPropValue +GeomInfo.addGeomAttr = _addGeomAttr +GeomInfo.setGeomAttrValue = _setGeomAttrValue + + +# +# Document +# + +def _addMaterial(self, name): + """(Deprecated) Add a material element to the document.""" + warnings.warn("This function is deprecated; call Document.addMaterialNode() instead.", DeprecationWarning, stacklevel = 2) + return self.addMaterialNode(name) + +def _getMaterials(self): + """(Deprecated) Return a vector of all materials in the document.""" + warnings.warn("This function is deprecated; call Document.getMaterialNodes() instead.", DeprecationWarning, stacklevel = 2) + return self.getMaterialNodes() + +Document.addMaterial = _addMaterial +Document.getMaterials = _getMaterials + + +# +# Value +# + +def _typeToName(t): + "(Deprecated) Return the MaterialX type string associated with the given Python type." + warnings.warn("This function is deprecated; call MaterialX.getTypeString instead.", DeprecationWarning, stacklevel = 2) + return getTypeString(t()) + +def _valueToString(value): + "(Deprecated) Convert a Python value to its correponding MaterialX value string." + warnings.warn("This function is deprecated; call MaterialX.getValueString instead.", DeprecationWarning, stacklevel = 2) + return getValueString(value) + +def _stringToValue(string, t): + "(Deprecated) Convert a MaterialX value string and Python type to the corresponding Python value." + warnings.warn("This function is deprecated; call MaterialX.createValueFromStrings instead.", DeprecationWarning, stacklevel = 2) + return createValueFromStrings(string, getTypeString(t())) + +typeToName = _typeToName +valueToString = _valueToString +stringToValue = _stringToValue + + +# +# XmlIo +# + +readFromXmlFile = readFromXmlFileBase + + +# +# Default Data Paths +# + +def getDefaultDataSearchPath(): + """ + Return the default data search path. + """ + return FileSearchPath(os.path.dirname(__file__)) + +def getDefaultDataLibraryFolders(): + """ + Return list of default data library folders + """ + return [ 'libraries' ] diff --git a/MaterialX/python/MaterialXTest/__init__.py b/MaterialX/python/MaterialXTest/__init__.py old mode 100644 new mode 100755 diff --git a/MaterialX/python/MaterialXTest/genshader.py b/MaterialX/python/MaterialXTest/genshader.py old mode 100644 new mode 100755 index b6a81ba..ef197d2 --- a/MaterialX/python/MaterialXTest/genshader.py +++ b/MaterialX/python/MaterialXTest/genshader.py @@ -1,126 +1,125 @@ -#!/usr/bin/env python -''' -Unit tests for shader generation in MaterialX Python. -''' - -import os, unittest - -import MaterialX as mx -import MaterialX.PyMaterialXGenShader as mx_gen_shader -import MaterialX.PyMaterialXGenOsl as mx_gen_osl - -class TestGenShader(unittest.TestCase): - def test_ShaderInterface(self): - doc = mx.createDocument() - searchPath = mx.getDefaultDataSearchPath() - mx.loadLibraries(mx.getDefaultDataLibraryFolders(), searchPath, doc) - - exampleName = u"shader_interface" - - # Create a nodedef taking three color3 and producing another color3 - nodeDef = doc.addNodeDef("ND_foo", "color3", "foo") - fooInputA = nodeDef.addInput("a", "color3") - fooInputB = nodeDef.addInput("b", "color3") - fooOutput = nodeDef.getOutput("out") - fooInputA.setValue(mx.Color3(1.0, 1.0, 0.0)) - fooInputB.setValue(mx.Color3(0.8, 0.1, 0.1)) - - # Create an implementation graph for the nodedef performing - # a multiplication of the three colors. - nodeGraph = doc.addNodeGraph("IMP_foo") - nodeGraph.setAttribute("nodedef", nodeDef.getName()) - - output = nodeGraph.addOutput(fooOutput.getName(), "color3") - mult1 = nodeGraph.addNode("multiply", "mult1", "color3") - in1 = mult1.addInput("in1", "color3") - in1.setInterfaceName(fooInputA.getName()) - in2 = mult1.addInput("in2", "color3") - in2.setInterfaceName(fooInputB.getName()) - output.setConnectedNode(mult1) - - doc.addNode("foo", "foo1", "color3") - output = doc.addOutput("foo_test", "color3"); - output.setNodeName("foo1"); - output.setAttribute("output", "o"); - - # Test for target - targetDefs = doc.getTargetDefs() - self.assertTrue(len(targetDefs)) - shadergen = mx_gen_osl.OslShaderGenerator.create() - target = shadergen.getTarget() - foundTarget = next(( - t for t in targetDefs - if t.getName() == target), None) - self.assertTrue(foundTarget) - context = mx_gen_shader.GenContext(shadergen) - context.registerSourceCodeSearchPath(searchPath) - shadergen.registerTypeDefs(doc); - - # Test generator with complete mode - context.getOptions().shaderInterfaceType = mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE; - shader = shadergen.generate(exampleName, output, context); - self.assertTrue(shader) - self.assertTrue(len(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) > 0) - - ps = shader.getStage(mx_gen_shader.PIXEL_STAGE); - uniforms = ps.getUniformBlock(mx_gen_osl.OSL_UNIFORMS) - self.assertTrue(uniforms.size() == 2) - - outputs = ps.getOutputBlock(mx_gen_osl.OSL_OUTPUTS) - self.assertTrue(outputs.size() == 1) - self.assertTrue(outputs[0].getName() == output.getName()) - - file = open(shader.getName() + "_complete.osl", "w+") - file.write(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) - file.close() - os.remove(shader.getName() + "_complete.osl"); - - # Test generator with reduced mode - context.getOptions().shaderInterfaceType = mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_REDUCED; - shader = shadergen.generate(exampleName, output, context); - self.assertTrue(shader) - self.assertTrue(len(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) > 0) - - ps = shader.getStage(mx_gen_shader.PIXEL_STAGE); - uniforms = ps.getUniformBlock(mx_gen_osl.OSL_UNIFORMS) - self.assertTrue(uniforms.size() == 0) - - outputs = ps.getOutputBlock(mx_gen_osl.OSL_OUTPUTS) - self.assertTrue(outputs.size() == 1) - self.assertTrue(outputs[0].getName() == output.getName()) - - file = open(shader.getName() + "_reduced.osl", "w+") - file.write(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) - file.close() - os.remove(shader.getName() + "_reduced.osl"); - - # Define a custom attribute - customAttribute = doc.addAttributeDef("AD_attribute_node_name"); - self.assertIsNotNone(customAttribute) - customAttribute.setType("string"); - customAttribute.setAttrName("node_name"); - customAttribute.setExportable(True); - - # Define a nodedef referencing the custom attribute. - stdSurfNodeDef = doc.getNodeDef("ND_standard_surface_surfaceshader"); - self.assertIsNotNone(stdSurfNodeDef) - stdSurfNodeDef.setAttribute("node_name", "Standard_Surface_Number_1"); - self.assertTrue(stdSurfNodeDef.getAttribute("node_name") == "Standard_Surface_Number_1") - stdSurf1 = doc.addNodeInstance(stdSurfNodeDef, "standardSurface1"); - self.assertIsNotNone(stdSurf1) - - # Register shader metadata - shadergen.registerShaderMetadata(doc, context); - - # Generate and test that attribute is in the code - context.getOptions().shaderInterfaceType = mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE; - shader = shadergen.generate(stdSurf1.getName(), stdSurf1, context); - self.assertIsNotNone(shader) - code = shader.getSourceCode(mx_gen_shader.PIXEL_STAGE) - self.assertTrue('Standard_Surface_Number_1' in code) - self.assertTrue('node_name' in code) - - print() - -if __name__ == '__main__': - unittest.main() +#!/usr/bin/env python +''' +Unit tests for shader generation in MaterialX Python. +''' + +import os, unittest + +import MaterialX as mx +import MaterialX.PyMaterialXGenShader as mx_gen_shader +import MaterialX.PyMaterialXGenOsl as mx_gen_osl + +class TestGenShader(unittest.TestCase): + def test_ShaderInterface(self): + doc = mx.createDocument() + searchPath = mx.getDefaultDataSearchPath() + mx.loadLibraries(mx.getDefaultDataLibraryFolders(), searchPath, doc) + + exampleName = u"shader_interface" + + # Create a nodedef taking three color3 and producing another color3 + nodeDef = doc.addNodeDef("ND_foo", "color3", "foo") + fooInputA = nodeDef.addInput("a", "color3") + fooInputB = nodeDef.addInput("b", "color3") + fooOutput = nodeDef.getOutput("out") + fooInputA.setValue(mx.Color3(1.0, 1.0, 0.0)) + fooInputB.setValue(mx.Color3(0.8, 0.1, 0.1)) + + # Create an implementation graph for the nodedef performing + # a multiplication of the three colors. + nodeGraph = doc.addNodeGraph("IMP_foo") + nodeGraph.setAttribute("nodedef", nodeDef.getName()) + + output = nodeGraph.addOutput(fooOutput.getName(), "color3") + mult1 = nodeGraph.addNode("multiply", "mult1", "color3") + in1 = mult1.addInput("in1", "color3") + in1.setInterfaceName(fooInputA.getName()) + in2 = mult1.addInput("in2", "color3") + in2.setInterfaceName(fooInputB.getName()) + output.setConnectedNode(mult1) + + doc.addNode("foo", "foo1", "color3") + output = doc.addOutput("foo_test", "color3"); + output.setNodeName("foo1"); + output.setAttribute("output", "o"); + + # Test for target + targetDefs = doc.getTargetDefs() + self.assertTrue(len(targetDefs)) + shadergen = mx_gen_osl.OslShaderGenerator.create() + target = shadergen.getTarget() + foundTarget = next(( + t for t in targetDefs + if t.getName() == target), None) + self.assertTrue(foundTarget) + context = mx_gen_shader.GenContext(shadergen) + context.registerSourceCodeSearchPath(searchPath) + + # Test generator with complete mode + context.getOptions().shaderInterfaceType = mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE; + shader = shadergen.generate(exampleName, output, context); + self.assertTrue(shader) + self.assertTrue(len(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) > 0) + + ps = shader.getStage(mx_gen_shader.PIXEL_STAGE); + uniforms = ps.getUniformBlock(mx_gen_osl.OSL_UNIFORMS) + self.assertTrue(uniforms.size() == 2) + + outputs = ps.getOutputBlock(mx_gen_osl.OSL_OUTPUTS) + self.assertTrue(outputs.size() == 1) + self.assertTrue(outputs[0].getName() == output.getName()) + + file = open(shader.getName() + "_complete.osl", "w+") + file.write(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) + file.close() + os.remove(shader.getName() + "_complete.osl"); + + # Test generator with reduced mode + context.getOptions().shaderInterfaceType = mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_REDUCED; + shader = shadergen.generate(exampleName, output, context); + self.assertTrue(shader) + self.assertTrue(len(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) > 0) + + ps = shader.getStage(mx_gen_shader.PIXEL_STAGE); + uniforms = ps.getUniformBlock(mx_gen_osl.OSL_UNIFORMS) + self.assertTrue(uniforms.size() == 0) + + outputs = ps.getOutputBlock(mx_gen_osl.OSL_OUTPUTS) + self.assertTrue(outputs.size() == 1) + self.assertTrue(outputs[0].getName() == output.getName()) + + file = open(shader.getName() + "_reduced.osl", "w+") + file.write(shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)) + file.close() + os.remove(shader.getName() + "_reduced.osl"); + + # Define a custom attribute + customAttribute = doc.addAttributeDef("AD_attribute_node_name"); + self.assertIsNotNone(customAttribute) + customAttribute.setType("string"); + customAttribute.setAttrName("node_name"); + customAttribute.setExportable(True); + + # Define a nodedef referencing the custom attribute. + stdSurfNodeDef = doc.getNodeDef("ND_standard_surface_surfaceshader"); + self.assertIsNotNone(stdSurfNodeDef) + stdSurfNodeDef.setAttribute("node_name", "Standard_Surface_Number_1"); + self.assertTrue(stdSurfNodeDef.getAttribute("node_name") == "Standard_Surface_Number_1") + stdSurf1 = doc.addNodeInstance(stdSurfNodeDef, "standardSurface1"); + self.assertIsNotNone(stdSurf1) + + # Register shader metadata + shadergen.registerShaderMetadata(doc, context); + + # Generate and test that attribute is in the code + context.getOptions().shaderInterfaceType = mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE; + shader = shadergen.generate(stdSurf1.getName(), stdSurf1, context); + self.assertIsNotNone(shader) + code = shader.getSourceCode(mx_gen_shader.PIXEL_STAGE) + self.assertTrue('Standard_Surface_Number_1' in code) + self.assertTrue('node_name' in code) + + print() + +if __name__ == '__main__': + unittest.main() diff --git a/MaterialX/python/MaterialXTest/main.py b/MaterialX/python/MaterialXTest/main.py old mode 100644 new mode 100755 index 1aa406c..6f2ae8a --- a/MaterialX/python/MaterialXTest/main.py +++ b/MaterialX/python/MaterialXTest/main.py @@ -1,517 +1,498 @@ -#!/usr/bin/env python -''' -Unit tests for MaterialX Python. -''' - -import math, os, unittest - -import MaterialX as mx - - -#-------------------------------------------------------------------------------- -_testValues = (1, - True, - 1.0, - mx.Color3(0.1, 0.2, 0.3), - mx.Color4(0.1, 0.2, 0.3, 0.4), - mx.Vector2(1.0, 2.0), - mx.Vector3(1.0, 2.0, 3.0), - mx.Vector4(1.0, 2.0, 3.0, 4.0), - mx.Matrix33(0.0), - mx.Matrix44(1.0), - 'value', - [1, 2, 3], - [False, True, False], - [1.0, 2.0, 3.0], - ['one', 'two', 'three']) - -_fileDir = os.path.dirname(os.path.abspath(__file__)) -_libraryDir = os.path.join(_fileDir, '../../libraries/stdlib/') -_exampleDir = os.path.join(_fileDir, '../../resources/Materials/Examples/') -_searchPath = _libraryDir + mx.PATH_LIST_SEPARATOR + _exampleDir - -_libraryFilenames = ('stdlib_defs.mtlx', - 'stdlib_ng.mtlx') -_exampleFilenames = ('StandardSurface/standard_surface_brass_tiled.mtlx', - 'StandardSurface/standard_surface_brick_procedural.mtlx', - 'StandardSurface/standard_surface_carpaint.mtlx', - 'StandardSurface/standard_surface_marble_solid.mtlx', - 'StandardSurface/standard_surface_look_brass_tiled.mtlx', - 'UsdPreviewSurface/usd_preview_surface_gold.mtlx', - 'UsdPreviewSurface/usd_preview_surface_plastic.mtlx') - -_epsilon = 1e-4 - - -#-------------------------------------------------------------------------------- -class TestMaterialX(unittest.TestCase): - def test_Globals(self): - self.assertTrue(mx.__version__ == mx.getVersionString()) - - def test_DataTypes(self): - for value in _testValues: - valueString = mx.getValueString(value) - typeString = mx.getTypeString(value) - newValue = mx.createValueFromStrings(valueString, typeString) - self.assertTrue(newValue == value) - self.assertTrue(mx.getTypeString(newValue) == typeString) - - def test_Vectors(self): - v1 = mx.Vector3(1, 2, 3) - v2 = mx.Vector3(2, 4, 6) - - # Indexing operators - self.assertTrue(v1[2] == 3) - v1[2] = 4 - self.assertTrue(v1[2] == 4) - v1[2] = 3 - - # Component-wise operators - self.assertTrue(v2 + v1 == mx.Vector3(3, 6, 9)) - self.assertTrue(v2 - v1 == mx.Vector3(1, 2, 3)) - self.assertTrue(v2 * v1 == mx.Vector3(2, 8, 18)) - self.assertTrue(v2 / v1 == mx.Vector3(2, 2, 2)) - v2 += v1 - self.assertTrue(v2 == mx.Vector3(3, 6, 9)) - v2 -= v1 - self.assertTrue(v2 == mx.Vector3(2, 4, 6)) - v2 *= v1 - self.assertTrue(v2 == mx.Vector3(2, 8, 18)) - v2 /= v1 - self.assertTrue(v2 == mx.Vector3(2, 4, 6)) - self.assertTrue(v1 * 2 == v2) - self.assertTrue(v2 / 2 == v1) - - # Unary operation - self.assertTrue(-v1 == mx.Vector3(-1, -2, -3)) - v1 *= -1 - self.assertTrue(+v1 == mx.Vector3(-1, -2, -3)) - v1 *= -1 - - # Geometric methods - v3 = mx.Vector4(4) - self.assertTrue(v3.getMagnitude() == 8) - self.assertTrue(v3.getNormalized().getMagnitude() == 1) - self.assertTrue(v1.dot(v2) == 28) - self.assertTrue(v1.cross(v2) == mx.Vector3()) - - # Vector copy - v4 = v2.copy() - self.assertTrue(v4 == v2) - v4[0] += 1; - self.assertTrue(v4 != v2) - - def test_Matrices(self): - # Translation and scale - trans = mx.Matrix44.createTranslation(mx.Vector3(1, 2, 3)) - scale = mx.Matrix44.createScale(mx.Vector3(2)) - self.assertTrue(trans == mx.Matrix44(1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 2, 3, 1)) - self.assertTrue(scale == mx.Matrix44(2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, 2, 0, - 0, 0, 0, 1)) - - # Indexing operators - self.assertTrue(trans[3, 2] == 3) - trans[3, 2] = 4 - self.assertTrue(trans[3, 2] == 4) - trans[3, 2] = 3 - - # Matrix methods - self.assertTrue(trans.getTranspose() == mx.Matrix44(1, 0, 0, 1, - 0, 1, 0, 2, - 0, 0, 1, 3, - 0, 0, 0, 1)) - self.assertTrue(scale.getTranspose() == scale) - self.assertTrue(trans.getDeterminant() == 1) - self.assertTrue(scale.getDeterminant() == 8) - self.assertTrue(trans.getInverse() == - mx.Matrix44.createTranslation(mx.Vector3(-1, -2, -3))) - - # Matrix copy - trans2 = trans.copy() - self.assertTrue(trans2 == trans) - trans2[0, 0] += 1; - self.assertTrue(trans2 != trans) - - # Matrix product - prod1 = trans * scale - prod2 = scale * trans - prod3 = trans * 2 - prod4 = trans.copy() - prod4 *= scale - self.assertTrue(prod1 == mx.Matrix44(2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, 2, 0, - 2, 4, 6, 1)) - self.assertTrue(prod2 == mx.Matrix44(2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, 2, 0, - 1, 2, 3, 1)) - self.assertTrue(prod3 == mx.Matrix44(2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, 2, 0, - 2, 4, 6, 2)) - self.assertTrue(prod4 == prod1) - - # Matrix division - quot1 = prod1 / scale - quot2 = prod2 / trans - quot3 = prod3 / 2 - quot4 = quot1.copy() - quot4 /= trans - self.assertTrue(quot1 == trans) - self.assertTrue(quot2 == scale) - self.assertTrue(quot3 == trans) - self.assertTrue(quot4 == mx.Matrix44.IDENTITY) - - # Unary operation - self.assertTrue(-trans == mx.Matrix44(-1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, -1, 0, - -1, -2, -3, -1)) - trans *= -1 - self.assertTrue(+trans == mx.Matrix44(-1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, -1, 0, - -1, -2, -3, -1)) - trans *= -1 - - # 2D rotation - rot1 = mx.Matrix33.createRotation(math.pi / 2) - rot2 = mx.Matrix33.createRotation(math.pi) - self.assertTrue((rot1 * rot1).isEquivalent(rot2, _epsilon)) - self.assertTrue(rot2.isEquivalent( - mx.Matrix33.createScale(mx.Vector2(-1)), _epsilon)) - self.assertTrue((rot2 * rot2).isEquivalent(mx.Matrix33.IDENTITY, _epsilon)) - - # 3D rotation - rotX = mx.Matrix44.createRotationX(math.pi) - rotY = mx.Matrix44.createRotationY(math.pi) - rotZ = mx.Matrix44.createRotationZ(math.pi) - self.assertTrue((rotX * rotY).isEquivalent( - mx.Matrix44.createScale(mx.Vector3(-1, -1, 1)), _epsilon)) - self.assertTrue((rotX * rotZ).isEquivalent( - mx.Matrix44.createScale(mx.Vector3(-1, 1, -1)), _epsilon)) - self.assertTrue((rotY * rotZ).isEquivalent( - mx.Matrix44.createScale(mx.Vector3(1, -1, -1)), _epsilon)) - - - def test_BuildDocument(self): - # Create a document. - doc = mx.createDocument() - - # Create a node graph with constant and image sources. - nodeGraph = doc.addNodeGraph() - self.assertTrue(nodeGraph) - self.assertRaises(LookupError, doc.addNodeGraph, nodeGraph.getName()) - constant = nodeGraph.addNode('constant') - image = nodeGraph.addNode('image') - - # Connect sources to outputs. - output1 = nodeGraph.addOutput() - output2 = nodeGraph.addOutput() - output1.setConnectedNode(constant) - output2.setConnectedNode(image) - self.assertTrue(output1.getConnectedNode() == constant) - self.assertTrue(output2.getConnectedNode() == image) - self.assertTrue(output1.getUpstreamElement() == constant) - self.assertTrue(output2.getUpstreamElement() == image) - - # Set constant node color. - color = mx.Color3(0.1, 0.2, 0.3) - constant.setInputValue('value', color) - self.assertTrue(constant.getInputValue('value') == color) - - # Set image node file. - file = 'image1.tif' - image.setInputValue('file', file, 'filename') - self.assertTrue(image.getInputValue('file') == file) - - # Create a custom nodedef. - nodeDef = doc.addNodeDef('nodeDef1', 'float', 'turbulence3d') - nodeDef.setInputValue('octaves', 3) - nodeDef.setInputValue('lacunarity', 2.0) - nodeDef.setInputValue('gain', 0.5) - - # Reference the custom nodedef. - custom = nodeGraph.addNode('turbulence3d', 'turbulence1', 'float') - self.assertTrue(custom.getInputValue('octaves') == 3) - custom.setInputValue('octaves', 5) - self.assertTrue(custom.getInputValue('octaves') == 5) - - # Test scoped attributes. - nodeGraph.setFilePrefix('folder/') - nodeGraph.setColorSpace('lin_rec709') - self.assertTrue(image.getInput('file').getResolvedValueString() == 'folder/image1.tif') - self.assertTrue(constant.getActiveColorSpace() == 'lin_rec709') - - # Create a simple shader interface. - simpleSrf = doc.addNodeDef('', 'surfaceshader', 'simpleSrf') - simpleSrf.setInputValue('diffColor', mx.Color3(1.0)) - simpleSrf.setInputValue('specColor', mx.Color3(0.0)) - roughness = simpleSrf.setInputValue('roughness', 0.25) - self.assertTrue(roughness.getIsUniform() == False) - roughness.setIsUniform(True); - self.assertTrue(roughness.getIsUniform() == True) - - # Instantiate shader and material nodes. - shaderNode = doc.addNodeInstance(simpleSrf) - materialNode = doc.addMaterialNode('', shaderNode) - - # Bind the diffuse color input to the constant color output. - shaderNode.setConnectedOutput('diffColor', output1) - self.assertTrue(shaderNode.getUpstreamElement() == constant) - - # Bind the roughness input to a value. - instanceRoughness = shaderNode.setInputValue('roughness', 0.5) - self.assertTrue(instanceRoughness.getValue() == 0.5) - self.assertTrue(instanceRoughness.getDefaultValue() == 0.25) - - # Create a look for the material. - look = doc.addLook() - self.assertTrue(len(doc.getLooks()) == 1) - - # Bind the material to a geometry string. - matAssign1 = look.addMaterialAssign("matAssign1", materialNode.getName()) - matAssign1.setGeom("/robot1") - self.assertTrue(matAssign1.getReferencedMaterial() == materialNode) - self.assertTrue(len(mx.getGeometryBindings(materialNode, "/robot1")) == 1) - self.assertTrue(len(mx.getGeometryBindings(materialNode, "/robot2")) == 0) - - # Bind the material to a collection. - matAssign2 = look.addMaterialAssign("matAssign2", materialNode.getName()) - collection = doc.addCollection() - collection.setIncludeGeom("/robot2") - collection.setExcludeGeom("/robot2/left_arm") - matAssign2.setCollection(collection) - self.assertTrue(len(mx.getGeometryBindings(materialNode, "/robot2")) == 1) - self.assertTrue(len(mx.getGeometryBindings(materialNode, "/robot2/right_arm")) == 1) - self.assertTrue(len(mx.getGeometryBindings(materialNode, "/robot2/left_arm")) == 0) - - # Create a property assignment. - propertyAssign = look.addPropertyAssign() - propertyAssign.setProperty("twosided") - propertyAssign.setGeom("/robot1") - propertyAssign.setValue(True) - self.assertTrue(propertyAssign.getProperty() == "twosided") - self.assertTrue(propertyAssign.getGeom() == "/robot1") - self.assertTrue(propertyAssign.getValue() == True) - - # Create a property set assignment. - propertySet = doc.addPropertySet() - propertySet.setPropertyValue('matte', False) - self.assertTrue(propertySet.getPropertyValue('matte') == False) - propertySetAssign = look.addPropertySetAssign() - propertySetAssign.setPropertySet(propertySet) - propertySetAssign.setGeom('/robot1') - self.assertTrue(propertySetAssign.getPropertySet() == propertySet) - self.assertTrue(propertySetAssign.getGeom() == '/robot1') - - # Create a variant set. - variantSet = doc.addVariantSet() - variantSet.addVariant("original") - variantSet.addVariant("damaged") - self.assertTrue(len(variantSet.getVariants()) == 2) - - # Validate the document. - valid, message = doc.validate() - self.assertTrue(valid, 'Document returned validation warnings: ' + message) - - # Disconnect outputs from sources. - output1.setConnectedNode(None) - output2.setConnectedNode(None) - self.assertTrue(output1.getConnectedNode() == None) - self.assertTrue(output2.getConnectedNode() == None) - - def test_TraverseGraph(self): - # Create a document. - doc = mx.createDocument() - - # Create a node graph with the following structure: - # - # [image1] [constant] [image2] - # \ / | - # [multiply] [contrast] [noise3d] - # \____________ | ____________/ - # [mix] - # | - # [output] - # - nodeGraph = doc.addNodeGraph() - image1 = nodeGraph.addNode('image') - image2 = nodeGraph.addNode('image') - constant = nodeGraph.addNode('constant') - multiply = nodeGraph.addNode('multiply') - contrast = nodeGraph.addNode('contrast') - noise3d = nodeGraph.addNode('noise3d') - mix = nodeGraph.addNode('mix') - output = nodeGraph.addOutput() - multiply.setConnectedNode('in1', image1) - multiply.setConnectedNode('in2', constant) - contrast.setConnectedNode('in', image2) - mix.setConnectedNode('fg', multiply) - mix.setConnectedNode('bg', contrast) - mix.setConnectedNode('mask', noise3d) - output.setConnectedNode(mix) - - # Validate the document. - valid, message = doc.validate() - self.assertTrue(valid, 'Document returned validation warnings: ' + message) - - # Traverse the document tree (implicit iterator). - nodeCount = 0 - for elem in doc.traverseTree(): - if elem.isA(mx.Node): - nodeCount += 1 - self.assertTrue(nodeCount == 7) - - # Traverse the document tree (explicit iterator). - nodeCount = 0 - maxElementDepth = 0 - treeIter = doc.traverseTree() - for elem in treeIter: - if elem.isA(mx.Node): - nodeCount += 1 - maxElementDepth = max(maxElementDepth, treeIter.getElementDepth()) - self.assertTrue(nodeCount == 7) - self.assertTrue(maxElementDepth == 3) - - # Traverse the document tree (prune subtree). - nodeCount = 0 - treeIter = doc.traverseTree() - for elem in treeIter: - if elem.isA(mx.Node): - nodeCount += 1 - if elem.isA(mx.NodeGraph): - treeIter.setPruneSubtree(True) - self.assertTrue(nodeCount == 0) - - # Traverse upstream from the graph output (implicit iterator). - nodeCount = 0 - for edge in output.traverseGraph(): - upstreamElem = edge.getUpstreamElement() - connectingElem = edge.getConnectingElement() - downstreamElem = edge.getDownstreamElement() - if upstreamElem.isA(mx.Node): - nodeCount += 1 - if downstreamElem.isA(mx.Node): - self.assertTrue(connectingElem.isA(mx.Input)) - self.assertTrue(nodeCount == 7) - - # Traverse upstream from the graph output (explicit iterator). - nodeCount = 0 - maxElementDepth = 0 - maxNodeDepth = 0 - graphIter = output.traverseGraph() - for edge in graphIter: - upstreamElem = edge.getUpstreamElement() - connectingElem = edge.getConnectingElement() - downstreamElem = edge.getDownstreamElement() - if upstreamElem.isA(mx.Node): - nodeCount += 1 - maxElementDepth = max(maxElementDepth, graphIter.getElementDepth()) - maxNodeDepth = max(maxNodeDepth, graphIter.getNodeDepth()) - self.assertTrue(nodeCount == 7) - self.assertTrue(maxElementDepth == 3) - self.assertTrue(maxNodeDepth == 3) - - # Traverse upstream from the graph output (prune subgraph). - nodeCount = 0 - graphIter = output.traverseGraph() - for edge in graphIter: - upstreamElem = edge.getUpstreamElement() - connectingElem = edge.getConnectingElement() - downstreamElem = edge.getDownstreamElement() - if upstreamElem.isA(mx.Node): - nodeCount += 1 - if upstreamElem.getCategory() == 'multiply': - graphIter.setPruneSubgraph(True) - self.assertTrue(nodeCount == 5) - - # Create and detect a cycle. - multiply.setConnectedNode('in2', mix) - self.assertTrue(output.hasUpstreamCycle()) - self.assertFalse(doc.validate()[0]) - multiply.setConnectedNode('in2', constant) - self.assertFalse(output.hasUpstreamCycle()) - self.assertTrue(doc.validate()[0]) - - # Create and detect a loop. - contrast.setConnectedNode('in', contrast) - self.assertTrue(output.hasUpstreamCycle()) - self.assertFalse(doc.validate()[0]) - contrast.setConnectedNode('in', image2) - self.assertFalse(output.hasUpstreamCycle()) - self.assertTrue(doc.validate()[0]) - - def test_Xmlio(self): - # Read the standard library. - libs = [] - for filename in _libraryFilenames: - lib = mx.createDocument() - mx.readFromXmlFile(lib, filename, _searchPath) - libs.append(lib) - - # Declare write predicate for write filter test - def skipLibraryElement(elem): - return not elem.hasSourceUri() - - # Read and validate each example document. - for filename in _exampleFilenames: - doc = mx.createDocument() - mx.readFromXmlFile(doc, filename, _searchPath) - valid, message = doc.validate() - self.assertTrue(valid, filename + ' returned validation warnings: ' + message) - - # Copy the document. - copiedDoc = doc.copy() - self.assertTrue(copiedDoc == doc) - copiedDoc.addLook() - self.assertTrue(copiedDoc != doc) - - # Traverse the document tree. - valueElementCount = 0 - for elem in doc.traverseTree(): - if elem.isA(mx.ValueElement): - valueElementCount += 1 - self.assertTrue(valueElementCount > 0) - - # Serialize to XML. - writeOptions = mx.XmlWriteOptions() - writeOptions.writeXIncludeEnable = False - xmlString = mx.writeToXmlString(doc, writeOptions) - - # Verify that the serialized document is identical. - writtenDoc = mx.createDocument() - mx.readFromXmlString(writtenDoc, xmlString) - self.assertTrue(writtenDoc == doc) - - # Combine document with the standard library. - doc2 = doc.copy() - for lib in libs: - doc2.importLibrary(lib) - self.assertTrue(doc2.validate()[0]) - - # Write without definitions - writeOptions.writeXIncludeEnable = False - writeOptions.elementPredicate = skipLibraryElement - result = mx.writeToXmlString(doc2, writeOptions) - doc3 = mx.createDocument() - mx.readFromXmlString(doc3, result) - self.assertTrue(len(doc3.getNodeDefs()) == 0) - - # Read the same document twice, and verify that duplicate elements - # are skipped. - doc = mx.createDocument() - filename = 'StandardSurface/standard_surface_carpaint.mtlx' - mx.readFromXmlFile(doc, filename, _searchPath) - mx.readFromXmlFile(doc, filename, _searchPath) - self.assertTrue(doc.validate()[0]) - -#-------------------------------------------------------------------------------- -if __name__ == '__main__': - unittest.main() +#!/usr/bin/env python +''' +Unit tests for MaterialX Python. +''' + +import math, os, unittest + +import MaterialX as mx + + +#-------------------------------------------------------------------------------- +_testValues = (1, + True, + 1.0, + mx.Color3(0.1, 0.2, 0.3), + mx.Color4(0.1, 0.2, 0.3, 0.4), + mx.Vector2(1.0, 2.0), + mx.Vector3(1.0, 2.0, 3.0), + mx.Vector4(1.0, 2.0, 3.0, 4.0), + mx.Matrix33(0.0), + mx.Matrix44(1.0), + 'value', + [1, 2, 3], + [False, True, False], + [1.0, 2.0, 3.0], + ['one', 'two', 'three']) + +_fileDir = os.path.dirname(os.path.abspath(__file__)) +_libraryDir = os.path.join(_fileDir, '../../libraries/stdlib/') +_exampleDir = os.path.join(_fileDir, '../../resources/Materials/Examples/') +_searchPath = _libraryDir + mx.PATH_LIST_SEPARATOR + _exampleDir + +_libraryFilenames = ('stdlib_defs.mtlx', + 'stdlib_ng.mtlx') +_exampleFilenames = ('StandardSurface/standard_surface_brass_tiled.mtlx', + 'StandardSurface/standard_surface_brick_procedural.mtlx', + 'StandardSurface/standard_surface_carpaint.mtlx', + 'StandardSurface/standard_surface_marble_solid.mtlx', + 'StandardSurface/standard_surface_look_brass_tiled.mtlx', + 'UsdPreviewSurface/usd_preview_surface_gold.mtlx', + 'UsdPreviewSurface/usd_preview_surface_plastic.mtlx') + +_epsilon = 1e-4 + + +#-------------------------------------------------------------------------------- +class TestMaterialX(unittest.TestCase): + def test_Globals(self): + self.assertTrue(mx.__version__ == mx.getVersionString()) + + def test_DataTypes(self): + for value in _testValues: + valueString = mx.getValueString(value) + typeString = mx.getTypeString(value) + newValue = mx.createValueFromStrings(valueString, typeString) + self.assertTrue(newValue == value) + self.assertTrue(mx.getTypeString(newValue) == typeString) + + def test_Vectors(self): + v1 = mx.Vector3(1, 2, 3) + v2 = mx.Vector3(2, 4, 6) + + # Indexing operators + self.assertTrue(v1[2] == 3) + v1[2] = 4 + self.assertTrue(v1[2] == 4) + v1[2] = 3 + + # Component-wise operators + self.assertTrue(v2 + v1 == mx.Vector3(3, 6, 9)) + self.assertTrue(v2 - v1 == mx.Vector3(1, 2, 3)) + self.assertTrue(v2 * v1 == mx.Vector3(2, 8, 18)) + self.assertTrue(v2 / v1 == mx.Vector3(2, 2, 2)) + v2 += v1 + self.assertTrue(v2 == mx.Vector3(3, 6, 9)) + v2 -= v1 + self.assertTrue(v2 == mx.Vector3(2, 4, 6)) + v2 *= v1 + self.assertTrue(v2 == mx.Vector3(2, 8, 18)) + v2 /= v1 + self.assertTrue(v2 == mx.Vector3(2, 4, 6)) + self.assertTrue(v1 * 2 == v2) + self.assertTrue(v2 / 2 == v1) + + # Geometric methods + v3 = mx.Vector4(4) + self.assertTrue(v3.getMagnitude() == 8) + self.assertTrue(v3.getNormalized().getMagnitude() == 1) + self.assertTrue(v1.dot(v2) == 28) + self.assertTrue(v1.cross(v2) == mx.Vector3()) + + # Vector copy + v4 = v2.copy() + self.assertTrue(v4 == v2) + v4[0] += 1; + self.assertTrue(v4 != v2) + + def test_Matrices(self): + # Translation and scale + trans = mx.Matrix44.createTranslation(mx.Vector3(1, 2, 3)) + scale = mx.Matrix44.createScale(mx.Vector3(2)) + self.assertTrue(trans == mx.Matrix44(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 1, 2, 3, 1)) + self.assertTrue(scale == mx.Matrix44(2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 2, 0, + 0, 0, 0, 1)) + + # Indexing operators + self.assertTrue(trans[3, 2] == 3) + trans[3, 2] = 4 + self.assertTrue(trans[3, 2] == 4) + trans[3, 2] = 3 + + # Matrix methods + self.assertTrue(trans.getTranspose() == mx.Matrix44(1, 0, 0, 1, + 0, 1, 0, 2, + 0, 0, 1, 3, + 0, 0, 0, 1)) + self.assertTrue(scale.getTranspose() == scale) + self.assertTrue(trans.getDeterminant() == 1) + self.assertTrue(scale.getDeterminant() == 8) + self.assertTrue(trans.getInverse() == + mx.Matrix44.createTranslation(mx.Vector3(-1, -2, -3))) + + # Matrix product + prod1 = trans * scale + prod2 = scale * trans + prod3 = trans * 2 + prod4 = trans + prod4 *= scale + self.assertTrue(prod1 == mx.Matrix44(2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 2, 0, + 2, 4, 6, 1)) + self.assertTrue(prod2 == mx.Matrix44(2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 2, 0, + 1, 2, 3, 1)) + self.assertTrue(prod3 == mx.Matrix44(2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 2, 0, + 2, 4, 6, 2)) + self.assertTrue(prod4 == prod1) + + # Matrix division + quot1 = prod1 / scale + quot2 = prod2 / trans + quot3 = prod3 / 2 + quot4 = quot1 + quot4 /= trans + self.assertTrue(quot1 == trans) + self.assertTrue(quot2 == scale) + self.assertTrue(quot3 == trans) + self.assertTrue(quot4 == mx.Matrix44.IDENTITY) + + # 2D rotation + rot1 = mx.Matrix33.createRotation(math.pi / 2) + rot2 = mx.Matrix33.createRotation(math.pi) + self.assertTrue((rot1 * rot1).isEquivalent(rot2, _epsilon)) + self.assertTrue(rot2.isEquivalent( + mx.Matrix33.createScale(mx.Vector2(-1)), _epsilon)) + self.assertTrue((rot2 * rot2).isEquivalent(mx.Matrix33.IDENTITY, _epsilon)) + + # 3D rotation + rotX = mx.Matrix44.createRotationX(math.pi) + rotY = mx.Matrix44.createRotationY(math.pi) + rotZ = mx.Matrix44.createRotationZ(math.pi) + self.assertTrue((rotX * rotY).isEquivalent( + mx.Matrix44.createScale(mx.Vector3(-1, -1, 1)), _epsilon)) + self.assertTrue((rotX * rotZ).isEquivalent( + mx.Matrix44.createScale(mx.Vector3(-1, 1, -1)), _epsilon)) + self.assertTrue((rotY * rotZ).isEquivalent( + mx.Matrix44.createScale(mx.Vector3(1, -1, -1)), _epsilon)) + + # Matrix copy + trans2 = trans.copy() + self.assertTrue(trans2 == trans) + trans2[0, 0] += 1; + self.assertTrue(trans2 != trans) + + def test_BuildDocument(self): + # Create a document. + doc = mx.createDocument() + + # Create a node graph with constant and image sources. + nodeGraph = doc.addNodeGraph() + self.assertTrue(nodeGraph) + self.assertRaises(LookupError, doc.addNodeGraph, nodeGraph.getName()) + constant = nodeGraph.addNode('constant') + image = nodeGraph.addNode('image') + + # Connect sources to outputs. + output1 = nodeGraph.addOutput() + output2 = nodeGraph.addOutput() + output1.setConnectedNode(constant) + output2.setConnectedNode(image) + self.assertTrue(output1.getConnectedNode() == constant) + self.assertTrue(output2.getConnectedNode() == image) + self.assertTrue(output1.getUpstreamElement() == constant) + self.assertTrue(output2.getUpstreamElement() == image) + + # Set constant node color. + color = mx.Color3(0.1, 0.2, 0.3) + constant.setInputValue('value', color) + self.assertTrue(constant.getInputValue('value') == color) + + # Set image node file. + file = 'image1.tif' + image.setInputValue('file', file, 'filename') + self.assertTrue(image.getInputValue('file') == file) + + # Create a custom nodedef. + nodeDef = doc.addNodeDef('nodeDef1', 'float', 'turbulence3d') + nodeDef.setInputValue('octaves', 3) + nodeDef.setInputValue('lacunarity', 2.0) + nodeDef.setInputValue('gain', 0.5) + + # Reference the custom nodedef. + custom = nodeGraph.addNode('turbulence3d', 'turbulence1', 'float') + self.assertTrue(custom.getInputValue('octaves') == 3) + custom.setInputValue('octaves', 5) + self.assertTrue(custom.getInputValue('octaves') == 5) + + # Test scoped attributes. + nodeGraph.setFilePrefix('folder/') + nodeGraph.setColorSpace('lin_rec709') + self.assertTrue(image.getInput('file').getResolvedValueString() == 'folder/image1.tif') + self.assertTrue(constant.getActiveColorSpace() == 'lin_rec709') + + # Create a simple shader interface. + simpleSrf = doc.addNodeDef('', 'surfaceshader', 'simpleSrf') + simpleSrf.setInputValue('diffColor', mx.Color3(1.0)) + simpleSrf.setInputValue('specColor', mx.Color3(0.0)) + roughness = simpleSrf.setInputValue('roughness', 0.25) + self.assertTrue(roughness.getIsUniform() == False) + roughness.setIsUniform(True); + self.assertTrue(roughness.getIsUniform() == True) + + # Instantiate shader and material nodes. + shaderNode = doc.addNodeInstance(simpleSrf) + materialNode = doc.addMaterialNode('', shaderNode) + + # Bind the diffuse color input to the constant color output. + shaderNode.setConnectedOutput('diffColor', output1) + self.assertTrue(shaderNode.getUpstreamElement() == constant) + + # Bind the roughness input to a value. + instanceRoughness = shaderNode.setInputValue('roughness', 0.5) + self.assertTrue(instanceRoughness.getValue() == 0.5) + self.assertTrue(instanceRoughness.getDefaultValue() == 0.25) + + # Create a look for the material. + look = doc.addLook() + self.assertTrue(len(doc.getLooks()) == 1) + + # Bind the material to a geometry string. + matAssign1 = look.addMaterialAssign("matAssign1", materialNode.getName()) + matAssign1.setGeom("/robot1") + self.assertTrue(matAssign1.getReferencedMaterial() == materialNode) + self.assertTrue(len(mx.getGeometryBindings(materialNode, "/robot1")) == 1) + self.assertTrue(len(mx.getGeometryBindings(materialNode, "/robot2")) == 0) + + # Bind the material to a collection. + matAssign2 = look.addMaterialAssign("matAssign2", materialNode.getName()) + collection = doc.addCollection() + collection.setIncludeGeom("/robot2") + collection.setExcludeGeom("/robot2/left_arm") + matAssign2.setCollection(collection) + self.assertTrue(len(mx.getGeometryBindings(materialNode, "/robot2")) == 1) + self.assertTrue(len(mx.getGeometryBindings(materialNode, "/robot2/right_arm")) == 1) + self.assertTrue(len(mx.getGeometryBindings(materialNode, "/robot2/left_arm")) == 0) + + # Create a property assignment. + propertyAssign = look.addPropertyAssign() + propertyAssign.setProperty("twosided") + propertyAssign.setGeom("/robot1") + propertyAssign.setValue(True) + self.assertTrue(propertyAssign.getProperty() == "twosided") + self.assertTrue(propertyAssign.getGeom() == "/robot1") + self.assertTrue(propertyAssign.getValue() == True) + + # Create a property set assignment. + propertySet = doc.addPropertySet() + propertySet.setPropertyValue('matte', False) + self.assertTrue(propertySet.getPropertyValue('matte') == False) + propertySetAssign = look.addPropertySetAssign() + propertySetAssign.setPropertySet(propertySet) + propertySetAssign.setGeom('/robot1') + self.assertTrue(propertySetAssign.getPropertySet() == propertySet) + self.assertTrue(propertySetAssign.getGeom() == '/robot1') + + # Create a variant set. + variantSet = doc.addVariantSet() + variantSet.addVariant("original") + variantSet.addVariant("damaged") + self.assertTrue(len(variantSet.getVariants()) == 2) + + # Validate the document. + valid, message = doc.validate() + self.assertTrue(valid, 'Document returned validation warnings: ' + message) + + # Disconnect outputs from sources. + output1.setConnectedNode(None) + output2.setConnectedNode(None) + self.assertTrue(output1.getConnectedNode() == None) + self.assertTrue(output2.getConnectedNode() == None) + + def test_TraverseGraph(self): + # Create a document. + doc = mx.createDocument() + + # Create a node graph with the following structure: + # + # [image1] [constant] [image2] + # \ / | + # [multiply] [contrast] [noise3d] + # \____________ | ____________/ + # [mix] + # | + # [output] + # + nodeGraph = doc.addNodeGraph() + image1 = nodeGraph.addNode('image') + image2 = nodeGraph.addNode('image') + constant = nodeGraph.addNode('constant') + multiply = nodeGraph.addNode('multiply') + contrast = nodeGraph.addNode('contrast') + noise3d = nodeGraph.addNode('noise3d') + mix = nodeGraph.addNode('mix') + output = nodeGraph.addOutput() + multiply.setConnectedNode('in1', image1) + multiply.setConnectedNode('in2', constant) + contrast.setConnectedNode('in', image2) + mix.setConnectedNode('fg', multiply) + mix.setConnectedNode('bg', contrast) + mix.setConnectedNode('mask', noise3d) + output.setConnectedNode(mix) + + # Validate the document. + valid, message = doc.validate() + self.assertTrue(valid, 'Document returned validation warnings: ' + message) + + # Traverse the document tree (implicit iterator). + nodeCount = 0 + for elem in doc.traverseTree(): + if elem.isA(mx.Node): + nodeCount += 1 + self.assertTrue(nodeCount == 7) + + # Traverse the document tree (explicit iterator). + nodeCount = 0 + maxElementDepth = 0 + treeIter = doc.traverseTree() + for elem in treeIter: + if elem.isA(mx.Node): + nodeCount += 1 + maxElementDepth = max(maxElementDepth, treeIter.getElementDepth()) + self.assertTrue(nodeCount == 7) + self.assertTrue(maxElementDepth == 3) + + # Traverse the document tree (prune subtree). + nodeCount = 0 + treeIter = doc.traverseTree() + for elem in treeIter: + if elem.isA(mx.Node): + nodeCount += 1 + if elem.isA(mx.NodeGraph): + treeIter.setPruneSubtree(True) + self.assertTrue(nodeCount == 0) + + # Traverse upstream from the graph output (implicit iterator). + nodeCount = 0 + for edge in output.traverseGraph(): + upstreamElem = edge.getUpstreamElement() + connectingElem = edge.getConnectingElement() + downstreamElem = edge.getDownstreamElement() + if upstreamElem.isA(mx.Node): + nodeCount += 1 + if downstreamElem.isA(mx.Node): + self.assertTrue(connectingElem.isA(mx.Input)) + self.assertTrue(nodeCount == 7) + + # Traverse upstream from the graph output (explicit iterator). + nodeCount = 0 + maxElementDepth = 0 + maxNodeDepth = 0 + graphIter = output.traverseGraph() + for edge in graphIter: + upstreamElem = edge.getUpstreamElement() + connectingElem = edge.getConnectingElement() + downstreamElem = edge.getDownstreamElement() + if upstreamElem.isA(mx.Node): + nodeCount += 1 + maxElementDepth = max(maxElementDepth, graphIter.getElementDepth()) + maxNodeDepth = max(maxNodeDepth, graphIter.getNodeDepth()) + self.assertTrue(nodeCount == 7) + self.assertTrue(maxElementDepth == 3) + self.assertTrue(maxNodeDepth == 3) + + # Traverse upstream from the graph output (prune subgraph). + nodeCount = 0 + graphIter = output.traverseGraph() + for edge in graphIter: + upstreamElem = edge.getUpstreamElement() + connectingElem = edge.getConnectingElement() + downstreamElem = edge.getDownstreamElement() + if upstreamElem.isA(mx.Node): + nodeCount += 1 + if upstreamElem.getCategory() == 'multiply': + graphIter.setPruneSubgraph(True) + self.assertTrue(nodeCount == 5) + + # Create and detect a cycle. + multiply.setConnectedNode('in2', mix) + self.assertTrue(output.hasUpstreamCycle()) + self.assertFalse(doc.validate()[0]) + multiply.setConnectedNode('in2', constant) + self.assertFalse(output.hasUpstreamCycle()) + self.assertTrue(doc.validate()[0]) + + # Create and detect a loop. + contrast.setConnectedNode('in', contrast) + self.assertTrue(output.hasUpstreamCycle()) + self.assertFalse(doc.validate()[0]) + contrast.setConnectedNode('in', image2) + self.assertFalse(output.hasUpstreamCycle()) + self.assertTrue(doc.validate()[0]) + + def test_Xmlio(self): + # Read the standard library. + libs = [] + for filename in _libraryFilenames: + lib = mx.createDocument() + mx.readFromXmlFile(lib, filename, _searchPath) + libs.append(lib) + + # Declare write predicate for write filter test + def skipLibraryElement(elem): + return not elem.hasSourceUri() + + # Read and validate each example document. + for filename in _exampleFilenames: + doc = mx.createDocument() + mx.readFromXmlFile(doc, filename, _searchPath) + valid, message = doc.validate() + self.assertTrue(valid, filename + ' returned validation warnings: ' + message) + + # Copy the document. + copiedDoc = doc.copy() + self.assertTrue(copiedDoc == doc) + copiedDoc.addLook() + self.assertTrue(copiedDoc != doc) + + # Traverse the document tree. + valueElementCount = 0 + for elem in doc.traverseTree(): + if elem.isA(mx.ValueElement): + valueElementCount += 1 + self.assertTrue(valueElementCount > 0) + + # Serialize to XML. + writeOptions = mx.XmlWriteOptions() + writeOptions.writeXIncludeEnable = False + xmlString = mx.writeToXmlString(doc, writeOptions) + + # Verify that the serialized document is identical. + writtenDoc = mx.createDocument() + mx.readFromXmlString(writtenDoc, xmlString) + self.assertTrue(writtenDoc == doc) + + # Combine document with the standard library. + doc2 = doc.copy() + for lib in libs: + doc2.importLibrary(lib) + self.assertTrue(doc2.validate()[0]) + + # Write without definitions + writeOptions.writeXIncludeEnable = False + writeOptions.elementPredicate = skipLibraryElement + result = mx.writeToXmlString(doc2, writeOptions) + doc3 = mx.createDocument() + mx.readFromXmlString(doc3, result) + self.assertTrue(len(doc3.getNodeDefs()) == 0) + + # Read the same document twice, and verify that duplicate elements + # are skipped. + doc = mx.createDocument() + filename = 'StandardSurface/standard_surface_carpaint.mtlx' + mx.readFromXmlFile(doc, filename, _searchPath) + mx.readFromXmlFile(doc, filename, _searchPath) + self.assertTrue(doc.validate()[0]) + +#-------------------------------------------------------------------------------- +if __name__ == '__main__': + unittest.main() diff --git a/MaterialX/python/MaterialXTest/tests_to_html.bat b/MaterialX/python/MaterialXTest/tests_to_html.bat old mode 100644 new mode 100755 index 5e38ddc..a29f951 --- a/MaterialX/python/MaterialXTest/tests_to_html.bat +++ b/MaterialX/python/MaterialXTest/tests_to_html.bat @@ -1,2 +1,2 @@ -@echo off -python tests_to_html.py -i1 ../../build %* -d +@echo off +python tests_to_html.py -i1 ../../build %* diff --git a/MaterialX/python/MaterialXTest/tests_to_html.py b/MaterialX/python/MaterialXTest/tests_to_html.py old mode 100644 new mode 100755 index 96ccbdd..bab2d64 --- a/MaterialX/python/MaterialXTest/tests_to_html.py +++ b/MaterialX/python/MaterialXTest/tests_to_html.py @@ -1,230 +1,218 @@ -#!/usr/bin/python - -import sys -import os -import datetime -import argparse - -try: - # Install pillow via pip to enable image differencing and statistics. - from PIL import Image, ImageChops, ImageStat - DIFF_ENABLED = True -except Exception: - DIFF_ENABLED = False - -def computeDiff(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 - - image1 = Image.open(image1Path).convert('RGB') - image2 = Image.open(image2Path).convert('RGB') - diff = ImageChops.difference(image1, image2) - diff.save(imageDiffPath) - diffStat = ImageStat.Stat(diff) - return sum(diffStat.rms) / (3.0 * 255.0) - except Exception: - if os.path.exists(imageDiffPath): - os.remove(imageDiffPath) - print ("Failed to create image diff between: " + image1Path + ", " + image2Path) - -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('-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) - parser.add_argument('-w', '--imagewidth', type=int, dest='imagewidth', action='store', help='Set image display width', default=256) - parser.add_argument('-ht', '--imageheight', type=int, dest='imageheight', action='store', help='Set image display height', default=256) - parser.add_argument('-cp', '--cellpadding', type=int, dest='cellpadding', action='store', help='Set table cell padding', default=0) - parser.add_argument('-tb', '--tableborder', type=int, dest='tableborder', action='store', help='Table border width. 0 means no border', default=3) - parser.add_argument('-l1', '--lang1', dest='lang1', action='store', help='First target language for comparison. Default is glsl', default="glsl") - parser.add_argument('-l2', '--lang2', dest='lang2', action='store', help='Second target language for comparison. Default is osl', default="osl") - parser.add_argument('-l3', '--lang3', dest='lang3', action='store', help='Third target language for comparison. Default is empty', default="") - parser.add_argument('-e', '--error', dest='error', action='store', help='Filter out results with RMS less than this. Negative means all results are kept.', default=-1, type=float) - - args = parser.parse_args(args) - - fh = open(args.outputfile,"w+") - fh.write("\n") - fh.write("") - fh.write("\n") - - 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: " + args.inputdir1 + ") vs "+ args.lang2 + " (in: " + args.inputdir2 + ") vs "+ args.lang3 + " (in: " + args.inputdir3 + ")

\n") - else: - 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.") - - # 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 = [] - langPaths1 = [] - for subdir, _, files in os.walk(args.inputdir1): - for curFile in files: - if curFile.endswith(args.lang1 + ".png"): - langFiles1.append(curFile) - langPaths1.append(subdir) - - # Get all destination files, matching source files - langFiles2 = [] - langPaths2 = [] - langFiles3 = [] - langPaths3 = [] - 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[len(args.inputdir1)+1:]) - else: - file2 = "" - path2 = None - langFiles2.append(file2) - langPaths2.append(path2) - - if useThirdLang: - file3 = file1[:-len(postFix)] + args.lang3 + ".png" - path3 = os.path.join(args.inputdir2, path1[len(args.inputdir1)+1:]) - else: - file3 = "" - path3 = None - langFiles3.append(file3) - langPaths3.append(path3) - - if langFiles1: - curPath = "" - for file1, file2, file3, path1, path2, path3 in zip(langFiles1, langFiles2, langFiles3, langPaths1, langPaths2, langPaths3): - - fullPath1 = os.path.join(path1, file1) if file1 else None - fullPath2 = os.path.join(path2, file2) if file2 else None - fullPath3 = os.path.join(path3, file3) if file3 else None - diffPath1 = diffPath2 = diffPath3 = None - diffRms1 = diffRms2 = diffRms3 = None - - if file1 and file2 and DIFF_ENABLED and args.CREATE_DIFF: - diffPath1 = fullPath1[0:-8] + "_" + args.lang1 + "-1_vs_" + args.lang2 + "-2_diff.png" - diffRms1 = computeDiff(fullPath1, fullPath2, diffPath1) - - if useThirdLang and file1 and file3 and DIFF_ENABLED and args.CREATE_DIFF: - diffPath2 = fullPath1[0:-8] + "_" + args.lang1 + "-1_vs_" + args.lang3 + "-3_diff.png" - diffRms2 = computeDiff(fullPath1, fullPath3, diffPath2) - diffPath3 = fullPath1[0:-8] + "_" + args.lang2 + "-2_vs_" + args.lang3 + "-3_diff.png" - diffRms3 = computeDiff(fullPath2, fullPath3, diffPath3) - - if args.error >= 0: - ok1 = (not diffPath1) or (not diffRms1) or (diffRms1 and diffRms1 <= args.error) - ok2 = (not diffPath2) or (not diffRms2) or (diffRms2 and diffRms2 <= args.error) - ok3 = (not diffPath3) or (not diffRms3) or (diffRms3 and diffRms3 <= args.error) - if ok1 and ok2 and ok3: - continue - - if curPath != path1: - if curPath != "": - fh.write("\n") - fh.write("

" + os.path.normpath(path1) + ":

\n") - fh.write("\n") - curPath = path1 - - def prependFileUri(filepath: str) -> str: - if os.path.isabs(filepath): - return 'file:///' + filepath - else: - return filepath - - fh.write("\n") - if fullPath1: - fh.write("\n") - if fullPath2: - fh.write("\n") - if fullPath3: - fh.write("\n") - if diffPath1: - fh.write("\n") - if diffPath2: - fh.write("\n") - if diffPath3: - fh.write("\n") - fh.write("\n") - - fh.write("\n") - if fullPath1: - fh.write("\n") - if fullPath2: - fh.write("\n") - if fullPath3: - fh.write("\n") - if diffPath1: - rms = " (RMS " + "%.5f" % diffRms1 + ")" if diffRms1 else "" - fh.write("\n") - if diffPath2: - rms = " (RMS " + "%.5f" % diffRms2 + ")" if diffRms2 else "" - fh.write("\n") - if diffPath3: - rms = " (RMS " + "%.5f" % diffRms3 + ")" if diffRms3 else "" - fh.write("\n") - fh.write("\n") - - fh.write("
" + file1) - if args.ENABLE_TIMESTAMPS and os.path.isfile(fullPath1): - fh.write("
(" + str(datetime.datetime.fromtimestamp(os.path.getmtime(fullPath1))) + ")") - fh.write("
" + file2) - if args.ENABLE_TIMESTAMPS and os.path.isfile(fullPath2): - fh.write("
(" + str(datetime.datetime.fromtimestamp(os.path.getmtime(fullPath2))) + ")") - fh.write("
" + file3) - if args.ENABLE_TIMESTAMPS and os.path.isfile(fullPath3): - fh.write("
(" + str(datetime.datetime.fromtimestamp(os.path.getmtime(fullPath3))) + ")") - fh.write("
" + args.lang1.upper() + " vs. " + args.lang2.upper() + rms + "" + args.lang1.upper() + " vs. " + args.lang3.upper() + rms + "" + args.lang2.upper() + " vs. " + args.lang3.upper() + rms + "
\n") - fh.write("\n") - fh.write("\n") - -if __name__ == "__main__": - main(sys.argv[1:]) +#!/usr/bin/python + +import sys +import os +import datetime +import argparse + +try: + # Use pip to install Pillow and Image to enable image diffs + from PIL import Image, ImageChops + DIFF_ENABLED = True +except Exception: + DIFF_ENABLED = False + +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 + + image1 = Image.open(image1Path).convert('RGB') + image2 = Image.open(image2Path).convert('RGB') + diff = ImageChops.difference(image1, image2) + diff.save(imageDiffPath) + except Exception: + if os.path.exists(imageDiffPath): + os.remove(imageDiffPath) + print ("Failed to create image diff between: " + image1Path + ", " + image2Path) + +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('-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) + parser.add_argument('-w', '--imagewidth', type=int, dest='imagewidth', action='store', help='Set image display width', default=256) + parser.add_argument('-ht', '--imageheight', type=int, dest='imageheight', action='store', help='Set image display height', default=256) + parser.add_argument('-cp', '--cellpadding', type=int, dest='cellpadding', action='store', help='Set table cell padding', default=0) + parser.add_argument('-tb', '--tableborder', type=int, dest='tableborder', action='store', help='Table border width. 0 means no border', default=3) + parser.add_argument('-l1', '--lang1', dest='lang1', action='store', help='First target language for comparison. Default is glsl', default="glsl") + parser.add_argument('-l2', '--lang2', dest='lang2', action='store', help='Second target language for comparison. Default is osl', default="osl") + parser.add_argument('-l3', '--lang3', dest='lang3', action='store', help='Third target language for comparison. Default is empty', default="") + + args = parser.parse_args(args) + + fh = open(args.outputfile,"w+") + fh.write("\n") + fh.write("") + fh.write("\n") + + 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: " + args.inputdir1 + ") vs "+ args.lang2 + " (in: " + args.inputdir2 + ") vs "+ args.lang3 + " (in: " + args.inputdir3 + ")

\n") + else: + 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.") + + # 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 = [] + langPaths1 = [] + for subdir, _, files in os.walk(args.inputdir1): + for curFile in files: + if curFile.endswith(args.lang1 + ".png"): + langFiles1.append(curFile) + langPaths1.append(subdir) + + # Get all destination files, matching source files + langFiles2 = [] + langPaths2 = [] + langFiles3 = [] + langPaths3 = [] + 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[len(args.inputdir1)+1:]) + else: + file2 = "" + path2 = None + langFiles2.append(file2) + langPaths2.append(path2) + + if useThirdLang: + file3 = file1[:-len(postFix)] + args.lang3 + ".png" + path3 = os.path.join(args.inputdir2, path1[len(args.inputdir1)+1:]) + else: + file3 = "" + path3 = None + langFiles3.append(file3) + langPaths3.append(path3) + + if langFiles1: + curPath = "" + for file1, file2, file3, path1, path2, path3 in zip(langFiles1, langFiles2, langFiles3, langPaths1, langPaths2, langPaths3): + + fullPath1 = os.path.join(path1, file1) if file1 else None + fullPath2 = os.path.join(path2, file2) if file2 else None + fullPath3 = os.path.join(path3, file3) if file3 else None + diffPath1 = None + diffPath2 = None + diffPath3 = None + + if curPath != path1: + if curPath != "": + fh.write("\n") + fh.write("

" + os.path.normpath(path1) + ":

\n") + fh.write("\n") + curPath = path1 + + if file1 and file2 and DIFF_ENABLED and args.CREATE_DIFF: + 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 + "-1_vs_" + args.lang3 + "-3_diff.png" + createDiff(fullPath1, fullPath3, diffPath2) + diffPath3 = fullPath1[0:-8] + "_" + args.lang2 + "-2_vs_" + args.lang3 + "-3_diff.png" + createDiff(fullPath2, fullPath3, diffPath3) + + def prependFileUri(filepath: str) -> str: + if os.path.isabs(filepath): + return 'file:///' + filepath + else: + return filepath + + fh.write("\n") + if fullPath1: + fh.write("\n") + if fullPath2: + fh.write("\n") + if fullPath3: + fh.write("\n") + if diffPath1: + fh.write("\n") + if diffPath2: + fh.write("\n") + if diffPath3: + fh.write("\n") + fh.write("\n") + + fh.write("\n") + if fullPath1: + fh.write("\n") + if fullPath2: + fh.write("\n") + if fullPath3: + fh.write("\n") + if diffPath1: + fh.write("\n") + if diffPath2: + fh.write("\n") + if diffPath3: + fh.write("\n") + fh.write("\n") + + fh.write("
" + file1) + if args.ENABLE_TIMESTAMPS and os.path.isfile(fullPath1): + fh.write("
(" + str(datetime.datetime.fromtimestamp(os.path.getmtime(fullPath1))) + ")") + fh.write("
" + file2) + if args.ENABLE_TIMESTAMPS and os.path.isfile(fullPath2): + fh.write("
(" + str(datetime.datetime.fromtimestamp(os.path.getmtime(fullPath2))) + ")") + fh.write("
" + file3) + if args.ENABLE_TIMESTAMPS and os.path.isfile(fullPath3): + fh.write("
(" + str(datetime.datetime.fromtimestamp(os.path.getmtime(fullPath3))) + ")") + fh.write("
Difference " + args.lang1 + " vs. " + args.lang2 + " Difference " + args.lang1 + " vs. " + args.lang3 + " Difference " + args.lang2 + " vs. " + args.lang3 + "
\n") + fh.write("\n") + fh.write("\n") + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/MaterialX/python/Scripts/README.md b/MaterialX/python/Scripts/README.md old mode 100644 new mode 100755 index a44550e..8989c24 --- a/MaterialX/python/Scripts/README.md +++ b/MaterialX/python/Scripts/README.md @@ -1,3 +1,3 @@ -# Python Code Examples - -This folder contains example Python scripts that generate, process, and validate material content using the MaterialX API. +# Python Code Examples + +This folder contains example Python scripts that generate, process, and validate material content using the MaterialX API. diff --git a/MaterialX/python/Scripts/baketextures.py b/MaterialX/python/Scripts/baketextures.py old mode 100644 new mode 100755 index 6595044..c0616fd --- a/MaterialX/python/Scripts/baketextures.py +++ b/MaterialX/python/Scripts/baketextures.py @@ -1,73 +1,72 @@ -#!/usr/bin/env python -''' -Generate a baked version of each material in the input document, using the TextureBaker class in the MaterialXRenderGlsl library. -''' - -import sys, os, argparse -from sys import platform - -import MaterialX as mx -from MaterialX import PyMaterialXRender as mx_render -from MaterialX import PyMaterialXRenderGlsl as mx_render_glsl -if platform == "darwin": - from MaterialX import PyMaterialXRenderMsl as mx_render_msl - -def main(): - parser = argparse.ArgumentParser(description="Generate a baked version of each material in the input document.") - parser.add_argument("--width", dest="width", type=int, default=1024, help="Specify the width of baked textures.") - parser.add_argument("--height", dest="height", type=int, default=1024, help="Specify the height of baked textures.") - parser.add_argument("--hdr", dest="hdr", action="store_true", help="Save images to hdr format.") - parser.add_argument("--average", dest="average", action="store_true", help="Average baked images to generate constant values.") - 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('--writeDocumentPerMaterial', dest='writeDocumentPerMaterial', type=mx.stringToBoolean, default=True, help='Specify whether to write baked materials to separate 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.") - opts = parser.parse_args() - - # Load standard and custom data libraries. - stdlib = mx.createDocument() - searchPath = mx.getDefaultDataSearchPath() - searchPath.append(os.path.dirname(opts.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()) - mx.loadLibraries(libraryFolders, searchPath, 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) - baker.bakeAllMaterials(doc, searchPath, opts.outputFilename) - -if __name__ == '__main__': - main() +#!/usr/bin/env python +''' +Generate a baked version of each material in the input document, using the TextureBaker class in the MaterialXRenderGlsl library. +''' + +import sys, os, argparse +from sys import platform + +import MaterialX as mx +from MaterialX import PyMaterialXRender as mx_render +from MaterialX import PyMaterialXRenderGlsl as mx_render_glsl +if platform == "darwin": + from MaterialX import PyMaterialXRenderMsl as mx_render_msl + +def main(): + parser = argparse.ArgumentParser(description="Generate a baked version of each material in the input document.") + parser.add_argument("--width", dest="width", type=int, default=1024, help="Specify the width of baked textures.") + parser.add_argument("--height", dest="height", type=int, default=1024, help="Specify the height of baked textures.") + parser.add_argument("--hdr", dest="hdr", action="store_true", help="Save images to hdr format.") + parser.add_argument("--average", dest="average", action="store_true", help="Average baked images to generate constant values.") + 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('--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.") + opts = parser.parse_args() + + doc = mx.createDocument() + try: + mx.readFromXmlFile(doc, opts.inputFilename) + except mx.ExceptionFileMissing as err: + print(err) + sys.exit(0) + + stdlib = mx.createDocument() + searchPath = mx.getDefaultDataSearchPath() + searchPath.append(os.path.dirname(opts.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()) + mx.loadLibraries(libraryFolders, searchPath, stdlib) + doc.importLibrary(stdlib) + + valid, msg = doc.validate() + if not valid: + print("Validation warnings for input document:") + print(msg) + + 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) + + if opts.average: + baker.setAverageImages(True) + baker.writeDocumentPerMaterial(opts.writeDocumentPerMaterial) + baker.bakeAllMaterials(doc, searchPath, opts.outputFilename) + +if __name__ == '__main__': + main() diff --git a/MaterialX/python/Scripts/comparenodedefs.py b/MaterialX/python/Scripts/comparenodedefs.py deleted file mode 100644 index edd0316..0000000 --- a/MaterialX/python/Scripts/comparenodedefs.py +++ /dev/null @@ -1,923 +0,0 @@ -#!/usr/bin/env python -''' -Compare node definitions between a specification Markdown document and a -data library MaterialX document. - -Report any differences between the two in their supported node sets, typed -node signatures, and default values. -''' - -import argparse -import re -from dataclasses import dataclass, field -from enum import Enum -from itertools import product -from pathlib import Path -import MaterialX as mx - - -# ----------------------------------------------------------------------------- -# Type System -# ----------------------------------------------------------------------------- - -def loadStandardLibraries(): - '''Load and return the standard MaterialX libraries as a document.''' - stdlib = mx.createDocument() - mx.loadLibraries(mx.getDefaultDataLibraryFolders(), mx.getDefaultDataSearchPath(), stdlib) - return stdlib - -def getStandardTypes(stdlib): - '''Extract the set of standard type names from library TypeDefs.''' - return {td.getName() for td in stdlib.getTypeDefs()} - -def buildTypeGroups(stdlib): - ''' - Build type groups from standard library TypeDefs. - Derives colorN, vectorN, matrixNN groups from type naming patterns. - ''' - groups = {} - for td in stdlib.getTypeDefs(): - name = td.getName() - # Match colorN, vectorN patterns (color3, vector2, etc.) - match = re.match(r'^(color|vector)(\d)$', name) - if match: - groupName = f'{match.group(1)}N' - groups.setdefault(groupName, set()).add(name) - continue - # Match matrixNN pattern (matrix33, matrix44) - match = re.match(r'^matrix(\d)\1$', name) - if match: - groups.setdefault('matrixNN', set()).add(name) - return groups - -def buildTypeGroupVariables(typeGroups): - '''Build type group variables (e.g., colorM from colorN) for "must differ" constraints.''' - variables = {} - for groupName in typeGroups: - if groupName.endswith('N') and not groupName.endswith('NN'): - variantName = groupName[:-1] + 'M' - variables[variantName] = groupName - return variables - -def parseSpecTypes(typeStr): - ''' - Parse a specification type string into (types, typeRef). - - Supported patterns: - - Simple types: "float", "color3" - - Comma-separated: "float, color3" - - Union with "or": "BSDF or VDF", "BSDF, EDF, or VDF" - - Type references: "Same as bg", "Same as in1 or float" - ''' - if typeStr is None or not typeStr.strip(): - return set(), None - - typeStr = typeStr.strip() - - # Handle "Same as X" and "Same as X or Y" references - sameAsMatch = re.match(r'^Same as\s+`?(\w+)`?(?:\s+or\s+(.+))?$', typeStr, re.IGNORECASE) - if sameAsMatch: - refPort = sameAsMatch.group(1) - extraTypes = sameAsMatch.group(2) - extraSet = set() - if extraTypes: - extraSet, _ = parseSpecTypes(extraTypes) - return extraSet, refPort - - # Normalize "or" to comma: "X or Y" -> "X, Y", "X, Y, or Z" -> "X, Y, Z" - normalized = re.sub(r',?\s+or\s+', ', ', typeStr) - - result = set() - for t in normalized.split(','): - t = t.strip() - if t: - result.add(t) - - return result, None - -def expandTypeSet(types, typeGroups, typeGroupVariables): - '''Expand type groups to concrete types. Returns list of (concreteType, groupName) tuples.''' - result = [] - for t in types: - if t in typeGroups: - for concrete in typeGroups[t]: - result.append((concrete, t)) - elif t in typeGroupVariables: - baseGroup = typeGroupVariables[t] - for concrete in typeGroups[baseGroup]: - result.append((concrete, t)) - else: - result.append((t, None)) - return result - - -# ----------------------------------------------------------------------------- -# Data Classes -# ----------------------------------------------------------------------------- - -class MatchType(Enum): - '''Types of signature matches between spec and library.''' - EXACT = 'exact' # Identical inputs and outputs - DIFFERENT_INPUTS = 'different_inputs' # Same outputs but different inputs - -class DiffType(Enum): - '''Categories of differences between spec and library, with display labels.''' - - # Invalid specification entries - SPEC_COLUMN_MISMATCH = 'Column Count Mismatches in Specification' - SPEC_EMPTY_PORT_NAME = 'Empty Port Names in Specification' - SPEC_UNRECOGNIZED_TYPE = 'Unrecognized Types in Specification' - # Node-level differences - NODE_MISSING_IN_LIBRARY = 'Nodes in Specification but not Data Library' - NODE_MISSING_IN_SPEC = 'Nodes in Data Library but not Specification' - # Signature-level differences - SIGNATURE_DIFFERENT_INPUTS = 'Nodes with Different Input Sets' - SIGNATURE_MISSING_IN_LIBRARY = 'Node Signatures in Specification but not Data Library' - SIGNATURE_MISSING_IN_SPEC = 'Node Signatures in Data Library but not Specification' - # Default value differences - DEFAULT_MISMATCH = 'Default Value Mismatches' - -@dataclass -class PortInfo: - '''Information about an input or output port from the specification.''' - name: str - types: set = field(default_factory=set) - typeRef: str = None # For "Same as X" references - default: str = None # Spec default string (before type-specific expansion) - -@dataclass(frozen=True) -class NodeSignature: - '''A typed combination of inputs and outputs, corresponding to one nodedef.''' - inputs: tuple # ((name, type), ...) sorted for hashing - outputs: tuple # ((name, type), ...) sorted for hashing - _displayInputs: tuple = None - _displayOutputs: tuple = None - - @classmethod - def create(cls, inputs, outputs): - '''Create a NodeSignature from input/output dicts of name -> type.''' - return cls( - inputs=tuple(sorted(inputs.items())), - outputs=tuple(sorted(outputs.items())), - _displayInputs=tuple(inputs.items()), - _displayOutputs=tuple(outputs.items()), - ) - - def __hash__(self): - return hash((self.inputs, self.outputs)) - - def __eq__(self, other): - if not isinstance(other, NodeSignature): - return False - return self.inputs == other.inputs and self.outputs == other.outputs - - def __str__(self): - insStr = ', '.join(f'{n}:{t}' for n, t in self._displayInputs) - outsStr = ', '.join(f'{n}:{t}' for n, t in self._displayOutputs) - return f'({insStr}) -> {outsStr}' - -@dataclass -class NodeInfo: - '''A node and its supported signatures.''' - name: str - signatures: set = field(default_factory=set) - _specInputs: dict = field(default_factory=dict) # For default value comparison - -@dataclass -class Difference: - '''A difference found between spec and data library.''' - diffType: DiffType - node: str - port: str = None - signature: NodeSignature = None - extraInLib: tuple = None - extraInSpec: tuple = None - valueType: str = None - specDefault: str = None - libDefault: str = None - -def formatDifference(diff): - '''Format a Difference for display, returning a list of lines.''' - # Default mismatch - if diff.diffType == DiffType.DEFAULT_MISMATCH: - return [ - f' {diff.node}.{diff.port} ({diff.valueType}):', - f' Signature: {diff.signature}', - f' Spec default: {diff.specDefault}', - f' Data library default: {diff.libDefault}', - ] - - # Different input sets - if diff.diffType == DiffType.SIGNATURE_DIFFERENT_INPUTS: - lines = [f' {diff.node}: {diff.signature}'] - if diff.extraInLib: - extraStr = ', '.join(f'{n}:{t}' for n, t in diff.extraInLib) - lines.append(f' Extra in library: {extraStr}') - if diff.extraInSpec: - extraStr = ', '.join(f'{n}:{t}' for n, t in diff.extraInSpec) - lines.append(f' Extra in spec: {extraStr}') - return lines - - # Signature mismatch (missing in spec or library) - if diff.signature: - return [f' {diff.node}: {diff.signature}'] - - # Spec validation error with port - if diff.port: - return [f' {diff.node}.{diff.port}'] - - # Node-level difference or simple spec validation error - return [f' {diff.node}'] - - -# ----------------------------------------------------------------------------- -# Default Value Utilities -# ----------------------------------------------------------------------------- - -def buildGeompropNames(stdlib): - '''Extract geomprop names from standard library GeomPropDefs.''' - return {gpd.getName() for gpd in stdlib.getGeomPropDefs()} - -def getComponentCount(typeName): - '''Get the number of components for a MaterialX type, or None if unknown.''' - if typeName in ('float', 'integer', 'boolean'): - return 1 - # Match colorN, vectorN patterns - match = re.match(r'^(color|vector)(\d)$', typeName) - if match: - return int(match.group(2)) - # Match matrixNN pattern - match = re.match(r'^matrix(\d)(\d)$', typeName) - if match: - return int(match.group(1)) * int(match.group(2)) - return None - -def expandDefaultPlaceholder(placeholder, typeName): - '''Expand a placeholder (0, 1, 0.5) to a type-appropriate value string.''' - count = getComponentCount(typeName) - if count is None: - return None - - if placeholder == '0': - if typeName == 'boolean': - return 'false' - return ', '.join(['0'] * count) - - if placeholder == '1': - if typeName == 'boolean': - return 'true' - # Identity matrices, not all-ones - if typeName == 'matrix33': - return '1, 0, 0, 0, 1, 0, 0, 0, 1' - if typeName == 'matrix44': - return '1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1' - return ', '.join(['1'] * count) - - if placeholder == '0.5': - if typeName in ('integer', 'boolean'): - return None # 0.5 doesn't apply to these types - return ', '.join(['0.5'] * count) - - return None - -def parseSpecDefault(value, specDefaultNotation): - '''Parse specification default value notation into normalized form.''' - if value is None: - return None - value = value.strip() - return specDefaultNotation.get(value, value) - -def expandSpecDefaultToValue(specDefault, valueType, geompropNames): - '''Parse a spec default to a typed MaterialX value. Returns (value, isGeomprop).''' - if specDefault is None or specDefault == '': - return None, False - - # Handle geomprop references - these are compared as strings, not typed values - if specDefault in geompropNames: - return specDefault, True - - # Expand placeholder values to type-appropriate strings - expansion = expandDefaultPlaceholder(specDefault, valueType) - if expansion is not None: - specDefault = expansion - - # Parse to typed value using MaterialX - try: - return mx.createValueFromStrings(specDefault, valueType), False - except Exception: - return None, False - -def formatDefaultValue(value, valueType, geompropNames): - '''Format a default value for display using spec notation (__zero__, etc.).''' - if value is None: - return 'None' - - # Handle string values (geomprops, empty strings, etc.) - if isinstance(value, str): - if value in geompropNames: - return f'_{value}_' - return '__empty__' if value == '' else value - - # Check if value matches a standard constant (__zero__, __one__, __half__) - for placeholder, display in [('0', '__zero__'), ('1', '__one__'), ('0.5', '__half__')]: - expansion = expandDefaultPlaceholder(placeholder, valueType) - if expansion is None: - continue - try: - if value == mx.createValueFromStrings(expansion, valueType): - return display - except Exception: - pass - - # Fall back to string representation - return str(value) - - -# ----------------------------------------------------------------------------- -# Markdown Table Parsing -# ----------------------------------------------------------------------------- - -def parseMarkdownTable(lines, startIdx): - '''Parse a markdown table. Returns (rows, columnMismatchCount, endIndex).''' - table = [] - headers = [] - columnMismatchCount = 0 - idx = startIdx - - # Parse header row - if idx < len(lines) and '|' in lines[idx]: - headerLine = lines[idx].strip() - headers = [h.strip().strip('`') for h in headerLine.split('|')[1:-1]] - idx += 1 - else: - return [], 0, startIdx - - # Skip separator row - if idx < len(lines) and '|' in lines[idx] and '-' in lines[idx]: - idx += 1 - else: - return [], 0, startIdx - - # Parse data rows - while idx < len(lines): - line = lines[idx].strip() - if not line or not line.startswith('|'): - break - - cells = [c.strip().strip('`') for c in line.split('|')[1:-1]] - if len(cells) == len(headers): - row = {headers[i].lower(): cells[i] for i in range(len(headers))} - table.append(row) - else: - columnMismatchCount += 1 - idx += 1 - - return table, columnMismatchCount, idx - - -# ----------------------------------------------------------------------------- -# Specification Document Parsing -# ----------------------------------------------------------------------------- - -def isValidTypeGroupAssignment(driverNames, combo, typeGroupVariables): - ''' - Check if type assignments satisfy group constraints (e.g., colorN ports must - match, colorM must differ from colorN). Returns (isValid, typeAssignment). - ''' - typeAssignment = {} - groupAssignments = {} # groupName -> concreteType assigned to that group - - for name, (concreteType, groupName) in zip(driverNames, combo): - typeAssignment[name] = concreteType - - # Skip constraint checking for None types (these will be resolved via typeRef) - if concreteType is None: - continue - - if not groupName: - continue - - # For group variables (colorM), get the base group (colorN) - baseGroup = typeGroupVariables.get(groupName, groupName) - isVariable = groupName in typeGroupVariables - - # Check consistency: all uses of the same group must have same concrete type - if groupName in groupAssignments: - if groupAssignments[groupName] != concreteType: - return False, None - else: - groupAssignments[groupName] = concreteType - - # For variables: must differ from base group if base is already assigned - if isVariable and baseGroup in groupAssignments: - if groupAssignments[baseGroup] == concreteType: - return False, None - - return True, typeAssignment - -def expandSpecSignatures(inputs, outputs, typeGroups, typeGroupVariables): - ''' - Expand spec port definitions into concrete NodeSignatures. - Handles type groups, type group variables, and "Same as X or Y" patterns. - ''' - allPorts = {**inputs, **outputs} - - # Identify driver ports and their type options - # - Ports with explicit types (no typeRef): use those types - # - Ports with both types AND typeRef ("Same as X or Y"): explicit types OR inherit from typeRef - drivers = {} - for name, port in allPorts.items(): - if port.types and not port.typeRef: - # Normal driver: explicit types only - drivers[name] = expandTypeSet(port.types, typeGroups, typeGroupVariables) - elif port.types and port.typeRef: - # "Same as X or Y" pattern: explicit types OR inherit from typeRef - expanded = expandTypeSet(port.types, typeGroups, typeGroupVariables) - expanded.append((None, None)) # None means "inherit from typeRef" - drivers[name] = expanded - - if not drivers: - return set() - - # Generate all combinations of driver types - driverNames = sorted(drivers.keys()) - driverTypeLists = [drivers[n] for n in driverNames] - - signatures = set() - for combo in product(*driverTypeLists): - # Validate type group constraints (skip None values which will be resolved via typeRef) - valid, typeAssignment = isValidTypeGroupAssignment(driverNames, combo, typeGroupVariables) - if not valid: - continue - - # Remove None assignments - these ports will be resolved via typeRef - typeAssignment = {k: v for k, v in typeAssignment.items() if v is not None} - - # Resolve typeRefs for this combination - resolved = resolveTypeAssignment(typeAssignment, allPorts) - if resolved is None: - continue - - # Build signature - sigInputs = {name: resolved[name] for name in inputs if name in resolved} - sigOutputs = {name: resolved[name] for name in outputs if name in resolved} - signatures.add(NodeSignature.create(sigInputs, sigOutputs)) - - return signatures - -def resolveTypeAssignment(baseAssignment, allPorts): - '''Resolve "Same as X" references to complete port type assignments.''' - assignment = baseAssignment.copy() - - # Iteratively resolve references (limit iterations to handle circular refs) - for _ in range(10): - changed = False - for name, port in allPorts.items(): - if name in assignment: - continue - if port.typeRef and port.typeRef in assignment: - assignment[name] = assignment[port.typeRef] - changed = True - if not changed: - break - - # Check all ports resolved - if set(assignment.keys()) != set(allPorts.keys()): - return None - - return assignment - -def resolvePortTypeRefs(ports): - '''Resolve type references between ports by copying types. Modifies ports in place.''' - # Limit iterations to handle circular refs - for _ in range(10): - changed = False - for port in ports.values(): - if port.typeRef: - refPort = ports.get(port.typeRef) - if refPort and refPort.types: - port.types.update(refPort.types) - port.typeRef = None - changed = True - if not changed: - break - -def parseSpecDocument(specPath, stdlib, geompropNames): - '''Parse a specification markdown document. Returns (nodes, invalidEntries).''' - # Build type system data from stdlib - standardTypes = getStandardTypes(stdlib) - typeGroups = buildTypeGroups(stdlib) - typeGroupVariables = buildTypeGroupVariables(typeGroups) - - # Build derived values for validation and parsing - knownTypes = standardTypes | set(typeGroups.keys()) | set(typeGroupVariables.keys()) - specDefaultNotation = { - '__zero__': '0', - '__one__': '1', - '__half__': '0.5', - '__empty__': '', - } - for name in geompropNames: - specDefaultNotation[f'_{name}_'] = name - - nodes = {} - invalidEntries = [] - - with open(specPath, 'r', encoding='utf-8') as f: - content = f.read() - - lines = content.split('\n') - currentNode = None - currentTableInputs = {} - currentTableOutputs = {} - idx = 0 - - def finalizeCurrentTable(): - '''Expand current table to signatures and add to node.''' - nonlocal currentTableInputs, currentTableOutputs - if currentNode and (currentTableInputs or currentTableOutputs): - node = nodes[currentNode] - # Expand to signatures (do NOT pre-resolve typeRefs - expansion handles them) - tableSigs = expandSpecSignatures(currentTableInputs, currentTableOutputs, typeGroups, typeGroupVariables) - node.signatures.update(tableSigs) - # Merge input port info for default comparison (resolve types for defaults) - allPorts = {**currentTableInputs, **currentTableOutputs} - resolvePortTypeRefs(allPorts) - for name, port in currentTableInputs.items(): - if name not in node._specInputs: - node._specInputs[name] = port - else: - node._specInputs[name].types.update(port.types) - currentTableInputs = {} - currentTableOutputs = {} - - while idx < len(lines): - line = lines[idx] - - # Look for node headers (### `nodename`) - nodeMatch = re.match(r'^###\s+`([^`]+)`', line) - if nodeMatch: - # Finalize previous table before switching nodes - finalizeCurrentTable() - currentNode = nodeMatch.group(1) - if currentNode not in nodes: - nodes[currentNode] = NodeInfo(name=currentNode) - idx += 1 - continue - - # Look for tables when we have a current node - if currentNode and '|' in line and 'Port' in line: - # Finalize previous table before starting new one - finalizeCurrentTable() - - rows, columnMismatchCount, idx = parseMarkdownTable(lines, idx) - - # Track column count mismatches - for _ in range(columnMismatchCount): - invalidEntries.append(Difference( - diffType=DiffType.SPEC_COLUMN_MISMATCH, - node=currentNode, - )) - - if rows: - for row in rows: - portName = row.get('port', '').strip('`*') - - # Track empty port names - if not portName: - invalidEntries.append(Difference( - diffType=DiffType.SPEC_EMPTY_PORT_NAME, - node=currentNode, - )) - continue - - portType = row.get('type', '') - portDefault = row.get('default', '') - portDesc = row.get('description', '') - - types, typeRef = parseSpecTypes(portType) - - # Track unrecognized types - if types - knownTypes: - invalidEntries.append(Difference( - diffType=DiffType.SPEC_UNRECOGNIZED_TYPE, - node=currentNode, - port=portName, - )) - - # Determine if this is an output port - isOutput = portName == 'out' or portDesc.lower().startswith('output') - target = currentTableOutputs if isOutput else currentTableInputs - - # Create port info for this table - portInfo = target.setdefault(portName, PortInfo( - name=portName, - default=parseSpecDefault(portDefault, specDefaultNotation), - )) - portInfo.types.update(types) - if typeRef and not portInfo.typeRef: - portInfo.typeRef = typeRef - continue - - idx += 1 - - # Finalize the last table - finalizeCurrentTable() - - return nodes, invalidEntries - - -# ----------------------------------------------------------------------------- -# Data Library Loading -# ----------------------------------------------------------------------------- - -def loadDataLibrary(mtlxPath): - '''Load a data library MTLX document. Returns (nodes, defaults).''' - doc = mx.createDocument() - mx.readFromXmlFile(doc, str(mtlxPath)) - - nodes = {} - defaults = {} # (nodeName, signature) -> {portName -> (value, isGeomprop)} - - for nodedef in doc.getNodeDefs(): - nodeName = nodedef.getNodeString() - node = nodes.setdefault(nodeName, NodeInfo(name=nodeName)) - - # Build signature from this nodedef - sigInputs = {inp.getName(): inp.getType() for inp in nodedef.getInputs()} - sigOutputs = {out.getName(): out.getType() for out in nodedef.getOutputs()} - sig = NodeSignature.create(sigInputs, sigOutputs) - node.signatures.add(sig) - - # Store defaults keyed by signature - sigDefaults = {} - for inp in nodedef.getInputs(): - if inp.hasDefaultGeomPropString(): - sigDefaults[inp.getName()] = (inp.getDefaultGeomPropString(), True) - elif inp.getValue() is not None: - sigDefaults[inp.getName()] = (inp.getValue(), False) - if sigDefaults: - defaults[(nodeName, sig)] = sigDefaults - - return nodes, defaults - - -# ----------------------------------------------------------------------------- -# Comparison Logic -# ----------------------------------------------------------------------------- - -def compareSignatureDefaults(nodeName, signature, specNode, libDefaults, geompropNames): - '''Compare default values for a matching signature. Returns list of Differences.''' - differences = [] - - for portName, valueType in signature.inputs: - specPort = specNode._specInputs.get(portName) - if not specPort or not specPort.default: - continue - - specValue, specIsGeomprop = expandSpecDefaultToValue(specPort.default, valueType, geompropNames) - libValue, libIsGeomprop = libDefaults.get(portName, (None, False)) - - # Skip if either value is unavailable - if specValue is None or libValue is None: - continue - - # Compare values (geomprops compare as strings, typed values use equality) - valuesMatch = (specValue == libValue) if (specIsGeomprop == libIsGeomprop) else False - - if not valuesMatch: - differences.append(Difference( - diffType=DiffType.DEFAULT_MISMATCH, - node=nodeName, - port=portName, - signature=signature, - valueType=valueType, - specDefault=formatDefaultValue(specValue, valueType, geompropNames), - libDefault=formatDefaultValue(libValue, valueType, geompropNames), - )) - - return differences - -def findLibraryMatch(specSig, libSigs): - '''Find a matching library signature. Returns (matchType, libSig, extraInLib, extraInSpec).''' - specInputs = set(specSig.inputs) - specOutputs = set(specSig.outputs) - - for libSig in libSigs: - libInputs = set(libSig.inputs) - libOutputs = set(libSig.outputs) - - # Check for exact match - if specInputs == libInputs and specOutputs == libOutputs: - return MatchType.EXACT, libSig, None, None - - # Check for different input sets (same outputs, different inputs) - if specOutputs == libOutputs and specInputs != libInputs: - # If there are common inputs, verify they have the same types - commonInputNames = {name for name, _ in specInputs} & {name for name, _ in libInputs} - if commonInputNames: - specInputDict = dict(specSig.inputs) - libInputDict = dict(libSig.inputs) - typesMatch = all(specInputDict[n] == libInputDict[n] for n in commonInputNames) - if not typesMatch: - continue # Common inputs have different types - not a match - - extraInLib = tuple(sorted(libInputs - specInputs)) - extraInSpec = tuple(sorted(specInputs - libInputs)) - return MatchType.DIFFERENT_INPUTS, libSig, extraInLib, extraInSpec - - return None, None, None, None - -def compareNodes(specNodes, libNodes, libDefaults, geompropNames, compareDefaults=False): - '''Compare nodes between spec and library. Returns list of Differences.''' - differences = [] - - specNames = set(specNodes.keys()) - libNames = set(libNodes.keys()) - - # Nodes in spec but not in library - for nodeName in sorted(specNames - libNames): - differences.append(Difference( - diffType=DiffType.NODE_MISSING_IN_LIBRARY, - node=nodeName)) - - # Nodes in library but not in spec - for nodeName in sorted(libNames - specNames): - differences.append(Difference( - diffType=DiffType.NODE_MISSING_IN_SPEC, - node=nodeName)) - - # Compare signatures for common nodes - for nodeName in sorted(specNames & libNames): - specNode = specNodes[nodeName] - libNode = libNodes[nodeName] - - specSigs = specNode.signatures - libSigs = libNode.signatures - - # Track which signatures have been matched - matchedLibSigs = set() - matchedSpecSigs = set() - inputDiffMatches = [] # (specSig, libSig, extraInLib, extraInSpec) - - # For each spec signature, find matching library signature - for specSig in specSigs: - matchType, libSig, extraInLib, extraInSpec = findLibraryMatch(specSig, libSigs) - - if matchType == MatchType.EXACT: - matchedLibSigs.add(libSig) - matchedSpecSigs.add(specSig) - # Compare defaults for exact matches - if compareDefaults: - sigDefaults = libDefaults.get((nodeName, libSig), {}) - differences.extend(compareSignatureDefaults( - nodeName, specSig, specNode, sigDefaults, geompropNames)) - - elif matchType == MatchType.DIFFERENT_INPUTS: - matchedLibSigs.add(libSig) - matchedSpecSigs.add(specSig) - inputDiffMatches.append((specSig, libSig, extraInLib, extraInSpec)) - # Compare defaults for different input matches too (for common ports) - if compareDefaults: - sigDefaults = libDefaults.get((nodeName, libSig), {}) - differences.extend(compareSignatureDefaults( - nodeName, specSig, specNode, sigDefaults, geompropNames)) - - # Report different input set matches - for specSig, libSig, extraInLib, extraInSpec in sorted(inputDiffMatches, key=lambda x: str(x[0])): - differences.append(Difference( - diffType=DiffType.SIGNATURE_DIFFERENT_INPUTS, - node=nodeName, - signature=specSig, - extraInLib=extraInLib, - extraInSpec=extraInSpec, - )) - - # Spec signatures not matched by any library signature - for specSig in sorted(specSigs - matchedSpecSigs, key=str): - differences.append(Difference( - diffType=DiffType.SIGNATURE_MISSING_IN_LIBRARY, - node=nodeName, - signature=specSig, - )) - - # Library signatures not matched by any spec signature - for libSig in sorted(libSigs - matchedLibSigs, key=str): - differences.append(Difference( - diffType=DiffType.SIGNATURE_MISSING_IN_SPEC, - node=nodeName, - signature=libSig, - )) - - return differences - - -# ----------------------------------------------------------------------------- -# Output Formatting -# ----------------------------------------------------------------------------- - -def printDifferences(differences): - '''Print the differences in a formatted way.''' - if not differences: - print("No differences found between specification and data library.") - return - - # Group differences by type - byType = {} - for diff in differences: - byType.setdefault(diff.diffType, []).append(diff) - - print(f"\n{'=' * 70}") - print(f"COMPARISON RESULTS: {len(differences)} difference(s) found") - print(f"{'=' * 70}") - - for diffType in DiffType: - if diffType not in byType: - continue - - diffs = byType[diffType] - print(f"\n{diffType.value} ({len(diffs)}):") - print("-" * 50) - - for diff in diffs: - for line in formatDifference(diff): - print(line) - - -# ----------------------------------------------------------------------------- -# Main Entry Point -# ----------------------------------------------------------------------------- - -def main(): - parser = argparse.ArgumentParser( - description="Compare node definitions between a specification Markdown document and a data library MaterialX document.") - parser.add_argument('--spec', dest='specFile', - help='Path to the specification Markdown document. Defaults to documents/Specification/MaterialX.StandardNodes.md') - parser.add_argument('--mtlx', dest='mtlxFile', - help='Path to the data library MaterialX document. Defaults to libraries/stdlib/stdlib_defs.mtlx') - parser.add_argument('--defaults', dest='compareDefaults', action='store_true', - help='Compare default values for inputs using MaterialX typed value comparison') - parser.add_argument('--listNodes', dest='listNodes', action='store_true', - help='List all nodes and their node signature counts') - opts = parser.parse_args() - - # Determine file paths - repoRoot = Path(__file__).resolve().parent.parent.parent - - specPath = Path(opts.specFile) if opts.specFile else repoRoot / 'documents' / 'Specification' / 'MaterialX.StandardNodes.md' - mtlxPath = Path(opts.mtlxFile) if opts.mtlxFile else repoRoot / 'libraries' / 'stdlib' / 'stdlib_defs.mtlx' - - # Verify files exist - if not specPath.exists(): - raise FileNotFoundError(f"Specification document not found: {specPath}") - - if not mtlxPath.exists(): - raise FileNotFoundError(f"MTLX document not found: {mtlxPath}") - - print(f"Comparing:") - print(f" Specification: {specPath}") - print(f" Data Library: {mtlxPath}") - - # Load standard libraries - stdlib = loadStandardLibraries() - geompropNames = buildGeompropNames(stdlib) - - # Parse specification - print("\nParsing specification...") - specNodes, invalidEntries = parseSpecDocument(specPath, stdlib, geompropNames) - specSigCount = sum(len(n.signatures) for n in specNodes.values()) - print(f" Found {len(specNodes)} nodes with {specSigCount} node signatures") - if invalidEntries: - print(f" Found {len(invalidEntries)} invalid specification entries") - - # Load data library - print("Loading data library...") - libNodes, libDefaults = loadDataLibrary(mtlxPath) - libSigCount = sum(len(n.signatures) for n in libNodes.values()) - print(f" Found {len(libNodes)} nodes with {libSigCount} node signatures") - - # List nodes if requested - if opts.listNodes: - print("\nNodes in Specification:") - for name in sorted(specNodes.keys()): - node = specNodes[name] - print(f" {name}: {len(node.signatures)} signature(s)") - - print("\nNodes in Data Library:") - for name in sorted(libNodes.keys()): - node = libNodes[name] - print(f" {name}: {len(node.signatures)} signature(s)") - - # Compare nodes - print("\nComparing node signatures...") - differences = compareNodes(specNodes, libNodes, libDefaults, geompropNames, opts.compareDefaults) - - # Include invalid spec entries in the differences - differences = invalidEntries + differences - - # Print differences - printDifferences(differences) - - -if __name__ == '__main__': - main() diff --git a/MaterialX/python/Scripts/creatematerial.py b/MaterialX/python/Scripts/creatematerial.py old mode 100644 new mode 100755 index f47afd8..c920d12 --- a/MaterialX/python/Scripts/creatematerial.py +++ b/MaterialX/python/Scripts/creatematerial.py @@ -1,268 +1,268 @@ -#!/usr/bin/env python -''' -Construct a MaterialX file from the textures in the given folder, using the standard data libraries -to build a mapping from texture filenames to shader inputs. - -By default the standard_surface shading model is assumed, with the --shadingModel option used to -select any other shading model in the data libraries. -''' - -import os -import re -import argparse -from difflib import SequenceMatcher - -import MaterialX as mx - -UDIM_TOKEN = '..' -UDIM_REGEX = r'\.\d+\.' -TEXTURE_EXTENSIONS = [ "exr", "png", "jpg", "jpeg", "tif", "hdr" ] -INPUT_ALIASES = { "roughness": "specular_roughness" } - -class UdimFilePath(mx.FilePath): - - def __init__(self, pathString): - super().__init__(pathString) - - self._isUdim = False - self._udimFiles = [] - self._udimRegex = re.compile(UDIM_REGEX) - - textureDir = self.getParentPath() - textureName = self.getBaseName() - textureExtension = self.getExtension() - - if not self._udimRegex.search(textureName): - self._udimFiles = [self] - return - - self._isUdim = True - fullNamePattern = self._udimRegex.sub(self._udimRegex.pattern.replace('\\', '\\\\'), - textureName) - - udimFiles = filter( - lambda f: re.search(fullNamePattern, f.asString()), - textureDir.getFilesInDirectory(textureExtension) - ) - self._udimFiles = [textureDir / f for f in udimFiles] - - def __str__(self): - return self.asPattern() - - def asPattern(self): - if not self._isUdim: - return self.asString() - - textureDir = self.getParentPath() - textureName = self.getBaseName() - - pattern = textureDir / mx.FilePath( - self._udimRegex.sub(UDIM_TOKEN, textureName)) - return pattern.asString() - - def isUdim(self): - return self._isUdim - - def getUdimFiles(self): - return self._udimFiles - - def getUdimNumbers(self): - def _extractUdimNumber(_file): - pattern = self._udimRegex.search(_file.getBaseName()) - if pattern: - return re.search(r"\d+", pattern.group()).group() - - return list(map(_extractUdimNumber, self._udimFiles)) - - def getNameWithoutExtension(self): - if self._isUdim: - name = self._udimRegex.split(self.getBaseName())[0] - else: - name = self.getBaseName().rsplit('.', 1)[0] - - return re.sub(r'[^\w\s]+', '_', name) - -def listTextures(textureDir, texturePrefix=None): - ''' - Return a list of texture filenames matching known extensions. - ''' - - texturePrefix = texturePrefix or "" - allTextures = [] - for ext in TEXTURE_EXTENSIONS: - textures = [textureDir / f for f in textureDir.getFilesInDirectory(ext) - if f.asString().lower().startswith(texturePrefix.lower())] - while textures: - textureFile = UdimFilePath(textures[0].asString()) - allTextures.append(textureFile) - for udimFile in textureFile.getUdimFiles(): - textures.remove(udimFile) - return allTextures - -def findBestMatch(textureName, shadingModel): - ''' - Given a texture name and shading model, return the shader input that is the closest match. - ''' - - parts = textureName.rsplit("_") - - baseTexName = parts[-1] - if baseTexName.lower() == 'color': - baseTexName = ''.join(parts[-2:]) - if baseTexName in INPUT_ALIASES: - baseTexName = INPUT_ALIASES.get(baseTexName.lower()) - - shaderInputs = shadingModel.getActiveInputs() - ratios = [] - for shaderInput in shaderInputs: - inputName = shaderInput.getName() - inputName = re.sub(r'[^a-zA-Z0-9\s]', '', inputName).lower() - baseTexName = re.sub(r'[^a-zA-Z0-9\s]', '', baseTexName).lower() - - sequenceScore = SequenceMatcher(None, inputName, baseTexName).ratio() - ratios.append(sequenceScore * 100) - - highscore = max(ratios) - if highscore < 50: - return None - - idx = ratios.index(highscore) - return shaderInputs[idx] - -def buildDocument(textureFiles, mtlxFile, shadingModel, colorspace, useTiledImage): - ''' - Build a MaterialX document from the given textures and shading model. - ''' - - # Find the default library nodedef, if any, for the requested shading model. - stdlib = mx.createDocument() - mx.loadLibraries(mx.getDefaultDataLibraryFolders(), mx.getDefaultDataSearchPath(), stdlib) - matchingNodeDefs = stdlib.getMatchingNodeDefs(shadingModel) - if not matchingNodeDefs: - print('Shading model', shadingModel, 'not found in the MaterialX data libraries') - return None - shadingModelNodeDef = matchingNodeDefs[0] - for nodeDef in matchingNodeDefs: - if nodeDef.getAttribute('isdefaultversion') == 'true': - shadingModelNodeDef = nodeDef - - # Create content document. - doc = mx.createDocument() - materialName = mx.createValidName(mtlxFile.getBaseName().rsplit('.', 1)[0]) - nodeGraph = doc.addNodeGraph('NG_' + materialName) - shaderNode = doc.addNode(shadingModel, 'SR_' + materialName, 'surfaceshader') - doc.addMaterialNode('M_' + materialName, shaderNode) - - # Iterate over texture files. - imageNodeCategory = 'tiledimage' if useTiledImage else 'image' - udimNumbers = set() - for textureFile in textureFiles: - textureName = textureFile.getNameWithoutExtension() - shaderInput = findBestMatch(textureName, shadingModelNodeDef) - - if not shaderInput: - print('Skipping', textureFile.getBaseName(), 'which does not match any', shadingModel, 'input') - continue - - inputName = shaderInput.getName() - inputType = shaderInput.getType() - - # Skip inputs that have already been created, e.g. in multi-UDIM materials. - if shaderNode.getInput(inputName) or nodeGraph.getChild(textureName): - continue - - mtlInput = shaderNode.addInput(inputName) - textureName = nodeGraph.createValidChildName(textureName) - imageNode = nodeGraph.addNode(imageNodeCategory, textureName, inputType) - - # Set color space. - if shaderInput.isColorType(): - imageNode.setColorSpace(colorspace) - - # Set file path. - filePathString = os.path.relpath(textureFile.asPattern(), mtlxFile.getParentPath().asString()) - imageNode.setInputValue('file', filePathString, 'filename') - - # Apply special cases for normal maps. - inputNode = imageNode - connNode = imageNode - inBetweenNodes = [] - if inputName.endswith('normal') and shadingModel == 'standard_surface': - inBetweenNodes = ["normalmap"] - for inNodeName in inBetweenNodes: - connNode = nodeGraph.addNode(inNodeName, textureName + '_' + inNodeName, inputType) - connNode.setConnectedNode('in', inputNode) - inputNode = connNode - - # Create output. - outputNode = nodeGraph.addOutput(textureName + '_output', inputType) - outputNode.setConnectedNode(connNode) - mtlInput.setConnectedOutput(outputNode) - mtlInput.setType(inputType) - - if textureFile.isUdim(): - udimNumbers.update(set(textureFile.getUdimNumbers())) - - # Create udim set - if udimNumbers: - geomInfoName = doc.createValidChildName('GI_' + materialName) - geomInfo = doc.addGeomInfo(geomInfoName) - geomInfo.setGeomPropValue('udimset', list(udimNumbers), "stringarray") - - # Return the new document - return doc - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('--outputFilename', dest='outputFilename', type=str, help='Filename of the output MaterialX document.') - parser.add_argument('--shadingModel', dest='shadingModel', type=str, default="standard_surface", help='The shading model used in analyzing input textures.') - parser.add_argument('--colorSpace', dest='colorSpace', type=str, help='The colorspace in which input textures should be interpreted, defaulting to srgb_texture.') - parser.add_argument('--texturePrefix', dest='texturePrefix', type=str, help='Filter input textures by the given prefix.') - parser.add_argument('--tiledImage', dest='tiledImage', action="store_true", help='Request tiledimage nodes instead of image nodes.') - parser.add_argument(dest='inputDirectory', nargs='?', help='Input folder that will be scanned for textures, defaulting to the current working directory.') - - options = parser.parse_args() - - texturePath = mx.FilePath.getCurrentPath() - if options.inputDirectory: - texturePath = mx.FilePath(options.inputDirectory) - if not texturePath.isDirectory(): - print('Input folder not found:', texturePath) - return - - mtlxFile = texturePath / mx.FilePath('material.mtlx') - if options.outputFilename: - mtlxFile = mx.FilePath(options.outputFilename) - - textureFiles = listTextures(texturePath, texturePrefix=options.texturePrefix) - if not textureFiles: - print('No matching textures found in input folder.') - return - - # Get shading model and color space. - shadingModel = 'standard_surface' - colorspace = 'srgb_texture' - if options.shadingModel: - shadingModel = options.shadingModel - if options.colorSpace: - colorspace = options.colorSpace - print('Analyzing textures in the', texturePath.asString(), 'folder for the', shadingModel, 'shading model.') - - # Create the MaterialX document. - doc = buildDocument(textureFiles, mtlxFile, shadingModel, colorspace, options.tiledImage) - if not doc: - return - - if options.outputFilename: - # Write the document to disk. - if not mtlxFile.getParentPath().exists(): - mtlxFile.getParentPath().createDirectory() - mx.writeToXmlFile(doc, mtlxFile.asString()) - print('Wrote MaterialX document to disk:', mtlxFile.asString()) - else: - # Print the document to the standard output. - print('Generated MaterialX document:') - print(mx.writeToXmlString(doc)) - -if __name__ == '__main__': - main() +#!/usr/bin/env python +''' +Construct a MaterialX file from the textures in the given folder, using the standard data libraries +to build a mapping from texture filenames to shader inputs. + +By default the standard_surface shading model is assumed, with the --shadingModel option used to +select any other shading model in the data libraries. +''' + +import os +import re +import argparse +from difflib import SequenceMatcher + +import MaterialX as mx + +UDIM_TOKEN = '..' +UDIM_REGEX = r'\.\d+\.' +TEXTURE_EXTENSIONS = [ "exr", "png", "jpg", "jpeg", "tif", "hdr" ] +INPUT_ALIASES = { "roughness": "specular_roughness" } + +class UdimFilePath(mx.FilePath): + + def __init__(self, pathString): + super().__init__(pathString) + + self._isUdim = False + self._udimFiles = [] + self._udimRegex = re.compile(UDIM_REGEX) + + textureDir = self.getParentPath() + textureName = self.getBaseName() + textureExtension = self.getExtension() + + if not self._udimRegex.search(textureName): + self._udimFiles = [self] + return + + self._isUdim = True + fullNamePattern = self._udimRegex.sub(self._udimRegex.pattern.replace('\\', '\\\\'), + textureName) + + udimFiles = filter( + lambda f: re.search(fullNamePattern, f.asString()), + textureDir.getFilesInDirectory(textureExtension) + ) + self._udimFiles = [textureDir / f for f in udimFiles] + + def __str__(self): + return self.asPattern() + + def asPattern(self): + if not self._isUdim: + return self.asString() + + textureDir = self.getParentPath() + textureName = self.getBaseName() + + pattern = textureDir / mx.FilePath( + self._udimRegex.sub(UDIM_TOKEN, textureName)) + return pattern.asString() + + def isUdim(self): + return self._isUdim + + def getUdimFiles(self): + return self._udimFiles + + def getUdimNumbers(self): + def _extractUdimNumber(_file): + pattern = self._udimRegex.search(_file.getBaseName()) + if pattern: + return re.search(r"\d+", pattern.group()).group() + + return list(map(_extractUdimNumber, self._udimFiles)) + + def getNameWithoutExtension(self): + if self._isUdim: + name = self._udimRegex.split(self.getBaseName())[0] + else: + name = self.getBaseName().rsplit('.', 1)[0] + + return re.sub(r'[^\w\s]+', '_', name) + +def listTextures(textureDir, texturePrefix=None): + ''' + Return a list of texture filenames matching known extensions. + ''' + + texturePrefix = texturePrefix or "" + allTextures = [] + for ext in TEXTURE_EXTENSIONS: + textures = [textureDir / f for f in textureDir.getFilesInDirectory(ext) + if f.asString().lower().startswith(texturePrefix.lower())] + while textures: + textureFile = UdimFilePath(textures[0].asString()) + allTextures.append(textureFile) + for udimFile in textureFile.getUdimFiles(): + textures.remove(udimFile) + return allTextures + +def findBestMatch(textureName, shadingModel): + ''' + Given a texture name and shading model, return the shader input that is the closest match. + ''' + + parts = textureName.rsplit("_") + + baseTexName = parts[-1] + if baseTexName.lower() == 'color': + baseTexName = ''.join(parts[-2:]) + if baseTexName in INPUT_ALIASES: + baseTexName = INPUT_ALIASES.get(baseTexName.lower()) + + shaderInputs = shadingModel.getActiveInputs() + ratios = [] + for shaderInput in shaderInputs: + inputName = shaderInput.getName() + inputName = re.sub(r'[^a-zA-Z0-9\s]', '', inputName).lower() + baseTexName = re.sub(r'[^a-zA-Z0-9\s]', '', baseTexName).lower() + + sequenceScore = SequenceMatcher(None, inputName, baseTexName).ratio() + ratios.append(sequenceScore * 100) + + highscore = max(ratios) + if highscore < 50: + return None + + idx = ratios.index(highscore) + return shaderInputs[idx] + +def buildDocument(textureFiles, mtlxFile, shadingModel, colorspace, useTiledImage): + ''' + Build a MaterialX document from the given textures and shading model. + ''' + + # Find the default library nodedef, if any, for the requested shading model. + stdlib = mx.createDocument() + mx.loadLibraries(mx.getDefaultDataLibraryFolders(), mx.getDefaultDataSearchPath(), stdlib) + matchingNodeDefs = stdlib.getMatchingNodeDefs(shadingModel) + if not matchingNodeDefs: + print('Shading model', shadingModel, 'not found in the MaterialX data libraries') + return None + shadingModelNodeDef = matchingNodeDefs[0] + for nodeDef in matchingNodeDefs: + if nodeDef.getAttribute('isdefaultversion') == 'true': + shadingModelNodeDef = nodeDef + + # Create content document. + doc = mx.createDocument() + materialName = mx.createValidName(mtlxFile.getBaseName().rsplit('.', 1)[0]) + nodeGraph = doc.addNodeGraph('NG_' + materialName) + shaderNode = doc.addNode(shadingModel, 'SR_' + materialName, 'surfaceshader') + doc.addMaterialNode('M_' + materialName, shaderNode) + + # Iterate over texture files. + imageNodeCategory = 'tiledimage' if useTiledImage else 'image' + udimNumbers = set() + for textureFile in textureFiles: + textureName = textureFile.getNameWithoutExtension() + shaderInput = findBestMatch(textureName, shadingModelNodeDef) + + if not shaderInput: + print('Skipping', textureFile.getBaseName(), 'which does not match any', shadingModel, 'input') + continue + + inputName = shaderInput.getName() + inputType = shaderInput.getType() + + # Skip inputs that have already been created, e.g. in multi-UDIM materials. + if shaderNode.getInput(inputName) or nodeGraph.getChild(textureName): + continue + + mtlInput = shaderNode.addInput(inputName) + textureName = nodeGraph.createValidChildName(textureName) + imageNode = nodeGraph.addNode(imageNodeCategory, textureName, inputType) + + # Set color space. + if shaderInput.isColorType(): + imageNode.setColorSpace(colorspace) + + # Set file path. + filePathString = os.path.relpath(textureFile.asPattern(), mtlxFile.getParentPath().asString()) + imageNode.setInputValue('file', filePathString, 'filename') + + # Apply special cases for normal maps. + inputNode = imageNode + connNode = imageNode + inBetweenNodes = [] + if inputName.endswith('normal') and shadingModel == 'standard_surface': + inBetweenNodes = ["normalmap"] + for inNodeName in inBetweenNodes: + connNode = nodeGraph.addNode(inNodeName, textureName + '_' + inNodeName, inputType) + connNode.setConnectedNode('in', inputNode) + inputNode = connNode + + # Create output. + outputNode = nodeGraph.addOutput(textureName + '_output', inputType) + outputNode.setConnectedNode(connNode) + mtlInput.setConnectedOutput(outputNode) + mtlInput.setType(inputType) + + if textureFile.isUdim(): + udimNumbers.update(set(textureFile.getUdimNumbers())) + + # Create udim set + if udimNumbers: + geomInfoName = doc.createValidChildName('GI_' + materialName) + geomInfo = doc.addGeomInfo(geomInfoName) + geomInfo.setGeomPropValue('udimset', list(udimNumbers), "stringarray") + + # Return the new document + return doc + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--outputFilename', dest='outputFilename', type=str, help='Filename of the output MaterialX document.') + parser.add_argument('--shadingModel', dest='shadingModel', type=str, default="standard_surface", help='The shading model used in analyzing input textures.') + parser.add_argument('--colorSpace', dest='colorSpace', type=str, help='The colorspace in which input textures should be interpreted, defaulting to srgb_texture.') + parser.add_argument('--texturePrefix', dest='texturePrefix', type=str, help='Filter input textures by the given prefix.') + parser.add_argument('--tiledImage', dest='tiledImage', action="store_true", help='Request tiledimage nodes instead of image nodes.') + parser.add_argument(dest='inputDirectory', nargs='?', help='Input folder that will be scanned for textures, defaulting to the current working directory.') + + options = parser.parse_args() + + texturePath = mx.FilePath.getCurrentPath() + if options.inputDirectory: + texturePath = mx.FilePath(options.inputDirectory) + if not texturePath.isDirectory(): + print('Input folder not found:', texturePath) + return + + mtlxFile = texturePath / mx.FilePath('material.mtlx') + if options.outputFilename: + mtlxFile = mx.FilePath(options.outputFilename) + + textureFiles = listTextures(texturePath, texturePrefix=options.texturePrefix) + if not textureFiles: + print('No matching textures found in input folder.') + return + + # Get shading model and color space. + shadingModel = 'standard_surface' + colorspace = 'srgb_texture' + if options.shadingModel: + shadingModel = options.shadingModel + if options.colorSpace: + colorspace = options.colorSpace + print('Analyzing textures in the', texturePath.asString(), 'folder for the', shadingModel, 'shading model.') + + # Create the MaterialX document. + doc = buildDocument(textureFiles, mtlxFile, shadingModel, colorspace, options.tiledImage) + if not doc: + return + + if options.outputFilename: + # Write the document to disk. + if not mtlxFile.getParentPath().exists(): + mtlxFile.getParentPath().createDirectory() + mx.writeToXmlFile(doc, mtlxFile.asString()) + print('Wrote MaterialX document to disk:', mtlxFile.asString()) + else: + # Print the document to the standard output. + print('Generated MaterialX document:') + print(mx.writeToXmlString(doc)) + +if __name__ == '__main__': + main() diff --git a/MaterialX/python/Scripts/generateshader.py b/MaterialX/python/Scripts/generateshader.py old mode 100644 new mode 100755 index 46ff359..7f8c45e --- a/MaterialX/python/Scripts/generateshader.py +++ b/MaterialX/python/Scripts/generateshader.py @@ -1,204 +1,208 @@ -#!/usr/bin/env python -''' -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 - -import MaterialX as mx -import MaterialX.PyMaterialXGenGlsl as mx_gen_glsl -import MaterialX.PyMaterialXGenMdl as mx_gen_mdl -import MaterialX.PyMaterialXGenMsl as mx_gen_msl -import MaterialX.PyMaterialXGenOsl as mx_gen_osl -import MaterialX.PyMaterialXGenSlang as mx_gen_slang -import MaterialX.PyMaterialXGenShader as mx_gen_shader - -def validateCode(sourceCodeFile, codevalidator, codevalidatorArgs): - if codevalidator: - cmd = codevalidator.split() - cmd.append(sourceCodeFile) - if codevalidatorArgs: - cmd.append(codevalidatorArgs) - cmd_flatten ='----- Run Validator: ' - for c in cmd: - cmd_flatten += c + ' ' - print(cmd_flatten) - try: - output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) - return output.decode(encoding='utf-8') - except subprocess.CalledProcessError as out: - return (out.output.decode(encoding='utf-8')) - return "" - -def getMaterialXFiles(rootPath): - filelist = [] - if os.path.isdir(rootPath): - for subdir, dirs, files in os.walk(rootPath): - for file in files: - if file.endswith('mtlx'): - filelist.append(os.path.join(subdir, file)) - else: - filelist.append( rootPath ) - - return filelist - -def main(): - 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, wgsl"). Default is glsl.') - parser.add_argument('--outputPath', dest='outputPath', help='File path to output shaders to. If not specified, is the location of the input document is used.') - parser.add_argument('--validator', dest='validator', nargs='?', const=' ', type=str, help='Name of executable to perform source code validation.') - parser.add_argument('--validatorArgs', dest='validatorArgs', nargs='?', const=' ', type=str, help='Optional arguments for code validator.') - parser.add_argument('--vulkanGlsl', dest='vulkanCompliantGlsl', default=False, type=bool, help='Set to True to generate Vulkan-compliant GLSL when using the genglsl target.') - parser.add_argument('--shaderInterfaceType', dest='shaderInterfaceType', default=0, type=int, help='Set the type of shader interface to be generated') - parser.add_argument(dest='inputFilename', help='Path to input document or folder containing input documents.') - opts = parser.parse_args() - - # 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, '--------------------') - - valid, msg = doc.validate() - if not valid: - print('Validation warnings for input document:') - print(msg) - - gentarget = 'glsl' - if opts.target: - gentarget = opts.target - if gentarget == 'osl': - shadergen = mx_gen_osl.OslShaderGenerator.create() - elif gentarget == 'mdl': - shadergen = mx_gen_mdl.MdlShaderGenerator.create() - elif gentarget == 'essl': - shadergen = mx_gen_glsl.EsslShaderGenerator.create() - elif gentarget == 'vulkan': - shadergen = mx_gen_glsl.VkShaderGenerator.create() - elif gentarget == 'wgsl': - shadergen = mx_gen_glsl.WgslShaderGenerator.create() - elif gentarget == 'msl': - shadergen = mx_gen_msl.MslShaderGenerator.create() - elif gentarget == 'slang': - shadergen = mx_gen_slang.SlangShaderGenerator.create() - else: - shadergen = mx_gen_glsl.GlslShaderGenerator.create() - - codeSearchPath = searchPath - codeSearchPath.append(os.path.dirname(inputFilename)) - context = mx_gen_shader.GenContext(shadergen) - context.registerSourceCodeSearchPath(codeSearchPath) - shadergen.registerTypeDefs(doc); - - # If we're generating Vulkan-compliant GLSL then set the binding context - if opts.vulkanCompliantGlsl: - bindingContext = mx_gen_glsl.GlslResourceBindingContext.create(0,0) - context.pushUserData('udbinding', bindingContext) - - genoptions = context.getOptions() - if opts.shaderInterfaceType == 0 or opts.shaderInterfaceType == 1: - genoptions.shaderInterfaceType = mx_gen_shader.ShaderInterfaceType(opts.shaderInterfaceType) - else: - genoptions.shaderInterfaceType = mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE - - print('- Set up CMS ...') - cms = mx_gen_shader.DefaultColorManagementSystem.create(shadergen.getTarget()) - cms.loadLibrary(doc) - shadergen.setColorManagementSystem(cms) - - print('- Set up Units ...') - unitsystem = mx_gen_shader.UnitSystem.create(shadergen.getTarget()) - registry = mx.UnitConverterRegistry.create() - distanceTypeDef = doc.getUnitTypeDef('distance') - registry.addUnitConverter(distanceTypeDef, mx.LinearUnitConverter.create(distanceTypeDef)) - angleTypeDef = doc.getUnitTypeDef('angle') - registry.addUnitConverter(angleTypeDef, mx.LinearUnitConverter.create(angleTypeDef)) - unitsystem.loadLibrary(stdlib) - unitsystem.setUnitConverterRegistry(registry) - shadergen.setUnitSystem(unitsystem) - genoptions.targetDistanceUnit = 'meter' - - pathPrefix = '' - if opts.outputPath and os.path.exists(opts.outputPath): - pathPrefix = opts.outputPath + os.path.sep - else: - pathPrefix = os.path.dirname(os.path.abspath(inputFilename)) - print('- Shader output path: ' + pathPrefix) - - failedShaders = "" - 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 - if gentarget in ['glsl', 'essl', 'vulkan', 'msl', 'wgsl']: - pixelSource = shader.getSourceCode(mx_gen_shader.PIXEL_STAGE) - filename = pathPrefix + "/" + shader.getName() + "." + gentarget + ".frag" - print('--- Wrote pixel shader to: ' + filename) - file = open(filename, 'w+') - file.write(pixelSource) - file.close() - errors = validateCode(filename, opts.validator, opts.validatorArgs) - - vertexSource = shader.getSourceCode(mx_gen_shader.VERTEX_STAGE) - filename = pathPrefix + "/" + shader.getName() + "." + gentarget + ".vert" - print('--- Wrote vertex shader to: ' + filename) - file = open(filename, 'w+') - file.write(vertexSource) - file.close() - errors += validateCode(filename, opts.validator, opts.validatorArgs) - - else: - pixelSource = shader.getSourceCode(mx_gen_shader.PIXEL_STAGE) - filename = pathPrefix + "/" + shader.getName() + "." + gentarget - print('--- Wrote pixel shader to: ' + filename) - file = open(filename, 'w+') - file.write(pixelSource) - file.close() - errors = validateCode(filename, opts.validator, opts.validatorArgs) - - if errors != "": - print("--- Validation failed for element: ", elemName) - print("----------------------------") - print('--- Error log: ', errors) - print("----------------------------") - failedShaders += (elemName + ' ') - else: - print("--- Validation passed for element:", elemName) - - else: - print("--- Validation failed for element:", elemName) - failedShaders += (elemName + ' ') - - if failedShaders != "": - sys.exit(-1) - -if __name__ == '__main__': - main() +#!/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. +''' + +import sys, os, argparse, subprocess + +import MaterialX as mx +import MaterialX.PyMaterialXGenGlsl as mx_gen_glsl +import MaterialX.PyMaterialXGenMdl as mx_gen_mdl +import MaterialX.PyMaterialXGenMsl as mx_gen_msl +import MaterialX.PyMaterialXGenOsl as mx_gen_osl +import MaterialX.PyMaterialXGenShader as mx_gen_shader + +def validateCode(sourceCodeFile, codevalidator, codevalidatorArgs): + if codevalidator: + cmd = codevalidator.split() + cmd.append(sourceCodeFile) + if codevalidatorArgs: + cmd.append(codevalidatorArgs) + cmd_flatten ='----- Run Validator: ' + for c in cmd: + cmd_flatten += c + ' ' + print(cmd_flatten) + try: + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + return output.decode(encoding='utf-8') + except subprocess.CalledProcessError as out: + return (out.output.decode(encoding='utf-8')) + return "" + +def getMaterialXFiles(rootPath): + filelist = [] + if os.path.isdir(rootPath): + for subdir, dirs, files in os.walk(rootPath): + for file in files: + if file.endswith('mtlx'): + filelist.append(os.path.join(subdir, file)) + else: + filelist.append( rootPath ) + + return filelist + +def main(): + parser = argparse.ArgumentParser(description='Generate shader code for each material / shader in a document.') + 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.') + parser.add_argument('--outputPath', dest='outputPath', help='File path to output shaders to. If not specified, is the location of the input document is used.') + parser.add_argument('--validator', dest='validator', nargs='?', const=' ', type=str, help='Name of executable to perform source code validation.') + parser.add_argument('--validatorArgs', dest='validatorArgs', nargs='?', const=' ', type=str, help='Optional arguments for code validator.') + parser.add_argument('--vulkanGlsl', dest='vulkanCompliantGlsl', default=False, type=bool, help='Set to True to generate Vulkan-compliant GLSL when using the genglsl target.') + parser.add_argument('--shaderInterfaceType', dest='shaderInterfaceType', default=0, type=int, help='Set the type of shader interface to be generated') + 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: + doc = mx.createDocument() + try: + mx.readFromXmlFile(doc, inputFilename) + 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:') + print(msg) + + gentarget = 'glsl' + if opts.target: + gentarget = opts.target + if gentarget == 'osl': + shadergen = mx_gen_osl.OslShaderGenerator.create() + elif gentarget == 'mdl': + shadergen = mx_gen_mdl.MdlShaderGenerator.create() + elif gentarget == 'essl': + shadergen = mx_gen_glsl.EsslShaderGenerator.create() + elif gentarget == 'vulkan': + shadergen = mx_gen_glsl.VkShaderGenerator.create() + elif gentarget == 'msl': + shadergen = mx_gen_msl.MslShaderGenerator.create() + else: + shadergen = mx_gen_glsl.GlslShaderGenerator.create() + + context = mx_gen_shader.GenContext(shadergen) + context.registerSourceCodeSearchPath(searchPath) + + # If we're generating Vulkan-compliant GLSL then set the binding context + if opts.vulkanCompliantGlsl: + bindingContext = mx_gen_glsl.GlslResourceBindingContext.create(0,0) + context.pushUserData('udbinding', bindingContext) + + genoptions = context.getOptions() + if opts.shaderInterfaceType == 0 or opts.shaderInterfaceType == 1: + genoptions.shaderInterfaceType = mx_gen_shader.ShaderInterfaceType(opts.shaderInterfaceType) + else: + genoptions.shaderInterfaceType = mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE + + print('- Set up CMS ...') + cms = mx_gen_shader.DefaultColorManagementSystem.create(shadergen.getTarget()) + cms.loadLibrary(doc) + shadergen.setColorManagementSystem(cms) + + print('- Set up Units ...') + unitsystem = mx_gen_shader.UnitSystem.create(shadergen.getTarget()) + registry = mx.UnitConverterRegistry.create() + distanceTypeDef = doc.getUnitTypeDef('distance') + registry.addUnitConverter(distanceTypeDef, mx.LinearUnitConverter.create(distanceTypeDef)) + angleTypeDef = doc.getUnitTypeDef('angle') + registry.addUnitConverter(angleTypeDef, mx.LinearUnitConverter.create(angleTypeDef)) + unitsystem.loadLibrary(stdlib) + unitsystem.setUnitConverterRegistry(registry) + 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 + else: + pathPrefix = os.path.dirname(os.path.abspath(inputFilename)) + 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) + if shader: + # Use extension of .vert and .frag as it's type is + # recognized by glslangValidator + if gentarget in ['glsl', 'essl', 'vulkan', 'msl']: + pixelSource = shader.getSourceCode(mx_gen_shader.PIXEL_STAGE) + filename = pathPrefix + "/" + shader.getName() + "." + gentarget + ".frag" + print('--- Wrote pixel shader to: ' + filename) + file = open(filename, 'w+') + file.write(pixelSource) + file.close() + errors = validateCode(filename, opts.validator, opts.validatorArgs) + + vertexSource = shader.getSourceCode(mx_gen_shader.VERTEX_STAGE) + filename = pathPrefix + "/" + shader.getName() + "." + gentarget + ".vert" + print('--- Wrote vertex shader to: ' + filename) + file = open(filename, 'w+') + file.write(vertexSource) + file.close() + errors += validateCode(filename, opts.validator, opts.validatorArgs) + + else: + pixelSource = shader.getSourceCode(mx_gen_shader.PIXEL_STAGE) + filename = pathPrefix + "/" + shader.getName() + "." + gentarget + print('--- Wrote pixel shader to: ' + filename) + file = open(filename, 'w+') + file.write(pixelSource) + file.close() + errors = validateCode(filename, opts.validator, opts.validatorArgs) + + if errors != "": + print("--- Validation failed for node: ", nodeName) + print("----------------------------") + print('--- Error log: ', errors) + print("----------------------------") + failedShaders += (nodeName + ' ') + else: + print("--- Validation passed for node:", nodeName) + + else: + print("--- Validation failed for node:", nodeName) + failedShaders += (nodeName + ' ') + + if failedShaders != "": + sys.exit(-1) + +if __name__ == '__main__': + main() diff --git a/MaterialX/python/Scripts/genmdl.py b/MaterialX/python/Scripts/genmdl.py old mode 100644 new mode 100755 index 5d1ef1c..32cea16 --- a/MaterialX/python/Scripts/genmdl.py +++ b/MaterialX/python/Scripts/genmdl.py @@ -1,1012 +1,1018 @@ -#!/usr/bin/env python -''' -Generate MDL implementation directory based on MaterialX nodedefs -''' - -import os -import sys - -os.environ['PYTHONIOENCODING'] = 'utf-8' - -import MaterialX as mx - -def usage(): - print ('genmdl.py: Generate implementation directory for mdl based on existing MaterialX nodedefs in stdlib') - print ('Usage: genmdl.py [ ]') - print ('- A new directory called "library/stdlib/genmdl/materialx" will be created with two files added:') - print (' - .ref_mdl: Module with signature stubs for each MaterialX nodedef') - print (' - _genmdl_impl.ref_mtlx: MaterialX nodedef implementation mapping file') - print ('- By default ="mymodule" and ="1.6"') - -def _getSubDirectories(libraryPath): - return [name for name in os.listdir(libraryPath) - if os.path.isdir(os.path.join(libraryPath, name))] - -def _getMTLXFilesInDirectory(path): - for file in os.listdir(path): - if file.endswith('.mtlx'): - yield file - -def _loadLibrary(file, doc): - libDoc = mx.createDocument() - mx.readFromXmlFile(libDoc, file) - libDoc.setSourceUri(file) - doc.importLibrary(libDoc) - -def _loadLibraries(doc, searchPath, libraryPath): - librarySubPaths = _getSubDirectories(libraryPath) - librarySubPaths.append(libraryPath) - for path in librarySubPaths: - filenames = _getMTLXFilesInDirectory(os.path.join(libraryPath, path)) - for filename in filenames: - filePath = os.path.join(libraryPath, os.path.join(path, filename)) - _loadLibrary(filePath, doc) - -def _writeHeader(file, version): - file.write('mdl ' + version + ';\n') - file.write('using core import *;\n') - IMPORT_LIST = { '::anno::*', '::base::*', '.::cm::*', '::math::*', '::state::*', '::tex::*', '::state::*', '.::vectormatrix::*', '.::hsv::*', '.::noise::*'} - # To verify what are the minimal imports required - for i in IMPORT_LIST: - file.write('import' + i + ';\n') - file.write('\n\n') - file.write('// Helper function mapping texture node addressmodes to MDL wrap modes\n') - file.write('::tex::wrap_mode map_addressmode( mx_addressmode_type value ) {\n') - file.write(' switch (value) {\n') - file.write(' case mx_addressmode_type_clamp:\n') - file.write(' return ::tex::wrap_clamp;\n') - file.write(' case mx_addressmode_type_mirror:\n') - file.write(' return ::tex::wrap_mirrored_repeat;\n') - file.write(' default:\n') - file.write( ' return ::tex::wrap_repeat;\n') - file.write(' }\n') - file.write('}\n\n') - -def _mapGeomProp(geomprop): - outputValue = '' - if len(geomprop): - if geomprop.find('UV') >= 0: - outputValue = 'mx_swizzle_xy(::state::texture_coordinate(0))' - elif geomprop.find('Pobject') >= 0: - outputValue = '::state::transform_point(::state::coordinate_internal,::state::coordinate_object,::state::position())' - elif geomprop.find('PWorld') >= 0: - outputValue = '::state::transform_point(::state::coordinate_internal,::state::coordinate_world,::state::position())' - elif geomprop.find('Nobject') >= 0: - outputValue = '::state::transform_normal(::state::coordinate_internal,::state::coordinate_object,::state::normal())' - elif geomprop.find('Nworld') >= 0: - outputValue = '::state::transform_normal(::state::coordinate_internal,::state::coordinate_world,::state::normal())' - elif geomprop.find('Tobject') >= 0: - outputValue = '::state::transform_vector(::state::coordinate_internal,::state::coordinate_object,::state::texture_tangent_u(0))' - elif geomprop.find('Tworld') >= 0: - outputValue = 'state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_u(0))' - elif geomprop.find('Bobject') >= 0: - outputValue = 'state::transform_vector(::state::coordinate_internal,::state::coordinate_object,::state::texture_tangent_v(0))' - elif geomprop.find('Bworld') >= 0: - outputValue = '::state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_v(0))' - return outputValue - -def _writeValueAssignment(file, outputValue, outputType, writeEmptyValues): - # Mapping of types to initializers - assignMap = dict() - assignMap['float2[]'] = 'float2[]' - - if outputType == 'color4': - outputType = 'mk_color4' - - elif outputType in assignMap: - outputType = assignMap[outputType] - writeEmptyValues = True - - if len(outputValue) or writeEmptyValues: - file.write(' = ') - if outputType: - file.write(outputType + '(') - if outputType == 'string': - file.write('"') - file.write(outputValue) - if outputType == 'string': - file.write('"') - if outputType: - file.write(')') - -def _mapType(typeName, typeMap, functionName): - if 'mx_constant_filename' == functionName: - return 'string' - elif ('transformpoint' in functionName) or ('transformvector' in functionName) or ('transformnormal' in functionName): - if typeName == 'string': - return 'mx_coordinatespace_type' - if typeName in typeMap: - return typeMap[typeName] - return typeName - -INDENT = '\t' -SPACE = ' ' -QUOTE = '"' -FUNCTION_PREFIX = 'mx_' -FUNCTION_PARAMETER_PREFIX = 'mxp_' - -# Basic template for writing out logic for "image" node definition -def _writeImageImplementation(file, outputType): - file.write(INDENT + 'if ( mxp_uaddressmode == mx_addressmode_type_constant\n') - file.write(INDENT + ' && ( mxp_texcoord.x < 0.0 || mxp_texcoord.x > 1.0))\n') - file.write(INDENT + INDENT + 'return mxp_default;\n') - file.write(INDENT + 'if ( mxp_vaddressmode == mx_addressmode_type_constant\n') - file.write(INDENT + ' && ( mxp_texcoord.y < 0.0 || mxp_texcoord.y > 1.0))\n') - file.write(INDENT + INDENT + 'return mxp_default;\n\n') - - file.write(INDENT + outputType + ' returnValue') - isColor4 = (outputType == 'color4') - if isColor4: - outputType = 'float4' - outputType = 'mk_color4( ::tex::lookup_' + outputType - else: - outputType = '::tex::lookup_' + outputType - outputValue = 'tex: mxp_file, \n' \ - + INDENT*6 + 'coord: mxp_texcoord,\n' \ - + INDENT*6 + 'wrap_u: map_addressmode(mxp_uaddressmode),\n' \ - + INDENT*6 + 'wrap_v: map_addressmode(mxp_vaddressmode)' - _writeValueAssignment(file, outputValue, outputType, True) - if isColor4: - file.write(')') - file.write(';\n') - file.write(INDENT + 'return returnValue;\n') - -def _writeOneArgumentFunc(file, outputType, functionName): - if outputType == 'color4': - file.write(INDENT + 'return mk_color4(' + functionName + '(mk_float4(mxp_in)));\n') - elif outputType == 'color': - file.write(INDENT + 'return color(' + functionName + '(mk_float3(mxp_in)));\n') - else: - file.write(INDENT + 'return ' + functionName + '(mxp_in);\n') - -def _writeOperatorFunc(file, outputType, arg1, functionName, arg2): - if outputType == 'color4': - file.write(INDENT + 'return mk_color4(mk_float4(' + arg1 +') ' + functionName + ' mk_float4(' + arg2 + '));\n') - elif outputType == 'float3x3' or outputType == 'float4x4': - file.write(INDENT + 'return ' + outputType + '(' + arg1 + ') ' + functionName + ' ' + outputType + '(' + arg2 + ');\n') - else: - file.write(INDENT + 'return ' + arg1 + ' ' + functionName + ' ' + arg2 + ';\n') - -def _writeTwoArgumentFunc(file, outputType, functionName, arg1="mxp_in1", arg2="mxp_in2"): - if outputType == 'color4': - file.write(INDENT + 'return mk_color4(' + functionName + '(mk_float4(' + arg1 + '), mk_float4(' + arg2 + ')));\n') - elif outputType == 'color': - file.write(INDENT + 'return color(' + functionName + '(float3(' + arg1 + '), float3(' + arg2 + ')));\n') - else: - file.write(INDENT + 'return ' + functionName + '(' + arg1 + ', ' + arg2 + ');\n') - -def _writeThreeArgumentFunc(file, outputType, functionName, arg1, arg2, arg3): - if outputType == 'color4': - file.write(INDENT + 'return mk_color4(' + functionName + '(mk_float4(' + arg1 + '), mk_float4(' + arg2 + '), mk_float4(' + arg3 + ')));\n') - elif outputType == 'color': - file.write(INDENT + 'return color(' + functionName + '(float3(' + arg1 + '), float3(' + arg2 + '), float3(' + arg3 + ')));\n') - else: - file.write(INDENT + 'return ' + functionName + '(' + outputType + '(' + arg1 + '),' + outputType + '(' + arg2 + '),' + outputType+ '(' + arg3 + '));\n') - -def _writeTransformMatrix(file, nodeName): - if nodeName.find('vector3M4') >= 0: - file.write(INDENT + 'float4 returnValue = mxp_mat * float4(mxp_in.x, mxp_in.y, mxp_in.z, 1.0);\n') - file.write(INDENT + 'return float3(returnValue.x, returnValue.y, returnValue.z);\n') - elif nodeName.find('vector2M3') >= 0: - file.write(INDENT + 'float3 returnValue = mxp_mat * float3(mxp_in.x, mxp_in.y, 1.0);\n') - file.write(INDENT + 'return float2(returnValue.x, returnValue.y);\n') - else: - file.write(INDENT + 'return mxp_mat * mxp_in;\n') - -def _writeTwoArgumentCombine(file, outputType): - if outputType == 'color': - outputType = 'color3'; - file.write(INDENT + 'return mk_' + outputType + '(mxp_in1, mxp_in2);\n') - -def _writeThreeArgumentCombine(file, outputType): - if outputType == 'color': - file.write(INDENT + 'return ' + outputType + '(mxp_in1, mxp_in2, mxp_in3);\n') - else: - file.write(INDENT + 'return mk_' + outputType + '(mxp_in1, mxp_in2, mxp_in3);\n') - -def _writeFourArgumentCombine(file, outputType): - if outputType == 'color': - outputType = 'color3'; - file.write(INDENT + 'return mk_' + outputType + '(mxp_in1, mxp_in2, mxp_in3, mxp_in4);\n') - -def _writeIfGreater(file, comparator): - file.write(INDENT + 'if (mxp_value1 ' + comparator + ' mxp_value2) { return mxp_in1; } return mxp_in2;\n' ) - -def _writeTransformSpace(file, outputType, functionName, input, fromspace, tospace): - file.write(INDENT + 'state::coordinate_space fromSpace = ::mx_map_space(' + fromspace + ');\n') - file.write(INDENT + 'state::coordinate_space toSpace = ::mx_map_space(' + tospace + ');\n') - file.write(INDENT + 'return mk_' + outputType + '( state::' + functionName + '(fromSpace, toSpace, ' + input + '));\n') - -def writeNormalMap(file): - file.write(INDENT + 'if (mxp_space == "tangent")\n') - file.write(INDENT + '{\n') - file.write(INDENT + ' float3 v = mxp_in * 2.0 - 1.0;\n') - file.write(INDENT + ' float3 B = ::math::normalize(::math::cross(mxp_normal, mxp_tangent));\n') - file.write(INDENT + ' return ::math::normalize(mxp_tangent * v.x * mxp_scale + B * v.y * mxp_scale + mxp_normal * v.z);\n') - file.write(INDENT + '}\n') - file.write(INDENT + 'else\n') - file.write(INDENT + '{\n') - file.write(INDENT + ' float3 n = mxp_in * 2.0 - 1.0;\n') - file.write(INDENT + ' return ::math::normalize(n);\n') - file.write(INDENT + '}\n') - -def _writeRemap(file, outputType): - if outputType == 'color4': - file.write(INDENT + 'color4 val = mk_color4(mxp_outlow);\n') - file.write(INDENT + 'color4 val2 = mx_add(val, mx_subtract(mk_color4(mxp_in), mk_color4(mxp_inlow)));\n') - file.write(INDENT + 'color4 val3 = mx_multiply(val2, mx_subtract(mk_color4(mxp_outhigh), mk_color4(mxp_outlow)));\n') - file.write(INDENT + 'return mx_divide(val3, mx_subtract(mk_color4(mxp_inhigh), mk_color4(mxp_inlow)));\n') - else: - file.write(INDENT + 'return mxp_outlow + (mxp_in - mxp_inlow) * (mxp_outhigh - mxp_outlow) / (mxp_inhigh - mxp_inlow);\n') - -def _writeSwitch(file, outputType): - file.write(INDENT + outputType + ' returnValue;\n') - file.write(INDENT + 'switch (int(mxp_which)) {\n') - file.write(INDENT*2 + 'case 0: returnValue=mxp_in1; break;\n') - file.write(INDENT*2 + 'case 1: returnValue=mxp_in2; break;\n') - file.write(INDENT*2 + 'case 2: returnValue=mxp_in3; break;\n') - file.write(INDENT*2 + 'case 3: returnValue=mxp_in4; break;\n') - file.write(INDENT*2 + 'case 4: returnValue=mxp_in5; break;\n') - file.write(INDENT*2 + 'default: returnValue=mxp_in1; break;\n') - file.write(INDENT + '}\n') - file.write(INDENT + 'return returnValue;\n') - -def _writeOverlay(file, outputType): - if outputType == 'color4': - file.write(INDENT + 'color4 upper, lower;\n') - file.write(INDENT + 'color4 fg_ = color4(mxp_fg);\n') - file.write(INDENT + 'color4 bg_ = color4(mxp_bg);\n') - file.write(INDENT + 'upper = mx_multiply(mx_multiply(mk_color4(2.0),bg_),fg_);\n') - file.write(INDENT + 'lower = mx_subtract(mx_add(bg_,fg_),mx_multiply(bg_,fg_));\n') - file.write(INDENT + 'color maskRGB = color(::math::step(float3(.5), float3(fg_.rgb)));\n') - file.write(INDENT + 'float maskA = ::math::step(.5, fg_.a);\n') - file.write(INDENT + 'color overlayvalRGB = ::math::lerp(lower.rgb, upper.rgb, maskRGB);\n') - file.write(INDENT + 'float overlayvalA = ::math::lerp(lower.a, upper.a, maskA);\n') - file.write(INDENT + 'color returnRGB = ::math::lerp(mxp_bg.rgb, overlayvalRGB, color(mxp_mix));\n') - file.write(INDENT + 'float returnA = ::math::lerp(mxp_bg.a, overlayvalA, mxp_mix);\n') - file.write(INDENT + 'return color4(returnRGB, returnA);\n') - else: - file.write(INDENT + outputType + ' upper, lower, mask, overlayval;\n') - file.write(INDENT + outputType + ' fg_ = ' + outputType + '(mxp_fg);\n') - file.write(INDENT + outputType + ' bg_ = ' + outputType + '(mxp_bg);\n') - file.write(INDENT + 'upper = 2.0*bg_*fg_;\n') - file.write(INDENT + 'lower = bg_+fg_-bg_*fg_;\n') - if outputType == 'color': - file.write(INDENT + 'mask = color(::math::step(float3(.5), float3(fg_)));\n') - else: - file.write(INDENT + 'mask = ::math::step(' + outputType + '(.5), fg_);\n') - file.write(INDENT + 'overlayval = ::math::lerp(lower, upper, mask);\n') - file.write(INDENT + 'return ' + outputType + '(::math::lerp(mxp_bg, overlayval, mxp_mix));\n') - -def _writeDisjointOver(file, outputType): - if outputType == 'float2': - file.write(INDENT + 'float2 result;\n') - file.write(INDENT + 'float summedAlpha = mxp_fg.y + mxp_bg.y;\n') - file.write(INDENT + 'if (summedAlpha <= 1)\n') - file.write(INDENT + '{\n') - file.write(INDENT + ' result.x = mxp_fg.x + mxp_bg.x;\n') - file.write(INDENT + '}\n') - file.write(INDENT + 'else\n') - file.write(INDENT + '{\n') - file.write(INDENT + ' if (::math::abs(mxp_bg.y) < FLOAT_EPS)\n') - file.write(INDENT + ' {\n') - file.write(INDENT + ' result.x = 0.0;\n') - file.write(INDENT + ' }\n') - file.write(INDENT + ' else\n') - file.write(INDENT + ' {\n') - file.write(INDENT + ' result.x = mxp_fg.x + ((mxp_bg.x * (1-mxp_fg.y)) / mxp_bg.y);\n') - file.write(INDENT + ' }\n') - file.write(INDENT + '}\n') - file.write(INDENT + 'result.y = ::math::min(summedAlpha, 1.0);\n') - file.write(INDENT + 'result.x = result.x * mxp_mix + (1.0 - mxp_mix) * mxp_bg.x;\n') - file.write(INDENT + 'result.y = result.y * mxp_mix + (1.0 - mxp_mix) * mxp_bg.y;\n') - file.write(INDENT + 'return result;\n') - else: - file.write(INDENT + 'color4 result;\n') - file.write(INDENT + 'float summedAlpha = mxp_fg.a + mxp_bg.a;\n') - file.write(INDENT + 'if (summedAlpha <= 1)\n') - file.write(INDENT + '{\n') - file.write(INDENT + ' result.rgb = mxp_fg.rgb + mxp_bg.rgb;\n') - file.write(INDENT + '}\n') - file.write(INDENT + 'else\n') - file.write(INDENT + '{\n') - file.write(INDENT + ' if (::math::abs(mxp_bg.a) < FLOAT_EPS)\n') - file.write(INDENT + ' {\n') - file.write(INDENT + ' result.rgb = color(0.0,0.0,0.0);\n') - file.write(INDENT + ' }\n') - file.write(INDENT + ' else\n') - file.write(INDENT + ' {\n') - file.write(INDENT + ' result.rgb = mxp_fg.rgb + ((mxp_bg.rgb * (1-mxp_fg.a)) / mxp_bg.a);\n') - file.write(INDENT + ' }\n') - file.write(INDENT + '}\n') - file.write(INDENT + 'result.a = ::math::min(summedAlpha, 1.0);\n') - file.write(INDENT + 'result.rgb = result.rgb * mxp_mix + (1.0 - mxp_mix) * mxp_bg.rgb;\n') - file.write(INDENT + 'result.a = result.a * mxp_mix + (1.0 - mxp_mix) * mxp_bg.a;\n') - file.write(INDENT + 'return result;\n') - -def main(): - - if len(sys.argv) < 2: - usage() - sys.exit(0) - - _startPath = os.path.abspath(sys.argv[1]) - if os.path.exists(_startPath) == False: - print('Start path does not exist: ' + _startPath + '. Using current directory.\n') - _startPath = os.path.abspath(os.getcwd()) - - moduleName = 'mymodule' - if len(sys.argv) > 2: - moduleName = sys.argv[2] - - version = '1.6' - if len(sys.argv) > 3: - version = sys.argv[3] - - LIBRARY = 'stdlib' - - doc = mx.createDocument() - searchPath = os.path.join(_startPath, 'libraries') - libraryPath = os.path.join(searchPath, LIBRARY) - _loadLibraries(doc, searchPath, libraryPath) - - DEFINITION_PREFIX = 'ND_' - IMPLEMENTATION_PREFIX = 'IM_' - IMPLEMENTATION_STRING = 'impl' - GENMDL = 'genmdl' - DESINATION_FOLDER = 'genmdl/materialx' - - # Create target directory if don't exist - impl_outputPath = os.path.join(libraryPath, GENMDL) - if not os.path.exists(impl_outputPath): - os.mkdir(impl_outputPath) - outputPath = os.path.join(libraryPath, DESINATION_FOLDER) - if not os.path.exists(outputPath): - os.mkdir(outputPath) - - file = None - - # Write to single file if module name specified - if len(moduleName): - file = open(outputPath + '/' + moduleName + '_ref.mdl', 'w+') - _writeHeader(file, version) - - # Dictionary to map from MaterialX type declarations - # to MDL type declarations - typeMap = dict() - typeMap['boolean'] = 'bool' - typeMap['integer'] = 'int' - typeMap['color2'] = 'float2' - typeMap['color3'] = 'color' - typeMap['color4'] = 'color4' - typeMap['vector2'] = 'float2' - typeMap['vector3'] = 'float3' - typeMap['vector4'] = 'float4' - typeMap['matrix33'] = 'float3x3' - typeMap['matrix44'] = 'float4x4' - typeMap['filename'] = 'texture_2d' # Assume all file textures are 2d for now - typeMap['geomname'] = 'string' - typeMap['floatarray'] = 'float[]' - typeMap['integerarray'] = 'int[]' - typeMap['color2array'] = 'float2[]' - typeMap['color3array'] = 'color[]' - typeMap['color4array'] = 'float4[]' - typeMap['vector2array'] = 'float2[]' - typeMap['vector3array'] = 'float3[]' - typeMap['vector4array'] = 'float4[]' - typeMap['stringarray'] = 'string[]' - typeMap['geomnamearray'] = 'string[]' - typeMap['surfaceshader'] = 'material' - typeMap['volumeshader'] = 'material' - typeMap['displacementshader'] = 'material' - typeMap['lightshader'] = 'material' - - functionTypeMap = dict() - functionTypeMap['mx_separate2_color2'] = 'mx_separate2_color2_type' - functionTypeMap['mx_separate3_color3'] = 'mx_separate3_color3_type' - functionTypeMap['mx_separate4_color4'] = 'mx_separate4_color4_type' - functionTypeMap['mx_separate2_vector2'] = 'mx_separate2_vector2_type' - functionTypeMap['mx_separate3_vector3'] = 'mx_separate3_vector3_type' - functionTypeMap['mx_separate4_vector4'] = 'mx_separate4_vector4_type' - - # Create an implementation per nodedef - # - implDoc = mx.createDocument() - nodedefs = doc.getNodeDefs() - nodeGraphs = doc.getNodeGraphs() - implementedCont = 0; - totalCount = 0; - for nodedef in nodedefs: - - # Skip any node definitions which are implemented as node graphs - nodeDefName = nodedef.getName() - #print(nodeDef) - implementationIsGraph = False - for nodeGraph in nodeGraphs: - graphName = nodeGraph.getName() - #print('Scane nodegraph: ' + nodeGraph.getName() + '\n') - if nodeGraph.getAttribute('nodedef') == nodeDefName: - file.write('// Nodedef: ' + nodeDefName + ' is represented by a nodegraph: ' + graphName + '\n') - implementationIsGraph = True - break - if implementationIsGraph: - continue - - # These definitions are for organization only - nodeGroup = nodedef.getAttribute('nodegroup') - if nodeGroup == 'organization': - continue - - # TODO: Skip array definitions for now - nodeCategory = nodedef.getAttribute('node') - if nodeCategory == 'geomcolor': - print('Skip ' + nodeDefName + ' implementation. Not supported in MDL') - #continue - elif nodeCategory == 'geomattrvalue': - print('Skip ' + nodeDefName + ' implementation. Not supported in MDL') - #continue - elif nodeCategory == 'geompropvalue': - print('Skip ' + nodeDefName + ' implementation. Not supported in MDL') - #continue - - if len(nodedef.getActiveOutputs()) == 0: - continue - - totalCount += 1 - - outputValue = '' - outputType = '' - - # String out definition prefix - nodeName = nodedef.getName() - if len(nodeName) > 3: - if (nodeName[0:3] == DEFINITION_PREFIX): - nodeName = nodeName[3:] - - filename = nodeName + '.ref_mdl' - - implname = IMPLEMENTATION_PREFIX + nodeName + '_' + GENMDL - impl = implDoc.addImplementation(implname) - impl.setNodeDef(nodedef) - if len(moduleName): - impl.setFile('stdlib/' + DESINATION_FOLDER + '/' + moduleName + '.ref_mdl') - else: - impl.setFile('stdlib/' + DESINATION_FOLDER + '/' + filename) - - functionName = FUNCTION_PREFIX + nodeName - functionCallName = functionName - if len(moduleName): - functionCallName = functionName - impl.setFunction(functionCallName) - impl.setLanguage(GENMDL) - - # If no module name, create a new mdl file per nodedef - if len(moduleName) == 0: - file = open(outputPath + '/materialx/' + filename, 'w+') - _writeHeader(file, version) - - outType = nodedef.getType() - routeInputToOutput = False - - # TODO: Skip multioutput nodes for now - #if outType == 'multioutput': - # continue - - # Create a signature for the nodedef - file.write('export ') - # Add output argument - if functionName in functionTypeMap: - outType = functionTypeMap[functionName] - else: - outType = _mapType(outType, typeMap, functionName) - - file.write(outType + SPACE) - file.write(functionName + '(\n') - - # Add input arguments - # - elems = nodedef.getActiveValueElements() - lastComma = len(elems) - len(nodedef.getActiveOutputs()) - i = 0 - channelString = '' - for elem in elems: - - dataType = '' - defaultgeomprop = '' - - # Skip output elements - if isinstance(elem, mx.Output): - outputValue = elem.getAttribute('default') - if outputValue == '[]': - outputValue = '' - if not outputValue: - outputValue = elem.getAttribute('defaultinput') - if outputValue: - outputValue = FUNCTION_PARAMETER_PREFIX + outputValue - routeInputToOutput = True - outputType = elem.getType() - outputType = _mapType(outputType, typeMap, functionName) - continue - - # Parameters map to uniforms - elif isinstance(elem, mx.Parameter): - dataType = 'uniform ' - # Inputs map to varyings - elif isinstance(elem, mx.Input): - dataType = '' - defaultgeomprop = elem.getAttribute('defaultgeomprop') - - # Determine type - typeString = elem.getType() - isFileTexture = (typeString == 'filename') - typeString = _mapType(typeString , typeMap, functionName) - isString = (typeString == 'string') - - # Determine value - isGeometryInput = len(defaultgeomprop) > 0 - if isGeometryInput: - valueString = _mapGeomProp(defaultgeomprop) - else: - valueString = elem.getValueString() - - parameterName = FUNCTION_PARAMETER_PREFIX + elem.getName(); - isEnumeration = len(elem.getAttribute('enum')) > 0 - # Remap enumerations. - # Note: This is hard-coded since there are no type enumerations in MaterialX to map from - if isEnumeration and not isGeometryInput: - ADDRESS_MODE = { 'constant', 'clamp', 'periodic', 'mirror'} - FILTER_LOOKUP = { 'closest', 'linear', 'cubic' } - COORDINATE_SPACES = { 'model', 'object' , 'world' } - FILTER_TYPE = { 'box', 'gaussian' } - if valueString in ADDRESS_MODE: - typeString = 'mx_addressmode_type' - valueString = typeString + '_' + valueString - elif valueString in FILTER_LOOKUP: - typeString = 'mx_filterlookup_type' - valueString = typeString + '_' + valueString - elif valueString in COORDINATE_SPACES: - typeString = 'mx_coordinatespace_type' - valueString = typeString + '_' + valueString - elif valueString in FILTER_TYPE: - typeString = 'mx_filter_type' - valueString = typeString + '_' + valueString - - if typeString == 'mx_coordinatespace_type' and valueString == '': - valueString = 'mx_coordinatespace_type_model' - file.write(INDENT + dataType + typeString + SPACE + parameterName) - _writeValueAssignment(file, valueString, typeString, isFileTexture or isString) - - if nodeCategory == 'swizzle' and parameterName == 'mxp_channels': - channelString = valueString - - # Add annotations if any - description = elem.getAttribute('doc') - if len(elem.getAttribute('enum')): - description = description + 'Enumeration {' + elem.getAttribute('enum') + '}.' - if len(elem.getAttribute('unittype')): - description = description + 'Unit Type:' + elem.getAttribute('unittype') + '.' - if len(elem.getAttribute('unit')): - description = description + ' Unit:' + elem.getAttribute('unit') + "." - uiname = elem.getAttribute('uiname') - uigroup = elem.getAttribute('uifolder') - if len(description) or len(uiname) or len(uigroup): - file.write(INDENT + '\n' + INDENT + '[[') - count = 0 - if len(description): - file.write("\n" + INDENT + INDENT + 'anno::description("' + description + '")') - count = count + 1 - if len(uiname): - if count > 0: - file.write(',') - file.write("\n" + INDENT + INDENT + 'anno::display_name("' + uiname + '")') - count = count + 1 - if len(uigroup): - if count > 0: - file.write(',') - file.write("\n" + INDENT + INDENT + 'anno::in_group("' + uigroup + '")') - file.write('\n' + INDENT + ']]') - - i = i + 1 - if i < lastComma: - file.write(',') - file.write('\n') - - file.write(')\n') - nodegroup = nodedef.getAttribute('nodegroup') - if len(nodegroup): - file.write(INDENT + '[[\n') - file.write(INDENT + INDENT + 'anno::description("Node Group: ' + nodegroup + '")\n') - file.write(INDENT + ']]\n') - if outputType == 'material': - if outputValue: - file.write('= ' + outputValue + '; // TODO \n\n') - else: - file.write('= material(); // TODO \n\n') - else: - file.write('{\n') - if functionName in functionTypeMap: - file.write(INDENT + '// No-op. Return default value for now\n') - file.write(INDENT + 'return ' + functionTypeMap[functionName] + '();\n') - else: - wroteImplementation = False - if nodeCategory == 'constant': - file.write(INDENT + 'return mxp_value;\n') - wroteImplementation = True - elif nodeCategory == 'absval': - _writeOneArgumentFunc(file, outputType, '::math::abs') - wroteImplementation = True - elif nodeCategory == 'ceil': - _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) - wroteImplementation = True - elif nodeCategory == 'round': - _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) - wroteImplementation = True - elif nodeCategory == 'floor': - _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) - wroteImplementation = True - elif nodeCategory == 'sin': - _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) - wroteImplementation = True - elif nodeCategory == 'asin': - _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) - wroteImplementation = True - elif nodeCategory == 'cos': - _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) - wroteImplementation = True - elif nodeCategory == 'acos': - _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) - wroteImplementation = True - elif nodeCategory == 'tan': - _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) - wroteImplementation = True - elif nodeCategory == 'atan2': - _writeTwoArgumentFunc(file, outputType, '::math::'+nodeCategory, arg1=mxp_iny, arg2=mxp_inx) - wroteImplementation = True - elif nodeCategory == 'sqrt': - _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) - wroteImplementation = True - elif nodeCategory == 'ln': - _writeOneArgumentFunc(file, outputType, '::math::log') - wroteImplementation = True - elif nodeCategory == 'exp': - _writeOneArgumentFunc(file, outputType, '::math::exp') - wroteImplementation = True - elif nodeCategory == 'sign': - _writeOneArgumentFunc(file, outputType, '::math::sign') - wroteImplementation = True - elif nodeCategory == 'max': - _writeTwoArgumentFunc(file, outputType, '::math::max') - wroteImplementation = True - elif nodeCategory == 'min': - _writeTwoArgumentFunc(file, outputType, '::math::min') - wroteImplementation = True - elif nodeCategory == 'add': - _writeOperatorFunc(file, outputType, 'mxp_in1', '+', 'mxp_in2') - wroteImplementation = True - elif nodeCategory == 'subtract': - _writeOperatorFunc(file, outputType, 'mxp_in1', '-', 'mxp_in2') - wroteImplementation = True - elif nodeCategory == 'invert': - _writeOperatorFunc(file, outputType, 'mxp_amount', '-', 'mxp_in') - wroteImplementation = True - elif nodeCategory == 'multiply': - _writeOperatorFunc(file, outputType, 'mxp_in1', '*', 'mxp_in2') - wroteImplementation = True - elif nodeCategory == 'divide': - if outputType == 'color4': - file.write(INDENT + 'return mk_color4(mk_float4(mxp_in1) / mk_float4(mxp_in2));') - wroteImplementation = True - elif outputType == 'float3x3' or outputType == 'float4x4': - file.write(INDENT + 'return vectormatrix::mx_divide(mxp_in1, mxp_in2);\n') - wroteImplementation = True - else: - file.write(INDENT + 'return mxp_in1 / mxp_in2;\n') - wroteImplementation = True - elif nodeCategory == 'modulo': - _writeTwoArgumentFunc(file, outputType, 'mx_mod') - wroteImplementation = True - elif nodeCategory == 'power': - _writeTwoArgumentFunc(file, outputType, '::math::pow') - wroteImplementation = True - elif nodeCategory == 'clamp': - _writeThreeArgumentFunc(file, outputType, '::math::clamp', 'mxp_in', 'mxp_low', 'mxp_high') - wroteImplementation = True - elif nodeCategory == 'normalize': - _writeOneArgumentFunc(file, outputType, '::math::normalize') - wroteImplementation = True - elif nodeCategory == 'magnitude': - _writeOneArgumentFunc(file, outputType, '::math::length') - wroteImplementation = True - elif nodeCategory == 'dotproduct': - _writeTwoArgumentFunc(file, outputType, '::math::dot') - wroteImplementation = True - elif nodeCategory == 'crossproduct': - _writeTwoArgumentFunc(file, outputType, '::math::cross') - wroteImplementation = True - elif nodeCategory == 'image': - _writeImageImplementation(file, outputType) - wroteImplementation = True - elif nodeCategory == 'transformmatrix': - _writeTransformMatrix(file, nodeName) - wroteImplementation = True - elif nodeCategory == 'determinant': - _writeOneArgumentFunc(file, outputType, 'vectormatrix::mx_determinant') - wroteImplementation = True - elif nodeCategory == 'smoothstep': - _writeThreeArgumentFunc(file, outputType, '::math::smoothstep', 'mxp_in', 'mxp_low', 'mxp_high') - wroteImplementation = True - elif nodeCategory == 'luminance': - if nodeName.find('color4') > 0: - file.write(INDENT + 'color rgb = color(mxp_in.rgb);\n') - file.write(INDENT + 'color4 returnValue = mk_color4(::math::luminance(rgb));\n') - file.write(INDENT + 'returnValue.a = mxp_in.a;\n') - file.write(INDENT + 'return returnValue;\n') - else: - _writeOneArgumentFunc(file, outputType, '::math::luminance') - wroteImplementation = True - elif nodeCategory == 'plus': - if outputType != 'color4': - _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_fg', '(mxp_bg+mxp_fg)', 'mxp_mix') - else: - file.write(INDENT + 'color rgb = ::math::lerp(mxp_fg.rgb, mxp_bg.rgb+mxp_fg.rgb, color(mxp_mix));\n') - file.write(INDENT + 'float a = ::math::lerp(mxp_fg.a, mxp_bg.a+mxp_fg.a, mxp_mix);\n') - file.write(INDENT + 'return color4(rgb,a);\n') - wroteImplementation = True - elif nodeCategory == 'minus': - if outputType != 'color4': - _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', '(mxp_bg-mxp_fg)', 'mxp_mix') - else: - file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb, mxp_bg.rgb-mxp_fg.rgb, color(mxp_mix));\n') - file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, mxp_bg.a-mxp_fg.a, mxp_mix);\n') - file.write(INDENT + 'return color4(rgb,a);\n') - wroteImplementation = True - elif nodeCategory == 'difference': - if outputType != 'color4': - _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', 'math::abs(mxp_bg-mxp_fg)', 'mxp_mix') - else: - file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb, math::abs(mxp_bg.rgb-mxp_fg.rgb), color(mxp_mix));\n') - file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, math::abs(mxp_bg.a-mxp_fg.a), mxp_mix);\n') - file.write(INDENT + 'return color4(rgb,a);\n') - wroteImplementation = True - elif nodeCategory == 'burn': - if outputType != 'color4': - burnString = outputType + '(1.0)-(' + outputType + '(1.0)-mxp_bg)/mxp_fg' - _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', burnString, 'mxp_mix') - else: - dodgeStringRGB = 'color(1.0)-(color(1.0)-mxp_bg.rgb)/mxp_fg.rgb' - dodgeStringA = '1.0-(1.0-mxp_bg.a)/mxp_fg.a' - file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb,'+ dodgeStringRGB + ', color(mxp_mix));\n') - file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, '+ dodgeStringA + ', mxp_mix);\n') - file.write(INDENT + 'return color4(rgb,a);\n') - wroteImplementation = True - elif nodeCategory == 'dodge': - if outputType != 'color4': - dodgeString = 'mxp_bg/(' + outputType + '(1.0)-mxp_fg)' - _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', dodgeString, 'mxp_mix') - else: - dodgeStringRGB = 'mxp_bg.rgb/(color(1.0)-mxp_fg.rgb)' - dodgeStringA = 'mxp_bg.a/(1.0-mxp_fg.a)' - file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb,'+ dodgeStringRGB + ', color(mxp_mix));\n') - file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, '+ dodgeStringA + ', mxp_mix);\n') - file.write(INDENT + 'return color4(rgb,a);\n') - wroteImplementation = True - elif nodeCategory == 'screen': - if outputType != 'color4': - _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', 'mxp_bg+mxp_fg-mxp_bg*mxp_fg', 'mxp_mix') - else: - file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb, mxp_bg.rgb+mxp_fg.rgb-mxp_bg.rgb*mxp_fg.rgb, color(mxp_mix));\n') - file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, mxp_bg.a+mxp_fg.a-mxp_bg.a*mxp_fg.a, mxp_mix);\n') - file.write(INDENT + 'return color4(rgb,a);\n') - wroteImplementation = True - elif nodeCategory == 'inside': - _writeOperatorFunc(file, outputType, 'mxp_in', '*', 'mxp_mask') - wroteImplementation = True - elif nodeCategory == 'outside': - _writeOperatorFunc(file, outputType, 'mxp_in', '*', '(1.0 - mxp_mask)') - wroteImplementation = True - elif nodeCategory == 'in': - if outputType == 'float2': - _writeOperatorFunc(file, outputType, 'mxp_fg', '*', 'mxp_bg*(1.0-mxp_fg.y)') - else: - _writeOperatorFunc(file, outputType, 'mxp_fg', '*', 'mx_multiply_color4FA(mxp_bg, 1.0-mxp_fg.a)') - wroteImplementation = True - elif nodeCategory == 'mix': - _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', 'mxp_fg', 'mxp_mix') - wroteImplementation = True - elif nodeCategory == 'combine2': - _writeTwoArgumentCombine(file, outputType) - wroteImplementation = True - elif nodeCategory == 'combine3': - _writeThreeArgumentCombine(file, outputType) - wroteImplementation = True - elif nodeCategory == 'combine4': - _writeFourArgumentCombine(file, outputType) - wroteImplementation = True - elif nodeCategory == 'ifgreater': - _writeIfGreater(file, '>') - wroteImplementation = True - elif nodeCategory == 'ifgreatereq': - _writeIfGreater(file, '>=') - wroteImplementation = True - elif nodeCategory == 'ifequal': - _writeIfGreater(file, '==') - wroteImplementation = True - elif nodeCategory == 'convert': - if outputType == 'float': - file.write(INDENT + 'return ' + outputType + '(mxp_in);\n') - elif outputType == 'color': - file.write(INDENT + 'return mk_color3(mxp_in);\n') - else: - file.write(INDENT + 'return mk_' + outputType + '(mxp_in);\n') - wroteImplementation = True - elif nodeCategory == 'ramplr': - if outputType == 'color4': - file.write(INDENT + 'color rgb = math::lerp(mxp_valuel.rgb, mxp_valuer.rgb, math::clamp(mxp_texcoord.x, 0.0, 1.0));\n') - file.write(INDENT + 'float a = math::lerp(mxp_valuel.a, mxp_valuer.a, math::clamp(mxp_texcoord.x, 0.0, 1.0));\n') - file.write(INDENT + 'return color4(rgb, a);') - else: - file.write(INDENT + 'return math::lerp(mxp_valuel, mxp_valuer, math::clamp(mxp_texcoord.x, 0.0, 1.0));\n') - wroteImplementation = True - elif nodeCategory == 'ramptb': - if outputType == 'color4': - file.write(INDENT + 'color rgb = math::lerp(mxp_valuet.rgb, mxp_valueb.rgb, math::clamp(mxp_texcoord.y, 0.0, 1.0));\n') - file.write(INDENT + 'float a = math::lerp(mxp_valuet.a, mxp_valueb.a, math::clamp(mxp_texcoord.y, 0.0, 1.0));\n') - file.write(INDENT + 'return color4(rgb, a);') - else: - file.write(INDENT + 'return math::lerp(mxp_valuet, mxp_valueb, math::clamp(mxp_texcoord.y, 0.0, 1.0));\n') - wroteImplementation = True - elif nodeCategory == 'splitlr': - if outputType == 'color4': - file.write(INDENT + 'color rgb = math::lerp(mxp_valuel.rgb, mxp_valuer.rgb, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') - file.write(INDENT + 'float a = math::lerp(mxp_valuel.a, mxp_valuer.a, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') - file.write(INDENT + 'return color4(rgb, a);') - else: - file.write(INDENT + 'return math::lerp(mxp_valuel, mxp_valuer, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') - wroteImplementation = True - elif nodeCategory == 'splittb': - if outputType == 'color4': - file.write(INDENT + 'color rgb = math::lerp(mxp_valuet.rgb, mxp_valueb.rgb, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') - file.write(INDENT + 'float a = math::lerp(mxp_valuet.a, mxp_valueb.a, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') - file.write(INDENT + 'return color4(rgb, a);') - else: - file.write(INDENT + 'return math::lerp(mxp_valuet, mxp_valueb, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') - wroteImplementation = True - elif nodeCategory == 'transformvector': - _writeTransformSpace(file, outputType, 'transform_vector', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') - wroteImplementation = True - elif nodeCategory == 'transformpoint': - _writeTransformSpace(file, outputType, 'transform_point', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') - wroteImplementation = True - elif nodeCategory == 'transformnormal': - _writeTransformSpace(file, outputType, 'transform_normal', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') - wroteImplementation = True - elif nodeCategory == 'position': - _writeTransformSpace(file, outputType, 'transform_point', 'state::position()', 'mx_coordinatespace_type_model', 'mxp_space') - wroteImplementation = True - elif nodeCategory == 'normal': - _writeTransformSpace(file, outputType, 'transform_normal', 'state::normal()', 'mx_coordinatespace_type_model', 'mxp_space') - wroteImplementation = True - elif nodeCategory == 'tangent': - _writeTransformSpace(file, outputType, 'transform_vector', 'state::texture_tangent_u(mxp_index)', 'mx_coordinatespace_type_model', 'mxp_space') - wroteImplementation = True - elif nodeCategory == 'bitangent': - _writeTransformSpace(file, outputType, 'transform_vector', 'state::texture_tangent_v(mxp_index)', 'mx_coordinatespace_type_model', 'mxp_space') - wroteImplementation = True - elif nodeCategory == 'texcoord': - file.write(INDENT + 'return mk_' + outputType + '(state::texture_coordinate(mxp_index));\n') - wroteImplementation = True - elif nodeCategory == 'transpose': - file.write(INDENT + 'return ::math::transpose(mxp_in);\n') - wroteImplementation = True - elif nodeCategory == 'determinant': - file.write(INDENT + 'return vectormatrix::mx_determinant(mxp_in);\n') - wroteImplementation = True - elif nodeCategory == 'rotate2d': - file.write(INDENT + 'return vectormatrix::mx_rotate(mxp_in, mxp_amount);\n') - wroteImplementation = True - elif nodeCategory == 'rotate3d': - file.write(INDENT + 'return vectormatrix::mx_rotate(mxp_in, mxp_amount, mxp_axis);\n') - wroteImplementation = True - elif nodeCategory == 'remap': - _writeRemap(file, outputType) - wroteImplementation = True - elif nodeCategory == 'time': - file.write(INDENT + 'return ::state::animation_time();\n') - wroteImplementation = True - elif nodeCategory == 'hsvtorgb': - file.write(INDENT + 'return ::hsv::mx_hsvtorgb(mxp_in);\n') - wroteImplementation = True - elif nodeCategory == 'rgbtohsv': - file.write(INDENT + 'return ::hsv::mx_rgbtohsv(mxp_in);\n') - wroteImplementation = True - elif nodeCategory == 'switch': - _writeSwitch(file, outputType) - wroteImplementation = True - elif nodeCategory == 'overlay': - _writeOverlay(file, outputType) - wroteImplementation = True - elif nodeCategory == 'normalmap': - writeNormalMap(file) - wroteImplementation = True - - elif nodeCategory == 'premult': - if outputType == 'float2': - file.write(INDENT + 'return float2(mxp_in.x * mxp_in.y, mxp_in.y);\n') - elif outputType == 'color4': - file.write(INDENT + 'return mk_color4(mxp_in.rgb * mxp_in.a, mxp_in.a);\n') - wroteImplementation = True - elif nodeCategory == 'unpremult': - if outputType == 'float2': - file.write(INDENT + 'return float2(mxp_in.x / mxp_in.y, mxp_in.y);\n') - elif outputType == 'color4': - file.write(INDENT + 'return mk_color4(mxp_in.rgb / mxp_in.a, mxp_in.a);\n') - wroteImplementation = True - elif nodeCategory == 'disjointover': - _writeDisjointOver(file, outputType) - wroteImplementation = True - elif nodeCategory == 'mask': - if outputType == 'float2': - file.write(INDENT + 'return (mxp_bg * mxp_fg.y * mxp_mix) + mxp_bg*(1.0-mxp_mix);\n') - elif outputType == 'color4': - file.write(INDENT + 'return mx_add(' + - 'mx_multiply_color4FA(mxp_bg,mxp_fg.a*mxp_mix),' + - 'mx_multiply_color4FA(mxp_bg, (1.0-mxp_mix)) );\n') - wroteImplementation = True - elif nodeCategory == 'matte': - if outputType == 'float2': - file.write(INDENT + 'return ' + - 'float2( mxp_fg.x*mxp_fg.y + mxp_bg.x*(1.0-mxp_fg.y), mxp_fg.y + (mxp_bg.y*(1.0-mxp_fg.y)) ) ' + - '* mxp_mix + (mxp_bg * (1.0-mxp_mix));\n') - elif outputType == 'color4': - file.write(INDENT + 'color4 ls = mk_color4(\n') - file.write(INDENT + ' mx_multiply_color3FA(mxp_fg.rgb,mxp_fg.a) +\n') - file.write(INDENT + ' mx_multiply_color3FA(mxp_bg.rgb,(1.0-mxp_fg.a)),\n') - file.write(INDENT + ' mxp_fg.a + (mxp_bg.a*(1.0-mxp_fg.a)) );\n') - file.write(INDENT + 'ls = mx_multiply(ls,mk_color4(mxp_mix));\n') - file.write(INDENT + 'color4 rs = mx_multiply_color4FA(mxp_bg,(1.0-mxp_mix));\n') - file.write(INDENT + 'color4 result = mx_add(ls, rs);\n') - file.write(INDENT + 'return result;\n') - wroteImplementation = True - elif nodeCategory == 'out': - if outputType == 'float2': - file.write(INDENT + 'return (mxp_fg*(1.0-mxp_bg.y) * mxp_mix) + (mxp_bg * (1.0-mxp_mix));\n') - elif outputType == 'color4': - file.write(INDENT + 'float4 result =\n') - file.write(INDENT + ' (mk_float4(mxp_fg)*(1.0-mk_float4(mxp_bg).z) * mxp_mix) +\n') - file.write(INDENT + ' (mk_float4(mxp_bg) * (1.0-mxp_mix));\n') - file.write(INDENT + 'return mk_color4(result);\n') - wroteImplementation = True - elif nodeCategory == 'over': - if outputType == 'float2': - file.write(INDENT + 'return mxp_fg + (mxp_bg*(1.0-mxp_fg.y));\n') - elif outputType == 'color4': - file.write(INDENT + 'float4 val = mk_float4(mxp_fg) + (mk_float4(mxp_bg)*(1.0-mk_float4(mxp_fg).y));\n') - file.write(INDENT + 'return mk_color4(val);\n') - wroteImplementation = True - - if wroteImplementation: - implementedCont += 1 - else: - file.write(INDENT + '// Not implemented: ' + functionName + '\n') - file.write(INDENT + outputType + ' defaultValue') - if routeInputToOutput: - outputType = '' - _writeValueAssignment(file, outputValue, outputType, outputType == 'texture_2d') - file.write(';\n') - file.write(INDENT + 'return defaultValue;\n') - file.write('}\n\n') - - if len(moduleName) == 0: - file.close() - - if len(moduleName): - file.close() - - # Save implementation reference file to disk - implFileName = moduleName + '_gen_' + IMPLEMENTATION_STRING + '.ref_mtlx' - implPath = os.path.join(impl_outputPath, implFileName) - print('Wrote implementation file: ' + implPath + '. ' + str(implementedCont) + '/' + str(totalCount) + '\n') - mx.writeToXmlFile(implDoc, implPath) - -if __name__ == '__main__': - main() +#!/usr/bin/env python +''' +Generate MDL implementation directory based on MaterialX nodedefs +''' + +import os +import sys + +os.environ['PYTHONIOENCODING'] = 'utf-8' + +import MaterialX as mx + +def usage(): + print ('genmdl.py: Generate implementation directory for mdl based on existing MaterialX nodedefs in stdlib') + print ('Usage: genmdl.py [ ]') + print ('- A new directory called "library/stdlib/genmdl/materialx" will be created with two files added:') + print (' - .ref_mdl: Module with signature stubs for each MaterialX nodedef') + print (' - _genmdl_impl.ref_mtlx: MaterialX nodedef implementation mapping file') + print ('- By default ="mymodule" and ="1.6"') + +def _getSubDirectories(libraryPath): + return [name for name in os.listdir(libraryPath) + if os.path.isdir(os.path.join(libraryPath, name))] + +def _getMTLXFilesInDirectory(path): + for file in os.listdir(path): + if file.endswith('.mtlx'): + yield file + +def _loadLibrary(file, doc): + libDoc = mx.createDocument() + mx.readFromXmlFile(libDoc, file) + libDoc.setSourceUri(file) + doc.importLibrary(libDoc) + +def _loadLibraries(doc, searchPath, libraryPath): + librarySubPaths = _getSubDirectories(libraryPath) + librarySubPaths.append(libraryPath) + for path in librarySubPaths: + filenames = _getMTLXFilesInDirectory(os.path.join(libraryPath, path)) + for filename in filenames: + filePath = os.path.join(libraryPath, os.path.join(path, filename)) + _loadLibrary(filePath, doc) + +def _writeHeader(file, version): + file.write('mdl ' + version + ';\n') + file.write('using core import *;\n') + IMPORT_LIST = { '::anno::*', '::base::*', '.::cm::*', '::math::*', '::state::*', '::tex::*', '::state::*', '.::vectormatrix::*', '.::hsv::*', '.::noise::*'} + # To verify what are the minimal imports required + for i in IMPORT_LIST: + file.write('import' + i + ';\n') + file.write('\n\n') + file.write('// Helper function mapping texture node addressmodes to MDL wrap modes\n') + file.write('::tex::wrap_mode map_addressmode( mx_addressmode_type value ) {\n') + file.write(' switch (value) {\n') + file.write(' case mx_addressmode_type_clamp:\n') + file.write(' return ::tex::wrap_clamp;\n') + file.write(' case mx_addressmode_type_mirror:\n') + file.write(' return ::tex::wrap_mirrored_repeat;\n') + file.write(' default:\n') + file.write( ' return ::tex::wrap_repeat;\n') + file.write(' }\n') + file.write('}\n\n') + +def _mapGeomProp(geomprop): + outputValue = '' + if len(geomprop): + if geomprop.find('UV') >= 0: + outputValue = 'mx_swizzle_xy(::state::texture_coordinate(0))' + elif geomprop.find('Pobject') >= 0: + outputValue = '::state::transform_point(::state::coordinate_internal,::state::coordinate_object,::state::position())' + elif geomprop.find('PWorld') >= 0: + outputValue = '::state::transform_point(::state::coordinate_internal,::state::coordinate_world,::state::position())' + elif geomprop.find('Nobject') >= 0: + outputValue = '::state::transform_normal(::state::coordinate_internal,::state::coordinate_object,::state::normal())' + elif geomprop.find('Nworld') >= 0: + outputValue = '::state::transform_normal(::state::coordinate_internal,::state::coordinate_world,::state::normal())' + elif geomprop.find('Tobject') >= 0: + outputValue = '::state::transform_vector(::state::coordinate_internal,::state::coordinate_object,::state::texture_tangent_u(0))' + elif geomprop.find('Tworld') >= 0: + outputValue = 'state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_u(0))' + elif geomprop.find('Bobject') >= 0: + outputValue = 'state::transform_vector(::state::coordinate_internal,::state::coordinate_object,::state::texture_tangent_v(0))' + elif geomprop.find('Bworld') >= 0: + outputValue = '::state::transform_vector(::state::coordinate_internal,::state::coordinate_world,::state::texture_tangent_v(0))' + return outputValue + +def _writeValueAssignment(file, outputValue, outputType, writeEmptyValues): + # Mapping of types to initializers + assignMap = dict() + assignMap['float2[]'] = 'float2[]' + + if outputType == 'color4': + outputType = 'mk_color4' + + elif outputType in assignMap: + outputType = assignMap[outputType] + writeEmptyValues = True + + if len(outputValue) or writeEmptyValues: + file.write(' = ') + if outputType: + file.write(outputType + '(') + if outputType == 'string': + file.write('"') + file.write(outputValue) + if outputType == 'string': + file.write('"') + if outputType: + file.write(')') + +def _mapType(typeName, typeMap, functionName): + if 'mx_constant_filename' == functionName: + return 'string' + elif ('transformpoint' in functionName) or ('transformvector' in functionName) or ('transformnormal' in functionName): + if typeName == 'string': + return 'mx_coordinatespace_type' + if typeName in typeMap: + return typeMap[typeName] + return typeName + +INDENT = '\t' +SPACE = ' ' +QUOTE = '"' +FUNCTION_PREFIX = 'mx_' +FUNCTION_PARAMETER_PREFIX = 'mxp_' + +# Basic template for writing out logic for "image" node definition +def _writeImageImplementation(file, outputType): + file.write(INDENT + 'if ( mxp_uaddressmode == mx_addressmode_type_constant\n') + file.write(INDENT + ' && ( mxp_texcoord.x < 0.0 || mxp_texcoord.x > 1.0))\n') + file.write(INDENT + INDENT + 'return mxp_default;\n') + file.write(INDENT + 'if ( mxp_vaddressmode == mx_addressmode_type_constant\n') + file.write(INDENT + ' && ( mxp_texcoord.y < 0.0 || mxp_texcoord.y > 1.0))\n') + file.write(INDENT + INDENT + 'return mxp_default;\n\n') + + file.write(INDENT + outputType + ' returnValue') + isColor4 = (outputType == 'color4') + if isColor4: + outputType = 'float4' + outputType = 'mk_color4( ::tex::lookup_' + outputType + else: + outputType = '::tex::lookup_' + outputType + outputValue = 'tex: mxp_file, \n' \ + + INDENT*6 + 'coord: mxp_texcoord,\n' \ + + INDENT*6 + 'wrap_u: map_addressmode(mxp_uaddressmode),\n' \ + + INDENT*6 + 'wrap_v: map_addressmode(mxp_vaddressmode)' + _writeValueAssignment(file, outputValue, outputType, True) + if isColor4: + file.write(')') + file.write(';\n') + file.write(INDENT + 'return returnValue;\n') + +def _writeOneArgumentFunc(file, outputType, functionName): + if outputType == 'color4': + file.write(INDENT + 'return mk_color4(' + functionName + '(mk_float4(mxp_in)));\n') + elif outputType == 'color': + file.write(INDENT + 'return color(' + functionName + '(mk_float3(mxp_in)));\n') + else: + file.write(INDENT + 'return ' + functionName + '(mxp_in);\n') + +def _writeOperatorFunc(file, outputType, arg1, functionName, arg2): + if outputType == 'color4': + file.write(INDENT + 'return mk_color4(mk_float4(' + arg1 +') ' + functionName + ' mk_float4(' + arg2 + '));\n') + elif outputType == 'float3x3' or outputType == 'float4x4': + file.write(INDENT + 'return ' + outputType + '(' + arg1 + ') ' + functionName + ' ' + outputType + '(' + arg2 + ');\n') + else: + file.write(INDENT + 'return ' + arg1 + ' ' + functionName + ' ' + arg2 + ';\n') + +def _writeTwoArgumentFunc(file, outputType, functionName, arg1="mxp_in1", arg2="mxp_in2"): + if outputType == 'color4': + file.write(INDENT + 'return mk_color4(' + functionName + '(mk_float4(' + arg1 + '), mk_float4(' + arg2 + ')));\n') + elif outputType == 'color': + file.write(INDENT + 'return color(' + functionName + '(float3(' + arg1 + '), float3(' + arg2 + ')));\n') + else: + file.write(INDENT + 'return ' + functionName + '(' + arg1 + ', ' + arg2 + ');\n') + +def _writeThreeArgumentFunc(file, outputType, functionName, arg1, arg2, arg3): + if outputType == 'color4': + file.write(INDENT + 'return mk_color4(' + functionName + '(mk_float4(' + arg1 + '), mk_float4(' + arg2 + '), mk_float4(' + arg3 + ')));\n') + elif outputType == 'color': + file.write(INDENT + 'return color(' + functionName + '(float3(' + arg1 + '), float3(' + arg2 + '), float3(' + arg3 + ')));\n') + else: + file.write(INDENT + 'return ' + functionName + '(' + outputType + '(' + arg1 + '),' + outputType + '(' + arg2 + '),' + outputType+ '(' + arg3 + '));\n') + +def _writeTransformMatrix(file, nodeName): + if nodeName.find('vector3M4') >= 0: + file.write(INDENT + 'float4 returnValue = mxp_mat * float4(mxp_in.x, mxp_in.y, mxp_in.z, 1.0);\n') + file.write(INDENT + 'return float3(returnValue.x, returnValue.y, returnValue.z);\n') + elif nodeName.find('vector2M3') >= 0: + file.write(INDENT + 'float3 returnValue = mxp_mat * float3(mxp_in.x, mxp_in.y, 1.0);\n') + file.write(INDENT + 'return float2(returnValue.x, returnValue.y);\n') + else: + file.write(INDENT + 'return mxp_mat * mxp_in;\n') + +def _writeTwoArgumentCombine(file, outputType): + if outputType == 'color': + outputType = 'color3'; + file.write(INDENT + 'return mk_' + outputType + '(mxp_in1, mxp_in2);\n') + +def _writeThreeArgumentCombine(file, outputType): + if outputType == 'color': + file.write(INDENT + 'return ' + outputType + '(mxp_in1, mxp_in2, mxp_in3);\n') + else: + file.write(INDENT + 'return mk_' + outputType + '(mxp_in1, mxp_in2, mxp_in3);\n') + +def _writeFourArgumentCombine(file, outputType): + if outputType == 'color': + outputType = 'color3'; + file.write(INDENT + 'return mk_' + outputType + '(mxp_in1, mxp_in2, mxp_in3, mxp_in4);\n') + +def _writeIfGreater(file, comparitor): + file.write(INDENT + 'if (mxp_value1 ' + comparitor + ' mxp_value2) { return mxp_in1; } return mxp_in2;\n' ) + +def _writeTranformSpace(file, outputType, functionName, input, fromspace, tospace): + file.write(INDENT + 'state::coordinate_space fromSpace = ::mx_map_space(' + fromspace + ');\n') + file.write(INDENT + 'state::coordinate_space toSpace = ::mx_map_space(' + tospace + ');\n') + file.write(INDENT + 'return mk_' + outputType + '( state::' + functionName + '(fromSpace, toSpace, ' + input + '));\n') + +def writeNormalMap(file): + file.write(INDENT + 'if (mxp_space == "tangent")\n') + file.write(INDENT + '{\n') + file.write(INDENT + ' float3 v = mxp_in * 2.0 - 1.0;\n') + file.write(INDENT + ' float3 B = ::math::normalize(::math::cross(mxp_normal, mxp_tangent));\n') + file.write(INDENT + ' return ::math::normalize(mxp_tangent * v.x * mxp_scale + B * v.y * mxp_scale + mxp_normal * v.z);\n') + file.write(INDENT + '}\n') + file.write(INDENT + 'else\n') + file.write(INDENT + '{\n') + file.write(INDENT + ' float3 n = mxp_in * 2.0 - 1.0;\n') + file.write(INDENT + ' return ::math::normalize(n);\n') + file.write(INDENT + '}\n') + +def _writeRemap(file, outputType): + if outputType == 'color4': + file.write(INDENT + 'color4 val = mk_color4(mxp_outlow);\n') + file.write(INDENT + 'color4 val2 = mx_add(val, mx_subtract(mk_color4(mxp_in), mk_color4(mxp_inlow)));\n') + file.write(INDENT + 'color4 val3 = mx_multiply(val2, mx_subtract(mk_color4(mxp_outhigh), mk_color4(mxp_outlow)));\n') + file.write(INDENT + 'return mx_divide(val3, mx_subtract(mk_color4(mxp_inhigh), mk_color4(mxp_inlow)));\n') + else: + file.write(INDENT + 'return mxp_outlow + (mxp_in - mxp_inlow) * (mxp_outhigh - mxp_outlow) / (mxp_inhigh - mxp_inlow);\n') + +def _writeSwitch(file, outputType): + file.write(INDENT + outputType + ' returnValue;\n') + file.write(INDENT + 'switch (int(mxp_which)) {\n') + file.write(INDENT*2 + 'case 0: returnValue=mxp_in1; break;\n') + file.write(INDENT*2 + 'case 1: returnValue=mxp_in2; break;\n') + file.write(INDENT*2 + 'case 2: returnValue=mxp_in3; break;\n') + file.write(INDENT*2 + 'case 3: returnValue=mxp_in4; break;\n') + file.write(INDENT*2 + 'case 4: returnValue=mxp_in5; break;\n') + file.write(INDENT*2 + 'default: returnValue=mxp_in1; break;\n') + file.write(INDENT + '}\n') + file.write(INDENT + 'return returnValue;\n') + +def _writeOverlay(file, outputType): + if outputType == 'color4': + file.write(INDENT + 'color4 upper, lower;\n') + file.write(INDENT + 'color4 fg_ = color4(mxp_fg);\n') + file.write(INDENT + 'color4 bg_ = color4(mxp_bg);\n') + file.write(INDENT + 'upper = mx_multiply(mx_multiply(mk_color4(2.0),bg_),fg_);\n') + file.write(INDENT + 'lower = mx_subtract(mx_add(bg_,fg_),mx_multiply(bg_,fg_));\n') + file.write(INDENT + 'color maskRGB = color(::math::step(float3(.5), float3(fg_.rgb)));\n') + file.write(INDENT + 'float maskA = ::math::step(.5, fg_.a);\n') + file.write(INDENT + 'color overlayvalRGB = ::math::lerp(lower.rgb, upper.rgb, maskRGB);\n') + file.write(INDENT + 'float overlayvalA = ::math::lerp(lower.a, upper.a, maskA);\n') + file.write(INDENT + 'color returnRGB = ::math::lerp(mxp_bg.rgb, overlayvalRGB, color(mxp_mix));\n') + file.write(INDENT + 'float returnA = ::math::lerp(mxp_bg.a, overlayvalA, mxp_mix);\n') + file.write(INDENT + 'return color4(returnRGB, returnA);\n') + else: + file.write(INDENT + outputType + ' upper, lower, mask, overlayval;\n') + file.write(INDENT + outputType + ' fg_ = ' + outputType + '(mxp_fg);\n') + file.write(INDENT + outputType + ' bg_ = ' + outputType + '(mxp_bg);\n') + file.write(INDENT + 'upper = 2.0*bg_*fg_;\n') + file.write(INDENT + 'lower = bg_+fg_-bg_*fg_;\n') + if outputType == 'color': + file.write(INDENT + 'mask = color(::math::step(float3(.5), float3(fg_)));\n') + else: + file.write(INDENT + 'mask = ::math::step(' + outputType + '(.5), fg_);\n') + file.write(INDENT + 'overlayval = ::math::lerp(lower, upper, mask);\n') + file.write(INDENT + 'return ' + outputType + '(::math::lerp(mxp_bg, overlayval, mxp_mix));\n') + +def _writeDisjointOver(file, outputType): + if outputType == 'float2': + file.write(INDENT + 'float2 result;\n') + file.write(INDENT + 'float summedAlpha = mxp_fg.y + mxp_bg.y;\n') + file.write(INDENT + 'if (summedAlpha <= 1)\n') + file.write(INDENT + '{\n') + file.write(INDENT + ' result.x = mxp_fg.x + mxp_bg.x;\n') + file.write(INDENT + '}\n') + file.write(INDENT + 'else\n') + file.write(INDENT + '{\n') + file.write(INDENT + ' if (::math::abs(mxp_bg.y) < FLOAT_EPS)\n') + file.write(INDENT + ' {\n') + file.write(INDENT + ' result.x = 0.0;\n') + file.write(INDENT + ' }\n') + file.write(INDENT + ' else\n') + file.write(INDENT + ' {\n') + file.write(INDENT + ' result.x = mxp_fg.x + ((mxp_bg.x * (1-mxp_fg.y)) / mxp_bg.y);\n') + file.write(INDENT + ' }\n') + file.write(INDENT + '}\n') + file.write(INDENT + 'result.y = ::math::min(summedAlpha, 1.0);\n') + file.write(INDENT + 'result.x = result.x * mxp_mix + (1.0 - mxp_mix) * mxp_bg.x;\n') + file.write(INDENT + 'result.y = result.y * mxp_mix + (1.0 - mxp_mix) * mxp_bg.y;\n') + file.write(INDENT + 'return result;\n') + else: + file.write(INDENT + 'color4 result;\n') + file.write(INDENT + 'float summedAlpha = mxp_fg.a + mxp_bg.a;\n') + file.write(INDENT + 'if (summedAlpha <= 1)\n') + file.write(INDENT + '{\n') + file.write(INDENT + ' result.rgb = mxp_fg.rgb + mxp_bg.rgb;\n') + file.write(INDENT + '}\n') + file.write(INDENT + 'else\n') + file.write(INDENT + '{\n') + file.write(INDENT + ' if (::math::abs(mxp_bg.a) < FLOAT_EPS)\n') + file.write(INDENT + ' {\n') + file.write(INDENT + ' result.rgb = color(0.0,0.0,0.0);\n') + file.write(INDENT + ' }\n') + file.write(INDENT + ' else\n') + file.write(INDENT + ' {\n') + file.write(INDENT + ' result.rgb = mxp_fg.rgb + ((mxp_bg.rgb * (1-mxp_fg.a)) / mxp_bg.a);\n') + file.write(INDENT + ' }\n') + file.write(INDENT + '}\n') + file.write(INDENT + 'result.a = ::math::min(summedAlpha, 1.0);\n') + file.write(INDENT + 'result.rgb = result.rgb * mxp_mix + (1.0 - mxp_mix) * mxp_bg.rgb;\n') + file.write(INDENT + 'result.a = result.a * mxp_mix + (1.0 - mxp_mix) * mxp_bg.a;\n') + file.write(INDENT + 'return result;\n') + +def main(): + + if len(sys.argv) < 2: + usage() + sys.exit(0) + + _startPath = os.path.abspath(sys.argv[1]) + if os.path.exists(_startPath) == False: + print('Start path does not exist: ' + _startPath + '. Using current directory.\n') + _startPath = os.path.abspath(os.getcwd()) + + moduleName = 'mymodule' + if len(sys.argv) > 2: + moduleName = sys.argv[2] + + version = '1.6' + if len(sys.argv) > 3: + version = sys.argv[3] + + LIBRARY = 'stdlib' + + doc = mx.createDocument() + searchPath = os.path.join(_startPath, 'libraries') + libraryPath = os.path.join(searchPath, LIBRARY) + _loadLibraries(doc, searchPath, libraryPath) + + DEFINITION_PREFIX = 'ND_' + IMPLEMENTATION_PREFIX = 'IM_' + IMPLEMENTATION_STRING = 'impl' + GENMDL = 'genmdl' + DESINATION_FOLDER = 'genmdl/materialx' + + # Create target directory if don't exist + impl_outputPath = os.path.join(libraryPath, GENMDL) + if not os.path.exists(impl_outputPath): + os.mkdir(impl_outputPath) + outputPath = os.path.join(libraryPath, DESINATION_FOLDER) + if not os.path.exists(outputPath): + os.mkdir(outputPath) + + file = None + + # Write to single file if module name specified + if len(moduleName): + file = open(outputPath + '/' + moduleName + '_ref.mdl', 'w+') + _writeHeader(file, version) + + # Dictionary to map from MaterialX type declarations + # to MDL type declarations + typeMap = dict() + typeMap['boolean'] = 'bool' + typeMap['integer'] = 'int' + typeMap['color2'] = 'float2' + typeMap['color3'] = 'color' + typeMap['color4'] = 'color4' + typeMap['vector2'] = 'float2' + typeMap['vector3'] = 'float3' + typeMap['vector4'] = 'float4' + typeMap['matrix33'] = 'float3x3' + typeMap['matrix44'] = 'float4x4' + typeMap['filename'] = 'texture_2d' # Assume all file textures are 2d for now + typeMap['geomname'] = 'string' + typeMap['floatarray'] = 'float[]' + typeMap['integerarray'] = 'int[]' + typeMap['color2array'] = 'float2[]' + typeMap['color3array'] = 'color[]' + typeMap['color4array'] = 'float4[]' + typeMap['vector2array'] = 'float2[]' + typeMap['vector3array'] = 'float3[]' + typeMap['vector4array'] = 'float4[]' + typeMap['stringarray'] = 'string[]' + typeMap['geomnamearray'] = 'string[]' + typeMap['surfaceshader'] = 'material' + typeMap['volumeshader'] = 'material' + typeMap['displacementshader'] = 'material' + typeMap['lightshader'] = 'material' + + functionTypeMap = dict() + functionTypeMap['mx_separate2_color2'] = 'mx_separate2_color2_type' + functionTypeMap['mx_separate3_color3'] = 'mx_separate3_color3_type' + functionTypeMap['mx_separate4_color4'] = 'mx_separate4_color4_type' + functionTypeMap['mx_separate2_vector2'] = 'mx_separate2_vector2_type' + functionTypeMap['mx_separate3_vector3'] = 'mx_separate3_vector3_type' + functionTypeMap['mx_separate4_vector4'] = 'mx_separate4_vector4_type' + + # Create an implementation per nodedef + # + implDoc = mx.createDocument() + nodedefs = doc.getNodeDefs() + nodeGraphs = doc.getNodeGraphs() + implementedCont = 0; + totalCount = 0; + for nodedef in nodedefs: + + # Skip any node definitions which are implemented as node graphs + nodeDefName = nodedef.getName() + #print(nodeDef) + implementationIsGraph = False + for nodeGraph in nodeGraphs: + graphName = nodeGraph.getName() + #print('Scane nodegraph: ' + nodeGraph.getName() + '\n') + if nodeGraph.getAttribute('nodedef') == nodeDefName: + file.write('// Nodedef: ' + nodeDefName + ' is represented by a nodegraph: ' + graphName + '\n') + implementationIsGraph = True + break + if implementationIsGraph: + continue + + # These definitions are for organization only + nodeGroup = nodedef.getAttribute('nodegroup') + if nodeGroup == 'organization': + continue + + # 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': + print('Skip ' + nodeDefName + ' implementation. Not supported in MDL') + #continue + elif nodeCategory == 'geomattrvalue': + print('Skip ' + nodeDefName + ' implementation. Not supported in MDL') + #continue + elif nodeCategory == 'geompropvalue': + print('Skip ' + nodeDefName + ' implementation. Not supported in MDL') + #continue + + if len(nodedef.getActiveOutputs()) == 0: + continue + + totalCount += 1 + + outputValue = '' + outputType = '' + + # String out definition prefix + nodeName = nodedef.getName() + if len(nodeName) > 3: + if (nodeName[0:3] == DEFINITION_PREFIX): + nodeName = nodeName[3:] + + filename = nodeName + '.ref_mdl' + + implname = IMPLEMENTATION_PREFIX + nodeName + '_' + GENMDL + impl = implDoc.addImplementation(implname) + impl.setNodeDef(nodedef) + if len(moduleName): + impl.setFile('stdlib/' + DESINATION_FOLDER + '/' + moduleName + '.ref_mdl') + else: + impl.setFile('stdlib/' + DESINATION_FOLDER + '/' + filename) + + functionName = FUNCTION_PREFIX + nodeName + functionCallName = functionName + if len(moduleName): + functionCallName = functionName + impl.setFunction(functionCallName) + impl.setLanguage(GENMDL) + + # If no module name, create a new mdl file per nodedef + if len(moduleName) == 0: + file = open(outputPath + '/materialx/' + filename, 'w+') + _writeHeader(file, version) + + outType = nodedef.getType() + routeInputToOutput = False + + # TODO: Skip multioutput nodes for now + #if outType == 'multioutput': + # continue + + # Create a signature for the nodedef + file.write('export ') + # Add output argument + if functionName in functionTypeMap: + outType = functionTypeMap[functionName] + else: + outType = _mapType(outType, typeMap, functionName) + + file.write(outType + SPACE) + file.write(functionName + '(\n') + + # Add input arguments + # + elems = nodedef.getActiveValueElements() + lastComma = len(elems) - len(nodedef.getActiveOutputs()) + i = 0 + channelString = '' + for elem in elems: + + dataType = '' + defaultgeomprop = '' + + # Skip output elements + if isinstance(elem, mx.Output): + outputValue = elem.getAttribute('default') + if outputValue == '[]': + outputValue = '' + if not outputValue: + outputValue = elem.getAttribute('defaultinput') + if outputValue: + outputValue = FUNCTION_PARAMETER_PREFIX + outputValue + routeInputToOutput = True + outputType = elem.getType() + outputType = _mapType(outputType, typeMap, functionName) + continue + + # Parameters map to uniforms + elif isinstance(elem, mx.Parameter): + dataType = 'uniform ' + # Inputs map to varyings + elif isinstance(elem, mx.Input): + dataType = '' + defaultgeomprop = elem.getAttribute('defaultgeomprop') + + # Determine type + typeString = elem.getType() + isFileTexture = (typeString == 'filename') + typeString = _mapType(typeString , typeMap, functionName) + isString = (typeString == 'string') + + # Determine value + isGeometryInput = len(defaultgeomprop) > 0 + if isGeometryInput: + valueString = _mapGeomProp(defaultgeomprop) + else: + valueString = elem.getValueString() + + parameterName = FUNCTION_PARAMETER_PREFIX + elem.getName(); + isEnumeration = len(elem.getAttribute('enum')) > 0 + # Remap enumerations. + # Note: This is hard-coded since there are no type enumerations in MaterialX to map from + if isEnumeration and not isGeometryInput: + ADDRESS_MODE = { 'constant', 'clamp', 'periodic', 'mirror'} + FILTER_LOOKUP = { 'closest', 'linear', 'cubic' } + COORDINATE_SPACES = { 'model', 'object' , 'world' } + FILTER_TYPE = { 'box', 'gaussian' } + if valueString in ADDRESS_MODE: + typeString = 'mx_addressmode_type' + valueString = typeString + '_' + valueString + elif valueString in FILTER_LOOKUP: + typeString = 'mx_filterlookup_type' + valueString = typeString + '_' + valueString + elif valueString in COORDINATE_SPACES: + typeString = 'mx_coordinatespace_type' + valueString = typeString + '_' + valueString + elif valueString in FILTER_TYPE: + typeString = 'mx_filter_type' + valueString = typeString + '_' + valueString + + if typeString == 'mx_coordinatespace_type' and valueString == '': + valueString = 'mx_coordinatespace_type_model' + file.write(INDENT + dataType + typeString + SPACE + parameterName) + _writeValueAssignment(file, valueString, typeString, isFileTexture or isString) + + if nodeCategory == 'swizzle' and parameterName == 'mxp_channels': + channelString = valueString + + # Add annotations if any + description = elem.getAttribute('doc') + if len(elem.getAttribute('enum')): + description = description + 'Enumeration {' + elem.getAttribute('enum') + '}.' + if len(elem.getAttribute('unittype')): + description = description + 'Unit Type:' + elem.getAttribute('unittype') + '.' + if len(elem.getAttribute('unit')): + description = description + ' Unit:' + elem.getAttribute('unit') + "." + uiname = elem.getAttribute('uiname') + uigroup = elem.getAttribute('uifolder') + if len(description) or len(uiname) or len(uigroup): + file.write(INDENT + '\n' + INDENT + '[[') + count = 0 + if len(description): + file.write("\n" + INDENT + INDENT + 'anno::description("' + description + '")') + count = count + 1 + if len(uiname): + if count > 0: + file.write(',') + file.write("\n" + INDENT + INDENT + 'anno::display_name("' + uiname + '")') + count = count + 1 + if len(uigroup): + if count > 0: + file.write(',') + file.write("\n" + INDENT + INDENT + 'anno::in_group("' + uigroup + '")') + file.write('\n' + INDENT + ']]') + + i = i + 1 + if i < lastComma: + file.write(',') + file.write('\n') + + file.write(')\n') + nodegroup = nodedef.getAttribute('nodegroup') + if len(nodegroup): + file.write(INDENT + '[[\n') + file.write(INDENT + INDENT + 'anno::description("Node Group: ' + nodegroup + '")\n') + file.write(INDENT + ']]\n') + if outputType == 'material': + if outputValue: + file.write('= ' + outputValue + '; // TODO \n\n') + else: + file.write('= material(); // TODO \n\n') + else: + file.write('{\n') + if functionName in functionTypeMap: + file.write(INDENT + '// No-op. Return default value for now\n') + file.write(INDENT + 'return ' + functionTypeMap[functionName] + '();\n') + else: + wroteImplementation = False + if nodeCategory == 'constant': + file.write(INDENT + 'return mxp_value;\n') + wroteImplementation = True + elif nodeCategory == 'absval': + _writeOneArgumentFunc(file, outputType, '::math::abs') + wroteImplementation = True + elif nodeCategory == 'ceil': + _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) + wroteImplementation = True + elif nodeCategory == 'round': + _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) + wroteImplementation = True + elif nodeCategory == 'floor': + _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) + wroteImplementation = True + elif nodeCategory == 'sin': + _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) + wroteImplementation = True + elif nodeCategory == 'asin': + _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) + wroteImplementation = True + elif nodeCategory == 'cos': + _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) + wroteImplementation = True + elif nodeCategory == 'acos': + _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) + wroteImplementation = True + elif nodeCategory == 'tan': + _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) + wroteImplementation = True + elif nodeCategory == 'atan2': + _writeTwoArgumentFunc(file, outputType, '::math::'+nodeCategory, arg1=mxp_iny, arg2=mxp_inx) + wroteImplementation = True + elif nodeCategory == 'sqrt': + _writeOneArgumentFunc(file, outputType, '::math::'+nodeCategory) + wroteImplementation = True + elif nodeCategory == 'ln': + _writeOneArgumentFunc(file, outputType, '::math::log') + wroteImplementation = True + elif nodeCategory == 'exp': + _writeOneArgumentFunc(file, outputType, '::math::exp') + wroteImplementation = True + elif nodeCategory == 'sign': + _writeOneArgumentFunc(file, outputType, '::math::sign') + wroteImplementation = True + elif nodeCategory == 'max': + _writeTwoArgumentFunc(file, outputType, '::math::max') + wroteImplementation = True + elif nodeCategory == 'min': + _writeTwoArgumentFunc(file, outputType, '::math::min') + wroteImplementation = True + elif nodeCategory == 'add': + _writeOperatorFunc(file, outputType, 'mxp_in1', '+', 'mxp_in2') + wroteImplementation = True + elif nodeCategory == 'subtract': + _writeOperatorFunc(file, outputType, 'mxp_in1', '-', 'mxp_in2') + wroteImplementation = True + elif nodeCategory == 'invert': + _writeOperatorFunc(file, outputType, 'mxp_amount', '-', 'mxp_in') + wroteImplementation = True + elif nodeCategory == 'multiply': + _writeOperatorFunc(file, outputType, 'mxp_in1', '*', 'mxp_in2') + wroteImplementation = True + elif nodeCategory == 'divide': + if outputType == 'color4': + file.write(INDENT + 'return mk_color4(mk_float4(mxp_in1) / mk_float4(mxp_in2));') + wroteImplementation = True + elif outputType == 'float3x3' or outputType == 'float4x4': + file.write(INDENT + 'return vectormatrix::mx_divide(mxp_in1, mxp_in2);\n') + wroteImplementation = True + else: + file.write(INDENT + 'return mxp_in1 / mxp_in2;\n') + wroteImplementation = True + elif nodeCategory == 'modulo': + _writeTwoArgumentFunc(file, outputType, 'mx_mod') + wroteImplementation = True + elif nodeCategory == 'power': + _writeTwoArgumentFunc(file, outputType, '::math::pow') + wroteImplementation = True + elif nodeCategory == 'clamp': + _writeThreeArgumentFunc(file, outputType, '::math::clamp', 'mxp_in', 'mxp_low', 'mxp_high') + wroteImplementation = True + elif nodeCategory == 'normalize': + _writeOneArgumentFunc(file, outputType, '::math::normalize') + wroteImplementation = True + elif nodeCategory == 'magnitude': + _writeOneArgumentFunc(file, outputType, '::math::length') + wroteImplementation = True + elif nodeCategory == 'dotproduct': + _writeTwoArgumentFunc(file, outputType, '::math::dot') + wroteImplementation = True + elif nodeCategory == 'crossproduct': + _writeTwoArgumentFunc(file, outputType, '::math::cross') + wroteImplementation = True + elif nodeCategory == 'image': + _writeImageImplementation(file, outputType) + wroteImplementation = True + elif nodeCategory == 'transformmatrix': + _writeTransformMatrix(file, nodeName) + wroteImplementation = True + elif nodeCategory == 'determinant': + _writeOneArgumentFunc(file, outputType, 'vectormatrix::mx_determinant') + wroteImplementation = True + elif nodeCategory == 'smoothstep': + _writeThreeArgumentFunc(file, outputType, '::math::smoothstep', 'mxp_in', 'mxp_low', 'mxp_high') + wroteImplementation = True + elif nodeCategory == 'luminance': + if nodeName.find('color4') > 0: + file.write(INDENT + 'color rgb = color(mxp_in.rgb);\n') + file.write(INDENT + 'color4 returnValue = mk_color4(::math::luminance(rgb));\n') + file.write(INDENT + 'returnValue.a = mxp_in.a;\n') + file.write(INDENT + 'return returnValue;\n') + else: + _writeOneArgumentFunc(file, outputType, '::math::luminance') + wroteImplementation = True + elif nodeCategory == 'plus': + if outputType != 'color4': + _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_fg', '(mxp_bg+mxp_fg)', 'mxp_mix') + else: + file.write(INDENT + 'color rgb = ::math::lerp(mxp_fg.rgb, mxp_bg.rgb+mxp_fg.rgb, color(mxp_mix));\n') + file.write(INDENT + 'float a = ::math::lerp(mxp_fg.a, mxp_bg.a+mxp_fg.a, mxp_mix);\n') + file.write(INDENT + 'return color4(rgb,a);\n') + wroteImplementation = True + elif nodeCategory == 'minus': + if outputType != 'color4': + _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', '(mxp_bg-mxp_fg)', 'mxp_mix') + else: + file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb, mxp_bg.rgb-mxp_fg.rgb, color(mxp_mix));\n') + file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, mxp_bg.a-mxp_fg.a, mxp_mix);\n') + file.write(INDENT + 'return color4(rgb,a);\n') + wroteImplementation = True + elif nodeCategory == 'difference': + if outputType != 'color4': + _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', 'math::abs(mxp_bg-mxp_fg)', 'mxp_mix') + else: + file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb, math::abs(mxp_bg.rgb-mxp_fg.rgb), color(mxp_mix));\n') + file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, math::abs(mxp_bg.a-mxp_fg.a), mxp_mix);\n') + file.write(INDENT + 'return color4(rgb,a);\n') + wroteImplementation = True + elif nodeCategory == 'burn': + if outputType != 'color4': + burnString = outputType + '(1.0)-(' + outputType + '(1.0)-mxp_bg)/mxp_fg' + _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', burnString, 'mxp_mix') + else: + dodgeStringRGB = 'color(1.0)-(color(1.0)-mxp_bg.rgb)/mxp_fg.rgb' + dodgeStringA = '1.0-(1.0-mxp_bg.a)/mxp_fg.a' + file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb,'+ dodgeStringRGB + ', color(mxp_mix));\n') + file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, '+ dodgeStringA + ', mxp_mix);\n') + file.write(INDENT + 'return color4(rgb,a);\n') + wroteImplementation = True + elif nodeCategory == 'dodge': + if outputType != 'color4': + dodgeString = 'mxp_bg/(' + outputType + '(1.0)-mxp_fg)' + _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', dodgeString, 'mxp_mix') + else: + dodgeStringRGB = 'mxp_bg.rgb/(color(1.0)-mxp_fg.rgb)' + dodgeStringA = 'mxp_bg.a/(1.0-mxp_fg.a)' + file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb,'+ dodgeStringRGB + ', color(mxp_mix));\n') + file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, '+ dodgeStringA + ', mxp_mix);\n') + file.write(INDENT + 'return color4(rgb,a);\n') + wroteImplementation = True + elif nodeCategory == 'screen': + if outputType != 'color4': + _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', 'mxp_bg+mxp_fg-mxp_bg*mxp_fg', 'mxp_mix') + else: + file.write(INDENT + 'color rgb = ::math::lerp(mxp_bg.rgb, mxp_bg.rgb+mxp_fg.rgb-mxp_bg.rgb*mxp_fg.rgb, color(mxp_mix));\n') + file.write(INDENT + 'float a = ::math::lerp(mxp_bg.a, mxp_bg.a+mxp_fg.a-mxp_bg.a*mxp_fg.a, mxp_mix);\n') + file.write(INDENT + 'return color4(rgb,a);\n') + wroteImplementation = True + elif nodeCategory == 'inside': + _writeOperatorFunc(file, outputType, 'mxp_in', '*', 'mxp_mask') + wroteImplementation = True + elif nodeCategory == 'outside': + _writeOperatorFunc(file, outputType, 'mxp_in', '*', '(1.0 - mxp_mask)') + wroteImplementation = True + elif nodeCategory == 'in': + if outputType == 'float2': + _writeOperatorFunc(file, outputType, 'mxp_fg', '*', 'mxp_bg*(1.0-mxp_fg.y)') + else: + _writeOperatorFunc(file, outputType, 'mxp_fg', '*', 'mx_multiply_color4FA(mxp_bg, 1.0-mxp_fg.a)') + wroteImplementation = True + elif nodeCategory == 'mix': + _writeThreeArgumentFunc(file, outputType, '::math::lerp', 'mxp_bg', 'mxp_fg', 'mxp_mix') + wroteImplementation = True + elif nodeCategory == 'combine2': + _writeTwoArgumentCombine(file, outputType) + wroteImplementation = True + elif nodeCategory == 'combine3': + _writeThreeArgumentCombine(file, outputType) + wroteImplementation = True + elif nodeCategory == 'combine4': + _writeFourArgumentCombine(file, outputType) + wroteImplementation = True + elif nodeCategory == 'ifgreater': + _writeIfGreater(file, '>') + wroteImplementation = True + elif nodeCategory == 'ifgreatereq': + _writeIfGreater(file, '>=') + wroteImplementation = True + elif nodeCategory == 'ifequal': + _writeIfGreater(file, '==') + wroteImplementation = True + elif nodeCategory == 'convert': + if outputType == 'float': + file.write(INDENT + 'return ' + outputType + '(mxp_in);\n') + elif outputType == 'color': + file.write(INDENT + 'return mk_color3(mxp_in);\n') + else: + file.write(INDENT + 'return mk_' + outputType + '(mxp_in);\n') + wroteImplementation = True + elif nodeCategory == 'ramplr': + if outputType == 'color4': + file.write(INDENT + 'color rgb = math::lerp(mxp_valuel.rgb, mxp_valuer.rgb, math::clamp(mxp_texcoord.x, 0.0, 1.0));\n') + file.write(INDENT + 'float a = math::lerp(mxp_valuel.a, mxp_valuer.a, math::clamp(mxp_texcoord.x, 0.0, 1.0));\n') + file.write(INDENT + 'return color4(rgb, a);') + else: + file.write(INDENT + 'return math::lerp(mxp_valuel, mxp_valuer, math::clamp(mxp_texcoord.x, 0.0, 1.0));\n') + wroteImplementation = True + elif nodeCategory == 'ramptb': + if outputType == 'color4': + file.write(INDENT + 'color rgb = math::lerp(mxp_valuet.rgb, mxp_valueb.rgb, math::clamp(mxp_texcoord.y, 0.0, 1.0));\n') + file.write(INDENT + 'float a = math::lerp(mxp_valuet.a, mxp_valueb.a, math::clamp(mxp_texcoord.y, 0.0, 1.0));\n') + file.write(INDENT + 'return color4(rgb, a);') + else: + file.write(INDENT + 'return math::lerp(mxp_valuet, mxp_valueb, math::clamp(mxp_texcoord.y, 0.0, 1.0));\n') + wroteImplementation = True + elif nodeCategory == 'splitlr': + if outputType == 'color4': + file.write(INDENT + 'color rgb = math::lerp(mxp_valuel.rgb, mxp_valuer.rgb, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') + file.write(INDENT + 'float a = math::lerp(mxp_valuel.a, mxp_valuer.a, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') + file.write(INDENT + 'return color4(rgb, a);') + else: + file.write(INDENT + 'return math::lerp(mxp_valuel, mxp_valuer, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') + wroteImplementation = True + elif nodeCategory == 'splittb': + if outputType == 'color4': + file.write(INDENT + 'color rgb = math::lerp(mxp_valuet.rgb, mxp_valueb.rgb, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') + file.write(INDENT + 'float a = math::lerp(mxp_valuet.a, mxp_valueb.a, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') + file.write(INDENT + 'return color4(rgb, a);') + else: + file.write(INDENT + 'return math::lerp(mxp_valuet, mxp_valueb, math::step(mxp_center, math::clamp(mxp_texcoord.x,0,1)));') + wroteImplementation = True + elif nodeCategory == 'transformvector': + _writeTranformSpace(file, outputType, 'transform_vector', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') + wroteImplementation = True + elif nodeCategory == 'transformpoint': + _writeTranformSpace(file, outputType, 'transform_point', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') + wroteImplementation = True + elif nodeCategory == 'transformnormal': + _writeTranformSpace(file, outputType, 'transform_normal', 'mxp_in', 'mxp_fromspace', 'mxp_tospace') + wroteImplementation = True + elif nodeCategory == 'position': + _writeTranformSpace(file, outputType, 'transform_point', 'state::position()', 'mx_coordinatespace_type_model', 'mxp_space') + wroteImplementation = True + elif nodeCategory == 'normal': + _writeTranformSpace(file, outputType, 'transform_normal', 'state::normal()', 'mx_coordinatespace_type_model', 'mxp_space') + wroteImplementation = True + elif nodeCategory == 'tangent': + _writeTranformSpace(file, outputType, 'transform_vector', 'state::texture_tangent_u(mxp_index)', 'mx_coordinatespace_type_model', 'mxp_space') + wroteImplementation = True + elif nodeCategory == 'bitangent': + _writeTranformSpace(file, outputType, 'transform_vector', 'state::texture_tangent_v(mxp_index)', 'mx_coordinatespace_type_model', 'mxp_space') + wroteImplementation = True + elif nodeCategory == 'texcoord': + file.write(INDENT + 'return mk_' + outputType + '(state::texture_coordinate(mxp_index));\n') + wroteImplementation = True + elif nodeCategory == 'transpose': + file.write(INDENT + 'return ::math::transpose(mxp_in);\n') + wroteImplementation = True + elif nodeCategory == 'determinant': + file.write(INDENT + 'return vectormatrix::mx_determinant(mxp_in);\n') + wroteImplementation = True + elif nodeCategory == 'rotate2d': + file.write(INDENT + 'return vectormatrix::mx_rotate(mxp_in, mxp_amount);\n') + wroteImplementation = True + elif nodeCategory == 'rotate3d': + file.write(INDENT + 'return vectormatrix::mx_rotate(mxp_in, mxp_amount, mxp_axis);\n') + wroteImplementation = True + elif nodeCategory == 'remap': + _writeRemap(file, outputType) + wroteImplementation = True + elif nodeCategory == 'time': + file.write(INDENT + 'return ::state::animation_time();\n') + wroteImplementation = True + elif nodeCategory == 'hsvtorgb': + file.write(INDENT + 'return ::hsv::mx_hsvtorgb(mxp_in);\n') + wroteImplementation = True + elif nodeCategory == 'rgbtohsv': + file.write(INDENT + 'return ::hsv::mx_rgbtohsv(mxp_in);\n') + wroteImplementation = True + elif nodeCategory == 'switch': + _writeSwitch(file, outputType) + wroteImplementation = True + elif nodeCategory == 'overlay': + _writeOverlay(file, outputType) + wroteImplementation = True + elif nodeCategory == 'normalmap': + writeNormalMap(file) + wroteImplementation = True + + elif nodeCategory == 'premult': + if outputType == 'float2': + file.write(INDENT + 'return float2(mxp_in.x * mxp_in.y, mxp_in.y);\n') + elif outputType == 'color4': + file.write(INDENT + 'return mk_color4(mxp_in.rgb * mxp_in.a, mxp_in.a);\n') + wroteImplementation = True + elif nodeCategory == 'unpremult': + if outputType == 'float2': + file.write(INDENT + 'return float2(mxp_in.x / mxp_in.y, mxp_in.y);\n') + elif outputType == 'color4': + file.write(INDENT + 'return mk_color4(mxp_in.rgb / mxp_in.a, mxp_in.a);\n') + wroteImplementation = True + elif nodeCategory == 'disjointover': + _writeDisjointOver(file, outputType) + wroteImplementation = True + elif nodeCategory == 'mask': + if outputType == 'float2': + file.write(INDENT + 'return (mxp_bg * mxp_fg.y * mxp_mix) + mxp_bg*(1.0-mxp_mix);\n') + elif outputType == 'color4': + file.write(INDENT + 'return mx_add(' + + 'mx_multiply_color4FA(mxp_bg,mxp_fg.a*mxp_mix),' + + 'mx_multiply_color4FA(mxp_bg, (1.0-mxp_mix)) );\n') + wroteImplementation = True + elif nodeCategory == 'matte': + if outputType == 'float2': + file.write(INDENT + 'return ' + + 'float2( mxp_fg.x*mxp_fg.y + mxp_bg.x*(1.0-mxp_fg.y), mxp_fg.y + (mxp_bg.y*(1.0-mxp_fg.y)) ) ' + + '* mxp_mix + (mxp_bg * (1.0-mxp_mix));\n') + elif outputType == 'color4': + file.write(INDENT + 'color4 ls = mk_color4(\n') + file.write(INDENT + ' mx_multiply_color3FA(mxp_fg.rgb,mxp_fg.a) +\n') + file.write(INDENT + ' mx_multiply_color3FA(mxp_bg.rgb,(1.0-mxp_fg.a)),\n') + file.write(INDENT + ' mxp_fg.a + (mxp_bg.a*(1.0-mxp_fg.a)) );\n') + file.write(INDENT + 'ls = mx_multiply(ls,mk_color4(mxp_mix));\n') + file.write(INDENT + 'color4 rs = mx_multiply_color4FA(mxp_bg,(1.0-mxp_mix));\n') + file.write(INDENT + 'color4 result = mx_add(ls, rs);\n') + file.write(INDENT + 'return result;\n') + wroteImplementation = True + elif nodeCategory == 'out': + if outputType == 'float2': + file.write(INDENT + 'return (mxp_fg*(1.0-mxp_bg.y) * mxp_mix) + (mxp_bg * (1.0-mxp_mix));\n') + elif outputType == 'color4': + file.write(INDENT + 'float4 result =\n') + file.write(INDENT + ' (mk_float4(mxp_fg)*(1.0-mk_float4(mxp_bg).z) * mxp_mix) +\n') + file.write(INDENT + ' (mk_float4(mxp_bg) * (1.0-mxp_mix));\n') + file.write(INDENT + 'return mk_color4(result);\n') + wroteImplementation = True + elif nodeCategory == 'over': + if outputType == 'float2': + file.write(INDENT + 'return mxp_fg + (mxp_bg*(1.0-mxp_fg.y));\n') + elif outputType == 'color4': + file.write(INDENT + 'float4 val = mk_float4(mxp_fg) + (mk_float4(mxp_bg)*(1.0-mk_float4(mxp_fg).y));\n') + file.write(INDENT + 'return mk_color4(val);\n') + wroteImplementation = True + + if wroteImplementation: + implementedCont += 1 + else: + file.write(INDENT + '// Not implemented: ' + functionName + '\n') + file.write(INDENT + outputType + ' defaultValue') + if routeInputToOutput: + outputType = '' + _writeValueAssignment(file, outputValue, outputType, outputType == 'texture_2d') + file.write(';\n') + file.write(INDENT + 'return defaultValue;\n') + file.write('}\n\n') + + if len(moduleName) == 0: + file.close() + + if len(moduleName): + file.close() + + # Save implementation reference file to disk + implFileName = moduleName + '_gen_' + IMPLEMENTATION_STRING + '.ref_mtlx' + implPath = os.path.join(impl_outputPath, implFileName) + print('Wrote implementation file: ' + implPath + '. ' + str(implementedCont) + '/' + str(totalCount) + '\n') + mx.writeToXmlFile(implDoc, implPath) + +if __name__ == '__main__': + main() diff --git a/MaterialX/python/Scripts/mxdoc.py b/MaterialX/python/Scripts/mxdoc.py old mode 100644 new mode 100755 index 7c9ba09..f3a178e --- a/MaterialX/python/Scripts/mxdoc.py +++ b/MaterialX/python/Scripts/mxdoc.py @@ -1,113 +1,113 @@ -#!/usr/bin/env python -''' -Print markdown documentation for each nodedef in the given document. -''' - -import argparse -import sys - -import MaterialX as mx - -HEADERS = ('Name', 'Type', 'Default Value', - 'UI name', 'UI min', 'UI max', 'UI Soft Min', 'UI Soft Max', 'UI step', 'UI group', 'UI Advanced', 'Doc', 'Uniform') - -ATTR_NAMES = ('uiname', 'uimin', 'uimax', 'uisoftmin', 'uisoftmax', 'uistep', 'uifolder', 'uiadvanced', 'doc', 'uniform' ) - -def main(): - parser = argparse.ArgumentParser(description="Print documentation for each nodedef in the given document.") - parser.add_argument(dest="inputFilename", help="Filename of the input MaterialX document.") - parser.add_argument('--docType', dest='documentType', default='md', help='Document type. Default is "md" (Markdown). Specify "html" for HTML output') - parser.add_argument('--showInherited', default=False, action='store_true', help='Show inherited inputs. Default is False') - opts = parser.parse_args() - - doc = mx.createDocument() - try: - mx.readFromXmlFile(doc, opts.inputFilename) - except mx.ExceptionFileMissing as err: - print(err) - sys.exit(0) - - for nd in doc.getNodeDefs(): - # HTML output - if opts.documentType == "html": - print('') - print('
    ') - print('
  • Nodedef: %s' % nd.getName()) - print('
  • Type: %s' % nd.getType()) - if len(nd.getNodeGroup()) > 0: - print('
  • Node Group: %s' % nd.getNodeGroup()) - if len(nd.getVersionString()) > 0: - print('
  • Version: %s. Is default: %s' % (nd.getVersionString(), nd.getDefaultVersion())) - if len(nd.getInheritString()) > 0: - print('
  • Inherits From: %s' % nd.getInheritString()) - print('
  • Doc: %s\n' % nd.getAttribute('doc')) - print('
') - print('') - for h in HEADERS: - print('') - print('') - inputList = nd.getActiveInputs() if opts.showInherited else nd.getInputs() - tokenList = nd.getActiveTokens() if opts.showInherited else nd.getTokens() - outputList = nd.getActiveOutputs() if opts.showInherited else nd.getOutputs() - totalList = inputList + tokenList + outputList; - for port in totalList: - print('') - infos = [] - if port in outputList: - infos.append(''+ port.getName() + '') - elif port in tokenList: - infos.append(port.getName()) - else: - infos.append(''+ port.getName() + '') - infos.append(port.getType()) - val = port.getValue() - if port.getType() == "float": - val = round(val, 6) - infos.append(str(val)) - for attrname in ATTR_NAMES: - infos.append(port.getAttribute(attrname)) - for info in infos: - print('') - print('') - print('
' + h + '
' + info + '
') - - # Markdown output - else: - print('- *Nodedef*: %s' % nd.getName()) - print('- *Type*: %s' % nd.getType()) - if len(nd.getNodeGroup()) > 0: - print('- *Node Group*: %s' % nd.getNodeGroup()) - if len(nd.getVersionString()) > 0: - print('- *Version*: %s. Is default: %s' % (nd.getVersionString(), nd.getDefaultVersion())) - if len(nd.getInheritString()) > 0: - print('- *Inherits From*: %s' % nd.getInheritString()) - print('- *Doc*: %s\n' % nd.getAttribute('doc')) - print('| ' + ' | '.join(HEADERS) + ' |') - print('|' + ' ---- |' * len(HEADERS) + '') - inputList = nd.getActiveInputs() if opts.showInherited else nd.getInputs() - tokenList = nd.getActiveTokens() if opts.showInherited else nd.getTokens() - outputList = nd.getActiveOutputs() if opts.showInherited else nd.getOutputs() - totalList = inputList + tokenList + outputList; - for port in totalList: - infos = [] - if port in outputList: - infos.append('*'+ port.getName() + '*') - elif port in tokenList: - infos.append(port.getName()) - else: - infos.append('**'+ port.getName() + '**') - infos.append(port.getType()) - val = port.getValue() - if port.getType() == "float": - val = round(val, 6) - infos.append(str(val)) - for attrname in ATTR_NAMES: - infos.append(port.getAttribute(attrname)) - print('| ' + " | ".join(infos) + ' |') - -if __name__ == '__main__': - main() +#!/usr/bin/env python +''' +Print markdown documentation for each nodedef in the given document. +''' + +import argparse +import sys + +import MaterialX as mx + +HEADERS = ('Name', 'Type', 'Default Value', + 'UI name', 'UI min', 'UI max', 'UI Soft Min', 'UI Soft Max', 'UI step', 'UI group', 'UI Advanced', 'Doc', 'Uniform') + +ATTR_NAMES = ('uiname', 'uimin', 'uimax', 'uisoftmin', 'uisoftmax', 'uistep', 'uifolder', 'uiadvanced', 'doc', 'uniform' ) + +def main(): + parser = argparse.ArgumentParser(description="Print documentation for each nodedef in the given document.") + parser.add_argument(dest="inputFilename", help="Filename of the input MaterialX document.") + parser.add_argument('--docType', dest='documentType', default='md', help='Document type. Default is "md" (Markdown). Specify "html" for HTML output') + parser.add_argument('--showInherited', default=False, action='store_true', help='Show inherited inputs. Default is False') + opts = parser.parse_args() + + doc = mx.createDocument() + try: + mx.readFromXmlFile(doc, opts.inputFilename) + except mx.ExceptionFileMissing as err: + print(err) + sys.exit(0) + + for nd in doc.getNodeDefs(): + # HTML output + if opts.documentType == "html": + print('') + print('
    ') + print('
  • Nodedef: %s' % nd.getName()) + print('
  • Type: %s' % nd.getType()) + if len(nd.getNodeGroup()) > 0: + print('
  • Node Group: %s' % nd.getNodeGroup()) + if len(nd.getVersionString()) > 0: + print('
  • Version: %s. Is default: %s' % (nd.getVersionString(), nd.getDefaultVersion())) + if len(nd.getInheritString()) > 0: + print('
  • Inherits From: %s' % nd.getInheritString()) + print('
  • Doc: %s\n' % nd.getAttribute('doc')) + print('
') + print('') + for h in HEADERS: + print('') + print('') + inputList = nd.getActiveInputs() if opts.showInherited else nd.getInputs() + tokenList = nd.getActiveTokens() if opts.showInherited else nd.getTokens() + outputList = nd.getActiveOutputs() if opts.showInherited else nd.getOutputs() + totalList = inputList + tokenList + outputList; + for port in totalList: + print('') + infos = [] + if port in outputList: + infos.append(''+ port.getName() + '') + elif port in tokenList: + infos.append(port.getName()) + else: + infos.append(''+ port.getName() + '') + infos.append(port.getType()) + val = port.getValue() + if port.getType() == "float": + val = round(val, 6) + infos.append(str(val)) + for attrname in ATTR_NAMES: + infos.append(port.getAttribute(attrname)) + for info in infos: + print('') + print('') + print('
' + h + '
' + info + '
') + + # Markdown output + else: + print('- *Nodedef*: %s' % nd.getName()) + print('- *Type*: %s' % nd.getType()) + if len(nd.getNodeGroup()) > 0: + print('- *Node Group*: %s' % nd.getNodeGroup()) + if len(nd.getVersionString()) > 0: + print('- *Version*: %s. Is default: %s' % (nd.getVersionString(), nd.getDefaultVersion())) + if len(nd.getInheritString()) > 0: + print('- *Inherits From*: %s' % nd.getInheritString()) + print('- *Doc*: %s\n' % nd.getAttribute('doc')) + print('| ' + ' | '.join(HEADERS) + ' |') + print('|' + ' ---- |' * len(HEADERS) + '') + inputList = nd.getActiveInputs() if opts.showInherited else nd.getInputs() + tokenList = nd.getActiveTokens() if opts.showInherited else nd.getTokens() + outputList = nd.getActiveOutputs() if opts.showInherited else nd.getOutputs() + totalList = inputList + tokenList + outputList; + for port in totalList: + infos = [] + if port in outputList: + infos.append('*'+ port.getName() + '*') + elif port in tokenList: + infos.append(port.getName()) + else: + infos.append('**'+ port.getName() + '**') + infos.append(port.getType()) + val = port.getValue() + if port.getType() == "float": + val = round(val, 6) + infos.append(str(val)) + for attrname in ATTR_NAMES: + infos.append(port.getAttribute(attrname)) + print('| ' + " | ".join(infos) + ' |') + +if __name__ == '__main__': + main() diff --git a/MaterialX/python/Scripts/mxformat.py b/MaterialX/python/Scripts/mxformat.py old mode 100644 new mode 100755 index 010d32e..5230695 --- a/MaterialX/python/Scripts/mxformat.py +++ b/MaterialX/python/Scripts/mxformat.py @@ -1,90 +1,65 @@ -#!/usr/bin/env python -''' -Reformat a folder of MaterialX documents in place, optionally upgrading -the documents to the latest version of the standard. -''' - -import argparse -import os -import xml.etree.ElementTree as ET - -import MaterialX as mx - -def is_well_formed(xml_string): - error = '' - try: - ET.fromstring(xml_string) - except ET.ParseError as e: - error = str(e) - -def main(): - parser = argparse.ArgumentParser(description="Reformat a folder of MaterialX documents in place.") - parser.add_argument('-y', '--yes', dest='yes', action="store_true", help="Proceed without asking for confirmation from the user.") - parser.add_argument('-u', '--upgrade', dest='upgrade', action="store_true", help='Upgrade documents to the latest version of the standard.') - parser.add_argument('-v', '--validate', dest='validate', action="store_true", help='Perform MaterialX validation on documents after reformatting.') - parser.add_argument('-x', '--xml_syntax', dest='xml_syntax', action="store_true", help='Check XML syntax after reformatting.') - parser.add_argument(dest="inputFolder", help="An input folder to scan for MaterialX documents.") - opts = parser.parse_args() - - validDocs = dict() - for root, dirs, files in os.walk(opts.inputFolder): - for filename in files: - fullpath = os.path.join(root, filename) - if fullpath.endswith('.mtlx'): - doc = mx.createDocument() - try: - readOptions = mx.XmlReadOptions() - readOptions.readComments = True - readOptions.readNewlines = True - readOptions.upgradeVersion = opts.upgrade - try: - mx.readFromXmlFile(doc, fullpath, mx.FileSearchPath(), readOptions) - except Exception as err: - print('Skipping "' + filename + '" due to exception: ' + str(err)) - continue - validDocs[fullpath] = doc - except mx.Exception: - pass - - if not validDocs: - print('No MaterialX documents were found in "%s"' % (opts.inputFolder)) - return - - print('Found %s MaterialX files in "%s"' % (len(validDocs), opts.inputFolder)) - - mxVersion = mx.getVersionIntegers() - - if not opts.yes: - if opts.upgrade: - question = 'Would you like to upgrade all %i documents to MaterialX v%i.%i in place (y/n)?' % (len(validDocs), mxVersion[0], mxVersion[1]) - else: - question = 'Would you like to reformat all %i documents in place (y/n)?' % len(validDocs) - answer = input(question) - if answer != 'y' and answer != 'Y': - return - - validate = opts.validate - if validate: - print(f'- Validate documents') - xml_syntax = opts.xml_syntax - if xml_syntax: - print(f'- Check XML syntax') - for (filename, doc) in validDocs.items(): - if xml_syntax: - xml_string = mx.writeToXmlString(doc) - errors = is_well_formed(xml_string) - if errors: - print(f'- Warning: Document {filename} is not well-formed XML: {errors}') - if validate: - is_valid, errors = doc.validate() - if not is_valid: - print(f'- Warning: Document {filename} is invalid. Errors {errors}.') - mx.writeToXmlFile(doc, filename) - - if opts.upgrade: - print('Upgraded %i documents to MaterialX v%i.%i' % (len(validDocs), mxVersion[0], mxVersion[1])) - else: - print('Reformatted %i documents ' % len(validDocs)) - -if __name__ == '__main__': - main() +#!/usr/bin/env python +''' +Reformat a folder of MaterialX documents in place, optionally upgrading +the documents to the latest version of the standard. +''' + +import argparse +import os + +import MaterialX as mx + +def main(): + parser = argparse.ArgumentParser(description="Reformat a folder of MaterialX documents in place.") + parser.add_argument("--yes", dest="yes", action="store_true", help="Proceed without asking for confirmation from the user.") + parser.add_argument('--upgrade', dest='upgrade', action="store_true", help='Upgrade documents to the latest version of the standard.') + parser.add_argument(dest="inputFolder", help="An input folder to scan for MaterialX documents.") + opts = parser.parse_args() + + validDocs = dict() + for root, dirs, files in os.walk(opts.inputFolder): + for file in files: + if file.endswith('.mtlx'): + filename = os.path.join(root, file) + doc = mx.createDocument() + try: + readOptions = mx.XmlReadOptions() + readOptions.readComments = True + readOptions.readNewlines = True + readOptions.upgradeVersion = opts.upgrade + try: + mx.readFromXmlFile(doc, filename, mx.FileSearchPath(), readOptions) + except Exception as err: + print('Skipping "' + file + '" due to exception: ' + str(err)) + continue + validDocs[filename] = doc + except mx.Exception: + pass + + if not validDocs: + print('No MaterialX documents were found in "%s"' % (opts.inputFolder)) + return + + print('Found %s MaterialX files in "%s"' % (len(validDocs), opts.inputFolder)) + + mxVersion = mx.getVersionIntegers() + + if not opts.yes: + if opts.upgrade: + question = 'Would you like to upgrade all %i documents to MaterialX v%i.%i in place (y/n)?' % (len(validDocs), mxVersion[0], mxVersion[1]) + else: + question = 'Would you like to reformat all %i documents in place (y/n)?' % len(validDocs) + answer = input(question) + if answer != 'y' and answer != 'Y': + return + + for (filename, doc) in validDocs.items(): + mx.writeToXmlFile(doc, filename) + + if opts.upgrade: + print('Upgraded %i documents to MaterialX v%i.%i' % (len(validDocs), mxVersion[0], mxVersion[1])) + else: + print('Reformatted %i documents ' % len(validDocs)) + +if __name__ == '__main__': + main() diff --git a/MaterialX/python/Scripts/mxvalidate.py b/MaterialX/python/Scripts/mxvalidate.py index e0ccf34..7c8ad6b 100755 --- a/MaterialX/python/Scripts/mxvalidate.py +++ b/MaterialX/python/Scripts/mxvalidate.py @@ -1,363 +1,359 @@ -#!/usr/bin/env python -''' -Verify that the given file is a valid MaterialX document. -''' - -import argparse -import sys - -import MaterialX as mx - -def main(): - parser = argparse.ArgumentParser(description="Verify that the given file is a valid MaterialX document.") - parser.add_argument("--resolve", dest="resolve", action="store_true", help="Resolve inheritance and string substitutions.") - parser.add_argument("--verbose", dest="verbose", action="store_true", help="Print summary of elements found in the document.") - parser.add_argument("--stdlib", dest="stdlib", action="store_true", help="Import standard MaterialX libraries into the document.") - parser.add_argument(dest="inputFilename", help="Filename of the input document.") - opts = parser.parse_args() - - # Load standard libraries if requested. - stdlib = None - if opts.stdlib: - stdlib = mx.createDocument() - try: - mx.loadLibraries(mx.getDefaultDataLibraryFolders(), mx.getDefaultDataSearchPath(), stdlib) - except Exception as err: - print(err) - sys.exit(0) - - # 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() - looks = doc.getLooks() - lookgroups = doc.getLookGroups() - collections = doc.getCollections() - nodedefs = doc.getNodeDefs() - implementations = doc.getImplementations() - geominfos = doc.getGeomInfos() - geompropdefs = doc.getGeomPropDefs() - typedefs = doc.getTypeDefs() - propsets = doc.getPropertySets() - variantsets = doc.getVariantSets() - backdrops = doc.getBackdrops() - - print("----------------------------------") - print("Document Version: {}.{:02d}".format(*doc.getVersionIntegers())) - print("%4d Custom Type%s%s" % (len(typedefs), pl(typedefs), listContents(typedefs, opts.resolve))) - print("%4d Custom GeomProp%s%s" % (len(geompropdefs), pl(geompropdefs), listContents(geompropdefs, opts.resolve))) - print("%4d NodeDef%s%s" % (len(nodedefs), pl(nodedefs), listContents(nodedefs, opts.resolve))) - print("%4d Implementation%s%s" % (len(implementations), pl(implementations), listContents(implementations, opts.resolve))) - print("%4d Nodegraph%s%s" % (len(nodegraphs), pl(nodegraphs), listContents(nodegraphs, opts.resolve))) - print("%4d VariantSet%s%s" % (len(variantsets), pl(variantsets), listContents(variantsets, opts.resolve))) - print("%4d Material%s%s" % (len(materials), pl(materials), listContents(materials, opts.resolve))) - print("%4d Collection%s%s" % (len(collections), pl(collections), listContents(collections, opts.resolve))) - print("%4d GeomInfo%s%s" % (len(geominfos), pl(geominfos), listContents(geominfos, opts.resolve))) - print("%4d PropertySet%s%s" % (len(propsets), pl(propsets), listContents(propsets, opts.resolve))) - print("%4d Look%s%s" % (len(looks), pl(looks), listContents(looks, opts.resolve))) - print("%4d LookGroup%s%s" % (len(lookgroups), pl(lookgroups), listContents(lookgroups, opts.resolve))) - print("%4d Top-level backdrop%s%s" % (len(backdrops), pl(backdrops), listContents(backdrops, opts.resolve))) - print("----------------------------------") - -def listContents(elemlist, resolve): - if len(elemlist) == 0: - return '' - names = [] - for elem in elemlist: - - if elem.isA(mx.NodeDef): - outtype = elem.getType() - outs = "" - if outtype == "multioutput": - for ot in elem.getOutputs(): - outs = outs + \ - '\n\t %s output "%s"' % (ot.getType(), ot.getName()) - names.append('%s %s "%s"%s' % - (outtype, elem.getNodeString(), elem.getName(), outs)) - names.append(listNodedefInterface(elem)) - - elif elem.isA(mx.Implementation): - impl = elem.getName() - targs = [] - if elem.hasTarget(): - targs.append("target %s" % elem.getTarget()) - if targs: - impl = "%s (%s)" % (impl, ", ".join(targs)) - if elem.hasFunction(): - if elem.hasFile(): - impl = "%s [%s:%s()]" % ( - impl, elem.getFile(), elem.getFunction()) - else: - impl = "%s [function %s()]" % (impl, elem.getFunction()) - elif elem.hasFile(): - impl = "%s [%s]" % (impl, elem.getFile()) - names.append(impl) - - elif elem.isA(mx.Backdrop): - names.append('%s: contains "%s"' % - (elem.getName(), elem.getContainsString())) - - elif elem.isA(mx.NodeGraph): - nchildnodes = len(elem.getChildren()) - elem.getOutputCount() - backdrops = elem.getBackdrops() - nbackdrops = len(backdrops) - outs = "" - if nbackdrops > 0: - for bd in backdrops: - outs = outs + '\n\t backdrop "%s"' % (bd.getName()) - outs = outs + ' contains "%s"' % bd.getContainsString() - if elem.getOutputCount() > 0: - for ot in elem.getOutputs(): - outs = outs + '\n\t %s output "%s"' % (ot.getType(), ot.getName()) - outs = outs + traverseInputs(ot, "", 0) - nd = elem.getNodeDef() - if nd: - names.append('%s (implementation for nodedef "%s"): %d nodes%s' % ( - elem.getName(), nd.getName(), nchildnodes, outs)) - else: - names.append("%s: %d nodes, %d backdrop%s%s" % ( - elem.getName(), nchildnodes, nbackdrops, pl(backdrops), outs)) - - elif elem.isA(mx.Node, mx.SURFACE_MATERIAL_NODE_STRING): - shaders = mx.getShaderNodes(elem) - names.append("%s: %d connected shader node%s" % (elem.getName(), len(shaders), pl(shaders))) - for shader in shaders: - names.append('Shader node "%s" (%s), with bindings:%s' % (shader.getName(), shader.getCategory(), listShaderBindings(shader))) - - elif elem.isA(mx.GeomInfo): - props = elem.getGeomProps() - if props: - propnames = " (Geomprops: " + ", ".join(map( - lambda x: "%s=%s" % (x.getName(), getConvertedValue(x)), props)) + ")" - else: - propnames = "" - - tokens = elem.getTokens() - if tokens: - tokennames = " (Tokens: " + ", ".join(map( - lambda x: "%s=%s" % (x.getName(), x.getValueString()), tokens)) + ")" - else: - tokennames = "" - names.append("%s%s%s" % (elem.getName(), propnames, tokennames)) - - elif elem.isA(mx.VariantSet): - vars = elem.getVariants() - if vars: - varnames = " (variants " + ", ".join(map( - lambda x: '"' + x.getName()+'"', vars)) + ")" - else: - varnames = "" - names.append("%s%s" % (elem.getName(), varnames)) - - elif elem.isA(mx.PropertySet): - props = elem.getProperties() - if props: - propnames = " (" + ", ".join(map( - lambda x: "%s %s%s" % (x.getType(), x.getName(), getTarget(x)), props)) + ")" - else: - propnames = "" - names.append("%s%s" % (elem.getName(), propnames)) - - elif elem.isA(mx.LookGroup): - lks = elem.getLooks() - if lks: - names.append("%s (looks: %s)" % (elem.getName(), lks)) - else: - names.append("%s (no looks)" % (elem.getName())) - - elif elem.isA(mx.Look): - mas = "" - if resolve: - mtlassns = elem.getActiveMaterialAssigns() - else: - mtlassns = elem.getMaterialAssigns() - for mtlassn in mtlassns: - mas = mas + "\n\t MaterialAssign %s to%s" % ( - mtlassn.getMaterial(), getGeoms(mtlassn, resolve)) - pas = "" - if resolve: - propassns = elem.getActivePropertyAssigns() - else: - propassns = elem.getPropertyAssigns() - for propassn in propassns: - propertyname = propassn.getAttribute("property") - pas = pas + "\n\t PropertyAssign %s %s to%s" % ( - propassn.getType(), propertyname, getGeoms(propassn, resolve)) - - psas = "" - if resolve: - propsetassns = elem.getActivePropertySetAssigns() - else: - propsetassns = elem.getPropertySetAssigns() - for propsetassn in propsetassns: - propertysetname = propsetassn.getAttribute("propertyset") - psas = psas + "\n\t PropertySetAssign %s to%s" % ( - propertysetname, getGeoms(propsetassn, resolve)) - - varas = "" - if resolve: - variantassns = elem.getActiveVariantAssigns() - else: - variantassns = elem.getVariantAssigns() - for varassn in variantassns: - varas = varas + "\n\t VariantAssign %s from variantset %s" % ( - varassn.getVariantString(), varassn.getVariantSetString()) - - visas = "" - if resolve: - visassns = elem.getActiveVisibilities() - else: - visassns = elem.getVisibilities() - for vis in visassns: - visstr = 'on' if vis.getVisible() else 'off' - visas = visas + "\n\t Set %s visibility%s %s to%s" % ( - vis.getVisibilityType(), getViewerGeoms(vis), visstr, getGeoms(vis, resolve)) - - names.append("%s%s%s%s%s%s" % - (elem.getName(), mas, pas, psas, varas, visas)) - - else: - names.append(elem.getName()) - return ":\n\t" + "\n\t".join(names) - -def listShaderBindings(shader): - s = '' - for inp in shader.getInputs(): - bname = inp.getName() - btype = inp.getType() - if inp.hasOutputString(): - outname = inp.getOutputString() - if inp.hasNodeGraphString(): - ngname = inp.getNodeGraphString() - s = s + '\n\t %s "%s" -> nodegraph "%s" output "%s"' % (btype, bname, ngname, outname) - else: - s = s + '\n\t %s "%s" -> output "%s"' % (btype, bname, outname) - else: - bval = getConvertedValue(inp) - s = s + '\n\t %s "%s" = %s' % (btype, bname, bval) - return s - -def listNodedefInterface(nodedef): - s = '' - for inp in nodedef.getActiveInputs(): - iname = inp.getName() - itype = inp.getType() - if s: - s = s + '\n\t' - s = s + ' %s input "%s"' % (itype, iname) - for tok in nodedef.getActiveTokens(): - tname = tok.getName() - ttype = tok.getType() - if s: - s = s + '\n\t' - s = s + ' %s token "%s"' % (ttype, tname) - return s - -def traverseInputs(node, port, depth): - s = '' - if node.isA(mx.Output): - parent = node.getConnectedNode() - s = s + traverseInputs(parent, "", depth+1) - else: - s = s + '%s%s -> %s %s "%s"' % (spc(depth), port, - node.getType(), node.getCategory(), node.getName()) - ins = node.getActiveInputs() - for i in ins: - if i.hasInterfaceName(): - intname = i.getInterfaceName() - s = s + \ - '%s%s ^- %s interface "%s"' % (spc(depth+1), - i.getName(), i.getType(), intname) - elif i.hasValueString(): - val = getConvertedValue(i) - s = s + \ - '%s%s = %s value %s' % ( - spc(depth+1), i.getName(), i.getType(), val) - else: - parent = i.getConnectedNode() - if parent: - s = s + traverseInputs(parent, i.getName(), depth+1) - toks = node.getActiveTokens() - for i in toks: - if i.hasInterfaceName(): - intname = i.getInterfaceName() - s = s + \ - '%s[T]%s ^- %s interface "%s"' % ( - spc(depth+1), i.getName(), i.getType(), intname) - elif i.hasValueString(): - val = i.getValueString() - s = s + \ - '%s[T]%s = %s value "%s"' % ( - spc(depth+1), i.getName(), i.getType(), val) - else: - s = s + \ - '%s[T]%s error: no valueString' % ( - spc(depth+1), i.getName()) - return s - -def pl(elem): - if len(elem) == 1: - return "" - else: - return "s" - -def spc(depth): - return "\n\t " + ": "*depth - -# Return a value string for the element, converting units if appropriate -def getConvertedValue(elem): - if elem.getType() in ["float", "vector2", "vector3", "vector4"]: - if elem.hasUnit(): - u = elem.getUnit() - print ("[Unit for %s is %s]" % (elem.getName(), u)) - if elem.hasUnitType(): - utype = elem.getUnitType() - print ("[Unittype for %s is %s]" % (elem.getName(), utype)) - # NOTDONE... - return elem.getValueString() - -def getGeoms(elem, resolve): - s = "" - if elem.hasGeom(): - if resolve: - s = s + ' geom "%s"' % elem.getActiveGeom() - else: - s = s + ' geom "%s"' % elem.getGeom() - if elem.hasCollectionString(): - s = s + ' collection "%s"' % elem.getCollectionString() - return s - -def getViewerGeoms(elem): - s = "" - if elem.hasViewerGeom(): - s = s + ' viewergeom "%s"' % elem.getViewerGeom() - if elem.hasViewerCollection(): - s = s + ' viewercollection "%s"' % elem.getViewerCollection() - if s: - s = " of" + s - return s - -def getTarget(elem): - if elem.hasTarget(): - return ' [target "%s"]' % elem.getTarget() - else: - return "" - -if __name__ == '__main__': - main() +#!/usr/bin/env python +''' +Verify that the given file is a valid MaterialX document. +''' + +import argparse +import sys + +import MaterialX as mx + +def main(): + parser = argparse.ArgumentParser(description="Verify that the given file is a valid MaterialX document.") + parser.add_argument("--resolve", dest="resolve", action="store_true", help="Resolve inheritance and string substitutions.") + parser.add_argument("--verbose", dest="verbose", action="store_true", help="Print summary of elements found in the document.") + parser.add_argument("--stdlib", dest="stdlib", action="store_true", help="Import standard MaterialX libraries into the document.") + 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) + + if opts.stdlib: + stdlib = mx.createDocument() + try: + mx.loadLibraries(mx.getDefaultDataLibraryFolders(), mx.getDefaultDataSearchPath(), stdlib) + except Exception as err: + print(err) + sys.exit(0) + doc.importLibrary(stdlib) + + (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) + + if opts.verbose: + nodegraphs = doc.getNodeGraphs() + materials = doc.getMaterialNodes() + looks = doc.getLooks() + lookgroups = doc.getLookGroups() + collections = doc.getCollections() + nodedefs = doc.getNodeDefs() + implementations = doc.getImplementations() + geominfos = doc.getGeomInfos() + geompropdefs = doc.getGeomPropDefs() + typedefs = doc.getTypeDefs() + propsets = doc.getPropertySets() + variantsets = doc.getVariantSets() + backdrops = doc.getBackdrops() + + print("----------------------------------") + print("Document Version: {}.{:02d}".format(*doc.getVersionIntegers())) + print("%4d Custom Type%s%s" % (len(typedefs), pl(typedefs), listContents(typedefs, opts.resolve))) + print("%4d Custom GeomProp%s%s" % (len(geompropdefs), pl(geompropdefs), listContents(geompropdefs, opts.resolve))) + print("%4d NodeDef%s%s" % (len(nodedefs), pl(nodedefs), listContents(nodedefs, opts.resolve))) + print("%4d Implementation%s%s" % (len(implementations), pl(implementations), listContents(implementations, opts.resolve))) + print("%4d Nodegraph%s%s" % (len(nodegraphs), pl(nodegraphs), listContents(nodegraphs, opts.resolve))) + print("%4d VariantSet%s%s" % (len(variantsets), pl(variantsets), listContents(variantsets, opts.resolve))) + print("%4d Material%s%s" % (len(materials), pl(materials), listContents(materials, opts.resolve))) + print("%4d Collection%s%s" % (len(collections), pl(collections), listContents(collections, opts.resolve))) + print("%4d GeomInfo%s%s" % (len(geominfos), pl(geominfos), listContents(geominfos, opts.resolve))) + print("%4d PropertySet%s%s" % (len(propsets), pl(propsets), listContents(propsets, opts.resolve))) + print("%4d Look%s%s" % (len(looks), pl(looks), listContents(looks, opts.resolve))) + print("%4d LookGroup%s%s" % (len(lookgroups), pl(lookgroups), listContents(lookgroups, opts.resolve))) + print("%4d Top-level backdrop%s%s" % (len(backdrops), pl(backdrops), listContents(backdrops, opts.resolve))) + print("----------------------------------") + +def listContents(elemlist, resolve): + if len(elemlist) == 0: + return '' + names = [] + for elem in elemlist: + + if elem.isA(mx.NodeDef): + outtype = elem.getType() + outs = "" + if outtype == "multioutput": + for ot in elem.getOutputs(): + outs = outs + \ + '\n\t %s output "%s"' % (ot.getType(), ot.getName()) + names.append('%s %s "%s"%s' % + (outtype, elem.getNodeString(), elem.getName(), outs)) + names.append(listNodedefInterface(elem)) + + elif elem.isA(mx.Implementation): + impl = elem.getName() + targs = [] + if elem.hasTarget(): + targs.append("target %s" % elem.getTarget()) + if targs: + impl = "%s (%s)" % (impl, ", ".join(targs)) + if elem.hasFunction(): + if elem.hasFile(): + impl = "%s [%s:%s()]" % ( + impl, elem.getFile(), elem.getFunction()) + else: + impl = "%s [function %s()]" % (impl, elem.getFunction()) + elif elem.hasFile(): + impl = "%s [%s]" % (impl, elem.getFile()) + names.append(impl) + + elif elem.isA(mx.Backdrop): + names.append('%s: contains "%s"' % + (elem.getName(), elem.getContainsString())) + + elif elem.isA(mx.NodeGraph): + nchildnodes = len(elem.getChildren()) - elem.getOutputCount() + backdrops = elem.getBackdrops() + nbackdrops = len(backdrops) + outs = "" + if nbackdrops > 0: + for bd in backdrops: + outs = outs + '\n\t backdrop "%s"' % (bd.getName()) + outs = outs + ' contains "%s"' % bd.getContainsString() + if elem.getOutputCount() > 0: + for ot in elem.getOutputs(): + outs = outs + '\n\t %s output "%s"' % (ot.getType(), ot.getName()) + outs = outs + traverseInputs(ot, "", 0) + nd = elem.getNodeDef() + if nd: + names.append('%s (implementation for nodedef "%s"): %d nodes%s' % ( + elem.getName(), nd.getName(), nchildnodes, outs)) + else: + names.append("%s: %d nodes, %d backdrop%s%s" % ( + elem.getName(), nchildnodes, nbackdrops, pl(backdrops), outs)) + + elif elem.isA(mx.Node, mx.SURFACE_MATERIAL_NODE_STRING): + shaders = mx.getShaderNodes(elem) + names.append("%s: %d connected shader node%s" % (elem.getName(), len(shaders), pl(shaders))) + for shader in shaders: + names.append('Shader node "%s" (%s), with bindings:%s' % (shader.getName(), shader.getCategory(), listShaderBindings(shader))) + + elif elem.isA(mx.GeomInfo): + props = elem.getGeomProps() + if props: + propnames = " (Geomprops: " + ", ".join(map( + lambda x: "%s=%s" % (x.getName(), getConvertedValue(x)), props)) + ")" + else: + propnames = "" + + tokens = elem.getTokens() + if tokens: + tokennames = " (Tokens: " + ", ".join(map( + lambda x: "%s=%s" % (x.getName(), x.getValueString()), tokens)) + ")" + else: + tokennames = "" + names.append("%s%s%s" % (elem.getName(), propnames, tokennames)) + + elif elem.isA(mx.VariantSet): + vars = elem.getVariants() + if vars: + varnames = " (variants " + ", ".join(map( + lambda x: '"' + x.getName()+'"', vars)) + ")" + else: + varnames = "" + names.append("%s%s" % (elem.getName(), varnames)) + + elif elem.isA(mx.PropertySet): + props = elem.getProperties() + if props: + propnames = " (" + ", ".join(map( + lambda x: "%s %s%s" % (x.getType(), x.getName(), getTarget(x)), props)) + ")" + else: + propnames = "" + names.append("%s%s" % (elem.getName(), propnames)) + + elif elem.isA(mx.LookGroup): + lks = elem.getLooks() + if lks: + names.append("%s (looks: %s)" % (elem.getName(), lks)) + else: + names.append("%s (no looks)" % (elem.getName())) + + elif elem.isA(mx.Look): + mas = "" + if resolve: + mtlassns = elem.getActiveMaterialAssigns() + else: + mtlassns = elem.getMaterialAssigns() + for mtlassn in mtlassns: + mas = mas + "\n\t MaterialAssign %s to%s" % ( + mtlassn.getMaterial(), getGeoms(mtlassn, resolve)) + pas = "" + if resolve: + propassns = elem.getActivePropertyAssigns() + else: + propassns = elem.getPropertyAssigns() + for propassn in propassns: + propertyname = propassn.getAttribute("property") + pas = pas + "\n\t PropertyAssign %s %s to%s" % ( + propassn.getType(), propertyname, getGeoms(propassn, resolve)) + + psas = "" + if resolve: + propsetassns = elem.getActivePropertySetAssigns() + else: + propsetassns = elem.getPropertySetAssigns() + for propsetassn in propsetassns: + propertysetname = propsetassn.getAttribute("propertyset") + psas = psas + "\n\t PropertySetAssign %s to%s" % ( + propertysetname, getGeoms(propsetassn, resolve)) + + varas = "" + if resolve: + variantassns = elem.getActiveVariantAssigns() + else: + variantassns = elem.getVariantAssigns() + for varassn in variantassns: + varas = varas + "\n\t VariantAssign %s from variantset %s" % ( + varassn.getVariantString(), varassn.getVariantSetString()) + + visas = "" + if resolve: + visassns = elem.getActiveVisibilities() + else: + visassns = elem.getVisibilities() + for vis in visassns: + visstr = 'on' if vis.getVisible() else 'off' + visas = visas + "\n\t Set %s visibility%s %s to%s" % ( + vis.getVisibilityType(), getViewerGeoms(vis), visstr, getGeoms(vis, resolve)) + + names.append("%s%s%s%s%s%s" % + (elem.getName(), mas, pas, psas, varas, visas)) + + else: + names.append(elem.getName()) + return ":\n\t" + "\n\t".join(names) + +def listShaderBindings(shader): + s = '' + for inp in shader.getInputs(): + bname = inp.getName() + btype = inp.getType() + if inp.hasOutputString(): + outname = inp.getOutputString() + if inp.hasNodeGraphString(): + ngname = inp.getNodeGraphString() + s = s + '\n\t %s "%s" -> nodegraph "%s" output "%s"' % (btype, bname, ngname, outname) + else: + s = s + '\n\t %s "%s" -> output "%s"' % (btype, bname, outname) + else: + bval = getConvertedValue(inp) + s = s + '\n\t %s "%s" = %s' % (btype, bname, bval) + return s + +def listNodedefInterface(nodedef): + s = '' + for inp in nodedef.getActiveInputs(): + iname = inp.getName() + itype = inp.getType() + if s: + s = s + '\n\t' + s = s + ' %s input "%s"' % (itype, iname) + for tok in nodedef.getActiveTokens(): + tname = tok.getName() + ttype = tok.getType() + if s: + s = s + '\n\t' + s = s + ' %s token "%s"' % (ttype, tname) + return s + +def traverseInputs(node, port, depth): + s = '' + if node.isA(mx.Output): + parent = node.getConnectedNode() + s = s + traverseInputs(parent, "", depth+1) + else: + s = s + '%s%s -> %s %s "%s"' % (spc(depth), port, + node.getType(), node.getCategory(), node.getName()) + ins = node.getActiveInputs() + for i in ins: + if i.hasInterfaceName(): + intname = i.getInterfaceName() + s = s + \ + '%s%s ^- %s interface "%s"' % (spc(depth+1), + i.getName(), i.getType(), intname) + elif i.hasValueString(): + val = getConvertedValue(i) + s = s + \ + '%s%s = %s value %s' % ( + spc(depth+1), i.getName(), i.getType(), val) + else: + parent = i.getConnectedNode() + if parent: + s = s + traverseInputs(parent, i.getName(), depth+1) + toks = node.getActiveTokens() + for i in toks: + if i.hasInterfaceName(): + intname = i.getInterfaceName() + s = s + \ + '%s[T]%s ^- %s interface "%s"' % ( + spc(depth+1), i.getName(), i.getType(), intname) + elif i.hasValueString(): + val = i.getValueString() + s = s + \ + '%s[T]%s = %s value "%s"' % ( + spc(depth+1), i.getName(), i.getType(), val) + else: + s = s + \ + '%s[T]%s error: no valueString' % ( + spc(depth+1), i.getName()) + return s + +def pl(elem): + if len(elem) == 1: + return "" + else: + return "s" + +def spc(depth): + return "\n\t " + ": "*depth + +# Return a value string for the element, converting units if appropriate +def getConvertedValue(elem): + if elem.getType() in ["float", "vector2", "vector3", "vector4"]: + if elem.hasUnit(): + u = elem.getUnit() + print ("[Unit for %s is %s]" % (elem.getName(), u)) + if elem.hasUnitType(): + utype = elem.getUnitType() + print ("[Unittype for %s is %s]" % (elem.getName(), utype)) + # NOTDONE... + return elem.getValueString() + +def getGeoms(elem, resolve): + s = "" + if elem.hasGeom(): + if resolve: + s = s + ' geom "%s"' % elem.getActiveGeom() + else: + s = s + ' geom "%s"' % elem.getGeom() + if elem.hasCollectionString(): + s = s + ' collection "%s"' % elem.getCollectionString() + return s + +def getViewerGeoms(elem): + s = "" + if elem.hasViewerGeom(): + s = s + ' viewergeom "%s"' % elem.getViewerGeom() + if elem.hasViewerCollection(): + s = s + ' viewercollection "%s"' % elem.getViewerCollection() + if s: + s = " of" + s + return s + +def getTarget(elem): + if elem.hasTarget(): + return ' [target "%s"]' % elem.getTarget() + else: + return "" + +if __name__ == '__main__': + main() diff --git a/MaterialX/python/Scripts/oiio_loader.py b/MaterialX/python/Scripts/oiio_loader.py deleted file mode 100644 index 587c003..0000000 --- a/MaterialX/python/Scripts/oiio_loader.py +++ /dev/null @@ -1,429 +0,0 @@ -""" -Sample MaterialX ImageLoader implementation using OpenImageIO package. - -This module provides a MaterialX-compatible ImageLoader implementation using OpenImageIO (OIIO). -The test will test loading an image, save it out, and optionally previewing it. - -Steps: - 1. Create an OIIOLoader which is derived from the ImageLoader interface class. - 2. Create a new ImageHandler and register the loader with it. - 3. Request to acquire an image using the ImageHandler. An EXR image is requested. - 4. OIIOLoader will return supported extensions and match the requested image format. - 5. As such the OIIOLoader will be requested to load in the EXR image, convert the - data and return a MaterialX Image. - 6. Try to acquire the image again. This should returnt the cached MaterialX Image. - 7. Save the image back to disk in the original format. - - The image can optionally be previewed after load before save. - -- Python Dependencies: - - OpenImageIO (version 3.0.6.1) - - API Docs can be found here: https://openimageio.readthedocs.io/en/v3.0.6.1/) - - numpy : For numerical operations on image data - - matplotlib : If image preview is desired. -""" -import ctypes -import os -import argparse - -import logging -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger("OIIOLoad") - -try: - import MaterialX as mx - import MaterialX.PyMaterialXRender as mx_render -except ImportError: - logger.error("Required modules not found. Please install MaterialX.") - raise -try: - import OpenImageIO as oiio - import numpy as np -except ImportError: - logger.error("Required modules not found. Please install OpenImageIO and numpy.") - raise - -have_matplot = False -try: - import matplotlib.pyplot as plt - have_matplot = True -except ImportError: - logger.warning("matplotlib module not found. Image preview display is disabled.") - -class OiioImageLoader(mx_render.ImageLoader): - """ - A MaterialX ImageLoader implementation that uses OpenImageIO to read image files. - - Inherits from MaterialX.ImageLoader and implements the required interface methods. - Supports common image formats like PNG, JPEG, TIFF, EXR, HDR, etc. - """ - - def __init__(self): - """ - Initialize the OiioImageLoader and set supported extensions.""" - super().__init__() - - # Set all extensions supported by OpenImageIO. e.g. - # openexr:exr,sxr,mxr;tiff:tif,tiff,tx,env,sm,vsm;jpeg:jpg,jpe,jpeg,jif,jfif,jfi;bmp:bmp,dib;cineon:cin;dds:dds;dpx:dpx;fits:fits;hdr:hdr,rgbe;ico:ico;iff:iff,z;null:null,nul;png:png;pnm:ppm,pgm,pbm,pnm,pfm;psd:psd,pdd,psb;rla:rla;sgi:sgi,rgb,rgba,bw,int,inta;softimage:pic;targa:tga,tpic;term:term;webp:webp;zfile:zfile - self._extensions = set() - oiio_extensions = oiio.get_string_attribute("extension_list") - # Split string by ";" - for group in oiio_extensions.split(";"): - # Each group is like "openexr:exr,sxr,mxr" - if ":" in group: - _, exts = group.split(":", 1) - self._extensions.update(ext.strip() for ext in exts.split(",")) - else: - self._extensions.update(ext.strip() for ext in group.split(",")) - logger.debug(f"Cache supported extensions: {self._extensions}") - - self.preview = False - self.identifier = "OpenImageIO Custom Image Loader" - self.color_space = {} - - def supportedExtensions(self): - """ - Derived method to return a set of supported image file extensions. - """ - logger.info(f"OIIO supported extensions: {self._extensions}") - return self._extensions - - def set_preview(self, value): - """ - Set whether to preview images when loading and saving - - @param value: Boolean indicating whether to enable preview - """ - self.preview = value - - def get_identifier(self): - return "OIIO Custom Loader" - - def previewImage(self, title, data, width, height, nchannels, color_space): - """ - Utility method to preview an image using matplotlib. - Handles normalization and dtype for correct display. - - @param title: Title for the preview window - @param data: Image data array - @param width: Image width - @param height: Image height - @param nchannels: Number of image channels - @param color_space: Color space of the image - """ - if not self.preview: - return - - if have_matplot: - # If the image is float16 (half), convert to float32 - if data.dtype == np.float16: - data = data.astype(np.float32) - - flat = data.reshape(height, width, nchannels) - # Always display as RGB (first 3 channels or repeat if less) - if nchannels >= 3: - rgb = flat[..., :3] - else: - rgb = np.repeat(flat[..., :1], 3, axis=-1) - - # Determine if normalization is needed - if np.issubdtype(flat.dtype, np.floating): - # If float, normalize to [0, 1] for display - rgb_disp = np.clip(rgb, 0.0, 1.0) - elif np.issubdtype(flat.dtype, np.integer): - # If integer, assume 8 or 16 bit, scale if needed - if flat.dtype == np.uint8: - rgb_disp = rgb # matplotlib expects [0,255] for uint8 - elif flat.dtype == np.uint16: - # Scale 16-bit to 8-bit for display - rgb_disp = (rgb / 257).astype(np.uint8) - else: - # For other integer types, try to scale to [0,255] - rgb_disp = np.clip(rgb, 0, 255).astype(np.uint8) - else: - rgb_disp = rgb - - # Set title bar text for the preview window - fig, ax = plt.subplots() - ax.imshow(rgb_disp) - ax.axis("off") - #fig.patch.set_facecolor("black") - fig.canvas.manager.set_window_title(title) - info = f"Dimensions:({width}x{height}), {nchannels} channels, type={data.dtype}, colorspace={color_space}" - fig.suptitle(title, fontsize=12) - plt.title(info, fontsize=9) - plt.show() - - def loadImage(self, filePath): - """ - Load an image from the file system (MaterialX interface method). - - @param filePath (MaterialX.FilePath): Path to the image file - @returns MaterialX.ImagePtr: MaterialX Image object or None if loading fails - """ - file_path_str = filePath.asString() - logger.info(f"Load using OIIO loader: {file_path_str}") - - if not os.path.exists(file_path_str): - print(f"Error: File '{file_path_str}' does not exist") - return None - - try: - # Open the image file - img_input = oiio.ImageInput.open(file_path_str) - if not img_input: - print(f"Error: Could not open '{file_path_str}' - {oiio.geterror()}") - return None - - # Get image specifications - spec = img_input.spec() - color_space = spec.getattribute("oiio:ColorSpace") - logger.info(f"ColorSpace: {color_space}") - self.color_space[file_path_str] = color_space - - # Check channel count - channels = spec.nchannels - if channels > 4: - channels = 4 - - # Determine MaterialX base type from OIIO format - base_type = self._oiio_to_materialx_type(spec.format.basetype) - if base_type is None: - img_input.close() - print(f"Error: Unsupported image format for '{file_path_str}'") - return None - - # Create MaterialX image - mx_image = mx_render.Image.create(spec.width, spec.height, channels, base_type) - mx_image.createResourceBuffer() - logger.debug(f"Create buffer with width: {spec.width}, height: {spec.height}, channels: {spec.nchannels} -> {channels}") - - # Read the image data using the correct OIIO Python API (returns a bytes object) - logger.debug(f"Reading image data from '{file_path_str}' with spec: {spec}") - data = img_input.read_image(0, 0, 0, channels, spec.format) - if len(data) > 0: - logger.debug(f"Done Reading image data from '{file_path_str}' with spec: {spec}") - else: - logger.error(f"Could not read image data.") - return None - - self.previewImage("Loaded MaterialX Image", data, spec.width, spec.height, channels, color_space) - - # Steps: - # - Copy the OIIO data into the MaterialX image resource buffer - resource_buffer_ptr = mx_image.getResourceBuffer() - bytes_per_channel = spec.format.size() - total_bytes = spec.width * spec.height * channels * bytes_per_channel - logger.info(f"Total bytes read in: {total_bytes} (width: {spec.width}, height: {spec.height}, channels: {channels}, format: {spec.format})") - try: - ctypes.memmove(resource_buffer_ptr, (ctypes.c_char * total_bytes).from_buffer_copy(data), total_bytes) - except Exception as e: - logger.error(f"Failed to update image resource buffer: {e}") - - img_input.close() - - return mx_image - - except Exception as e: - print(f"Error loading image from '{file_path_str}': {str(e)}") - return None - - return None - - def saveImage(self, filePath, image, verticalFlip=False): - """ - @brief Saves an image to disk using OpenImageIO (OIIO). - - @param filePath The file path where the image will be saved. Expected to have an asString() method. - @param image The MaterialX image object to save. - @param verticalFlip Whether to vertically flip the image before saving. (Currently unused.) - @return True if the image was saved successfully, False otherwise. - """ - filename = filePath.asString() - width = image.getWidth() - height = image.getHeight() - - # Clamp to RGBA - src_channels = image.getChannelCount() - channels = min(src_channels, 4) - if src_channels > 4: - logger.warning(f"Image has {src_channels} channels. Saving only first {channels} (RGBA).") - - mx_basetype = image.getBaseType() - oiio_format = self._materialx_to_oiio_type(mx_basetype) - logger.info(f"mx_basetype: {mx_basetype}, oiio_format: {oiio_format}, base_stride: {image.getBaseStride()}") - if oiio_format is None: - logger.error(f"Unsupported MaterialX base type for OIIO: {mx_basetype}") - return False - - buffer_addr = image.getResourceBuffer() - np_type = self._materialx_type_to_np_type(mx_basetype) - if np_type is None: - logger.error(f"No NumPy dtype mapping for base type: {mx_basetype}") - return False - - try: - # Steps: - # - Maps the MaterialX base type to OIIO and NumPy types. - # - Allocates a NumPy array for the pixel data. - # - Copies the raw buffer from the image into the NumPy array. - # - Optionally previews the image for debugging. - # - Creates an OIIO ImageOutput and writes the image to disk. - # - base_stride = image.getBaseStride() # bytes per channel element - total_bytes = width * height * src_channels * base_stride - - buf_type = (ctypes.c_char * total_bytes) - buf = buf_type.from_address(buffer_addr) - - np_buffer = np.frombuffer(buf, dtype=np_type) - - # Validate total elements before reshape to catch mismatches early - expected_elems = width * height * src_channels - if np_buffer.size != expected_elems: - logger.error(f"Buffer element count mismatch: got {np_buffer.size}, expected {expected_elems}.") - return False - - np_buffer = np_buffer.reshape((height, width, src_channels)) - - # Keep only up to RGBA - pixels = np_buffer[..., :channels].copy() - - if verticalFlip: - logger.info("Applying vertical flip before saving image.") - pixels = np.flipud(pixels) - - logger.info("Previewing image after load into Image and reload for save...") - # Remove "saved_" prefix if present - search_name = filename.replace("saved_", "") - color_space = "Unknown" - for key in self.color_space: - value = self.color_space[key] - path = os.path.basename(key) - if path in search_name: - color_space = value - logger.info(f"colorspace lookup for: {search_name}. list: {color_space}") - self.previewImage("OpenImageIO Output Image", pixels, width, height, channels, color_space) - - except Exception as e: - logger.error(f"Error copying buffer to pixels: {e}") - return False - - out = oiio.ImageOutput.create(filename) - if not out: - logger.error("Failed to create OIIO ImageOutput.") - return False - - try: - spec = oiio.ImageSpec(width, height, channels, oiio_format) - out.open(filename, spec) - out.write_image(pixels) - logger.info(f"Image saved to {filename} (w={width}, h={height}, c={channels}, type={mx_basetype})") - out.close() - return True - except Exception as e: - logger.error(f"Failed to write image: {e}") - try: - out.close() - finally: - pass - return False - - def _oiio_to_materialx_type(self, oiio_basetype): - """Convert OIIO base type to MaterialX Image base type.""" - type_mapping = { - oiio.UINT8: mx_render.BaseType.UINT8, - oiio.INT8: mx_render.BaseType.INT8, - oiio.UINT16: mx_render.BaseType.UINT16, - oiio.INT16: mx_render.BaseType.INT16, - oiio.HALF: mx_render.BaseType.HALF, - oiio.FLOAT: mx_render.BaseType.FLOAT - } - return_val = type_mapping.get(oiio_basetype, None) - logger.debug(f"OIIO to MaterialX type mapping: {return_val} from {oiio_basetype}") - return return_val - - def _materialx_to_oiio_type(self, mx_basetype): - """Convert MaterialX Image base type to OIIO type.""" - type_mapping = { - mx_render.BaseType.UINT8: oiio.UINT8, - mx_render.BaseType.UINT16: oiio.UINT16, - mx_render.BaseType.INT8: oiio.INT8, - mx_render.BaseType.INT16: oiio.INT16, - mx_render.BaseType.HALF: oiio.HALF, - mx_render.BaseType.FLOAT: oiio.FLOAT, - } - return_val = type_mapping.get(mx_basetype, None) - logger.debug(f"MaterialX type mapping: {mx_basetype} to {return_val}") - return return_val - - def _materialx_type_to_np_type(self, mx_basetype): - """Map MaterialX base type to NumPy dtype with explicit widths.""" - type_mapping = { - mx_render.BaseType.UINT8: np.uint8, - mx_render.BaseType.UINT16: np.uint16, - mx_render.BaseType.INT8: np.int8, - mx_render.BaseType.INT16: np.int16, - mx_render.BaseType.HALF: np.float16, - mx_render.BaseType.FLOAT: np.float32, - } - return type_mapping.get(mx_basetype, None) - - -def test_load_save(): - """ - Example usage of the OiioImageLoader class with MaterialX ImageHandler. - """ - parser = argparse.ArgumentParser(description="MaterialX OIIO Image Handler") - parser.add_argument("path", help="Path to the image file") - parser.add_argument("--flip", action="store_true", help="Flip the image vertically") - parser.add_argument("--preview", action="store_true", help="Preview the image before saving") - args = parser.parse_args() - - test_image_path = args.path - if not os.path.exists(test_image_path): - logger.error(f"Image file not found: {test_image_path}") - return - - # Create MaterialX handler with custom OIIO image loader - loader = OiioImageLoader() - loader.set_preview(args.preview) - handler = mx_render.ImageHandler.create(loader) - logger.info(f"Created image handler with loader ({loader.get_identifier()}): {handler is not None}") - handler.addLoader(loader) - - mx_filepath = mx.FilePath(test_image_path) - - # Load image using handler API - logger.info('-'*45) - logger.info(f"Loading image from path: {mx_filepath.asString()}") - mx_image = handler.acquireImage(mx_filepath) - if mx_image: - # Q: How to check for failed image load as you - # get back a 1x1 pixel image. - if mx_image.getWidth() == 1 and mx_image.getHeight() == 1: - logger.warning("Failed to load image. Got 1x1 pixel image returned") - return - logger.info(f"MaterialX Image loaded via Image Handler:") - logger.info(f" Dimensions: {mx_image.getWidth()}x{mx_image.getHeight()}") - logger.info(f" Channels: {mx_image.getChannelCount()}") - logger.info(f" Base type: {mx_image.getBaseType()}") - - # Save image using handler API (to a new file) - logger.info('-'*45) - - # Retrieve cached image - mx_image = handler.acquireImage(mx_filepath) - if mx_image: - out_path = mx.FilePath("saved_" + os.path.basename(test_image_path)) - if handler.saveImage(out_path, mx_image, verticalFlip=args.flip): - logger.info(f"MaterialX Image saved to {out_path.asString()}") - else: - logger.error("Failed to save image.") - else: - logger.error("Failed to acquire image for saving.") - else: - logger.error("Failed to load image.") - -if __name__ == "__main__": - test_load_save() diff --git a/MaterialX/python/Scripts/pybind_docs.py b/MaterialX/python/Scripts/pybind_docs.py deleted file mode 100644 index 207fbfe..0000000 --- a/MaterialX/python/Scripts/pybind_docs.py +++ /dev/null @@ -1,514 +0,0 @@ -#!/usr/bin/env python -""" -pybind11 documentation insertion tool. - -Extracts documentation from Doxygen XML and inserts it into pybind11 bindings -using string matching via signature lookup table. - -Logic: -- Builds a multi-key lookup for all functions (MaterialX::, mx::, Class::method, method) -- Handles free functions without by assuming MaterialX namespace -- Adds class context tracking to correctly document lambda-based bindings -- Supports .def(...) and .def_static(...); skips .def_readonly_static(...) -""" - -import argparse -import re -import json -import xml.etree.ElementTree as ET -from pathlib import Path -from typing import Dict, Optional - -# Defaults (can be overridden by CLI) -DOXYGEN_XML_DIR = Path("build/documents/doxygen_xml") -PYBIND_DIR = Path("source/PyMaterialX") - - -class DocExtractor: - """Extracts documentation from Doxygen XML files and builds a lookup table.""" - - def __init__(self, xml_dir: Path): - self.xml_dir = xml_dir - self.class_docs: Dict[str, str] = {} - self.func_docs: Dict[str, Dict] = {} - # Multi-key lookup: all name variants point to the same doc - self.func_lookup: Dict[str, Dict] = {} - - def extract(self): - if not self.xml_dir.exists(): - raise FileNotFoundError(f"Doxygen XML directory not found: {self.xml_dir}") - - for xml_file in self.xml_dir.glob("*.xml"): - self._process_xml_file(xml_file) - - self._build_lookup_table() - print(f"Extracted {len(self.class_docs)} classes and {len(self.func_docs)} functions") - print(f"Built lookup table with {len(self.func_lookup)} keys") - - def _process_xml_file(self, xml_file: Path): - tree = ET.parse(xml_file) - root = tree.getroot() - - # Class / struct documentation - for compound in root.findall(".//compounddef[@kind='class']") + root.findall(".//compounddef[@kind='struct']"): - self._extract_class_doc(compound) - - # Function documentation - for member in root.findall(".//memberdef[@kind='function']"): - self._extract_func_doc(member) - - def _extract_class_doc(self, compound): - name = self._get_text(compound.find("compoundname")) - brief = self._get_text(compound.find("briefdescription/para")) - detail = self._extract_detail(compound.find("detaileddescription")) - doc = "\n\n".join(filter(None, [brief, detail])) - if doc: - normalized = self._normalize_name(name) - self.class_docs[normalized] = doc - - def _extract_func_doc(self, member): - name = self._get_text(member.find("name")) - qualified = self._get_text(member.find("qualifiedname")) - - # Many free functions have no ; use the bare name - # and normalize to MaterialX::name so lookups can resolve. - if not qualified and name: - qualified = name - - if not qualified: - return - - brief = self._get_text(member.find("briefdescription/para")) - detail = self._extract_detail(member.find("detaileddescription")) - params = self._extract_params(member) - returns = self._get_text(member.find(".//simplesect[@kind='return']")) - - normalized = self._normalize_name(qualified) - self.func_docs[normalized] = { - "brief": brief, - "detail": detail, - "params": params, - "returns": returns, - } - - def _build_lookup_table(self): - for qualified_name, doc in self.func_docs.items(): - for variant in self._generate_name_variants(qualified_name): - if variant not in self.func_lookup: - self.func_lookup[variant] = doc - - def _generate_name_variants(self, qualified_name: str) -> list: - variants = [qualified_name] - parts = qualified_name.split("::") - # Class::method - if len(parts) >= 2: - variants.append("::".join(parts[-2:])) - # method - if len(parts) >= 1: - variants.append(parts[-1]) - # mx:: variant if MaterialX:: - if qualified_name.startswith("MaterialX::"): - mx_variant = qualified_name.replace("MaterialX::", "mx::", 1) - variants.append(mx_variant) - if len(parts) >= 3: - variants.append(f"mx::{parts[-2]}::{parts[-1]}") - return variants - - def _normalize_name(self, name: str) -> str: - if not name: - return name - return name if name.startswith("MaterialX::") else f"MaterialX::{name}" - - def _get_text(self, elem) -> str: - if elem is None: - return "" - text = "".join(elem.itertext()) - return re.sub(r"\s+", " ", text).strip() - - def _extract_detail(self, elem, exclude_tags={"parameterlist", "simplesect"}) -> str: - if elem is None: - return "" - parts = [] - for para in elem.findall("para"): - if not any(para.find(tag) is not None for tag in exclude_tags): - t = self._get_text(para) - if t: - parts.append(t) - return "\n\n".join(parts) - - def _extract_params(self, member) -> Dict[str, str]: - params = {} - for param_item in member.findall(".//parameterlist[@kind='param']/parameteritem"): - name = self._get_text(param_item.find("parameternamelist/parametername")) - desc = self._get_text(param_item.find("parameterdescription")) - if name: - params[name] = desc - return params - - -class DocInserter: - """Inserts documentation into pybind11 binding files.""" - - def __init__(self, extractor: DocExtractor, pybind_dir: Path, force_replace: bool = False): - self.extractor = extractor - self.pybind_dir = pybind_dir - self.force_replace = force_replace - - self.class_pattern = re.compile(r"py::class_<") - self.def_pattern = re.compile(r"\.def(?:_static)?\s*\(") - # Match .def and .def_static; skip .def_readonly_static (constants) - self.def_pattern = re.compile(r"\.def(?:_static)?\s*\(") - self.skip_pattern = re.compile(r"\.def_readonly_static\s*\(") - - def process_all_files(self): - cpp_files = list(self.pybind_dir.rglob("*.cpp")) - patched = 0 - for cpp_file in cpp_files: - if self._process_file(cpp_file): - patched += 1 - print(f"\nProcessed {len(cpp_files)} files, patched {patched}") - - def _process_file(self, cpp_file: Path) -> bool: - content = cpp_file.read_text(encoding="utf-8") - original = content - - content = self._insert_class_docs(content) - content = self._insert_method_docs(content) - - if content != original: - cpp_file.write_text(content, encoding="utf-8") - print(f" - {cpp_file.relative_to(self.pybind_dir.parent)}") - return True - else: - print(f" - {cpp_file.relative_to(self.pybind_dir.parent)}") - return False - - def _insert_class_docs(self, content: str) -> str: - result = [] - pos = 0 - - for match in self.class_pattern.finditer(content): - result.append(content[pos:match.start()]) - - start = match.start() - template_end = self._find_template_end(content, start) - if template_end == -1: - result.append(content[start:match.end()]) - pos = match.end() - continue - - paren_start = content.find('(', template_end) - if paren_start == -1: - result.append(content[start:match.end()]) - pos = match.end() - continue - - paren_end = self._find_matching_paren(content, paren_start) - if paren_end == -1: - result.append(content[start:match.end()]) - pos = match.end() - continue - - args_text = content[paren_start + 1:paren_end] - class_name = self._extract_class_name(args_text) - - if class_name: - doc = self.extractor.class_docs.get(self.extractor._normalize_name(class_name)) - if doc: - args = self._split_args(args_text) - if len(args) >= 3 and not self.force_replace: - result.append(content[start:paren_end + 1]) - pos = paren_end + 1 - continue - - escaped = self._escape_for_cpp(doc) - if len(args) >= 3 and self.force_replace: - new_args = args[:2] + [f'"{escaped}"'] + args[3:] - result.append(content[start:paren_start + 1]) - result.append(", ".join(new_args)) - result.append(")") - else: - result.append(content[start:paren_end]) - result.append(f', "{escaped}")') - pos = paren_end + 1 - continue - - result.append(content[start:paren_end + 1]) - pos = paren_end + 1 - - result.append(content[pos:]) - return "".join(result) - - def _insert_method_docs(self, content: str) -> str: - # Build a map of line numbers to class contexts - class_contexts = self._extract_class_contexts(content) - - result = [] - pos = 0 - - for match in self.def_pattern.finditer(content): - if self.skip_pattern.match(content, match.start()): - continue - - result.append(content[pos:match.start()]) - - start = match.start() - paren_start = content.find('(', start) - if paren_start == -1: - result.append(content[start:match.end()]) - pos = match.end() - continue - - paren_end = self._find_matching_paren(content, paren_start) - if paren_end == -1: - result.append(content[start:match.end()]) - pos = match.end() - continue - - args_text = content[paren_start + 1:paren_end] - args = self._split_args(args_text) - - if len(args) < 2: - result.append(content[start:paren_end + 1]) - pos = paren_end + 1 - continue - - has_doc = self._has_docstring(args) - if has_doc and not self.force_replace: - result.append(content[start:paren_end + 1]) - pos = paren_end + 1 - continue - - callable_ref = args[1].strip() - - current_line = content[:start].count('\n') - class_context = class_contexts.get(current_line) - - doc_entry = self._find_doc_for_callable(callable_ref, class_context) - - if doc_entry: - docstring = self._build_docstring(doc_entry) - escaped = self._escape_for_cpp(docstring) - - if has_doc and self.force_replace: - doc_idx = self._find_docstring_arg_index(args) - if doc_idx is not None: - new_args = args[:doc_idx] + [f'"{escaped}"'] + args[doc_idx + 1:] - result.append(content[start:paren_start + 1]) - result.append(", ".join(new_args)) - result.append(")") - pos = paren_end + 1 - continue - - result.append(content[start:paren_end]) - result.append(f', "{escaped}")') - pos = paren_end + 1 - continue - - result.append(content[start:paren_end + 1]) - pos = paren_end + 1 - - result.append(content[pos:]) - return "".join(result) - - def _extract_class_contexts(self, content: str) -> Dict[int, str]: - contexts = {} - for match in self.class_pattern.finditer(content): - start = match.start() - template_end = self._find_template_end(content, start) - if template_end == -1: - continue - template_start = content.find('<', start) + 1 - template_content = content[template_start:template_end - 1] - class_type = template_content.split(',')[0].strip() - class_name = class_type.split('::')[-1] if '::' in class_type else class_type - - start_line = content[:start].count('\n') - end_pos = content.find(';', start) - if end_pos != -1: - end_line = content[:end_pos].count('\n') - for line in range(start_line, end_line + 1): - contexts[line] = class_name - return contexts - - def _find_doc_for_callable(self, callable_ref: str, class_context: Optional[str] = None) -> Optional[Dict]: - callable_ref = callable_ref.strip() - - # Function pointers like &mx::Class::method or &MaterialX::name - if callable_ref.startswith('&'): - name = callable_ref[1:].strip() - name = re.sub(r'[,\s]+$', '', name) - return self.extractor.func_lookup.get(name) - - # Lambdas: look for elem.method( or obj->method( - method_match = re.search(r'[\.\->](\w+)\s*\(', callable_ref) - if method_match: - method_name = method_match.group(1) - if class_context: - for prefix in ("", "mx::", "MaterialX::"): - qualified = f"{prefix}{class_context}::{method_name}" if prefix else f"{class_context}::{method_name}" - doc = self.extractor.func_lookup.get(qualified) - if doc: - return doc - return self.extractor.func_lookup.get(method_name) - - return None - - def _build_docstring(self, doc_entry: Dict) -> str: - parts = [] - if doc_entry.get("brief"): - parts.append(doc_entry["brief"]) - if doc_entry.get("detail"): - parts.append(doc_entry["detail"]) - params = doc_entry.get("params", {}) - if params: - param_lines = ["Args:"] - for name, desc in params.items(): - param_lines.append(f" {name}: {desc}" if desc else f" {name}:") - parts.append("\n".join(param_lines)) - if doc_entry.get("returns"): - parts.append(f"Returns:\n {doc_entry['returns']}") - return "\n\n".join(parts) - - def _escape_for_cpp(self, s: str) -> str: - if not s: - return "" - s = s.replace("\\", "\\\\").replace('"', '\\"') - s = s.replace("\n", "\\n") - return s - - def _find_template_end(self, content: str, start: int) -> int: - pos = content.find('<', start) - if pos == -1: - return -1 - depth = 1 - i = pos + 1 - in_string = False - while i < len(content) and depth > 0: - c = content[i] - if c == '"' and content[i - 1] != '\\': - in_string = not in_string - elif not in_string: - if c == '<': - depth += 1 - elif c == '>': - depth -= 1 - i += 1 - return i if depth == 0 else -1 - - def _find_matching_paren(self, content: str, start: int) -> int: - depth = 0 - in_string = False - escape = False - for i in range(start, len(content)): - c = content[i] - if escape: - escape = False - continue - if c == '\\': - escape = True - continue - if c == '"': - in_string = not in_string - continue - if not in_string: - if c == '(': - depth += 1 - elif c == ')': - depth -= 1 - if depth == 0: - return i - return -1 - - def _split_args(self, args_text: str) -> list: - args = [] - current = [] - depth = 0 - in_string = False - escape = False - for c in args_text: - if escape: - current.append(c) - escape = False - continue - if c == '\\': - current.append(c) - escape = True - continue - if c == '"': - in_string = not in_string - current.append(c) - continue - if not in_string: - if c in '(<': - depth += 1 - elif c in ')>': - depth -= 1 - elif c == ',' and depth == 0: - args.append("".join(current).strip()) - current = [] - continue - current.append(c) - if current: - args.append("".join(current).strip()) - return args - - def _extract_class_name(self, args_text: str) -> Optional[str]: - args = self._split_args(args_text) - if len(args) >= 2: - return args[1].strip().strip('"') - return None - - def _has_docstring(self, args: list) -> bool: - for arg in args[2:]: - a = arg.strip() - if not a.startswith("py::arg") and a.startswith('"'): - return True - return False - - def _find_docstring_arg_index(self, args: list) -> Optional[int]: - for i, arg in enumerate(args[2:], start=2): - a = arg.strip() - if not a.startswith("py::arg") and a.startswith('"'): - return i - return None - - -def main(): - parser = argparse.ArgumentParser(description="Extract Doxygen docs and insert into pybind11 bindings (simplified)") - parser.add_argument("-d", "--doxygen_xml_dir", type=Path, default=Path("build/documents/doxygen_xml"), help="Path to Doxygen XML output directory") - parser.add_argument("-p", "--pybind_dir", type=Path, default=Path("source/PyMaterialX"), help="Path to pybind11 bindings directory") - parser.add_argument("-f", "--force", action="store_true", help="Force replace existing docstrings") - parser.add_argument("-j", "--write_json", action="store_true", help="Write extracted docs to JSON files") - - args = parser.parse_args() - - if not args.doxygen_xml_dir.exists(): - print(f"Error: Doxygen XML directory not found: {args.doxygen_xml_dir}") - return 1 - if not args.pybind_dir.exists(): - print(f"Error: Pybind directory not found: {args.pybind_dir}") - return 1 - - print("Extracting documentation from Doxygen XML...") - extractor = DocExtractor(args.doxygen_xml_dir) - extractor.extract() - - if args.write_json: - print("\nWriting JSON files...") - Path("class_docs.json").write_text(json.dumps(extractor.class_docs, indent=2), encoding="utf-8") - Path("func_docs.json").write_text(json.dumps(extractor.func_docs, indent=2), encoding="utf-8") - print(" - class_docs.json") - print(" - func_docs.json") - - print(f"\n{'Replacing' if args.force else 'Inserting'} documentation in pybind11 files...") - inserter = DocInserter(extractor, args.pybind_dir, args.force) - inserter.process_all_files() - - print("\nDone!") - return 0 - - -if __name__ == "__main__": - exit(main()) - diff --git a/MaterialX/python/Scripts/translateshader.py b/MaterialX/python/Scripts/translateshader.py old mode 100644 new mode 100755 index 08c94b5..b518e0a --- a/MaterialX/python/Scripts/translateshader.py +++ b/MaterialX/python/Scripts/translateshader.py @@ -1,101 +1,101 @@ -#!/usr/bin/env python -''' -Generate a baked translated version of each material in the input document, using the ShaderTranslator class in the MaterialXShaderGen library -and the TextureBaker class in the MaterialXRenderGlsl library. -''' - -import sys, os, argparse -from sys import platform - -import MaterialX as mx -from MaterialX import PyMaterialXGenShader as mx_gen_shader -from MaterialX import PyMaterialXRender as mx_render -from MaterialX import PyMaterialXRenderGlsl as mx_render_glsl -if platform == "darwin": - from MaterialX import PyMaterialXRenderMsl as mx_render_msl - -def main(): - parser = argparse.ArgumentParser(description="Generate a translated baked version of each material in the input document.") - parser.add_argument("--width", dest="width", type=int, default=0, help="Specify an optional width for baked textures (defaults to the maximum image height in the source document).") - parser.add_argument("--height", dest="height", type=int, default=0, help="Specify an optional height for baked textures (defaults to the maximum image width in the source document).") - parser.add_argument("--hdr", dest="hdr", action="store_true", help="Bake images with high dynamic range (e.g. in HDR or EXR format).") - 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('--writeDocumentPerMaterial', dest='writeDocumentPerMaterial', type=mx.stringToBoolean, default=True, help='Specify whether to write baked materials to separate 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() - - # Load standard and custom data libraries. - stdlib = mx.createDocument() - searchPath = mx.getDefaultDataSearchPath() - searchPath.append(os.path.dirname(opts.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()) - mx.loadLibraries(libraryFolders, searchPath, 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) - - # Check the document for a UDIM set. - udimSetValue = doc.getGeomPropValue(mx.UDIM_SET_PROPERTY) - udimSet = udimSetValue.getData() if udimSetValue else [] - - # Compute baking resolution from the source document. - imageHandler = mx_render.ImageHandler.create(mx_render.StbImageLoader.create()) - imageHandler.setSearchPath(searchPath) - if udimSet: - resolver = doc.createStringResolver() - resolver.setUdimString(udimSet[0]) - imageHandler.setFilenameResolver(resolver) - imageVec = imageHandler.getReferencedImages(doc) - bakeWidth, bakeHeight = mx_render.getMaxDimensions(imageVec) - - # Apply baking resolution settings. - if opts.width > 0: - bakeWidth = opts.width - if opts.height > 0: - bakeHeight = opts.height - bakeWidth = max(bakeWidth, 4) - bakeHeight = max(bakeHeight, 4) - - # Translate materials between shading models - translator = mx_gen_shader.ShaderTranslator.create() - try: - translator.translateAllMaterials(doc, opts.destShader) - except mx.Exception as err: - print(err) - sys.exit(0) - - # Bake translated materials to flat textures. - 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(bakeWidth, bakeHeight, baseType) - else: - baker = mx_render_glsl.TextureBaker.create(bakeWidth, bakeHeight, baseType) - baker.writeDocumentPerMaterial(opts.writeDocumentPerMaterial) - baker.bakeAllMaterials(doc, searchPath, opts.outputFilename) - -if __name__ == '__main__': - main() +#!/usr/bin/env python +''' +Generate a baked translated version of each material in the input document, using the ShaderTranslator class in the MaterialXShaderGen library +and the TextureBaker class in the MaterialXRenderGlsl library. +''' + +import sys, os, argparse +from sys import platform + +import MaterialX as mx +from MaterialX import PyMaterialXGenShader as mx_gen_shader +from MaterialX import PyMaterialXRender as mx_render +from MaterialX import PyMaterialXRenderGlsl as mx_render_glsl +if platform == "darwin": + from MaterialX import PyMaterialXRenderMsl as mx_render_msl + +def main(): + parser = argparse.ArgumentParser(description="Generate a translated baked version of each material in the input document.") + parser.add_argument("--width", dest="width", type=int, default=0, help="Specify an optional width for baked textures (defaults to the maximum image height in the source document).") + parser.add_argument("--height", dest="height", type=int, default=0, help="Specify an optional height for baked textures (defaults to the maximum image width in the source document).") + parser.add_argument("--hdr", dest="hdr", action="store_true", help="Bake images with high dynamic range (e.g. in HDR or EXR format).") + 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('--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) + + stdlib = mx.createDocument() + searchPath = mx.getDefaultDataSearchPath() + searchPath.append(os.path.dirname(opts.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()) + mx.loadLibraries(libraryFolders, searchPath, stdlib) + doc.importLibrary(stdlib) + + valid, msg = doc.validate() + if not valid: + print("Validation warnings for input document:") + print(msg) + + # Check the document for a UDIM set. + udimSetValue = doc.getGeomPropValue(mx.UDIM_SET_PROPERTY) + udimSet = udimSetValue.getData() if udimSetValue else [] + + # Compute baking resolution from the source document. + imageHandler = mx_render.ImageHandler.create(mx_render.StbImageLoader.create()) + imageHandler.setSearchPath(searchPath) + if udimSet: + resolver = doc.createStringResolver() + resolver.setUdimString(udimSet[0]) + imageHandler.setFilenameResolver(resolver) + imageVec = imageHandler.getReferencedImages(doc) + bakeWidth, bakeHeight = mx_render.getMaxDimensions(imageVec) + + # Apply baking resolution settings. + if opts.width > 0: + bakeWidth = opts.width + if opts.height > 0: + bakeHeight = opts.height + bakeWidth = max(bakeWidth, 4) + bakeHeight = max(bakeHeight, 4) + + # Translate materials between shading models + translator = mx_gen_shader.ShaderTranslator.create() + try: + translator.translateAllMaterials(doc, opts.destShader) + except mx.Exception as err: + print(err) + sys.exit(0) + + # Bake translated materials to flat textures. + 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(bakeWidth, bakeHeight, baseType) + else: + baker = mx_render_glsl.TextureBaker.create(bakeWidth, bakeHeight, baseType) + baker.writeDocumentPerMaterial(opts.writeDocumentPerMaterial) + baker.bakeAllMaterials(doc, searchPath, opts.outputFilename) + +if __name__ == '__main__': + main() diff --git a/MaterialX/python/Scripts/writenodegraphs.py b/MaterialX/python/Scripts/writenodegraphs.py index 6d31281..88d1b43 100755 --- a/MaterialX/python/Scripts/writenodegraphs.py +++ b/MaterialX/python/Scripts/writenodegraphs.py @@ -1,138 +1,138 @@ -#!/usr/bin/env python -''' -Generate the "NodeGraphs.mtlx" example file programmatically. -''' - -import MaterialX as mx - -def main(): - doc = mx.createDocument() - - # - # Nodegraph example 1 - # - ng1 = doc.addNodeGraph("NG_example1") - img1 = ng1.addNode("image", "img1", "color3") - # Because filenames look like string types, it is necessary to explicitly declare - # this parameter value as type "filename". - img1.setInputValue("file", "layer1.tif", "filename") - - img2 = ng1.addNode("image", "img2", "color3") - img2.setInputValue("file", "layer2.tif", "filename") - - img3 = ng1.addNode("image", "img3", "float") - img3.setInputValue("file", "mask1.tif", "filename") - - n0 = ng1.addNode("mix", "n0", "color3") - # To connect an input to another node, you must first add the input with the expected - # type, and then setConnectedNode() that input to the desired Node object. - infg = n0.addInput("fg", "color3") - infg.setConnectedNode(img1) - inbg = n0.addInput("bg", "color3") - inbg.setConnectedNode(img2) - inmx = n0.addInput("mix", "float") - inmx.setConnectedNode(img3) - - n1 = ng1.addNode("multiply", "n1", "color3") - inp1 = n1.addInput("in1", "color3") - inp1.setConnectedNode(n0) - inp2 = n1.setInputValue("in2", 0.22) - - nout = ng1.addOutput("diffuse", "color3") - nout.setConnectedNode(n1) - - # - # Nodegraph example 3 - # - ng3 = doc.addNodeGraph("NG_example3") - - img1 = ng3.addNode("image", "img1", "color3") - img1.setInputValue("file", "", "filename") - - img2 = ng3.addNode("image", "img2", "color3") - img2.setInputValue("file", "", "filename") - - img3 = ng3.addNode("image", "img3", "float") - img3.setInputValue("file", "", "filename") - - img4 = ng3.addNode("image", "img4", "float") - img4.setInputValue("file", "", "filename") - - n5 = ng3.addNode("constant", "n5", "color3") - # For colorN, vectorN or matrix types, use the appropriate mx Type constructor. - n5.setInputValue("value", mx.Color3(0.8,1.0,1.3)) - - n6 = ng3.addNode("multiply", "n6", "color3") - inp1 = n6.addInput("in1", "color3") - inp1.setConnectedNode(n5) - inp2 = n6.addInput("in2", "color3") - inp2.setConnectedNode(img1) - - n7 = ng3.addNode("contrast", "n7", "color3") - inp = n7.addInput("in", "color3") - inp.setConnectedNode(img2) - n7.setInputValue("amount", 0.2) - n7.setInputValue("pivot", 0.5) - - n8 = ng3.addNode("mix", "n8", "color3") - infg = n8.addInput("fg", "color3") - infg.setConnectedNode(n7) - inbg = n8.addInput("bg", "color3") - inbg.setConnectedNode(n6) - inmx = n8.addInput("mix", "float") - inmx.setConnectedNode(img3) - - t1 = ng3.addNode("texcoord", "t1", "vector2") - - m1 = ng3.addNode("multiply", "m1", "vector2") - inp1 = m1.addInput("in1", "vector2") - inp1.setConnectedNode(t1) - m1.setInputValue("in2", 0.003) - # If limited floating-point precision results in output value strings like "0.00299999", - # you could instead write this as a ValueString (must add the input to the node first): - # inp2 = m1.addInput("in2", "float") - # inp2.setValueString("0.003") - - n9 = ng3.addNode("noise2d", "n9", "color3") - intx = n9.addInput("texcoord", "vector2") - intx.setConnectedNode(m1) - n9.setInputValue("amplitude", mx.Vector3(0.05,0.04,0.06)) - - n10 = ng3.addNode("inside", "n10", "color3") - inmask = n10.addInput("mask", "float") - inmask.setConnectedNode(img4) - inp = n10.addInput("in", "color3") - inp.setConnectedNode(n9) - - n11 = ng3.addNode("add", "n11", "color3") - inp1 = n11.addInput("in1", "color3") - inp1.setConnectedNode(n10) - inp2 = n11.addInput("in2", "color3") - inp2.setConnectedNode(n8) - - nout1 = ng3.addOutput("albedo", "color3") - nout1.setConnectedNode(n11) - nout2 = ng3.addOutput("areamask", "float") - nout2.setConnectedNode(img3) - - # It is not necessary to validate a document before writing but it's nice - # to know for sure. And you can validate any element (and its children) - # independently, not just the whole document. - rc = ng1.validate() - if (len(rc) >= 1 and rc[0]): - print("Nodegraph %s is valid." % ng1.getName()) - else: - print("Nodegraph %s is NOT valid: %s" % (ng1.getName(), str(rc[1]))) - rc = ng3.validate() - if (len(rc) >= 1 and rc[0]): - print("Nodegraph %s is valid." % ng3.getName()) - else: - print("Nodegraph %s is NOT valid: %s" % (ng3.getName(), str(rc[1]))) - - outfile = "myNodeGraphs.mtlx" - mx.writeToXmlFile(doc, outfile) - print("Wrote nodegraphs to %s" % outfile) - -if __name__ == '__main__': - main() - +#!/usr/bin/env python +''' +Generate the "NodeGraphs.mtlx" example file programmatically. +''' + +import MaterialX as mx + +def main(): + doc = mx.createDocument() + + # + # Nodegraph example 1 + # + ng1 = doc.addNodeGraph("NG_example1") + img1 = ng1.addNode("image", "img1", "color3") + # Because filenames look like string types, it is necessary to explicitly declare + # this parameter value as type "filename". + img1.setInputValue("file", "layer1.tif", "filename") + + img2 = ng1.addNode("image", "img2", "color3") + img2.setInputValue("file", "layer2.tif", "filename") + + img3 = ng1.addNode("image", "img3", "float") + img3.setInputValue("file", "mask1.tif", "filename") + + n0 = ng1.addNode("mix", "n0", "color3") + # To connect an input to another node, you must first add the input with the expected + # type, and then setConnectedNode() that input to the desired Node object. + infg = n0.addInput("fg", "color3") + infg.setConnectedNode(img1) + inbg = n0.addInput("bg", "color3") + inbg.setConnectedNode(img2) + inmx = n0.addInput("mix", "float") + inmx.setConnectedNode(img3) + + n1 = ng1.addNode("multiply", "n1", "color3") + inp1 = n1.addInput("in1", "color3") + inp1.setConnectedNode(n0) + inp2 = n1.setInputValue("in2", 0.22) + + nout = ng1.addOutput("diffuse", "color3") + nout.setConnectedNode(n1) + + # + # Nodegraph example 3 + # + ng3 = doc.addNodeGraph("NG_example3") + + img1 = ng3.addNode("image", "img1", "color3") + img1.setInputValue("file", "", "filename") + + img2 = ng3.addNode("image", "img2", "color3") + img2.setInputValue("file", "", "filename") + + img3 = ng3.addNode("image", "img3", "float") + img3.setInputValue("file", "", "filename") + + img4 = ng3.addNode("image", "img4", "float") + img4.setInputValue("file", "", "filename") + + n5 = ng3.addNode("constant", "n5", "color3") + # For colorN, vectorN or matrix types, use the appropriate mx Type constructor. + n5.setInputValue("value", mx.Color3(0.8,1.0,1.3)) + + n6 = ng3.addNode("multiply", "n6", "color3") + inp1 = n6.addInput("in1", "color3") + inp1.setConnectedNode(n5) + inp2 = n6.addInput("in2", "color3") + inp2.setConnectedNode(img1) + + n7 = ng3.addNode("contrast", "n7", "color3") + inp = n7.addInput("in", "color3") + inp.setConnectedNode(img2) + n7.setInputValue("amount", 0.2) + n7.setInputValue("pivot", 0.5) + + n8 = ng3.addNode("mix", "n8", "color3") + infg = n8.addInput("fg", "color3") + infg.setConnectedNode(n7) + inbg = n8.addInput("bg", "color3") + inbg.setConnectedNode(n6) + inmx = n8.addInput("mix", "float") + inmx.setConnectedNode(img3) + + t1 = ng3.addNode("texcoord", "t1", "vector2") + + m1 = ng3.addNode("multiply", "m1", "vector2") + inp1 = m1.addInput("in1", "vector2") + inp1.setConnectedNode(t1) + m1.setInputValue("in2", 0.003) + # If limited floating-point precision results in output value strings like "0.00299999", + # you could instead write this as a ValueString (must add the input to the node first): + # inp2 = m1.addInput("in2", "float") + # inp2.setValueString("0.003") + + n9 = ng3.addNode("noise2d", "n9", "color3") + intx = n9.addInput("texcoord", "vector2") + intx.setConnectedNode(m1) + n9.setInputValue("amplitude", mx.Vector3(0.05,0.04,0.06)) + + n10 = ng3.addNode("inside", "n10", "color3") + inmask = n10.addInput("mask", "float") + inmask.setConnectedNode(img4) + inp = n10.addInput("in", "color3") + inp.setConnectedNode(n9) + + n11 = ng3.addNode("add", "n11", "color3") + inp1 = n11.addInput("in1", "color3") + inp1.setConnectedNode(n10) + inp2 = n11.addInput("in2", "color3") + inp2.setConnectedNode(n8) + + nout1 = ng3.addOutput("albedo", "color3") + nout1.setConnectedNode(n11) + nout2 = ng3.addOutput("areamask", "float") + nout2.setConnectedNode(img3) + + # It is not necessary to validate a document before writing but it's nice + # to know for sure. And you can validate any element (and its children) + # independently, not just the whole document. + rc = ng1.validate() + if (len(rc) >= 1 and rc[0]): + print("Nodegraph %s is valid." % ng1.getName()) + else: + print("Nodegraph %s is NOT valid: %s" % (ng1.getName(), str(rc[1]))) + rc = ng3.validate() + if (len(rc) >= 1 and rc[0]): + print("Nodegraph %s is valid." % ng3.getName()) + else: + print("Nodegraph %s is NOT valid: %s" % (ng3.getName(), str(rc[1]))) + + outfile = "myNodeGraphs.mtlx" + mx.writeToXmlFile(doc, outfile) + print("Wrote nodegraphs to %s" % outfile) + +if __name__ == '__main__': + main() + diff --git a/MaterialX/python/mtx_skbuild_plugin.py b/MaterialX/python/mtx_skbuild_plugin.py new file mode 100755 index 0000000..8e86283 --- /dev/null +++ b/MaterialX/python/mtx_skbuild_plugin.py @@ -0,0 +1,90 @@ +""" +This is a custom scikit-build-core plugin that will +fetch the MaterialX version from the CMake project. +""" +import os +import tempfile +import subprocess +from pathlib import Path +from typing import FrozenSet, Dict, Optional, Union, List + +from scikit_build_core.file_api.query import stateless_query +from scikit_build_core.file_api.reply import load_reply_dir + + +def dynamic_metadata( + fields: FrozenSet[str], + settings: Optional[Dict[str, object]] = None, +) -> Dict[str, Union[str, Dict[str, Optional[str]]]]: + print("mtx_skbuild_plugin: Computing MaterialX version from CMake...") + + if fields != {"version"}: + msg = "Only the 'version' field is supported" + raise ValueError(msg) + + if settings: + msg = "No inline configuration is supported" + raise ValueError(msg) + + current_dir = os.path.dirname(__file__) + + with tempfile.TemporaryDirectory() as tmpdir: + # We will use CMake's file API to get the version + # instead of parsing the CMakeLists files. + + # First generate the query folder so that CMake can generate replies. + reply_dir = stateless_query(Path(tmpdir)) + + # Run cmake (configure). CMake will generate a reply automatically. + try: + subprocess.run( + [ + "cmake", + "-S", + os.path.dirname(current_dir), + "-B", + tmpdir, + "-DMATERIALX_BUILD_SHARED_LIBS=OFF", + "-DMATERIALX_BUILD_PYTHON=OFF", + "-DMATERIALX_TEST_RENDER=OFF", + "-DMATERIALX_BUILD_TESTS=OFF", + "-DMATERIALX_INSTALL_PYTHON=OFF", + "-DMATERIALX_BUILD_RENDER=OFF", + ], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=True, + text=True, + ) + except subprocess.CalledProcessError as exc: + print(exc.stdout) + raise RuntimeError( + "Failed to configure project to get the version" + ) from exc + + # Get the generated replies. + index = load_reply_dir(reply_dir) + + # Get the version from the CMAKE_PROJECT_VERSION variable. + entries = [ + entry + for entry in index.reply.cache_v2.entries + if entry.name == "CMAKE_PROJECT_VERSION" + ] + + if not entries: + raise ValueError("Could not find MaterialX version from CMake project") + + if len(entries) > 1: + raise ValueError("More than one entry for CMAKE_PROJECT_VERSION found...") + + version = entries[0].value + print("mtx_skbuild_plugin: Computed version: {0}".format(version)) + + return {"version": version} + + +def get_requires_for_dynamic_metadata( + _settings: Optional[Dict[str, object]] = None, +) -> List[str]: + return ["cmake"] diff --git a/MaterialX/python/setup.py.in b/MaterialX/python/setup.py.in old mode 100644 new mode 100755 index 072bafa..09d3cbb --- a/MaterialX/python/setup.py.in +++ b/MaterialX/python/setup.py.in @@ -1,18 +1,18 @@ -from setuptools import setup -import os - -os.chdir(os.path.dirname(os.path.abspath(__file__))) - -def getRecursivePackageData(root): - packageData = [] - for dirpath, dirnames, filenames in os.walk(root): - relpath = os.path.relpath(dirpath, root) - packageData.append(os.path.join(relpath, '*.*')) - return packageData - -setup(name='MaterialX', - url='www.materialx.org', - version='${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION}', - packages=['MaterialX'], - package_data={'MaterialX' : getRecursivePackageData('MaterialX')}, - zip_safe = False) +from setuptools import setup +import os + +os.chdir(os.path.dirname(os.path.abspath(__file__))) + +def getRecursivePackageData(root): + packageData = [] + for dirpath, dirnames, filenames in os.walk(root): + relpath = os.path.relpath(dirpath, root) + packageData.append(os.path.join(relpath, '*.*')) + return packageData + +setup(name='MaterialX', + url='www.materialx.org', + version='${MATERIALX_MAJOR_VERSION}.${MATERIALX_MINOR_VERSION}.${MATERIALX_BUILD_VERSION}', + packages=['MaterialX'], + package_data={'MaterialX' : getRecursivePackageData('MaterialX')}, + zip_safe = False) diff --git a/MaterialX/resources/CMakeLists.txt b/MaterialX/resources/CMakeLists.txt old mode 100644 new mode 100755 index 10212c9..9a5062b --- a/MaterialX/resources/CMakeLists.txt +++ b/MaterialX/resources/CMakeLists.txt @@ -1,4 +1,4 @@ -if(NOT SKBUILD) - install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ - DESTINATION "resources" MESSAGE_NEVER) -endif() +if(NOT SKBUILD) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ + DESTINATION "resources" MESSAGE_NEVER) +endif() diff --git a/MaterialX/resources/Geometry/boombox.glb b/MaterialX/resources/Geometry/boombox.glb old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Geometry/chess_set.glb b/MaterialX/resources/Geometry/chess_set.glb old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Geometry/shaderball.glb b/MaterialX/resources/Geometry/shaderball.glb old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Geometry/shaderball_ao.png b/MaterialX/resources/Geometry/shaderball_ao.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/brass_color.jpg b/MaterialX/resources/Images/brass_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/brass_roughness.jpg b/MaterialX/resources/Images/brass_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/brick_base_gray.jpg b/MaterialX/resources/Images/brick_base_gray.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/brick_dirt_mask.jpg b/MaterialX/resources/Images/brick_dirt_mask.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/brick_mask.jpg b/MaterialX/resources/Images/brick_mask.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/brick_normal.jpg b/MaterialX/resources/Images/brick_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/brick_roughness.jpg b/MaterialX/resources/Images/brick_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/brick_variation_mask.jpg b/MaterialX/resources/Images/brick_variation_mask.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/cloth.bmp b/MaterialX/resources/Images/cloth.bmp old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/cloth.gif b/MaterialX/resources/Images/cloth.gif old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/cloth.jpg b/MaterialX/resources/Images/cloth.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/cloth.png b/MaterialX/resources/Images/cloth.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/cloth.tga b/MaterialX/resources/Images/cloth.tga old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/gamma_chart.exr b/MaterialX/resources/Images/gamma_chart.exr deleted file mode 100644 index 45ce98e..0000000 Binary files a/MaterialX/resources/Images/gamma_chart.exr and /dev/null differ diff --git a/MaterialX/resources/Images/greysphere_calibration.png b/MaterialX/resources/Images/greysphere_calibration.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/grid.png b/MaterialX/resources/Images/grid.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/grid_udim/grid.1001.png b/MaterialX/resources/Images/grid_udim/grid.1001.png deleted file mode 100644 index 46d670f..0000000 Binary files a/MaterialX/resources/Images/grid_udim/grid.1001.png and /dev/null differ diff --git a/MaterialX/resources/Images/grid_udim/grid.1002.png b/MaterialX/resources/Images/grid_udim/grid.1002.png deleted file mode 100644 index 6e25a2a..0000000 Binary files a/MaterialX/resources/Images/grid_udim/grid.1002.png and /dev/null differ diff --git a/MaterialX/resources/Images/grid_udim/grid.1003.png b/MaterialX/resources/Images/grid_udim/grid.1003.png deleted file mode 100644 index f0bc2e4..0000000 Binary files a/MaterialX/resources/Images/grid_udim/grid.1003.png and /dev/null differ diff --git a/MaterialX/resources/Images/grid_udim/grid.1011.png b/MaterialX/resources/Images/grid_udim/grid.1011.png deleted file mode 100644 index f3df995..0000000 Binary files a/MaterialX/resources/Images/grid_udim/grid.1011.png and /dev/null differ diff --git a/MaterialX/resources/Images/grid_udim/grid.1012.png b/MaterialX/resources/Images/grid_udim/grid.1012.png deleted file mode 100644 index bbd2e4e..0000000 Binary files a/MaterialX/resources/Images/grid_udim/grid.1012.png and /dev/null differ diff --git a/MaterialX/resources/Images/grid_udim/grid.1013.png b/MaterialX/resources/Images/grid_udim/grid.1013.png deleted file mode 100644 index 67da022..0000000 Binary files a/MaterialX/resources/Images/grid_udim/grid.1013.png and /dev/null differ diff --git a/MaterialX/resources/Images/marble.png b/MaterialX/resources/Images/marble.png new file mode 100755 index 0000000..9e962bb Binary files /dev/null and b/MaterialX/resources/Images/marble.png differ diff --git a/MaterialX/resources/Images/mesh_wire_norm.png b/MaterialX/resources/Images/mesh_wire_norm.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/onyx_color.jpg b/MaterialX/resources/Images/onyx_color.jpg deleted file mode 100644 index a681f60..0000000 Binary files a/MaterialX/resources/Images/onyx_color.jpg and /dev/null differ diff --git a/MaterialX/resources/Images/onyx_roughness.jpg b/MaterialX/resources/Images/onyx_roughness.jpg deleted file mode 100644 index 70f9ff5..0000000 Binary files a/MaterialX/resources/Images/onyx_roughness.jpg and /dev/null differ diff --git a/MaterialX/resources/Images/plain_heightmap.png b/MaterialX/resources/Images/plain_heightmap.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/wood_color.jpg b/MaterialX/resources/Images/wood_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Images/wood_roughness.jpg b/MaterialX/resources/Images/wood_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/environment_map.mtlx b/MaterialX/resources/Lights/environment_map.mtlx old mode 100644 new mode 100755 index b4aad60..7c63177 --- a/MaterialX/resources/Lights/environment_map.mtlx +++ b/MaterialX/resources/Lights/environment_map.mtlx @@ -1,19 +1,60 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Lights/goegap.hdr b/MaterialX/resources/Lights/goegap.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/goegap_split.hdr b/MaterialX/resources/Lights/goegap_split.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/goegap_split.mtlx b/MaterialX/resources/Lights/goegap_split.mtlx old mode 100644 new mode 100755 index f987f99..4485668 --- a/MaterialX/resources/Lights/goegap_split.mtlx +++ b/MaterialX/resources/Lights/goegap_split.mtlx @@ -1,8 +1,8 @@ - - - - - - - - + + + + + + + + diff --git a/MaterialX/resources/Lights/irradiance/goegap.hdr b/MaterialX/resources/Lights/irradiance/goegap.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/irradiance/goegap_split.hdr b/MaterialX/resources/Lights/irradiance/goegap_split.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/irradiance/san_giuseppe_bridge.hdr b/MaterialX/resources/Lights/irradiance/san_giuseppe_bridge.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/irradiance/san_giuseppe_bridge_split.hdr b/MaterialX/resources/Lights/irradiance/san_giuseppe_bridge_split.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/irradiance/table_mountain.hdr b/MaterialX/resources/Lights/irradiance/table_mountain.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/irradiance/table_mountain_split.hdr b/MaterialX/resources/Lights/irradiance/table_mountain_split.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/san_giuseppe_bridge.hdr b/MaterialX/resources/Lights/san_giuseppe_bridge.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/san_giuseppe_bridge_split.hdr b/MaterialX/resources/Lights/san_giuseppe_bridge_split.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/san_giuseppe_bridge_split.mtlx b/MaterialX/resources/Lights/san_giuseppe_bridge_split.mtlx old mode 100644 new mode 100755 index 31938e9..f0b7620 --- a/MaterialX/resources/Lights/san_giuseppe_bridge_split.mtlx +++ b/MaterialX/resources/Lights/san_giuseppe_bridge_split.mtlx @@ -1,8 +1,8 @@ - - - - - - - - + + + + + + + + diff --git a/MaterialX/resources/Lights/table_mountain.hdr b/MaterialX/resources/Lights/table_mountain.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/table_mountain_split.hdr b/MaterialX/resources/Lights/table_mountain_split.hdr old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Lights/table_mountain_split.mtlx b/MaterialX/resources/Lights/table_mountain_split.mtlx old mode 100644 new mode 100755 index 658b60b..bcea283 --- a/MaterialX/resources/Lights/table_mountain_split.mtlx +++ b/MaterialX/resources/Lights/table_mountain_split.mtlx @@ -1,8 +1,8 @@ - - - - - - - - + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_carpaint.mtlx b/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_carpaint.mtlx deleted file mode 100644 index 7c5a0ae..0000000 --- a/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_carpaint.mtlx +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_glass.mtlx b/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_glass.mtlx deleted file mode 100644 index dfb1fab..0000000 --- a/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_glass.mtlx +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_gold.mtlx b/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_gold.mtlx deleted file mode 100644 index f0dde69..0000000 --- a/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_gold.mtlx +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_plastic.mtlx b/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_plastic.mtlx deleted file mode 100644 index 7b2561b..0000000 --- a/MaterialX/resources/Materials/Examples/DisneyPrincipled/disney_principled_plastic.mtlx +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/MaterialX/resources/Materials/Examples/GltfPbr/boombox/BoomBox_baseColor.png b/MaterialX/resources/Materials/Examples/GltfPbr/boombox/BoomBox_baseColor.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/GltfPbr/boombox/BoomBox_emissive.png b/MaterialX/resources/Materials/Examples/GltfPbr/boombox/BoomBox_emissive.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/GltfPbr/boombox/BoomBox_normal.png b/MaterialX/resources/Materials/Examples/GltfPbr/boombox/BoomBox_normal.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/GltfPbr/boombox/BoomBox_occlusionRoughnessMetallic.png b/MaterialX/resources/Materials/Examples/GltfPbr/boombox/BoomBox_occlusionRoughnessMetallic.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_boombox.mtlx b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_boombox.mtlx old mode 100644 new mode 100755 index 411f316..afdb912 --- a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_boombox.mtlx +++ b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_boombox.mtlx @@ -1,30 +1,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_carpaint.mtlx b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_carpaint.mtlx old mode 100644 new mode 100755 index c6ec4bb..96d74b7 --- a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_carpaint.mtlx +++ b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_carpaint.mtlx @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx old mode 100644 new mode 100755 index 88d7031..f67c4cb --- a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx +++ b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx @@ -1,33 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_glass.mtlx b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_glass.mtlx old mode 100644 new mode 100755 index 3eb394c..590640a --- a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_glass.mtlx +++ b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_glass.mtlx @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_gold.mtlx b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_gold.mtlx old mode 100644 new mode 100755 index 6d93c5d..28419fd --- a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_gold.mtlx +++ b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_gold.mtlx @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_plastic.mtlx b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_plastic.mtlx old mode 100644 new mode 100755 index 0a4c99c..f033e7f --- a/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_plastic.mtlx +++ b/MaterialX/resources/Materials/Examples/GltfPbr/gltf_pbr_plastic.mtlx @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_aluminum_brushed.mtlx b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_aluminum_brushed.mtlx old mode 100644 new mode 100755 index daac59d..3b36eb3 --- a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_aluminum_brushed.mtlx +++ b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_aluminum_brushed.mtlx @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_carpaint.mtlx b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_carpaint.mtlx old mode 100644 new mode 100755 index 0d98dc2..664ae7e --- a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_carpaint.mtlx +++ b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_carpaint.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_default.mtlx b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_default.mtlx old mode 100644 new mode 100755 index 2f541d8..8508bfc --- a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_default.mtlx +++ b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_default.mtlx @@ -1,46 +1,46 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_glass.mtlx b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_glass.mtlx old mode 100644 new mode 100755 index f2e82e8..f5627d2 --- a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_glass.mtlx +++ b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_glass.mtlx @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_honey.mtlx b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_honey.mtlx old mode 100644 new mode 100755 index aff78be..80616f5 --- a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_honey.mtlx +++ b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_honey.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_ketchup.mtlx b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_ketchup.mtlx old mode 100644 new mode 100755 index 78e2d0a..9c684f5 --- a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_ketchup.mtlx +++ b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_ketchup.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_lightbulb.mtlx b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_lightbulb.mtlx old mode 100644 new mode 100755 index 7e1218c..54d2066 --- a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_lightbulb.mtlx +++ b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_lightbulb.mtlx @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_pearl.mtlx b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_pearl.mtlx old mode 100644 new mode 100755 index cc71642..38896ab --- a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_pearl.mtlx +++ b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_pearl.mtlx @@ -1,20 +1,20 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_soapbubble.mtlx b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_soapbubble.mtlx old mode 100644 new mode 100755 index 7de701d..f7e0ba5 --- a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_soapbubble.mtlx +++ b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_soapbubble.mtlx @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_velvet.mtlx b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_velvet.mtlx old mode 100644 new mode 100755 index 61c83e2..b8c8de7 --- a/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_velvet.mtlx +++ b/MaterialX/resources/Materials/Examples/OpenPbr/open_pbr_velvet.mtlx @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx b/MaterialX/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx deleted file mode 100644 index b3dbd80..0000000 --- a/MaterialX/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_black_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_black_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_black_normal.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_black_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_black_roughness.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_black_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_shared_metallic.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_shared_metallic.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_white_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_white_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_white_normal.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_white_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_white_roughness.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/bishop_white_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/castle_black_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/castle_black_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/castle_shared_metallic.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/castle_shared_metallic.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/castle_shared_normal.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/castle_shared_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/castle_shared_roughness.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/castle_shared_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/castle_white_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/castle_white_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/chessboard_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/chessboard_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/chessboard_metallic.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/chessboard_metallic.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/chessboard_normal.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/chessboard_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/chessboard_roughness.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/chessboard_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_black_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_black_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_black_normal.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_black_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_black_roughness.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_black_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_shared_metallic.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_shared_metallic.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_shared_scattering.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_shared_scattering.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_white_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_white_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_white_normal.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_white_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_white_roughness.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/king_white_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_black_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_black_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_black_normal.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_black_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_black_roughness.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_black_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_white_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_white_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_white_normal.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_white_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_white_roughness.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/knight_white_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/pawn_black_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/pawn_black_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_metallic.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_metallic.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_normal.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_roughness.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/pawn_white_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/pawn_white_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_black_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_black_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_black_normal.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_black_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_black_roughness.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_black_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_shared_metallic.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_shared_metallic.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_shared_scattering.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_shared_scattering.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_white_base_color.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_white_base_color.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_white_normal.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_white_normal.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_white_roughness.jpg b/MaterialX/resources/Materials/Examples/StandardSurface/chess_set/queen_white_roughness.jpg old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_brass_tiled.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_brass_tiled.mtlx old mode 100644 new mode 100755 index f97a98f..c2da9ab --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_brass_tiled.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_brass_tiled.mtlx @@ -1,28 +1,28 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_brick_procedural.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_brick_procedural.mtlx old mode 100644 new mode 100755 index 1728ba4..a04b0cf --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_brick_procedural.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_brick_procedural.mtlx @@ -1,132 +1,132 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_carpaint.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_carpaint.mtlx old mode 100644 new mode 100755 index 7389708..1252208 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_carpaint.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_carpaint.mtlx @@ -1,16 +1,16 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx old mode 100644 new mode 100755 index 3cbaf02..22b5977 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx @@ -1,555 +1,555 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_chrome.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_chrome.mtlx old mode 100644 new mode 100755 index 81a5df6..803ea1b --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_chrome.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_chrome.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_copper.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_copper.mtlx old mode 100644 new mode 100755 index 6eadaef..50b3461 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_copper.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_copper.mtlx @@ -1,16 +1,16 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_default.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_default.mtlx old mode 100644 new mode 100755 index b4f0966..0d8f1fb --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_default.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_default.mtlx @@ -1,47 +1,47 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_glass.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_glass.mtlx old mode 100644 new mode 100755 index 5a5461e..ba720db --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_glass.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_glass.mtlx @@ -1,21 +1,21 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_glass_tinted.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_glass_tinted.mtlx old mode 100644 new mode 100755 index ef515a1..abac693 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_glass_tinted.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_glass_tinted.mtlx @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_gold.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_gold.mtlx old mode 100644 new mode 100755 index d8f0e6b..9797036 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_gold.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_gold.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_greysphere.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_greysphere.mtlx old mode 100644 new mode 100755 index a5bba1b..098e470 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_greysphere.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_greysphere.mtlx @@ -1,10 +1,13 @@ - - - - - - - - - - + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.mtlx old mode 100644 new mode 100755 index b33bcd5..96b55df --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.mtlx @@ -1,26 +1,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_jade.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_jade.mtlx old mode 100644 new mode 100755 index 0becdec..38fa7ce --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_jade.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_jade.mtlx @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx old mode 100644 new mode 100755 index 510f1c2..41cb6e7 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_look_wood_tiled.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_look_wood_tiled.mtlx old mode 100644 new mode 100755 index 9a9073d..937c1f9 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_look_wood_tiled.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_look_wood_tiled.mtlx @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_marble_solid.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_marble_solid.mtlx old mode 100644 new mode 100755 index 59c1131..b8e5b20 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_marble_solid.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_marble_solid.mtlx @@ -1,67 +1,67 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_metal_brushed.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_metal_brushed.mtlx old mode 100644 new mode 100755 index aabc1d0..e1ba75d --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_metal_brushed.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_metal_brushed.mtlx @@ -1,17 +1,17 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_plastic.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_plastic.mtlx old mode 100644 new mode 100755 index 2c16ff4..1051c41 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_plastic.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_plastic.mtlx @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_thin_film.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_thin_film.mtlx old mode 100644 new mode 100755 index 7bda7f3..4796198 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_thin_film.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_thin_film.mtlx @@ -1,20 +1,20 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_velvet.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_velvet.mtlx old mode 100644 new mode 100755 index 473578c..5186ffe --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_velvet.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_velvet.mtlx @@ -1,17 +1,17 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_wood_tiled.mtlx b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_wood_tiled.mtlx old mode 100644 new mode 100755 index ed6690f..e7d70c5 --- a/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_wood_tiled.mtlx +++ b/MaterialX/resources/Materials/Examples/StandardSurface/standard_surface_wood_tiled.mtlx @@ -1,28 +1,28 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.mtlx b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.mtlx old mode 100644 new mode 100755 index 85f6f3e..1a58f00 --- a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.mtlx +++ b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.mtlx @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.mtlx b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.mtlx old mode 100644 new mode 100755 index 3fb1b00..5d2a94b --- a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.mtlx +++ b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.mtlx @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx old mode 100644 new mode 100755 index 5fa69b7..035b84e --- a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx +++ b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx @@ -1,23 +1,22 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.mtlx b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.mtlx old mode 100644 new mode 100755 index 5cc6ab5..e0a1b0a --- a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.mtlx +++ b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.mtlx @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.mtlx b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.mtlx old mode 100644 new mode 100755 index c1e0e06..4265eb6 --- a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.mtlx +++ b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.mtlx @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.mtlx b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.mtlx old mode 100644 new mode 100755 index 58fd5bf..aac696c --- a/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.mtlx +++ b/MaterialX/resources/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.mtlx @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/README.md b/MaterialX/resources/Materials/TestSuite/README.md old mode 100644 new mode 100755 index 327684d..2450c46 --- a/MaterialX/resources/Materials/TestSuite/README.md +++ b/MaterialX/resources/Materials/TestSuite/README.md @@ -1,22 +1,22 @@ -# Shader Generation and Render Test Suite - -The sub-folders in the test suite contain a set of input MaterialX documents. During execution of the test suite, each file is parsed to determine renderable elements. For each element the appropriate shader generator is used to produce source code for ShaderGen tests. For Render validation tests the code is compiled, and/or rendered. - -## Folder layout - -- The main grouping of input files is by library: ([stdlib](stdlib) and [pbrlib](pbrlib)). -- Additional sub-folders group documents based on Element group or category. For example math tests are found in [stdlib/math](stdlib/math)), with: - - `math.mtlx` - - `math_operators.mtlx` - - `transform.mtlx` - - `trig.mtlx`, and - - `vector_math.mtlx` - - documents containing the various Elements to test. -- It is possible to add additional tests by simply adding new MaterialX documents under the TestSuite sub-folder. -- The [Geometry](../../Geometry) and [Images](../../Images) folders provide stock input geometry and images for usage by the test suite. -- The [Utilities folder](Utilities) provides utilities used for rendering with `testrender` as well as the light configuration specification for hardware rendering. - -At the top level, the [options file (_options.mtlx)](_options.mtlx) is a MaterialX document that defines the set of execution options for Render tests. The values may be edited locally as desired. - -For details on how to build the unit test module to use this test suite see the [source documentation](../../../source/MaterialXTest/README.md). +# Shader Generation and Render Test Suite + +The sub-folders in the test suite contain a set of input MaterialX documents. During execution of the test suite, each file is parsed to determine renderable elements. For each element the appropriate shader generator is used to produced source code for ShaderGen tests. For Render validation tests the code is compiled, and/or rendered. + +## Folder layout + +- The main grouping of input files is by library: ([stdlib](stdlib) and [pbrlib](pbrlib)). +- Additional sub-folders group documents based on Element group or category. For example math tests are found in [stdlib/math](stdlib/math)), with: + - `math.mtlx` + - `math_operators.mtlx` + - `transform.mtlx` + - `trig.mtlx`, and + - `vector_math.mtlx` + + documents containing the various Elements to test. +- It is possible to add additional tests by simply adding new MaterialX documents under the TestSuite sub-folder. +- The [Geometry](../../Geometry) and [Images](../../Images) folders provide stock input geometry and images for usage by the test suite. +- The [Utilities folder](Utilities) provides utilities used for rendering with `testrender` as well as the light configuration specification for hardware rendering. + +At the top level, the [options file (_options.mtlx)](_options.mtlx) is a MaterialX document that defines the set of execution options for Render tests. The values may be edited locally as desired. + +For details on how to build the unit test module to use this test suite see the [source documentation](../../../source/MaterialXTest/README.md). diff --git a/MaterialX/resources/Materials/TestSuite/_options.mtlx b/MaterialX/resources/Materials/TestSuite/_options.mtlx old mode 100644 new mode 100755 index a5d0623..f514e4e --- a/MaterialX/resources/Materials/TestSuite/_options.mtlx +++ b/MaterialX/resources/Materials/TestSuite/_options.mtlx @@ -1,74 +1,82 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/libraries/metal/brass_wire_mesh.mtlx b/MaterialX/resources/Materials/TestSuite/libraries/metal/brass_wire_mesh.mtlx old mode 100644 new mode 100755 index ce3fb71..8fa1b4e --- a/MaterialX/resources/Materials/TestSuite/libraries/metal/brass_wire_mesh.mtlx +++ b/MaterialX/resources/Materials/TestSuite/libraries/metal/brass_wire_mesh.mtlx @@ -1,56 +1,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/libraries/metal/libraries/metal_definition.mtlx b/MaterialX/resources/Materials/TestSuite/libraries/metal/libraries/metal_definition.mtlx old mode 100644 new mode 100755 index b95bff5..03a7e6b --- a/MaterialX/resources/Materials/TestSuite/libraries/metal/libraries/metal_definition.mtlx +++ b/MaterialX/resources/Materials/TestSuite/libraries/metal/libraries/metal_definition.mtlx @@ -1,44 +1,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/libraries/metal/textures/mesh_wire_cutout.png b/MaterialX/resources/Materials/TestSuite/libraries/metal/textures/mesh_wire_cutout.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/TestSuite/libraries/metal/textures/mesh_wire_norm.png b/MaterialX/resources/Materials/TestSuite/libraries/metal/textures/mesh_wire_norm.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/TestSuite/libraries/metal/textures/mesh_wire_spec.png b/MaterialX/resources/Materials/TestSuite/libraries/metal/textures/mesh_wire_spec.png old mode 100644 new mode 100755 diff --git a/MaterialX/resources/Materials/TestSuite/lights/light_compound_test.mtlx b/MaterialX/resources/Materials/TestSuite/lights/light_compound_test.mtlx old mode 100644 new mode 100755 index be598b2..45c2321 --- a/MaterialX/resources/Materials/TestSuite/lights/light_compound_test.mtlx +++ b/MaterialX/resources/Materials/TestSuite/lights/light_compound_test.mtlx @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/lights/light_rig_test_1.mtlx b/MaterialX/resources/Materials/TestSuite/lights/light_rig_test_1.mtlx old mode 100644 new mode 100755 index f86312f..028674c --- a/MaterialX/resources/Materials/TestSuite/lights/light_rig_test_1.mtlx +++ b/MaterialX/resources/Materials/TestSuite/lights/light_rig_test_1.mtlx @@ -1,56 +1,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/lights/light_rig_test_2.mtlx b/MaterialX/resources/Materials/TestSuite/lights/light_rig_test_2.mtlx old mode 100644 new mode 100755 index 51e5ebb..3380e1b --- a/MaterialX/resources/Materials/TestSuite/lights/light_rig_test_2.mtlx +++ b/MaterialX/resources/Materials/TestSuite/lights/light_rig_test_2.mtlx @@ -1,28 +1,28 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/locale/numericformat.mtlx b/MaterialX/resources/Materials/TestSuite/locale/numericformat.mtlx old mode 100644 new mode 100755 index e9aa360..9589d5a --- a/MaterialX/resources/Materials/TestSuite/locale/numericformat.mtlx +++ b/MaterialX/resources/Materials/TestSuite/locale/numericformat.mtlx @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/locale/utf8.mtlx b/MaterialX/resources/Materials/TestSuite/locale/utf8.mtlx old mode 100644 new mode 100755 index dde51c7..66afc60 --- a/MaterialX/resources/Materials/TestSuite/locale/utf8.mtlx +++ b/MaterialX/resources/Materials/TestSuite/locale/utf8.mtlx @@ -1,16 +1,16 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/nprlib/edge_brighten.mtlx b/MaterialX/resources/Materials/TestSuite/nprlib/edge_brighten.mtlx old mode 100644 new mode 100755 index 822ed6b..c915482 --- a/MaterialX/resources/Materials/TestSuite/nprlib/edge_brighten.mtlx +++ b/MaterialX/resources/Materials/TestSuite/nprlib/edge_brighten.mtlx @@ -1,18 +1,18 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/nprlib/gooch_shade.mtlx b/MaterialX/resources/Materials/TestSuite/nprlib/gooch_shade.mtlx old mode 100644 new mode 100755 index 4a7049a..6aed779 --- a/MaterialX/resources/Materials/TestSuite/nprlib/gooch_shade.mtlx +++ b/MaterialX/resources/Materials/TestSuite/nprlib/gooch_shade.mtlx @@ -1,30 +1,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/nprlib/starfield.mtlx b/MaterialX/resources/Materials/TestSuite/nprlib/starfield.mtlx old mode 100644 new mode 100755 index ae832fb..ca05811 --- a/MaterialX/resources/Materials/TestSuite/nprlib/starfield.mtlx +++ b/MaterialX/resources/Materials/TestSuite/nprlib/starfield.mtlx @@ -1,25 +1,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/nprlib/toon_shade.mtlx b/MaterialX/resources/Materials/TestSuite/nprlib/toon_shade.mtlx old mode 100644 new mode 100755 index a849e20..85f0e8d --- a/MaterialX/resources/Materials/TestSuite/nprlib/toon_shade.mtlx +++ b/MaterialX/resources/Materials/TestSuite/nprlib/toon_shade.mtlx @@ -1,151 +1,151 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/add_bsdf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/add_bsdf.mtlx old mode 100644 new mode 100755 index 398b321..667a751 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/add_bsdf.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/add_bsdf.mtlx @@ -1,38 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/blackbody.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/blackbody.mtlx old mode 100644 new mode 100755 index 4c7dee8..5b87902 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/blackbody.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/blackbody.mtlx @@ -1,16 +1,16 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/bsdf_graph.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/bsdf_graph.mtlx old mode 100644 new mode 100755 index d95d636..ab4031f --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/bsdf_graph.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/bsdf_graph.mtlx @@ -1,46 +1,46 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/burley_diffuse.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/burley_diffuse.mtlx old mode 100644 new mode 100755 index 97343b3..7c5603f --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/burley_diffuse.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/burley_diffuse.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx deleted file mode 100644 index 8d95ffe..0000000 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/chiang_hair_bsdf.mtlx +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/conductor.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/conductor.mtlx old mode 100644 new mode 100755 index e2d5540..4dceb11 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/conductor.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/conductor.mtlx @@ -1,25 +1,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/dielectric.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/dielectric.mtlx old mode 100644 new mode 100755 index c62ba5b..2e58f2f --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/dielectric.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/dielectric.mtlx @@ -1,43 +1,43 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx old mode 100644 new mode 100755 index bc31308..ad8e7bc --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx @@ -1,98 +1,98 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/layer_bsdf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/layer_bsdf.mtlx old mode 100644 new mode 100755 index bb8a5ca..6d0a3ce --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/layer_bsdf.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/layer_bsdf.mtlx @@ -1,57 +1,57 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/mix_bsdf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/mix_bsdf.mtlx old mode 100644 new mode 100755 index 84ab911..20ccf98 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/mix_bsdf.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/mix_bsdf.mtlx @@ -1,90 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/multiply_bsdf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/multiply_bsdf.mtlx old mode 100644 new mode 100755 index 215cf1c..6a40f9a --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/multiply_bsdf.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/multiply_bsdf.mtlx @@ -1,28 +1,28 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/oren_nayar_diffuse.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/oren_nayar_diffuse.mtlx old mode 100644 new mode 100755 index 1262a86..7c4fc3a --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/oren_nayar_diffuse.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/oren_nayar_diffuse.mtlx @@ -1,56 +1,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/sheen_bsdf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/sheen_bsdf.mtlx deleted file mode 100644 index db9de82..0000000 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/sheen_bsdf.mtlx +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/subsurface_bsdf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/subsurface_bsdf.mtlx deleted file mode 100644 index 3861146..0000000 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/subsurface_bsdf.mtlx +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx old mode 100644 new mode 100755 index 8ebc444..f8df7aa --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx @@ -1,156 +1,156 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/translucent_bsdf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/translucent_bsdf.mtlx old mode 100644 new mode 100755 index 175b285..31c7ddb --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/translucent_bsdf.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/translucent_bsdf.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/varying_ior.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/varying_ior.mtlx old mode 100644 new mode 100755 index c501b7a..50ef47a --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/varying_ior.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/varying_ior.mtlx @@ -1,52 +1,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/vertical_layering.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/vertical_layering.mtlx old mode 100644 new mode 100755 index b78ed0f..e6289ee --- a/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/vertical_layering.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/bsdf/vertical_layering.mtlx @@ -1,200 +1,200 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/displacement/displaced_material.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/displacement/displaced_material.mtlx old mode 100644 new mode 100755 index 2265ed2..693e2d6 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/displacement/displaced_material.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/displacement/displaced_material.mtlx @@ -1,40 +1,40 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/displacement/displacement.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/displacement/displacement.mtlx old mode 100644 new mode 100755 index ad6ae8d..842f15d --- a/MaterialX/resources/Materials/TestSuite/pbrlib/displacement/displacement.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/displacement/displacement.mtlx @@ -1,45 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/edf/add_edf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/edf/add_edf.mtlx old mode 100644 new mode 100755 index f12be57..6d03ba0 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/edf/add_edf.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/edf/add_edf.mtlx @@ -1,19 +1,19 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/edf/edf_graph.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/edf/edf_graph.mtlx old mode 100644 new mode 100755 index 5b33be4..273aecd --- a/MaterialX/resources/Materials/TestSuite/pbrlib/edf/edf_graph.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/edf/edf_graph.mtlx @@ -1,58 +1,58 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/edf/generalized_schlick_edf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/edf/generalized_schlick_edf.mtlx old mode 100644 new mode 100755 index 69ec36f..8c62d44 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/edf/generalized_schlick_edf.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/edf/generalized_schlick_edf.mtlx @@ -1,18 +1,18 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/edf/mix_edf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/edf/mix_edf.mtlx old mode 100644 new mode 100755 index 05f2a5e..2a59f16 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/edf/mix_edf.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/edf/mix_edf.mtlx @@ -1,20 +1,20 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/edf/multiply_edf.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/edf/multiply_edf.mtlx old mode 100644 new mode 100755 index 7bed14f..32bc9ac --- a/MaterialX/resources/Materials/TestSuite/pbrlib/edf/multiply_edf.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/edf/multiply_edf.mtlx @@ -1,28 +1,28 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/multioutput/multioutput.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/multioutput/multioutput.mtlx old mode 100644 new mode 100755 index a645158..063f254 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/multioutput/multioutput.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/multioutput/multioutput.mtlx @@ -1,92 +1,92 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/multioutput/multishaderoutput.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/multioutput/multishaderoutput.mtlx old mode 100644 new mode 100755 index 2a620c3..028d598 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/multioutput/multishaderoutput.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/multioutput/multishaderoutput.mtlx @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx deleted file mode 100644 index 056c79b..0000000 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/chiang_hair_surfaceshader.mtlx +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_add.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_add.mtlx old mode 100644 new mode 100755 index c1de5cf..b16baba --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_add.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_add.mtlx @@ -1,67 +1,67 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx old mode 100644 new mode 100755 index 87cc821..7825737 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_conductor.mtlx @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_dielectric.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_dielectric.mtlx old mode 100644 new mode 100755 index c8d96de..223e818 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_dielectric.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_dielectric.mtlx @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_diffuse.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_diffuse.mtlx old mode 100644 new mode 100755 index 92e286b..99b68b0 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_diffuse.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_diffuse.mtlx @@ -1,17 +1,17 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx old mode 100644 new mode 100755 index f21d752..380e3ce --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_emission.mtlx @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_generalized_schlick.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_generalized_schlick.mtlx old mode 100644 new mode 100755 index 75eedac..a1cd529 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_generalized_schlick.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_generalized_schlick.mtlx @@ -1,28 +1,28 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx old mode 100644 new mode 100755 index 73737a6..b2d694c --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_iridescence.mtlx @@ -1,21 +1,21 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_layer.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_layer.mtlx old mode 100644 new mode 100755 index c50fcf8..f9ca6b8 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_layer.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_layer.mtlx @@ -1,50 +1,50 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_mix.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_mix.mtlx old mode 100644 new mode 100755 index 038d662..abc1a60 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_mix.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_mix.mtlx @@ -1,67 +1,67 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sheen.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sheen.mtlx old mode 100644 new mode 100755 index 2107419..b99e8c9 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sheen.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sheen.mtlx @@ -1,16 +1,16 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sss.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sss.mtlx old mode 100644 new mode 100755 index 61ba552..fdf174f --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sss.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_sss.mtlx @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_surface.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_surface.mtlx old mode 100644 new mode 100755 index 8a50c2d..726edb4 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_surface.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_surface.mtlx @@ -1,33 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx old mode 100644 new mode 100755 index 122741a..2ea72c8 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/lama/lama_translucent.mtlx @@ -1,17 +1,17 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/mapped_surfaceshader.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/mapped_surfaceshader.mtlx old mode 100644 new mode 100755 index 9df7199..6820754 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/mapped_surfaceshader.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/mapped_surfaceshader.mtlx @@ -1,117 +1,117 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/network_surfaceshader.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/network_surfaceshader.mtlx old mode 100644 new mode 100755 index 0b27eaf..8229925 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/network_surfaceshader.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/network_surfaceshader.mtlx @@ -1,22 +1,22 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/nodegraph_surfaceshader.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/nodegraph_surfaceshader.mtlx old mode 100644 new mode 100755 index 1270195..a9df6f5 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/nodegraph_surfaceshader.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/nodegraph_surfaceshader.mtlx @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx old mode 100644 new mode 100755 index d7a1345..086060f --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/normalmapped_surfaceshader.mtlx @@ -1,51 +1,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/shader_ops.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/shader_ops.mtlx old mode 100644 new mode 100755 index 6f3e1ec..2d7308e --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/shader_ops.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/shader_ops.mtlx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/sheen.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/sheen.mtlx old mode 100644 new mode 100755 index ba06958..381151f --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/sheen.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/sheen.mtlx @@ -1,43 +1,43 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/standard_surface_onyx_hextiled.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/standard_surface_onyx_hextiled.mtlx deleted file mode 100644 index 19b08a2..0000000 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/standard_surface_onyx_hextiled.mtlx +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/subsurface.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/subsurface.mtlx old mode 100644 new mode 100755 index b505fea..3f52926 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/subsurface.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/subsurface.mtlx @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/surface_ops.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/surface_ops.mtlx old mode 100644 new mode 100755 index 825491a..e841536 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/surface_ops.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/surface_ops.mtlx @@ -1,79 +1,79 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/surfacematerial_with_graph.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/surfacematerial_with_graph.mtlx old mode 100644 new mode 100755 index ad15863..321b430 --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/surfacematerial_with_graph.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/surfacematerial_with_graph.mtlx @@ -1,53 +1,53 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/transparency_hints.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/transparency_hints.mtlx old mode 100644 new mode 100755 index 0773e7e..cd7ca9e --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/transparency_hints.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/transparency_hints.mtlx @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx old mode 100644 new mode 100755 index 71d3da0..42634cc --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_normal_map.mtlx @@ -1,32 +1,27 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_uv_texture.mtlx b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_uv_texture.mtlx old mode 100644 new mode 100755 index ec6d378..eb261bd --- a/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_uv_texture.mtlx +++ b/MaterialX/resources/Materials/TestSuite/pbrlib/surfaceshader/usd_uv_texture.mtlx @@ -1,17 +1,17 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx new file mode 100755 index 0000000..e18548f --- /dev/null +++ b/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/adjustment.mtlx @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/hsvtorgb.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/hsvtorgb.mtlx old mode 100644 new mode 100755 index 0bb19da..a277478 --- a/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/hsvtorgb.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/hsvtorgb.mtlx @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx deleted file mode 100644 index 6260df8..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/luminance.mtlx +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx deleted file mode 100644 index 9175411..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/remap.mtlx +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/smoothstep.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/smoothstep.mtlx old mode 100644 new mode 100755 index 20962e7..abaddce --- a/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/smoothstep.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/adjustment/smoothstep.mtlx @@ -1,74 +1,74 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/animated/clock.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/animated/clock.mtlx deleted file mode 100644 index 5393a4d..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/animated/clock.mtlx +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/application/time_frame.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/application/time_frame.mtlx old mode 100644 new mode 100755 index 1740e7f..999fa1d --- a/MaterialX/resources/Materials/TestSuite/stdlib/application/time_frame.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/application/time_frame.mtlx @@ -1,25 +1,27 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/channel/channel.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/channel/channel.mtlx new file mode 100755 index 0000000..7205069 --- /dev/null +++ b/MaterialX/resources/Materials/TestSuite/stdlib/channel/channel.mtlx @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/channel/combine.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/channel/combine.mtlx deleted file mode 100644 index 403b344..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/channel/combine.mtlx +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/channel/extract.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/channel/extract.mtlx deleted file mode 100644 index 467707a..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/channel/extract.mtlx +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx old mode 100644 new mode 100755 index 35039cf..65cdf48 --- a/MaterialX/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/color_management/color3_vec3_cm_test.mtlx @@ -1,32 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/color_management/color_management.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/color_management/color_management.mtlx old mode 100644 new mode 100755 index 63f97e2..874c170 --- a/MaterialX/resources/Materials/TestSuite/stdlib/color_management/color_management.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/color_management/color_management.mtlx @@ -1,192 +1,192 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/color_management/filename_cm_test.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/color_management/filename_cm_test.mtlx old mode 100644 new mode 100755 index 0736be5..c2d43ee --- a/MaterialX/resources/Materials/TestSuite/stdlib/color_management/filename_cm_test.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/color_management/filename_cm_test.mtlx @@ -1,51 +1,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/color_management/native_color_management.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/color_management/native_color_management.mtlx deleted file mode 100644 index 4ac22be..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/color_management/native_color_management.mtlx +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/color_management/ocio_color_management.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/color_management/ocio_color_management.mtlx deleted file mode 100644 index ac44e30..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/color_management/ocio_color_management.mtlx +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx old mode 100644 new mode 100755 index b60b980..c8fbd0b --- a/MaterialX/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/compositing/compositing.mtlx @@ -1,373 +1,398 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_if_float.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_if_float.mtlx old mode 100644 new mode 100755 index 76dbc85..91e5729 --- a/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_if_float.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_if_float.mtlx @@ -1,271 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_if_int.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_if_int.mtlx old mode 100644 new mode 100755 index afc0306..5a9b59a --- a/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_if_int.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_if_int.mtlx @@ -1,367 +1,367 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_logic.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_logic.mtlx old mode 100644 new mode 100755 index f9187b1..ec84310 --- a/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_logic.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_logic.mtlx @@ -1,34 +1,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx new file mode 100755 index 0000000..1d454c9 --- /dev/null +++ b/MaterialX/resources/Materials/TestSuite/stdlib/conditional/conditional_switch.mtlx @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/convert/convert.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/convert/convert.mtlx new file mode 100755 index 0000000..174cd22 --- /dev/null +++ b/MaterialX/resources/Materials/TestSuite/stdlib/convert/convert.mtlx @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/convolution/blur.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/convolution/blur.mtlx old mode 100644 new mode 100755 index 20092c1..390ad6a --- a/MaterialX/resources/Materials/TestSuite/stdlib/convolution/blur.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/convolution/blur.mtlx @@ -1,88 +1,88 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/convolution/heighttonormal.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/convolution/heighttonormal.mtlx old mode 100644 new mode 100755 index d75d6a3..ab2fdf9 --- a/MaterialX/resources/Materials/TestSuite/stdlib/convolution/heighttonormal.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/convolution/heighttonormal.mtlx @@ -1,39 +1,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx deleted file mode 100644 index 86bddc9..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/defaultgeomprop/defaultgeomprop.mtlx +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_from_nodegraph.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_from_nodegraph.mtlx old mode 100644 new mode 100755 index 11a4b3c..854d157 --- a/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_from_nodegraph.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_from_nodegraph.mtlx @@ -1,29 +1,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_reduced_interface.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_reduced_interface.mtlx old mode 100644 new mode 100755 index efcf3ee..d34cf4a --- a/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_reduced_interface.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_reduced_interface.mtlx @@ -1,47 +1,47 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx old mode 100644 new mode 100755 index 55a8cfa..aad6628 --- a/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_using_definitions.mtlx @@ -1,386 +1,386 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_with_enum_interface.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_with_enum_interface.mtlx deleted file mode 100644 index 9fc41ec..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/definition/definition_with_enum_interface.mtlx +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/definition/surfacematerial_definition.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/definition/surfacematerial_definition.mtlx old mode 100644 new mode 100755 index ee54399..85fbfb4 --- a/MaterialX/resources/Materials/TestSuite/stdlib/definition/surfacematerial_definition.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/definition/surfacematerial_definition.mtlx @@ -1,42 +1,42 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/geometric/geompropvalue.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/geometric/geompropvalue.mtlx old mode 100644 new mode 100755 index 109a5e0..f254543 --- a/MaterialX/resources/Materials/TestSuite/stdlib/geometric/geompropvalue.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/geometric/geompropvalue.mtlx @@ -1,56 +1,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/geometric/look_assignment_order.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/geometric/look_assignment_order.mtlx old mode 100644 new mode 100755 index 0a57def..411254a --- a/MaterialX/resources/Materials/TestSuite/stdlib/geometric/look_assignment_order.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/geometric/look_assignment_order.mtlx @@ -1,28 +1,28 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/geometric/streams.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/geometric/streams.mtlx old mode 100644 new mode 100755 index 41ae52d..d4c2e62 --- a/MaterialX/resources/Materials/TestSuite/stdlib/geometric/streams.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/geometric/streams.mtlx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/materials/material_node_discovery.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/materials/material_node_discovery.mtlx old mode 100644 new mode 100755 index 7cf951e..25519e0 --- a/MaterialX/resources/Materials/TestSuite/stdlib/materials/material_node_discovery.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/materials/material_node_discovery.mtlx @@ -1,49 +1,49 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/math/math.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/math/math.mtlx old mode 100644 new mode 100755 index 1d0ca86..57118b0 --- a/MaterialX/resources/Materials/TestSuite/stdlib/math/math.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/math/math.mtlx @@ -1,757 +1,757 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/math/math_operators.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/math/math_operators.mtlx old mode 100644 new mode 100755 index c9bc79e..3151bcf --- a/MaterialX/resources/Materials/TestSuite/stdlib/math/math_operators.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/math/math_operators.mtlx @@ -1,724 +1,688 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/math/matrix.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/math/matrix.mtlx old mode 100644 new mode 100755 index 4c0bed3..184741f --- a/MaterialX/resources/Materials/TestSuite/stdlib/math/matrix.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/math/matrix.mtlx @@ -1,29 +1,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/math/transform.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/math/transform.mtlx old mode 100644 new mode 100755 index 90f862e..30271de --- a/MaterialX/resources/Materials/TestSuite/stdlib/math/transform.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/math/transform.mtlx @@ -1,203 +1,203 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/math/trig.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/math/trig.mtlx old mode 100644 new mode 100755 index bb17c67..7530a34 --- a/MaterialX/resources/Materials/TestSuite/stdlib/math/trig.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/math/trig.mtlx @@ -1,217 +1,217 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/math/vector_math.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/math/vector_math.mtlx old mode 100644 new mode 100755 index e3211cb..26b691c --- a/MaterialX/resources/Materials/TestSuite/stdlib/math/vector_math.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/math/vector_math.mtlx @@ -1,142 +1,142 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/cascade_nodegraphs.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/cascade_nodegraphs.mtlx old mode 100644 new mode 100755 index 1d91cee..b22efc1 --- a/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/cascade_nodegraphs.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/cascade_nodegraphs.mtlx @@ -1,62 +1,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/nodegraph_multioutput.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/nodegraph_multioutput.mtlx old mode 100644 new mode 100755 index d1ac440..9cffe0e --- a/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/nodegraph_multioutput.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/nodegraph_multioutput.mtlx @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/nodegraph_nodegraph.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/nodegraph_nodegraph.mtlx old mode 100644 new mode 100755 index e3508c3..08a181b --- a/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/nodegraph_nodegraph.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/nodegraph_nodegraph.mtlx @@ -1,120 +1,120 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/surfacematerial_nodegraph_to_surfaceshader.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/surfacematerial_nodegraph_to_surfaceshader.mtlx old mode 100644 new mode 100755 index aeaf1a3..568d238 --- a/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/surfacematerial_nodegraph_to_surfaceshader.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/surfacematerial_nodegraph_to_surfaceshader.mtlx @@ -1,31 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/top_level_input.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/top_level_input.mtlx old mode 100644 new mode 100755 index 5ed87ac..f28357e --- a/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/top_level_input.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/nodegraphs/top_level_input.mtlx @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/noise/noise.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/noise/noise.mtlx old mode 100644 new mode 100755 index 57cc811..8cca8dc --- a/MaterialX/resources/Materials/TestSuite/stdlib/noise/noise.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/noise/noise.mtlx @@ -1,149 +1,127 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/noise/procedural.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/noise/procedural.mtlx old mode 100644 new mode 100755 index ff374f3..1155c28 --- a/MaterialX/resources/Materials/TestSuite/stdlib/noise/procedural.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/noise/procedural.mtlx @@ -1,107 +1,107 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/noise/shared_function.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/noise/shared_function.mtlx old mode 100644 new mode 100755 index 3fae0a8..b1e211c --- a/MaterialX/resources/Materials/TestSuite/stdlib/noise/shared_function.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/noise/shared_function.mtlx @@ -1,34 +1,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/organization/organization.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/organization/organization.mtlx old mode 100644 new mode 100755 index c107ae1..9a546ce --- a/MaterialX/resources/Materials/TestSuite/stdlib/organization/organization.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/organization/organization.mtlx @@ -1,103 +1,103 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/procedural/linepattern.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/procedural/linepattern.mtlx old mode 100644 new mode 100755 index 98d012c..b9cb67c --- a/MaterialX/resources/Materials/TestSuite/stdlib/procedural/linepattern.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/procedural/linepattern.mtlx @@ -1,39 +1,39 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/procedural/tiledshape.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/procedural/tiledshape.mtlx old mode 100644 new mode 100755 index da75aca..0cdbcb9 --- a/MaterialX/resources/Materials/TestSuite/stdlib/procedural/tiledshape.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/procedural/tiledshape.mtlx @@ -1,38 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/shader/backsurface.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/shader/backsurface.mtlx deleted file mode 100644 index 4bd2c12..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/shader/backsurface.mtlx +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/shader/surface.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/shader/surface.mtlx old mode 100644 new mode 100755 index f2ff365..d2a7597 --- a/MaterialX/resources/Materials/TestSuite/stdlib/shader/surface.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/shader/surface.mtlx @@ -1,84 +1,84 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/structs/struct_texcoord.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/structs/struct_texcoord.mtlx deleted file mode 100644 index 074ca75..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/structs/struct_texcoord.mtlx +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/structs/struct_texcoordGroup.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/structs/struct_texcoordGroup.mtlx deleted file mode 100644 index acd7c19..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/structs/struct_texcoordGroup.mtlx +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/hextiled.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/hextiled.mtlx deleted file mode 100644 index 3e0c513..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/hextiled.mtlx +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/image.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/image.mtlx old mode 100644 new mode 100755 index d8dfb30..c138408 --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/image.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/texture/image.mtlx @@ -1,30 +1,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_addressing.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_addressing.mtlx old mode 100644 new mode 100755 index 5f99395..fa9fa5a --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_addressing.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_addressing.mtlx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_codecs.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_codecs.mtlx old mode 100644 new mode 100755 index 375d15d..abde002 --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_codecs.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_codecs.mtlx @@ -1,35 +1,35 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_default.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_default.mtlx old mode 100644 new mode 100755 index a863a15..0a88e0e --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_default.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_default.mtlx @@ -1,36 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_transform.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_transform.mtlx old mode 100644 new mode 100755 index 3b77f06..f8b9e09 --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_transform.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/texture/image_transform.mtlx @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/ramp.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/ramp.mtlx old mode 100644 new mode 100755 index af88901..b8c412b --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/ramp.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/texture/ramp.mtlx @@ -1,134 +1,134 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/split.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/split.mtlx old mode 100644 new mode 100755 index 17bf6a4..1bcb1e9 --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/split.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/texture/split.mtlx @@ -1,96 +1,96 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/tiledimage.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/tiledimage.mtlx old mode 100644 new mode 100755 index 2dd6eec..a0fe8e7 --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/tiledimage.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/texture/tiledimage.mtlx @@ -1,64 +1,64 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx new file mode 100755 index 0000000..1a20d70 --- /dev/null +++ b/MaterialX/resources/Materials/TestSuite/stdlib/texture/tokenGraph.mtlx @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/token_graph.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/token_graph.mtlx deleted file mode 100644 index f44314d..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/token_graph.mtlx +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/token_graph_material.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/token_graph_material.mtlx deleted file mode 100644 index 604b620..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/token_graph_material.mtlx +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/triplanarprojection.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/triplanarprojection.mtlx old mode 100644 new mode 100755 index cf21da3..5e99513 --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/triplanarprojection.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/texture/triplanarprojection.mtlx @@ -1,62 +1,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/texture/udim.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/texture/udim.mtlx deleted file mode 100644 index 5b495bc..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/texture/udim.mtlx +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/units/constant_unit.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/units/constant_unit.mtlx old mode 100644 new mode 100755 index 01030d7..2d5bcee --- a/MaterialX/resources/Materials/TestSuite/stdlib/units/constant_unit.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/units/constant_unit.mtlx @@ -1,7 +1,7 @@ - - - - - - - + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/units/distance_units.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/units/distance_units.mtlx old mode 100644 new mode 100755 index 504c57d..2ec1217 --- a/MaterialX/resources/Materials/TestSuite/stdlib/units/distance_units.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/units/distance_units.mtlx @@ -1,33 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/units/image_unit.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/units/image_unit.mtlx old mode 100644 new mode 100755 index 4ec1310..98be787 --- a/MaterialX/resources/Materials/TestSuite/stdlib/units/image_unit.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/units/image_unit.mtlx @@ -1,22 +1,22 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/units/standard_surface_unit.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/units/standard_surface_unit.mtlx old mode 100644 new mode 100755 index cda637f..3bb81dd --- a/MaterialX/resources/Materials/TestSuite/stdlib/units/standard_surface_unit.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/units/standard_surface_unit.mtlx @@ -1,21 +1,21 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/units/texture_units.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/units/texture_units.mtlx old mode 100644 new mode 100755 index 36c2f8d..ab40f2e --- a/MaterialX/resources/Materials/TestSuite/stdlib/units/texture_units.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/units/texture_units.mtlx @@ -1,29 +1,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/units/tiledimage_unit.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/units/tiledimage_unit.mtlx old mode 100644 new mode 100755 index bc6f7f0..8911db4 --- a/MaterialX/resources/Materials/TestSuite/stdlib/units/tiledimage_unit.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/units/tiledimage_unit.mtlx @@ -1,78 +1,78 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_22.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_22.mtlx old mode 100644 new mode 100755 index a9eff39..1d6a996 --- a/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_22.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_22.mtlx @@ -1,70 +1,70 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_25.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_25.mtlx old mode 100644 new mode 100755 index df723e7..4d81011 --- a/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_25.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_25.mtlx @@ -1,28 +1,28 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_36.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_36.mtlx old mode 100644 new mode 100755 index 08a0494..abeb3f5 --- a/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_36.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_36.mtlx @@ -1,180 +1,180 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx old mode 100644 new mode 100755 index 7404b75..44996df --- a/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_37.mtlx @@ -1,113 +1,113 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_38.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_38.mtlx deleted file mode 100644 index f7b3fb7..0000000 --- a/MaterialX/resources/Materials/TestSuite/stdlib/upgrade/syntax_1_38.mtlx +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MaterialX/resources/Materials/TestSuite/stdlib/version/multiple_version_test.mtlx b/MaterialX/resources/Materials/TestSuite/stdlib/version/multiple_version_test.mtlx old mode 100644 new mode 100755 index f066b63..ced4c95 --- a/MaterialX/resources/Materials/TestSuite/stdlib/version/multiple_version_test.mtlx +++ b/MaterialX/resources/Materials/TestSuite/stdlib/version/multiple_version_test.mtlx @@ -1,38 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MaterialX/resources/README.md b/MaterialX/resources/README.md old mode 100644 new mode 100755 index 6b353e0..97061c8 --- a/MaterialX/resources/README.md +++ b/MaterialX/resources/README.md @@ -1,5 +1,5 @@ -# Resources - -- [Geometry](Geometry): Sample geometry files. Includes files used by test suite. -- [Images](Images): Sample image files. Includes files used by test suite. -- [Materials](Materials) : Set of MaterialX documents. Includes [test suite files](Materials/TestSuite). +# Resources + +- [Geometry](Geometry): Sample geometry files. Includes files used by test suite. +- [Images](Images): Sample image files. Includes files used by test suite. +- [Materials](Materials) : Set of MaterialX documents. Includes [test suite files](Materials/TestSuite).