diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 1a72b718dc..cd40d2493a 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -31,12 +31,21 @@ jobs:
compiler_version: "14"
python: 3.9
- - name: Linux_GCC_14_Python311
+ - name: Linux_GCC_14_Python311_expand_lib
os: ubuntu-24.04
compiler: gcc
compiler_version: "14"
python: 3.11
test_render: ON
+ cmake_config: -DMATERIALX_BUILD_EXPAND_TEMPLATE_ELEMS=ON -DMATERIALX_BUILD_BAKE_NAMED_VALUES=ON
+
+ - name: Linux_GCC_14_Python311_unexpanded_lib
+ os: ubuntu-24.04
+ compiler: gcc
+ compiler_version: "14"
+ python: 3.11
+ test_render: ON
+ cmake_config: -DMATERIALX_BUILD_EXPAND_TEMPLATE_ELEMS=OFF -DMATERIALX_BUILD_BAKE_NAMED_VALUES=OFF
- name: Linux_GCC_CoverageAnalysis
os: ubuntu-24.04
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ece0165fa7..cf3e21b5f7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -51,6 +51,8 @@ option(MATERIALX_BUILD_BENCHMARK_TESTS "Build benchmark tests." OFF)
option(MATERIALX_BUILD_SHARED_LIBS "Build MaterialX libraries as shared rather than static." OFF)
option(MATERIALX_BUILD_DATA_LIBRARY "Build generated products from the MaterialX data library." OFF)
+option(MATERIALX_BUILD_EXPAND_TEMPLATE_ELEMS "Process the data library files at build time to expand any template elements." ON)
+option(MATERIALX_BUILD_BAKE_NAMED_VALUES "Process the data library files at build time to bake out the named values." ON)
option(MATERIALX_BUILD_MONOLITHIC "Build a single monolithic MaterialX library." OFF)
option(MATERIALX_BUILD_USE_CCACHE "Enable the use of ccache to speed up build time, if present." ON)
option(MATERIALX_PYTHON_LTO "Enable link-time optimizations for MaterialX Python." ON)
@@ -68,6 +70,10 @@ if (MATERIALX_BUILD_IOS)
set(CMAKE_SYSTEM_NAME iOS)
endif()
+list(APPEND CMAKE_MODULE_PATH
+ ${PROJECT_SOURCE_DIR}/cmake/macros)
+include(Public)
+
# Apple ecosystem cross-compilation
# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos
set(MATERIALX_BUILD_APPLE_EMBEDDED OFF)
@@ -305,131 +311,6 @@ else()
endif()
endif()
-# Shared functions
-function(assign_source_group prefix)
- foreach(_source IN ITEMS ${ARGN})
- if(IS_ABSOLUTE "${_source}")
- file(RELATIVE_PATH _source_rel "${CMAKE_CURRENT_SOURCE_DIR}" "${_source}")
- else()
- set(_source_rel "${_source}")
- endif()
- get_filename_component(_source_path "${_source_rel}" PATH)
- string(REPLACE "/" "\\" _source_path_msvc "${_source_path}")
- source_group("${prefix}\\${_source_path_msvc}" FILES "${_source}")
- endforeach()
-endfunction(assign_source_group)
-
-function(mx_add_library MATERIALX_MODULE_NAME)
- set(options ADD_OBJECTIVE_C_CODE)
- set(oneValueArgs EXPORT_DEFINE)
- set(multiValueArgs
- SOURCE_FILES
- HEADER_FILES
- INLINED_FILES
- MTLX_MODULES)
- cmake_parse_arguments(args
- "${options}"
- "${oneValueArgs}"
- "${multiValueArgs}"
- ${ARGN})
-
- if (APPLE AND args_ADD_OBJECTIVE_C_CODE)
- file(GLOB_RECURSE materialx_source_oc "${CMAKE_CURRENT_SOURCE_DIR}/*.m*")
- set_source_files_properties(${materialx_source_oc} PROPERTIES
- COMPILE_FLAGS "-x objective-c++")
- set(args_SOURCE_FILES ${args_SOURCE_FILES} ${materialx_source_oc})
- endif()
-
- assign_source_group("Source Files" ${args_SOURCE_FILES})
- assign_source_group("Source Files" ${args_INLINED_FILES})
- assign_source_group("Header Files" ${args_HEADER_FILES})
-
- if (NOT MATERIALX_BUILD_MONOLITHIC)
- set(TARGET_NAME ${MATERIALX_MODULE_NAME})
- add_library(${TARGET_NAME})
-
- # Create version resource
- if(MATERIALX_BUILD_SHARED_LIBS AND MSVC)
- configure_file(${PROJECT_SOURCE_DIR}/cmake/modules/MaterialXVersion.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
- target_sources(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
- endif()
-
- target_link_libraries(${TARGET_NAME}
- PUBLIC
- ${args_MTLX_MODULES}
- ${CMAKE_DL_LIBS})
-
- target_include_directories(${TARGET_NAME}
- PUBLIC
- $
- $
- PRIVATE
- ${EXTERNAL_INCLUDE_DIRS})
-
- set_target_properties(
- ${TARGET_NAME} PROPERTIES
- OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX}
- COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}"
- LINK_FLAGS "${EXTERNAL_LINK_FLAGS}"
- INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}"
- VERSION "${MATERIALX_LIBRARY_VERSION}"
- SOVERSION "${MATERIALX_MAJOR_VERSION}")
- else()
- set(TARGET_NAME ${MATERIALX_MONOLITHIC_TARGET})
- add_library(${MATERIALX_MODULE_NAME} ALIAS ${MATERIALX_MONOLITHIC_TARGET})
-
- # Store the aliased MaterialX modules name to create CMake export aliases later.
- set_property(GLOBAL APPEND PROPERTY MATERIALX_MODULES ${MATERIALX_MODULE_NAME})
- endif()
-
- set_target_properties(${TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden)
- set_target_properties(${TARGET_NAME} PROPERTIES CMAKE_VISIBILITY_INLINES_HIDDEN 1)
-
- target_sources(${TARGET_NAME}
- PRIVATE
- ${args_SOURCE_FILES}
- PUBLIC
- FILE_SET
- mxHeaders
- TYPE
- HEADERS
- BASE_DIRS
- ${CMAKE_CURRENT_SOURCE_DIR}/..
- ${CMAKE_CURRENT_BINARY_DIR}/..
- FILES
- ${args_HEADER_FILES}
- ${args_INLINED_FILES})
-
- target_include_directories(${TARGET_NAME} PUBLIC
- $)
-
- target_compile_definitions(${TARGET_NAME} PRIVATE "-D${args_EXPORT_DEFINE}")
-
- if(NOT SKBUILD)
- if(NOT MATERIALX_BUILD_MONOLITHIC)
- install(TARGETS ${MATERIALX_MODULE_NAME}
- EXPORT MaterialX
- ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH}
- LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH}
- RUNTIME DESTINATION ${MATERIALX_INSTALL_BIN_PATH}
- FILE_SET mxHeaders DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH})
- endif()
-
- if(MSVC)
- if(MATERIALX_BUILD_SHARED_LIBS)
- install(FILES $
- DESTINATION ${MATERIALX_INSTALL_BIN_PATH} OPTIONAL)
- else()
- install(FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/$/$.pdb"
- DESTINATION ${MATERIALX_INSTALL_LIB_PATH} OPTIONAL)
- endif()
- endif()
- endif()
-
- # Pass TARGET_NAME back to call site, so the caller can modify the build target.
- set(TARGET_NAME ${TARGET_NAME} PARENT_SCOPE)
-endfunction()
-
# Propagate shared library setting to NanoGUI
if(MATERIALX_BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS "ON")
@@ -437,15 +318,55 @@ else()
set(BUILD_SHARED_LIBS "OFF")
endif()
+# If we're baking the named "Value:" entries - then we have to also expand any
+# template elements
+if (MATERIALX_BUILD_BAKE_NAMED_VALUES)
+ set(MATERIALX_BUILD_EXPAND_TEMPLATE_ELEMS ON)
+endif()
+
+if (MATERIALX_BUILD_EXPAND_TEMPLATE_ELEMS OR MATERIALX_BUILD_BAKE_NAMED_VALUES)
+ set(MATERIALX_BUILD_DATA_LIBRARY ON)
+endif()
+
# Build a monolithic target - needs to be added before the other build targets that may be included.
if (MATERIALX_BUILD_MONOLITHIC)
set(MATERIALX_MONOLITHIC_TARGET MaterialX)
add_subdirectory(source)
endif()
+message("XXX : MATERIALX_BUILD_BAKE_NAMED_VALUES : ${MATERIALX_BUILD_BAKE_NAMED_VALUES}")
+message("XXX : MATERIALX_BUILD_EXPAND_TEMPLATE_ELEMS : ${MATERIALX_BUILD_EXPAND_TEMPLATE_ELEMS}")
+message("XXX : MATERIALX_BUILD_DATA_LIBRARY : ${MATERIALX_BUILD_DATA_LIBRARY}")
+
# Add core subdirectories
add_subdirectory(source/MaterialXCore)
add_subdirectory(source/MaterialXFormat)
+if (MATERIALX_BUILD_EXPAND_TEMPLATE_ELEMS OR MATERIALX_BUILD_BAKE_NAMED_VALUES)
+ if (CMAKE_CROSSCOMPILING)
+ set(_MaterialXBuildLibrary "${CMAKE_BINARY_DIR}/BUILD_TOOLS/MaterialXBuildLibrary")
+
+ add_custom_command(
+ OUTPUT ${_MaterialXBuildLibrary}
+ COMMAND ${CMAKE_COMMAND}
+ -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+ -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${CMAKE_BINARY_DIR}/BUILD_TOOLS
+ -DMATERIALX_MAJOR_VERSION=${MATERIALX_MAJOR_VERSION}
+ -DMATERIALX_MINOR_VERSION=${MATERIALX_MINOR_VERSION}
+ -DMATERIALX_BUILD_VERSION=${MATERIALX_BUILD_VERSION}
+ -DMATERIALX_NAMESPACE=${MATERIALX_NAMESPACE}
+ -DMATERIALX_BUILD_BAKE_NAMED_VALUES=ON
+ -B"BUILD_TOOLS"
+ -H"${CMAKE_SOURCE_DIR}/source/MaterialXBuildTools"
+ COMMAND ${CMAKE_COMMAND} --build BUILD_TOOLS
+ DEPENDS MaterialXCore MaterialXFormat
+ )
+ add_custom_target(MaterialXBuildLibrary ALL
+ DEPENDS ${_MaterialXBuildLibrary})
+ else()
+ set(_MaterialXBuildLibrary MaterialXBuildLibrary)
+ add_subdirectory(source/MaterialXBuildTools/buildLibrary)
+ endif()
+endif()
# Add shader generation subdirectories
add_subdirectory(source/MaterialXGenShader)
diff --git a/cmake/macros/Public.cmake b/cmake/macros/Public.cmake
new file mode 100644
index 0000000000..79d93e3266
--- /dev/null
+++ b/cmake/macros/Public.cmake
@@ -0,0 +1,126 @@
+# Shared functions need to be extracted to allow them to be shared with the subproject
+# in source/MaterialXBuildTools
+
+function(assign_source_group prefix)
+ foreach(_source IN ITEMS ${ARGN})
+ if(IS_ABSOLUTE "${_source}")
+ file(RELATIVE_PATH _source_rel "${CMAKE_CURRENT_SOURCE_DIR}" "${_source}")
+ else()
+ set(_source_rel "${_source}")
+ endif()
+ get_filename_component(_source_path "${_source_rel}" PATH)
+ string(REPLACE "/" "\\" _source_path_msvc "${_source_path}")
+ source_group("${prefix}\\${_source_path_msvc}" FILES "${_source}")
+ endforeach()
+endfunction(assign_source_group)
+
+function(mx_add_library MATERIALX_MODULE_NAME)
+ set(options ADD_OBJECTIVE_C_CODE)
+ set(oneValueArgs EXPORT_DEFINE)
+ set(multiValueArgs
+ SOURCE_FILES
+ HEADER_FILES
+ INLINED_FILES
+ MTLX_MODULES)
+ cmake_parse_arguments(args
+ "${options}"
+ "${oneValueArgs}"
+ "${multiValueArgs}"
+ ${ARGN})
+
+ if (APPLE AND args_ADD_OBJECTIVE_C_CODE)
+ file(GLOB_RECURSE materialx_source_oc "${CMAKE_CURRENT_SOURCE_DIR}/*.m*")
+ set_source_files_properties(${materialx_source_oc} PROPERTIES
+ COMPILE_FLAGS "-x objective-c++")
+ set(args_SOURCE_FILES ${args_SOURCE_FILES} ${materialx_source_oc})
+ endif()
+
+ assign_source_group("Source Files" ${args_SOURCE_FILES})
+ assign_source_group("Source Files" ${args_INLINED_FILES})
+ assign_source_group("Header Files" ${args_HEADER_FILES})
+
+ if (NOT MATERIALX_BUILD_MONOLITHIC)
+ set(TARGET_NAME ${MATERIALX_MODULE_NAME})
+ add_library(${TARGET_NAME})
+
+ # Create version resource
+ if(MATERIALX_BUILD_SHARED_LIBS AND MSVC)
+ configure_file(${PROJECT_SOURCE_DIR}/cmake/modules/MaterialXVersion.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
+ target_sources(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
+ endif()
+
+ target_link_libraries(${TARGET_NAME}
+ PUBLIC
+ ${args_MTLX_MODULES}
+ ${CMAKE_DL_LIBS})
+
+ target_include_directories(${TARGET_NAME}
+ PUBLIC
+ $
+ $
+ PRIVATE
+ ${EXTERNAL_INCLUDE_DIRS})
+
+ set_target_properties(
+ ${TARGET_NAME} PROPERTIES
+ OUTPUT_NAME ${MATERIALX_MODULE_NAME}${MATERIALX_LIBNAME_SUFFIX}
+ COMPILE_FLAGS "${EXTERNAL_COMPILE_FLAGS}"
+ LINK_FLAGS "${EXTERNAL_LINK_FLAGS}"
+ INSTALL_RPATH "${MATERIALX_SAME_DIR_RPATH}"
+ VERSION "${MATERIALX_LIBRARY_VERSION}"
+ SOVERSION "${MATERIALX_MAJOR_VERSION}")
+ else()
+ set(TARGET_NAME ${MATERIALX_MONOLITHIC_TARGET})
+ add_library(${MATERIALX_MODULE_NAME} ALIAS ${MATERIALX_MONOLITHIC_TARGET})
+
+ # Store the aliased MaterialX modules name to create CMake export aliases later.
+ set_property(GLOBAL APPEND PROPERTY MATERIALX_MODULES ${MATERIALX_MODULE_NAME})
+ endif()
+
+ set_target_properties(${TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden)
+ set_target_properties(${TARGET_NAME} PROPERTIES CMAKE_VISIBILITY_INLINES_HIDDEN 1)
+
+ target_sources(${TARGET_NAME}
+ PRIVATE
+ ${args_SOURCE_FILES}
+ PUBLIC
+ FILE_SET
+ mxHeaders
+ TYPE
+ HEADERS
+ BASE_DIRS
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${CMAKE_CURRENT_BINARY_DIR}/..
+ FILES
+ ${args_HEADER_FILES}
+ ${args_INLINED_FILES})
+
+ target_include_directories(${TARGET_NAME} PUBLIC
+ $)
+
+ target_compile_definitions(${TARGET_NAME} PRIVATE "-D${args_EXPORT_DEFINE}")
+
+ if(NOT SKBUILD)
+ if(NOT MATERIALX_BUILD_MONOLITHIC)
+ install(TARGETS ${MATERIALX_MODULE_NAME}
+ EXPORT MaterialX
+ ARCHIVE DESTINATION ${MATERIALX_INSTALL_LIB_PATH}
+ LIBRARY DESTINATION ${MATERIALX_INSTALL_LIB_PATH}
+ RUNTIME DESTINATION ${MATERIALX_INSTALL_BIN_PATH}
+ FILE_SET mxHeaders DESTINATION ${MATERIALX_INSTALL_INCLUDE_PATH})
+ endif()
+
+ if(MSVC)
+ if(MATERIALX_BUILD_SHARED_LIBS)
+ install(FILES $
+ DESTINATION ${MATERIALX_INSTALL_BIN_PATH} OPTIONAL)
+ else()
+ install(FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/$/$.pdb"
+ DESTINATION ${MATERIALX_INSTALL_LIB_PATH} OPTIONAL)
+ endif()
+ endif()
+ endif()
+
+ # Pass TARGET_NAME back to call site, so the caller can modify the build target.
+ set(TARGET_NAME ${TARGET_NAME} PARENT_SCOPE)
+endfunction()
diff --git a/javascript/MaterialXTest/xmlIo.spec.js b/javascript/MaterialXTest/xmlIo.spec.js
index 670b0df43d..591459d472 100644
--- a/javascript/MaterialXTest/xmlIo.spec.js
+++ b/javascript/MaterialXTest/xmlIo.spec.js
@@ -10,7 +10,7 @@ describe('XmlIo', () =>
// These should be relative to cwd
const includeTestPath = 'data/includes';
- const libraryPath = '../../libraries/stdlib';
+ const libraryPath = '../build/libraries/DataLibraryBuild/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.
diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt
index cc8139aef3..af2decab62 100644
--- a/libraries/CMakeLists.txt
+++ b/libraries/CMakeLists.txt
@@ -1,3 +1,4 @@
+
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
@@ -5,17 +6,54 @@ if(MATERIALX_BUILD_DATA_LIBRARY)
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)
-
- foreach(SOURCE_FILE IN LISTS MATERIALX_DATA_LIBRARY_SOURCE_FILES)
+ file(GLOB_RECURSE MATERIALX_DATA_LIBRARY_MTLX_SOURCE_FILES
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ LIST_DIRECTORIES false
+ *.mtlx)
+
+ file(GLOB_RECURSE MATERIALX_DATA_LIBRARY_SHADER_SOURCE_FILES
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ LIST_DIRECTORIES false
+ *.md
+ *.glsl
+ *.osl
+ *.h
+ *.metal)
+
+ if (MATERIALX_BUILD_EXPAND_TEMPLATE_ELEMS OR MATERIALX_BUILD_BAKE_NAMED_VALUES)
+ foreach(SOURCE_FILE IN LISTS MATERIALX_DATA_LIBRARY_MTLX_SOURCE_FILES)
+ set(DEST_FILEPATH ${DATA_LIBRARY_BUILD_DIR}/${SOURCE_FILE})
+ list(APPEND MATERIALX_DATA_LIBRARY_MTLX_BUILD_FILES ${DEST_FILEPATH})
+ endforeach()
+
+ if (MATERIALX_BUILD_EXPAND_TEMPLATE_ELEMS)
+ set(EXPAND_TEMPLATE_ELEMS_ARG "--expandTemplateElems")
+ endif()
+ if (MATERIALX_BUILD_BAKE_NAMED_VALUES)
+ set(BAKE_NAMED_VALUES_ARG "--bakeNamedValues")
+ endif()
+
+ add_custom_command(
+ OUTPUT ${MATERIALX_DATA_LIBRARY_MTLX_BUILD_FILES}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${DATA_LIBRARY_BUILD_DIR}
+ COMMAND ${_MaterialXBuildLibrary} --sourceLibraryRoot ${CMAKE_CURRENT_SOURCE_DIR} --destLibraryRoot ${DATA_LIBRARY_BUILD_DIR} ${EXPAND_TEMPLATE_ELEMS_ARG} ${BAKE_NAMED_VALUES_ARG}
+ DEPENDS ${MATERIALX_DATA_LIBRARY_MTLX_SOURCE_FILES} MaterialXBuildLibrary
+ )
+
+ list(APPEND MATERIALX_DATA_LIBRARY_BUILD_FILES ${MATERIALX_DATA_LIBRARY_MTLX_BUILD_FILES})
+ else()
+ foreach(SOURCE_FILE IN LISTS MATERIALX_DATA_LIBRARY_MTLX_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()
+ endif()
+
+ foreach(SOURCE_FILE IN LISTS MATERIALX_DATA_LIBRARY_SHADER_SOURCE_FILES)
set(SOURCE_FILEPATH ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE})
set(DEST_FILEPATH ${DATA_LIBRARY_BUILD_DIR}/${SOURCE_FILE})
add_custom_command(
diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx
index d99125b635..f4442bc1d5 100644
--- a/libraries/stdlib/stdlib_defs.mtlx
+++ b/libraries/stdlib/stdlib_defs.mtlx
@@ -11,23 +11,23 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
@@ -123,174 +123,43 @@
Node:
Samples data from a single image, or from a layer within a multi-layer image.
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -466,54 +233,26 @@
A constant value. When exposed as a public parameter, this is a way to create a
value that can be accessed in multiple places in the opgraph.
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
-
-
-
+
+
+
-
+
+
+
-
-
-
+
+
+
-
+
+
+
-
-
-
+
+
+
-
+
+
+
-
-
-
+
+
+
-
+
+
+
+
+
-
-
-
+
+
+
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
-
-
-
-
-
+
+
+
-
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ Node:
+ Take one 1-4 channel input "in" plus a separate float "mask" input and apply the same
+ operator to all channels: in * (1-mask)
+ -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/libraries/stdlib/stdlib_ng.mtlx b/libraries/stdlib/stdlib_ng.mtlx
index 08025aedd2..53b1064e15 100644
--- a/libraries/stdlib/stdlib_ng.mtlx
+++ b/libraries/stdlib/stdlib_ng.mtlx
@@ -3582,193 +3582,45 @@
Raise incoming half/float/color/vector values to the "in2" power.
Negative "in1" values will result in negative output values. ie. out = sign(in1)*pow(abs(in1),in2)
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/python/MaterialXTest/main.py b/python/MaterialXTest/main.py
index 7f878b3d28..a2ed00ad5e 100644
--- a/python/MaterialXTest/main.py
+++ b/python/MaterialXTest/main.py
@@ -25,8 +25,9 @@
[1.0, 2.0, 3.0],
['one', 'two', 'three'])
+_defaultSearchPath = mx.getDefaultDataSearchPath().asString()
_fileDir = os.path.dirname(os.path.abspath(__file__))
-_libraryDir = os.path.join(_fileDir, '../../libraries/stdlib/')
+_libraryDir = os.path.join(_defaultSearchPath, 'libraries/stdlib/')
_exampleDir = os.path.join(_fileDir, '../../resources/Materials/Examples/')
_searchPath = _libraryDir + mx.PATH_LIST_SEPARATOR + _exampleDir
diff --git a/source/JsMaterialX/CMakeLists.txt b/source/JsMaterialX/CMakeLists.txt
index aaadafda74..242dcdd559 100644
--- a/source/JsMaterialX/CMakeLists.txt
+++ b/source/JsMaterialX/CMakeLists.txt
@@ -87,7 +87,7 @@ else()
endif()
-set(JS_LINK_FLAGS_GENSHADER "${JS_LINK_FLAGS_CORE} --preload-file ${PROJECT_SOURCE_DIR}/libraries@libraries ")
+set(JS_LINK_FLAGS_GENSHADER "${JS_LINK_FLAGS_CORE} --preload-file ${PROJECT_BINARY_DIR}/libraries/DataLibraryBuild@libraries ")
add_executable(JsMaterialXCore MaterialXLib.cpp
${CORE_DEPS}
@@ -132,6 +132,8 @@ set_target_properties(JsMaterialXGenShader
INSTALL_RPATH "${MATERIALX_UP_TWO_RPATH}"
SOVERSION "${MATERIALX_MAJOR_VERSION}")
+add_dependencies(JsMaterialXGenShader MaterialXBuildData)
+
target_link_libraries(JsMaterialXCore
PUBLIC MaterialXCore
PUBLIC MaterialXFormat
diff --git a/source/MaterialXBuildTools/CMakeLists.txt b/source/MaterialXBuildTools/CMakeLists.txt
new file mode 100644
index 0000000000..dbab900ece
--- /dev/null
+++ b/source/MaterialXBuildTools/CMakeLists.txt
@@ -0,0 +1,19 @@
+# This subproject is necessary to support building the build tools on the host machine
+# where they may be used when cross compiling for another target
+
+cmake_minimum_required(VERSION 3.26)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
+set(CMAKE_MACOSX_RPATH ON)
+
+project(MaterialXBuildTools)
+
+list(APPEND CMAKE_MODULE_PATH
+ ${PROJECT_SOURCE_DIR}/../../cmake/macros)
+
+include(Public)
+
+add_subdirectory(../MaterialXCore MaterialXCore)
+add_subdirectory(../MaterialXFormat MaterialXFormat)
+
+add_subdirectory(buildLibrary)
diff --git a/source/MaterialXBuildTools/buildLibrary/CMakeLists.txt b/source/MaterialXBuildTools/buildLibrary/CMakeLists.txt
new file mode 100644
index 0000000000..bc7183aa3c
--- /dev/null
+++ b/source/MaterialXBuildTools/buildLibrary/CMakeLists.txt
@@ -0,0 +1,10 @@
+set(TARGET_NAME MaterialXBuildLibrary)
+
+file(GLOB materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
+file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*")
+
+add_executable(${TARGET_NAME} ${materialx_source} ${materialx_headers})
+
+target_link_libraries(${TARGET_NAME} PRIVATE
+ MaterialXFormat
+ MaterialXCore)
diff --git a/source/MaterialXBuildTools/buildLibrary/Main.cpp b/source/MaterialXBuildTools/buildLibrary/Main.cpp
new file mode 100644
index 0000000000..9b7d5570af
--- /dev/null
+++ b/source/MaterialXBuildTools/buildLibrary/Main.cpp
@@ -0,0 +1,199 @@
+//
+// Copyright Contributors to the MaterialX Project
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include
+#include
+#include
+#include
+#include
+
+namespace mx = MaterialX;
+
+#include
+
+const std::string cmdLineOptions =
+ " Options: \n"
+ " --sourceLibraryRoot [FILEPATH] Directory containing the source data library files.\n"
+ " --destLibraryRoot [FILEPATH] Directory to write the modified data library files.\n"
+ " --help Display the complete list of command-line options\n";
+
+template void parseToken(std::string token, std::string type, T& res)
+{
+ if (token.empty())
+ {
+ return;
+ }
+
+ mx::ValuePtr value = mx::Value::createValueFromStrings(token, type);
+ if (!value)
+ {
+ std::cout << "Unable to parse token " << token << " as type " << type << std::endl;
+ return;
+ }
+
+ res = value->asA();
+}
+
+mx::FilePathVec getMaterialXFiles(const mx::FilePath& libraryRoot)
+{
+ mx::FilePathVec result;
+
+ auto subDirs = libraryRoot.getSubDirectories();
+ for (const auto& subDir : subDirs)
+ {
+ for (const auto& file : subDir.getFilesInDirectory("mtlx"))
+ {
+ auto absFile = subDir / file;
+ std::string absFileStr = absFile.asString();
+ std::string relFileStr = absFileStr.substr(libraryRoot.asString().size()+1);
+ result.emplace_back(mx::FilePath(relFileStr));
+ }
+ }
+ return result;
+}
+
+void replaceNamedValues(mx::DocumentPtr doc, mx::ConstDocumentPtr stdlib)
+{
+ const std::string typeValuePrefix = "Value:";
+
+ // replace named value "Value:" strings with concrete values
+ for (auto elem : doc->traverseTree())
+ {
+ auto port = elem->asA();
+ if (!port)
+ {
+ continue;
+ }
+
+ mx::StringVec const& attributeNames = port->getAttributeNames();
+ for (std::string const& attrName: attributeNames) {
+ std::string const& valueStr = port->getAttribute(attrName);
+
+ if (mx::stringStartsWith(valueStr, typeValuePrefix))
+ {
+ auto typeDef = stdlib->getTypeDef(port->getType());
+ if (!typeDef)
+ {
+ throw mx::Exception("Unable to find typeDef '"+port->getType()+"'");
+ }
+
+ auto valueNameStr = valueStr.substr(typeValuePrefix.size());
+ if (!typeDef->hasAttribute(valueNameStr))
+ {
+ throw mx::Exception("Unable to find named value '"+valueNameStr+"' for type '"+typeDef->getName()+"'");
+ }
+
+ port->setAttribute(attrName, typeDef->getAttribute(valueNameStr));
+ }
+ }
+ }
+}
+
+int main(int argc, char* const argv[])
+{
+ std::vector tokens;
+ for (int i = 1; i < argc; i++)
+ {
+ tokens.emplace_back(argv[i]);
+ }
+
+ std::string sourceLibraryRootStr = "";
+ std::string destLibraryRootStr = "";
+ bool bakeNamedValues = false;
+ bool expandTemplateElems = false;
+
+ for (size_t i = 0; i < tokens.size(); i++)
+ {
+ const std::string& token = tokens[i];
+ const std::string& nextToken = i + 1 < tokens.size() ? tokens[i + 1] : mx::EMPTY_STRING;
+
+ if (token == "--sourceLibraryRoot")
+ {
+ sourceLibraryRootStr = nextToken;
+ }
+ else if (token == "--destLibraryRoot")
+ {
+ destLibraryRootStr = nextToken;
+ }
+ else if (token == "--bakeNamedValues")
+ {
+ bakeNamedValues = true;
+ continue;
+ }
+ else if (token == "--expandTemplateElems")
+ {
+ expandTemplateElems = true;
+ continue;
+ }
+ else if (token == "--help")
+ {
+ std::cout << " MaterialXBuildLibrary version " << mx::getVersionString() << std::endl;
+ std::cout << cmdLineOptions << std::endl;
+ return 0;
+ }
+ else
+ {
+ std::cout << "Unrecognized command-line option: " << token << std::endl;
+ std::cout << "Launch the viewer with '--help' for a complete list of supported options." << std::endl;
+ continue;
+ }
+
+ if (nextToken.empty())
+ {
+ std::cout << "Expected another token following command-line option: " << token << std::endl;
+ }
+ else
+ {
+ i++;
+ }
+ }
+
+ mx::FilePath sourceLibraryRoot = mx::FilePath(sourceLibraryRootStr);
+ mx::FilePath destLibrarayRoot = mx::FilePath(destLibraryRootStr);
+
+ if (!sourceLibraryRoot.isDirectory())
+ {
+ std::cerr << "Source Library Root is not a directory" << std::endl;
+ return 1;
+ }
+
+ if (!destLibrarayRoot.isDirectory())
+ {
+ std::cerr << "Destination Library Root is not a directory" << std::endl;
+ return 1;
+ }
+
+ mx::DocumentPtr stdlib = mx::createDocument();
+ mx::loadLibraries({}, mx::FileSearchPath(sourceLibraryRootStr), stdlib);
+
+ mx::FilePathVec mtlxFiles = getMaterialXFiles(sourceLibraryRoot);
+
+ mx::XmlReadOptions readOptions;
+ readOptions.readComments = true;
+ readOptions.readNewlines = true;
+ readOptions.expandTemplateElems = expandTemplateElems;
+
+ mx::XmlWriteOptions writeOptions;
+ writeOptions.createDirectories = true;
+
+ for (const auto& mtlxFile : mtlxFiles)
+ {
+ mx::DocumentPtr doc = mx::createDocument();
+
+ mx::FilePath sourceFile = sourceLibraryRoot / mtlxFile;
+ mx::FilePath destFile = destLibrarayRoot / mtlxFile;
+
+ mx::readFromXmlFile(doc, sourceFile, mx::FileSearchPath(), &readOptions);
+
+ if (bakeNamedValues)
+ {
+ replaceNamedValues(doc, stdlib);
+ }
+
+ mx::writeToXmlFile(doc, destFile, &writeOptions);
+ }
+
+ return 0;
+}
diff --git a/source/MaterialXCore/CMakeLists.txt b/source/MaterialXCore/CMakeLists.txt
index c3c845afda..53a3b4c7b0 100644
--- a/source/MaterialXCore/CMakeLists.txt
+++ b/source/MaterialXCore/CMakeLists.txt
@@ -15,3 +15,9 @@ mx_add_library(MaterialXCore
target_include_directories(${TARGET_NAME}
PUBLIC
$)
+
+# This define controls if the named "Value:" are dynamically evaluated at runtime
+target_compile_definitions(${TARGET_NAME}
+ PRIVATE
+ MATERIALX_BUILD_BAKE_NAMED_VALUES=$
+)
diff --git a/source/MaterialXCore/Element.cpp b/source/MaterialXCore/Element.cpp
index e36a6fcbdf..595aa0787d 100644
--- a/source/MaterialXCore/Element.cpp
+++ b/source/MaterialXCore/Element.cpp
@@ -644,6 +644,36 @@ TypeDefPtr TypedElement::getTypeDef() const
//
// ValueElement methods
//
+/// Get the value string of a element.
+const string ValueElement::getValueString() const
+{
+#if MATERIALX_BUILD_BAKE_NAMED_VALUES
+ return getAttribute(VALUE_ATTRIBUTE);
+#else
+ const string typeValuePrefix = "Value:";
+
+ auto valueStr = getAttribute(VALUE_ATTRIBUTE);
+ if (!stringStartsWith(valueStr, typeValuePrefix))
+ {
+ return valueStr;
+ }
+
+ auto typeDef = getTypeDef();
+ if (!typeDef)
+ {
+ throw Exception("Unable to find typeDef '"+getType()+"'");
+ }
+
+ auto valueNameStr = valueStr.substr(typeValuePrefix.size());
+ if (!typeDef->hasAttribute(valueNameStr))
+ {
+ throw Exception("Unable to find named value '"+valueNameStr+"' for type '"+typeDef->getName()+"'");
+ }
+
+ return typeDef->getAttribute(valueNameStr);
+#endif
+}
+
string ValueElement::getResolvedValueString(StringResolverPtr resolver) const
{
diff --git a/source/MaterialXCore/Element.h b/source/MaterialXCore/Element.h
index 89f5c87152..7c7125bf0c 100644
--- a/source/MaterialXCore/Element.h
+++ b/source/MaterialXCore/Element.h
@@ -954,10 +954,7 @@ class MX_CORE_API ValueElement : public TypedElement
}
/// Get the value string of a element.
- const string& getValueString() const
- {
- return getAttribute(VALUE_ATTRIBUTE);
- }
+ const string getValueString() const;
/// Return the resolved value string of an element, applying any string
/// substitutions that are defined at the element's scope.
diff --git a/source/MaterialXFormat/XmlIo.cpp b/source/MaterialXFormat/XmlIo.cpp
index 83e4721dc1..5a20f9a896 100644
--- a/source/MaterialXFormat/XmlIo.cpp
+++ b/source/MaterialXFormat/XmlIo.cpp
@@ -167,6 +167,70 @@ void elementFromXml(const xml_node& xmlNode, ElementPtr elem, const XmlReadOptio
}
}
+void recursivelyReplaceStrings(ElementPtr elem, const StringMap& strReplaceMapping)
+{
+ for (const auto& attrName : elem->getAttributeNames())
+ {
+ auto attrValue = elem->getAttribute(attrName);
+ auto newAttrValue = replaceSubstrings(attrValue, strReplaceMapping);
+ elem->setAttribute(attrName, newAttrValue);
+ }
+
+ for (auto childElem : elem->getChildren())
+ {
+ recursivelyReplaceStrings(childElem, strReplaceMapping);
+ }
+}
+
+void expandXMLTemplateElems(DocumentPtr doc)
+{
+ // replace node definitions that use a TypeList
+ for (auto elem : doc->traverseTree())
+ {
+ if (elem->getCategory() != "template")
+ continue;
+
+ if (!elem->hasAttribute("varName")) {
+ // std::cerr << " without 'varName' attribute found" << std::endl;
+ continue;
+ }
+
+ if (!elem->hasAttribute("options")) {
+ // std::cerr << " without 'options' attribute found" << std::endl;
+ continue;
+ }
+
+ const auto typeNameAttr = elem->getAttribute("varName");
+ const auto optionsAttr = elem->getAttribute("options");
+
+ const auto options = splitString(optionsAttr, ARRAY_VALID_SEPARATORS);
+
+ const auto childElems = elem->getChildren();
+
+ auto parentElem = elem->getParent();
+ const auto origIndex = parentElem->getChildIndex(elem->getName());
+
+ for (const auto& childElem : childElems)
+ {
+ auto index = origIndex;
+
+ for (const auto& option : options)
+ {
+ StringMap strReplaceMapping = {{"@"+typeNameAttr+"@", option}};
+
+ string newName = replaceSubstrings(childElem->getName(), strReplaceMapping);
+
+ auto newChildElem = parentElem->addChildOfCategory(childElem->getCategory(), newName);
+ parentElem->setChildIndex(newChildElem->getName(), index++);
+ newChildElem->copyContentFrom(childElem);
+
+ recursivelyReplaceStrings(newChildElem, strReplaceMapping);
+ }
+ parentElem->removeChild(elem->getName());
+ }
+ }
+}
+
void documentFromXml(DocumentPtr doc, const xml_document& xmlDoc, const FileSearchPath& searchPath, const XmlReadOptions* readOptions)
{
xml_node xmlRoot = xmlDoc.child(Document::CATEGORY.c_str());
@@ -211,6 +275,11 @@ void documentFromXml(DocumentPtr doc, const xml_document& xmlDoc, const FileSear
// Build the element tree.
elementFromXml(xmlRoot, doc, readOptions);
+ if (!readOptions || readOptions->expandTemplateElems)
+ {
+ expandXMLTemplateElems(doc);
+ }
+
// Upgrade version if requested.
if (!readOptions || readOptions->upgradeVersion)
{
@@ -268,9 +337,6 @@ unsigned int getParseOptions(const XmlReadOptions* readOptions)
//
XmlReadOptions::XmlReadOptions() :
- readComments(false),
- readNewlines(false),
- upgradeVersion(true),
readXIncludeFunction(readFromXmlFile)
{
}
@@ -279,8 +345,7 @@ XmlReadOptions::XmlReadOptions() :
// XmlWriteOptions methods
//
-XmlWriteOptions::XmlWriteOptions() :
- writeXIncludeEnable(true)
+XmlWriteOptions::XmlWriteOptions()
{
}
@@ -355,6 +420,13 @@ void writeToXmlStream(DocumentPtr doc, std::ostream& stream, const XmlWriteOptio
void writeToXmlFile(DocumentPtr doc, const FilePath& filename, const XmlWriteOptions* writeOptions)
{
+ if (writeOptions && writeOptions->createDirectories)
+ {
+ if (!filename.getParentPath().isDirectory())
+ {
+ filename.getParentPath().createDirectory();
+ }
+ }
std::ofstream ofs(filename.asString());
writeToXmlStream(doc, ofs, writeOptions);
}
diff --git a/source/MaterialXFormat/XmlIo.h b/source/MaterialXFormat/XmlIo.h
index 5c80ae8005..f971043730 100644
--- a/source/MaterialXFormat/XmlIo.h
+++ b/source/MaterialXFormat/XmlIo.h
@@ -39,15 +39,15 @@ class MX_FORMAT_API XmlReadOptions
/// If true, then XML comments will be read into documents as comment elements.
/// Defaults to false.
- bool readComments;
+ bool readComments = false;
/// If true, then XML newlines will be read into documents as newline elements.
/// Defaults to false.
- bool readNewlines;
+ bool readNewlines = false;
/// If true, then documents from earlier versions of MaterialX will be upgraded
/// to the current version. Defaults to true.
- bool upgradeVersion;
+ bool upgradeVersion = true;
/// If provided, this function will be invoked when an XInclude reference
/// needs to be read into a document. Defaults to readFromXmlFile.
@@ -56,6 +56,9 @@ class MX_FORMAT_API XmlReadOptions
/// The vector of parent XIncludes at the scope of the current document.
/// Defaults to an empty vector.
StringVec parentXIncludes;
+
+ /// Expand any tags present in the document
+ bool expandTemplateElems = true;
};
/// @class XmlWriteOptions
@@ -68,11 +71,15 @@ class MX_FORMAT_API XmlWriteOptions
/// If true, elements with source file markings will be written as
/// XIncludes rather than explicit data. Defaults to true.
- bool writeXIncludeEnable;
+ bool writeXIncludeEnable = true;
/// If provided, this function will be used to exclude specific elements
/// (those returning false) from the write operation. Defaults to nullptr.
ElementPredicate elementPredicate;
+
+ /// If true, any necessary directories will be created to write the
+ /// file.
+ bool createDirectories = false;
};
/// @class ExceptionParseError