diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c11603dd70..3f67667550 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -68,10 +68,10 @@ jobs: cmake_config: -DMATERIALX_BUILD_SHARED_LIBS=ON python: 3.9 - - name: MacOS_Xcode_14_Python311 + - name: MacOS_Xcode_15_Python311 os: macos-14 compiler: xcode - compiler_version: "14.3" + compiler_version: "15.1" python: 3.11 static_analysis: ON cmake_config: -DCMAKE_EXPORT_COMPILE_COMMANDS=ON @@ -389,7 +389,7 @@ jobs: fail-fast: false matrix: python-minor: ['7', '8', '9', '10', '11', '12'] - os: ['ubuntu-22.04', 'windows-2022', 'macos-13'] + os: ['ubuntu-22.04', 'windows-2022', 'macos-14-large'] steps: - name: Sync Repository diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fedc1ceaa..6fb0c98143 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ ## [1.39.2] - Development +### Added +- Added support for the [Chiang Hair BSDF](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1968), with initial implementations in hardware shading languages and MDL. +- Added support for the [Disney Principled](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2004) shading model, implemented as a language-independent graph. +- Added support for [data library referencing](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2054), enabling improved performance in shader generation. +- Added support for [custom structure types](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1831) in MaterialX. +- Added support for [functional equivalence](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2003) tests between MaterialX elements. +- Added support for [transmission effects](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2027) in the translation graph from Standard Surface to glTF PBR. +- Added support for [coated emission](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2087) in the translation graph from Standard Surface to UsdPreviewSurface. +- Added support for [Apple framework builds](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2020). +- Added support for [MDL 1.9](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2102) in shader generation. +- Added support for [viewdirection space](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2036) in hardware shading languages. +- Added a [combined version define](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2031) to MaterialX C++. +- Added a [release signing workflow](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2009) to GitHub Actions. +- Added documentation for [keyboard shortcuts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2026) in the MaterialX Viewer. + +### Changed +- Reduced duplication between the [MSL and GLSL implementations](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2068) of nodes. + +### Fixed +- Fixed [unintentional camera orbiting](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2032) in the render view of the MaterialX Graph Editor. +- Fixed [banding artifacts](https://github.com/AcademySoftwareFoundation/MaterialX/pull/1977) in the MaterialX Viewer on MacOS. +- Fixed a call to the [anisotropic_vdf closure](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2016) in OSL shader generation. + +### Removed +- Removed support for the [legacy OSL closures](https://github.com/AcademySoftwareFoundation/MaterialX/pull/2121), focusing exclusively on the MaterialX-synchronized closures in OSL 1.12 and beyond. + ## [1.39.1] - 2024-09-03 ### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index 31db83e8fe..569cceeebd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,6 @@ option(MATERIALX_TEST_RENDER "Run rendering tests for MaterialX Render module. G option(MATERIALX_WARNINGS_AS_ERRORS "Interpret all compiler warnings as errors." OFF) option(MATERIALX_COVERAGE_ANALYSIS "Build MaterialX libraries with coverage analysis on supporting platforms." OFF) option(MATERIALX_DYNAMIC_ANALYSIS "Build MaterialX libraries with dynamic analysis on supporting platforms." OFF) -option(MATERIALX_OSL_LEGACY_CLOSURES "Build OSL shader generation supporting the legacy OSL closures." OFF) option(MATERIALX_BUILD_IOS "Build MaterialX for iOS. (Deprecated. Set CMAKE_SYSTEM_NAME instead)" OFF) option(MATERIALX_BUILD_APPLE_FRAMEWORK "Build MaterialX as an Apple Framework" ${__build_apple_framework}) @@ -180,7 +179,6 @@ mark_as_advanced(MATERIALX_PYTHON_EXECUTABLE) mark_as_advanced(MATERIALX_PYTHON_OCIO_DIR) mark_as_advanced(MATERIALX_PYTHON_PYBIND11_DIR) mark_as_advanced(MATERIALX_OIIO_DIR) -mark_as_advanced(MATERIALX_OSL_LEGACY_CLOSURES) mark_as_advanced(MATERIALX_OSL_BINARY_OSLC) mark_as_advanced(MATERIALX_OSL_BINARY_TESTRENDER) mark_as_advanced(MATERIALX_OSL_INCLUDE_PATH) @@ -227,9 +225,6 @@ if(MATERIALX_BUILD_RENDER AND MATERIALX_BUILD_GEN_OSL AND MATERIALX_BUILD_TESTS) endif() # Add global definitions -if (MATERIALX_OSL_LEGACY_CLOSURES) - add_definitions(-DMATERIALX_OSL_LEGACY_CLOSURES) -endif() if(MATERIALX_BUILD_OIIO) add_definitions(-DMATERIALX_BUILD_OIIO) endif() diff --git a/documents/Specification/MaterialX.Proposals.md b/documents/Specification/MaterialX.Proposals.md index 86c165128e..1aaa930923 100644 --- a/documents/Specification/MaterialX.Proposals.md +++ b/documents/Specification/MaterialX.Proposals.md @@ -188,7 +188,25 @@ We have a standard 3d fractal noise, but a 2d variant would be useful as well. * `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 diff --git a/documents/Specification/MaterialX.Specification.md b/documents/Specification/MaterialX.Specification.md index df4f561978..4ad29dc963 100644 --- a/documents/Specification/MaterialX.Specification.md +++ b/documents/Specification/MaterialX.Specification.md @@ -887,16 +887,12 @@ Standard Noise nodes: * **`worleynoise2d`**: 2D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). - * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for texture coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. * `texcoord` (vector2): the 2D position at which the noise is evaluated. Default is to use the first set of texture coordinates. * **`worleynoise3d`**: 3D Worley noise using centered jitter, outputting float (distance metric to closest feature), vector2 (distance metrics to closest 2 features) or vector3 (distance metrics to closest 3 features). - * `metric` (uniform string): the distance metric to return, one of "distance" (Euclidean distance to feature), "distance2" (Euclidean distance squared), "manhattan" or "chebyshev". Default is "distance". - * `period` (float or vector3): the positive integer distance at which the noise function returns the same value for position coordinates repeated at that step. Default is 0, meaning the noise is not periodic. * `jitter` (float): amount to jitter the cell center position, with smaller values creating a more regular pattern. Default is 1.0. * `position` (vector3): the 3D position at which the noise is evaluated. Default is to use the current 3D object-space coordinate. diff --git a/javascript/MaterialXView/source/viewer.js b/javascript/MaterialXView/source/viewer.js index febe34c809..e558ad0bc9 100644 --- a/javascript/MaterialXView/source/viewer.js +++ b/javascript/MaterialXView/source/viewer.js @@ -90,14 +90,14 @@ export class Scene } this.#_rootNode = null; - const model = gltfData.scene; + let model = gltfData.scene; if (!model) { const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshBasicMaterial({ color: 0xdddddd }); const cube = new THREE.Mesh(geometry, material); - obj = new Group(); - obj.add(geometry); + model = new Group(); + model.add(cube); } else { diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index d60a54cf3b..6852090932 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -1,15 +1,9 @@ -if (MATERIALX_OSL_LEGACY_CLOSURES) - set(PBRLIB_SUFFIX "legacy") -else() - set(PBRLIB_SUFFIX "mtlx") -endif() - if(NOT SKBUILD) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}" PATTERN "CMakeLists.txt" EXCLUDE PATTERN "pbrlib_genosl_impl.*" EXCLUDE) - install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.${PBRLIB_SUFFIX}" + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.mtlx" DESTINATION "${MATERIALX_INSTALL_STDLIB_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) endif() @@ -23,6 +17,6 @@ if(MATERIALX_BUILD_PYTHON) DESTINATION "${MATERIALX_PYTHON_LIBRARIES_PATH}" PATTERN "CMakeLists.txt" EXCLUDE PATTERN "pbrlib_genosl_impl.*" EXCLUDE) - install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.${PBRLIB_SUFFIX}" + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pbrlib/genosl/pbrlib_genosl_impl.mtlx" DESTINATION "${MATERIALX_PYTHON_LIBRARIES_PATH}/pbrlib/genosl/" RENAME pbrlib_genosl_impl.mtlx) endif() diff --git a/libraries/README.md b/libraries/README.md index 15916f76e2..0ace221bcc 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -74,7 +74,4 @@ This folder contains the standard data libraries for MaterialX, providing declar - Basic GLSL and MSL `lightshader` node definitions and implementations are provided for the following light types: - point, directional, spot - Shader generation does not currently support: - - `ambientocclusion` node. - - `arrayappend` node. - - `curveadjust` node. - `displacementshader` and `volumeshader` nodes for hardware shading targets (GLSL, MSL). diff --git a/libraries/bxdf/translation/standard_surface_to_usd.mtlx b/libraries/bxdf/translation/standard_surface_to_usd.mtlx index 51c7d5fc6e..f1009e3a4c 100644 --- a/libraries/bxdf/translation/standard_surface_to_usd.mtlx +++ b/libraries/bxdf/translation/standard_surface_to_usd.mtlx @@ -12,6 +12,8 @@ + + @@ -47,13 +49,18 @@ + + + + + - + diff --git a/libraries/bxdf/usd_preview_surface.mtlx b/libraries/bxdf/usd_preview_surface.mtlx index 62600842cc..afc6954af9 100644 --- a/libraries/bxdf/usd_preview_surface.mtlx +++ b/libraries/bxdf/usd_preview_surface.mtlx @@ -6,21 +6,21 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx index c8f23958ae..45f83f164a 100644 --- a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx +++ b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx @@ -2,7 +2,7 @@ - + @@ -11,13 +11,13 @@ - + - + diff --git a/libraries/pbrlib/genosl/legacy/mx_anisotropic_vdf.osl b/libraries/pbrlib/genosl/legacy/mx_anisotropic_vdf.osl deleted file mode 100644 index 6d52e08509..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_anisotropic_vdf.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_anisotropic_vdf(vector absorption, vector scattering, float anisotropy, output VDF vdf) -{ - // Not implemented in vanilla OSL - vdf = 0; // volume_henyey_greenstein(color(absorption), color(scattering), color(0.0), anisotropy); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_burley_diffuse_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_burley_diffuse_bsdf.osl deleted file mode 100644 index 5f7d397dce..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_burley_diffuse_bsdf.osl +++ /dev/null @@ -1,6 +0,0 @@ -void mx_burley_diffuse_bsdf(float weight, color reflectance, float roughness, normal N, output BSDF bsdf) -{ - // TODO: Implement properly. - bsdf.response = reflectance * weight * oren_nayar(N, roughness); - bsdf.throughput = color(0.0); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl deleted file mode 100644 index 82cb6f32be..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_conductor_bsdf.osl +++ /dev/null @@ -1,32 +0,0 @@ -#include "../lib/mx_microfacet_specular.osl" - -void mx_conductor_bsdf(float weight, color ior_n, color ior_k, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, output BSDF bsdf) -{ - bsdf.throughput = color(0.0); - - if (weight < M_FLOAT_EPS) - { - bsdf.response = 0; - return; - } - - // Calculate conductor fresnel - // - // Fresnel should be based on microfacet normal - // but we have no access to that from here, so just use - // view direction and surface normal instead - // - float NdotV = fabs(dot(N,-I)); - color F = mx_fresnel_conductor(NdotV, ior_n, ior_k); - - // Calculate compensation for multiple scattering. - // This should normally be done inside the closure - // but since vanilla OSL doesen't support this we - // add it here in shader code instead. - vector2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); - float avgAlpha = mx_average_alpha(safeAlpha); - color comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - - // Set ior to 0.0 to disable the internal dielectric fresnel - bsdf.response = F * comp * weight * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, 0.0, false); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl deleted file mode 100644 index 5e50834746..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_dielectric_bsdf.osl +++ /dev/null @@ -1,36 +0,0 @@ -#include "../lib/mx_microfacet_specular.osl" - -void mx_dielectric_bsdf(float weight, color tint, float ior, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) -{ - if (scatter_mode == "T") - { - bsdf.response = tint * weight * microfacet(distribution, N, U, roughness.x, roughness.y, ior, 1); - bsdf.throughput = tint * weight; - return; - } - - float NdotV = clamp(dot(N,-I), M_FLOAT_EPS, 1.0); - float F0 = mx_ior_to_f0(ior); - float F = mx_fresnel_schlick(NdotV, F0); - - // Calculate compensation for multiple scattering. - // This should normally be done inside the closure - // but since vanilla OSL doesen't support this we - // add it here in shader code instead. - vector2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); - float avgAlpha = mx_average_alpha(safeAlpha); - float comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - - // Calculate throughput from directional albedo. - float dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, ior) * comp; - bsdf.throughput = 1.0 - dirAlbedo * weight; - - if (scatter_mode == "R") - { - bsdf.response = tint * weight * comp * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, ior, 0); - } - else - { - bsdf.response = tint * weight * comp * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, ior, 2); - } -} diff --git a/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl deleted file mode 100644 index cd022f8295..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_generalized_schlick_bsdf.osl +++ /dev/null @@ -1,38 +0,0 @@ -#include "../lib/mx_microfacet_specular.osl" - -void mx_generalized_schlick_bsdf(float weight, color color0, color color82, color color90, float exponent, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf) -{ - float avgF0 = dot(color0, color(1.0 / 3.0)); - float ior = mx_f0_to_ior(avgF0); - - if (scatter_mode == "T") - { - bsdf.response = weight * microfacet(distribution, N, U, roughness.x, roughness.y, ior, 1); - bsdf.throughput = weight; - return; - } - - float NdotV = fabs(dot(N,-I)); - color F = mx_fresnel_schlick(NdotV, color0, color90, exponent); - - // Calculate compensation for multiple scattering. - // This should normally be done inside the closure - // but since vanilla OSL doesen't support this we - // add it here in shader code instead. - vector2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); - float avgAlpha = mx_average_alpha(safeAlpha); - color comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); - - // Calculate throughput from directional albedo. - color dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, color0, color90) * comp; - float avgDirAlbedo = dot(dirAlbedo, color(1.0 / 3.0)); - bsdf.throughput = 1.0 - avgDirAlbedo * weight; - - // Calculate the reflection response, setting IOR to zero to disable internal Fresnel. - bsdf.response = F * comp * weight * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, 0.0, 0); - - if (scatter_mode == "RT") - { - bsdf.response += bsdf.throughput * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, ior, 1); - } -} diff --git a/libraries/pbrlib/genosl/legacy/mx_oren_nayar_diffuse_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_oren_nayar_diffuse_bsdf.osl deleted file mode 100644 index b9c5fba797..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_oren_nayar_diffuse_bsdf.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_oren_nayar_diffuse_bsdf(float weight, color _color, float roughness, normal N, int energy_compensation, output BSDF bsdf) -{ - bsdf.response = _color * weight * oren_nayar(N, roughness); - bsdf.throughput = color(0.0); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_sheen_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_sheen_bsdf.osl deleted file mode 100644 index e94325fe99..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_sheen_bsdf.osl +++ /dev/null @@ -1,24 +0,0 @@ -#include "../lib/mx_microfacet_sheen.osl" - -// TODO: Vanilla OSL doesn't have a proper sheen closure, -// so use 'diffuse' scaled by sheen directional albedo for now. -void mx_sheen_bsdf(float weight, color Ks, float roughness, vector N, output BSDF bsdf) -{ - if (weight < M_FLOAT_EPS) - { - bsdf.response = 0; - bsdf.throughput = color(1.0); - return; - } - - // TODO: Normalization should not be needed. My suspicion is that - // BSDF sampling of new outgoing direction in 'testrender' needs - // to be fixed. - vector V = normalize(-I); - - float NdotV = fabs(dot(N,V)); - float alpha = clamp(roughness, M_FLOAT_EPS, 1.0); - float albedo = weight * mx_imageworks_sheen_dir_albedo(NdotV, alpha); - bsdf.response = albedo * Ks * diffuse(N); - bsdf.throughput = 1.0 - albedo; -} diff --git a/libraries/pbrlib/genosl/legacy/mx_subsurface_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_subsurface_bsdf.osl deleted file mode 100644 index da0e3cc12a..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_subsurface_bsdf.osl +++ /dev/null @@ -1,6 +0,0 @@ -void mx_subsurface_bsdf(float weight, color _color, color radius, float anisotropy, normal N, output BSDF bsdf) -{ - // TODO: Subsurface closure is not supported by vanilla OSL. - bsdf.response = _color * weight * diffuse(N); - bsdf.throughput = color(0.0); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_surface.osl b/libraries/pbrlib/genosl/legacy/mx_surface.osl deleted file mode 100644 index d48320411e..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_surface.osl +++ /dev/null @@ -1,6 +0,0 @@ -void mx_surface(BSDF bsdf, EDF edf, float opacity, int thin_walled, output surfaceshader result) -{ - result.bsdf = bsdf.response; - result.edf = edf; - result.opacity = clamp(opacity, 0.0, 1.0); -} diff --git a/libraries/pbrlib/genosl/legacy/mx_translucent_bsdf.osl b/libraries/pbrlib/genosl/legacy/mx_translucent_bsdf.osl deleted file mode 100644 index fd56a37db8..0000000000 --- a/libraries/pbrlib/genosl/legacy/mx_translucent_bsdf.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_translucent_bsdf(float weight, color _color, normal N, output BSDF bsdf) -{ - bsdf.response = _color * weight * translucent(N); - bsdf.throughput = color(0.0); -} diff --git a/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl b/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl new file mode 100644 index 0000000000..002bdc3044 --- /dev/null +++ b/libraries/pbrlib/genosl/mx_chiang_hair_roughness.osl @@ -0,0 +1,7 @@ +void mx_chiang_hair_roughness(float longitudinal, float azimuthal, float scale_TT, float scale_TRT, output vector2 roughness_R, output vector2 roughness_TT, output vector2 roughness_TRT) +{ + // TODO: Write OSL implementation of this node. + roughness_R = vector2(0.0, 0.0); + roughness_TT = vector2(0.0, 0.0); + roughness_TRT = vector2(0.0, 0.0); +} diff --git a/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy b/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy deleted file mode 100644 index e4a424e1ac..0000000000 --- a/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx index d3849a5ddb..beac984518 100644 --- a/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx +++ b/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx @@ -22,6 +22,9 @@ + + + @@ -71,4 +74,13 @@ + + + + + + + + + diff --git a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx index 34000f3933..0625d17a25 100644 --- a/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx +++ b/libraries/stdlib/genglsl/stdlib_genglsl_impl.mtlx @@ -129,12 +129,6 @@ - - - - - - diff --git a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx index 1ba84b8083..05dbc995d6 100644 --- a/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx +++ b/libraries/stdlib/genmdl/stdlib_genmdl_impl.mtlx @@ -131,13 +131,6 @@ - - - - - - - @@ -698,7 +691,7 @@ - + diff --git a/libraries/stdlib/genmsl/lib/mx_texture.metal b/libraries/stdlib/genmsl/lib/mx_texture.metal index 479a8836bf..7e90b60686 100644 --- a/libraries/stdlib/genmsl/lib/mx_texture.metal +++ b/libraries/stdlib/genmsl/lib/mx_texture.metal @@ -2,13 +2,8 @@ struct MetalTexture { texture2d tex; sampler s; - int get_width() { return tex.get_width(); } - int get_height() { return tex.get_height(); } - int get_num_mip_levels() { return tex.get_num_mip_levels(); } }; -int get_width(MetalTexture mtlTex) { return mtlTex.get_width(); } - float4 texture(MetalTexture mtlTex, float2 uv) { return mtlTex.tex.sample(mtlTex.s, uv); @@ -21,10 +16,5 @@ float4 textureLod(MetalTexture mtlTex, float2 uv, float lod) int2 textureSize(MetalTexture mtlTex, int mipLevel) { - return int2(mtlTex.get_width(), mtlTex.get_height()); -} - -int texture_mips(MetalTexture mtlTex) -{ - return mtlTex.tex.get_num_mip_levels(); + return int2(mtlTex.tex.get_width(), mtlTex.tex.get_height()); } diff --git a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx index ac4ea4e0b2..ea09880543 100644 --- a/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx +++ b/libraries/stdlib/genmsl/stdlib_genmsl_impl.mtlx @@ -45,10 +45,6 @@ - - - - diff --git a/libraries/stdlib/genosl/mx_ambientocclusion_float.osl b/libraries/stdlib/genosl/mx_ambientocclusion_float.osl deleted file mode 100644 index 10baf0b736..0000000000 --- a/libraries/stdlib/genosl/mx_ambientocclusion_float.osl +++ /dev/null @@ -1,5 +0,0 @@ -void mx_ambientocclusion_float(float coneangle, float maxdistance, output float result) -{ - // This node is a stub and does not currently operate to specification - result = 0; -} diff --git a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx index 3c4c5c4a6e..bd2e2540b5 100644 --- a/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx +++ b/libraries/stdlib/genosl/stdlib_genosl_impl.mtlx @@ -131,13 +131,6 @@ - - - - - - - diff --git a/libraries/stdlib/stdlib_defs.mtlx b/libraries/stdlib/stdlib_defs.mtlx index 7d26d66639..7c24307f0e 100644 --- a/libraries/stdlib/stdlib_defs.mtlx +++ b/libraries/stdlib/stdlib_defs.mtlx @@ -1365,21 +1365,6 @@ - - - - - - - - - - - @@ -2910,44 +2895,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - registerImplementation("IM_mix_bsdf_" + OslShaderGenerator::TARGET, ClosureMixNode::create); - registerImplementation("IM_mix_edf_" + OslShaderGenerator::TARGET, ClosureMixNode::create); - // - registerImplementation("IM_add_bsdf_" + OslShaderGenerator::TARGET, ClosureAddNode::create); - registerImplementation("IM_add_edf_" + OslShaderGenerator::TARGET, ClosureAddNode::create); - // - registerImplementation("IM_multiply_bsdfC_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_bsdfF_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_edfC_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - registerImplementation("IM_multiply_edfF_" + OslShaderGenerator::TARGET, ClosureMultiplyNode::create); - -#endif // MATERIALX_OSL_LEGACY_CLOSURES - // registerImplementation("IM_surface_" + OslShaderGenerator::TARGET, SurfaceNodeOsl::create); @@ -157,10 +142,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G const bool isSurfaceShaderOutput = singleOutput && singleOutput->getType() == Type::SURFACESHADER; -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - const bool isBsdfOutput = singleOutput && singleOutput->getType() == Type::BSDF; -#endif - if (isSurfaceShaderOutput) { // Special case for having 'surfaceshader' as final output type. @@ -169,16 +150,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G // to understand this output. emitLine("output closure color " + singleOutput->getVariable() + " = 0", stage, false); } -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - else if (isBsdfOutput) - { - // Special case for having 'BSDF' as final output type. - // For legacy closures this type is a struct internally (response, throughput, thickness, ior) - // so we must declare this as a single closure color type in order for renderers - // to understand this output. - emitLine("output closure color " + singleOutput->getVariable() + " = 0", stage, false); - } -#endif else { // Just emit all outputs the way they are declared. @@ -252,18 +223,6 @@ ShaderPtr OslShaderGenerator::generate(const string& name, ElementPtr element, G emitLine(singleOutput->getVariable() + " = (" + result + ".bsdf + " + result + ".edf) * opacity_weight + transparent() * (1.0 - opacity_weight)", stage); emitScopeEnd(stage); } -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - else if (isBsdfOutput) - { - // Special case for having 'BSDF' as final output type. - // For legacy closures this type is a struct internally (response, throughput, thickness, ior) - // so we must declare this as a single closure color type in order for renderers - // to understand this output. - const ShaderGraphOutputSocket* socket = graph.getOutputSocket(0); - const string result = getUpstreamResult(socket, context); - emitLine(singleOutput->getVariable() + " = " + result + ".response", stage); - } -#endif else { // Assign results to final outputs. @@ -510,10 +469,10 @@ void OslShaderGenerator::emitMetadata(const ShaderPort* port, ShaderStage& stage { static const std::unordered_map UI_WIDGET_METADATA = { - { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) }, - { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("number", Type::STRING.getName())) }, - { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("filename", Type::STRING.getName())) }, - { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Value::createValueFromStrings("checkBox", Type::STRING.getName())) } + { Type::FLOAT, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) }, + { Type::INTEGER, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("number")) }, + { Type::FILENAME, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("filename")) }, + { Type::BOOLEAN, ShaderMetadata("widget", Type::STRING, Type::STRING.createValueFromStrings("checkBox")) } }; static const std::set METADATA_TYPE_BLACKLIST = diff --git a/source/MaterialXGenOsl/OslSyntax.cpp b/source/MaterialXGenOsl/OslSyntax.cpp index 797a891ce6..a85821c4fd 100644 --- a/source/MaterialXGenOsl/OslSyntax.cpp +++ b/source/MaterialXGenOsl/OslSyntax.cpp @@ -371,19 +371,6 @@ OslSyntax::OslSyntax() EMPTY_STRING, "struct textureresource { string filename; string colorspace; };")); -#ifdef MATERIALX_OSL_LEGACY_CLOSURES - - registerTypeSyntax( - Type::BSDF, - std::make_shared( - "BSDF", - "BSDF(null_closure, color(1.0))", - "{ 0, color(1.0) }", - "closure color", - "struct BSDF { closure color response; color throughput; };")); - -#else - registerTypeSyntax( Type::BSDF, std::make_shared( @@ -393,8 +380,6 @@ OslSyntax::OslSyntax() "closure color", "#define BSDF closure color")); -#endif // MATERIALX_OSL_LEGACY_CLOSURES - registerTypeSyntax( Type::EDF, std::make_shared( diff --git a/source/MaterialXGenShader/ShaderGenerator.cpp b/source/MaterialXGenShader/ShaderGenerator.cpp index 6c23382f81..398232bf39 100644 --- a/source/MaterialXGenShader/ShaderGenerator.cpp +++ b/source/MaterialXGenShader/ShaderGenerator.cpp @@ -344,6 +344,47 @@ ShaderNodeImplPtr ShaderGenerator::getImplementation(const NodeDef& nodedef, Gen return impl; } +/// Load any struct type definitions from the document in to the type cache. +void ShaderGenerator::loadStructTypeDefs(const DocumentPtr& doc) +{ + for (const auto& mxTypeDef : doc->getTypeDefs()) + { + const auto& typeDefName = mxTypeDef->getName(); + const auto& members = mxTypeDef->getMembers(); + + // If we don't have any member children then we're not going to consider ourselves a struct. + if (members.empty()) + continue; + + StructTypeDesc newStructTypeDesc; + for (const auto& member : members) + { + auto memberName = member->getName(); + auto memberTypeName = member->getType(); + auto memberType = TypeDesc::get(memberTypeName); + auto memberDefaultValue = member->getValueString(); + + newStructTypeDesc.addMember(memberName, memberType, memberDefaultValue); + } + + auto structIndex = StructTypeDesc::emplace_back(newStructTypeDesc); + + TypeDesc structTypeDesc(typeDefName, TypeDesc::BASETYPE_STRUCT, TypeDesc::SEMANTIC_NONE, 1, structIndex); + + TypeDescRegistry(structTypeDesc, typeDefName); + + StructTypeDesc::get(structIndex).setTypeDesc(TypeDesc::get(typeDefName)); + } + + _syntax->registerStructTypeDescSyntax(); +} + +/// Clear any struct type definitions loaded +void ShaderGenerator::clearStructTypeDefs() +{ + StructTypeDesc::clear(); +} + namespace { diff --git a/source/MaterialXGenShader/ShaderGenerator.h b/source/MaterialXGenShader/ShaderGenerator.h index fa60a4d63e..a2f54fec2e 100644 --- a/source/MaterialXGenShader/ShaderGenerator.h +++ b/source/MaterialXGenShader/ShaderGenerator.h @@ -191,6 +191,12 @@ class MX_GENSHADER_API ShaderGenerator return _tokenSubstitutions; } + /// Load any struct type definitions from the document in to the type cache. + void loadStructTypeDefs(const DocumentPtr& doc); + + /// Clear any struct type definitions loaded + void clearStructTypeDefs(); + /// Register metadata that should be exported to the generated shaders. /// Supported metadata includes standard UI attributes like "uiname", "uifolder", /// "uimin", "uimax", etc. diff --git a/source/MaterialXGenShader/ShaderNode.cpp b/source/MaterialXGenShader/ShaderNode.cpp index 4e90fcbb2d..d52810ffc4 100644 --- a/source/MaterialXGenShader/ShaderNode.cpp +++ b/source/MaterialXGenShader/ShaderNode.cpp @@ -437,7 +437,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context) const string& attrValue = nodeDef.getAttribute(nodedefAttr); if (!attrValue.empty()) { - ValuePtr value = Value::createValueFromStrings(attrValue, metadataEntry->type.getName()); + ValuePtr value = metadataEntry->type.createValueFromStrings(attrValue); if (!value) { value = metadataEntry->value; @@ -472,7 +472,7 @@ void ShaderNode::createMetadata(const NodeDef& nodeDef, GenContext& context) if (!attrValue.empty()) { const TypeDesc type = metadataEntry->type != Type::NONE ? metadataEntry->type : input->getType(); - ValuePtr value = Value::createValueFromStrings(attrValue, type.getName()); + ValuePtr value = type.createValueFromStrings(attrValue); if (!value) { value = metadataEntry->value; diff --git a/source/MaterialXGenShader/Syntax.cpp b/source/MaterialXGenShader/Syntax.cpp index 661aa41660..81daa9e0a7 100644 --- a/source/MaterialXGenShader/Syntax.cpp +++ b/source/MaterialXGenShader/Syntax.cpp @@ -190,6 +190,36 @@ bool Syntax::remapEnumeration(const string&, TypeDesc, const string&, std::pair< return false; } +void Syntax::registerStructTypeDescSyntax() +{ + for (const auto& typeName : StructTypeDesc::getStructTypeNames()) + { + const auto& typeDesc = TypeDesc::get(typeName); + const auto& structTypeDesc = StructTypeDesc::get(typeDesc.getStructIndex()); + + string structTypeName = typeName; + string defaultValue = typeName + "( "; + string uniformDefaultValue = EMPTY_STRING; + string typeAlias = EMPTY_STRING; + string typeDefinition = "struct " + structTypeName + " { "; + + for (const auto& x : structTypeDesc.getMembers()) + { + string memberName = x._name; + string memberType = x._typeDesc.getName(); + string memberDefaultValue = x._defaultValueStr; + + defaultValue += memberDefaultValue + ", "; + typeDefinition += memberType + " " + memberName + "; "; + } + + typeDefinition += " };"; + defaultValue += " )"; + + registerTypeSyntax(typeDesc, createStructSyntax(structTypeName, defaultValue, uniformDefaultValue, typeAlias, typeDefinition)); + } +} + const StringVec TypeSyntax::EMPTY_MEMBERS; TypeSyntax::TypeSyntax(const string& name, const string& defaultValue, const string& uniformDefaultValue, @@ -246,4 +276,36 @@ string AggregateTypeSyntax::getValue(const Value& value, bool /*uniform*/) const return valueString.empty() ? valueString : getName() + "(" + valueString + ")"; } +StructTypeSyntax::StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue, + const string& typeAlias, const string& typeDefinition, const StringVec& members) : + TypeSyntax(name, defaultValue, uniformDefaultValue, typeAlias, typeDefinition, members), _parentSyntax(parentSyntax) +{ +} + +string StructTypeSyntax::getValue(const Value& value, bool /*uniform*/) const +{ + const AggregateValue& aggValue = static_cast(value); + + string result = "{"; + + string separator = ""; + for (const auto& memberValue : aggValue.getMembers()) + { + result += separator; + separator = ";"; + + const string& memberTypeName = memberValue->getTypeString(); + TypeDesc memberTypeDesc = TypeDesc::get(memberTypeName); + + // Recursively use the syntax to generate the output, so we can support nested structs. + const string valueStr = _parentSyntax->getValue(memberTypeDesc, *memberValue, true); + + result += valueStr; + } + + result += "}"; + + return result; +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/Syntax.h b/source/MaterialXGenShader/Syntax.h index a4bb7e49b5..6f16633b59 100644 --- a/source/MaterialXGenShader/Syntax.h +++ b/source/MaterialXGenShader/Syntax.h @@ -20,6 +20,7 @@ MATERIALX_NAMESPACE_BEGIN class Syntax; class TypeSyntax; +class StructTypeSyntax; class TypeDesc; class ShaderPort; @@ -29,6 +30,8 @@ using SyntaxPtr = shared_ptr; using ConstSyntaxPtr = shared_ptr; /// Shared pointer to a TypeSyntax using TypeSyntaxPtr = shared_ptr; +/// Shared pointer to a StructTypeSyntax +using StructTypeSyntaxPtr = shared_ptr; /// Map holding identifier names and a counter for /// creating unique names from them. @@ -67,6 +70,8 @@ class MX_GENSHADER_API Syntax /// Multiple calls will add to the internal set of tokens. void registerInvalidTokens(const StringMap& tokens); + virtual void registerStructTypeDescSyntax(); + /// Returns a set of names that are reserved words for this language syntax. const StringSet& getReservedWords() const { return _reservedWords; } @@ -199,6 +204,19 @@ class MX_GENSHADER_API Syntax /// Protected constructor Syntax(); + virtual StructTypeSyntaxPtr createStructSyntax(const string& structTypeName, const string& defaultValue, + const string& uniformDefaultValue, const string& typeAlias, + const string& typeDefinition) const + { + return std::make_shared( + this, + structTypeName, + defaultValue, + uniformDefaultValue, + typeAlias, + typeDefinition); + } + vector _typeSyntaxes; std::unordered_map _typeSyntaxIndexByType; @@ -292,6 +310,20 @@ class MX_GENSHADER_API AggregateTypeSyntax : public TypeSyntax string getValue(const Value& value, bool uniform) const override; }; +/// Specialization of TypeSyntax for aggregate types. +class MX_GENSHADER_API StructTypeSyntax : public TypeSyntax +{ + public: + StructTypeSyntax(const Syntax* parentSyntax, const string& name, const string& defaultValue, const string& uniformDefaultValue, + const string& typeAlias = EMPTY_STRING, const string& typeDefinition = EMPTY_STRING, + const StringVec& members = EMPTY_MEMBERS); + + string getValue(const Value& value, bool uniform) const override; + + protected: + const Syntax* _parentSyntax; +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXGenShader/TypeDesc.cpp b/source/MaterialXGenShader/TypeDesc.cpp index 1267caf14d..5d51680211 100644 --- a/source/MaterialXGenShader/TypeDesc.cpp +++ b/source/MaterialXGenShader/TypeDesc.cpp @@ -5,7 +5,7 @@ #include -#include +#include MATERIALX_NAMESPACE_BEGIN @@ -28,6 +28,16 @@ TypeDescNameMap& typeNameMap() return map; } +using StructTypeDescStorage = vector; +StructTypeDescStorage& structTypeStorage() +{ + // TODO: Our use of the singleton pattern for TypeDescMap and StructTypeDestStorage + // is not thread-safe, and we should consider replacing this with thread-local + // data in the GenContext object. + static StructTypeDescStorage storage; + return storage; +} + } // anonymous namespace const string TypeDesc::NONE_TYPE_NAME = "none"; @@ -46,7 +56,52 @@ TypeDesc TypeDesc::get(const string& name) return it != types.end() ? it->second : Type::NONE; } -TypeDescRegistry::TypeDescRegistry(TypeDesc type, const std::string& name) +void TypeDesc::remove(const string& name) +{ + TypeDescNameMap& typenames = typeNameMap(); + + TypeDescMap& types = typeMap(); + + auto it = types.find(name); + if (it == types.end()) + return; + + typenames.erase(it->second.typeId()); + types.erase(it); +} + +ValuePtr TypeDesc::createValueFromStrings(const string& value) const +{ + ValuePtr newValue = Value::createValueFromStrings(value, getName()); + if (!isStruct()) + return newValue; + + // Value::createValueFromStrings() can only create a valid Value for a struct if it is passed + // the optional TypeDef argument, otherwise it just returns a "string" typed Value. + // So if this is a struct type we need to create a new AggregateValue. + + StringVec subValues = parseStructValueString(value); + + AggregateValuePtr result = AggregateValue::createAggregateValue(getName()); + auto structTypeDesc = StructTypeDesc::get(getStructIndex()); + const auto& members = structTypeDesc.getMembers(); + + if (subValues.size() != members.size()) + { + std::stringstream ss; + ss << "Wrong number of initializers - expect " << members.size(); + throw ExceptionShaderGenError(ss.str()); + } + + for (size_t i = 0; i < members.size(); ++i) + { + result->appendValue( members[i]._typeDesc.createValueFromStrings(subValues[i])); + } + + return result; +} + +TypeDescRegistry::TypeDescRegistry(TypeDesc type, const string& name) { TypeDescMap& types = typeMap(); TypeDescNameMap& typenames = typeNameMap(); @@ -86,4 +141,74 @@ TYPEDESC_REGISTER_TYPE(MATERIAL, "material") } // namespace Type +// +// StructTypeDesc methods +// + +void StructTypeDesc::addMember(const string& name, TypeDesc type, string defaultValueStr) +{ + _members.emplace_back(StructTypeDesc::StructMemberTypeDesc(name, type, defaultValueStr)); +} + +vector StructTypeDesc::getStructTypeNames() +{ + StructTypeDescStorage& structs = structTypeStorage(); + vector structNames; + for (const auto& x : structs) + { + structNames.emplace_back(x.typeDesc().getName()); + } + return structNames; +} + +StructTypeDesc& StructTypeDesc::get(unsigned int index) +{ + StructTypeDescStorage& structs = structTypeStorage(); + return structs[index]; +} + +uint16_t StructTypeDesc::emplace_back(StructTypeDesc structTypeDesc) +{ + StructTypeDescStorage& structs = structTypeStorage(); + if (structs.size() >= std::numeric_limits::max()) + { + throw ExceptionShaderGenError("Maximum number of custom struct types has been exceeded."); + } + uint16_t index = static_cast(structs.size()); + structs.emplace_back(structTypeDesc); + return index; +} + +void StructTypeDesc::clear() +{ + StructTypeDescStorage& structs = structTypeStorage(); + for (const auto& structType: structs) + { + // Need to add typeID to structTypeDesc - and use it here to reference back to typeDesc obj and remove it. + TypeDesc::remove(structType.typeDesc().getName()); + } + structs.clear(); +} + +const string& StructTypeDesc::getName() const +{ + return _typedesc.getName(); +} + +const vector& StructTypeDesc::getMembers() const +{ + return _members; +} + +TypeDesc createStructTypeDesc(std::string_view name) +{ + return {name, TypeDesc::BASETYPE_STRUCT}; +} + +void registerStructTypeDesc(std::string_view name) +{ + auto structTypeDesc = createStructTypeDesc(name); + TypeDescRegistry register_struct(structTypeDesc, string(name)); +} + MATERIALX_NAMESPACE_END diff --git a/source/MaterialXGenShader/TypeDesc.h b/source/MaterialXGenShader/TypeDesc.h index 1a537b7e58..95d2851915 100644 --- a/source/MaterialXGenShader/TypeDesc.h +++ b/source/MaterialXGenShader/TypeDesc.h @@ -10,6 +10,7 @@ /// Type descriptor for a MaterialX data type. #include +#include #include @@ -61,14 +62,21 @@ class MX_GENSHADER_API TypeDesc /// Empty constructor. constexpr TypeDesc() noexcept : - _id(0), _basetype(BASETYPE_NONE), _semantic(SEMANTIC_NONE), _size(0) { } + _id(0), + _basetype(BASETYPE_NONE), + _semantic(SEMANTIC_NONE), + _size(0), + _structIndex(0) + { + } /// Constructor. - constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1) noexcept : + constexpr TypeDesc(std::string_view name, uint8_t basetype, uint8_t semantic = SEMANTIC_NONE, uint16_t size = 1, uint16_t structIndex = 0) noexcept : _id(constexpr_hash(name)), // Note: We only store the hash to keep the class size minimal. _basetype(basetype), _semantic(semantic), - _size(size) + _size(size), + _structIndex(structIndex) { } @@ -112,6 +120,12 @@ class MX_GENSHADER_API TypeDesc /// Return true if the type represents a closure. bool isClosure() const { return (_semantic == SEMANTIC_CLOSURE || _semantic == SEMANTIC_SHADER || _semantic == SEMANTIC_MATERIAL); } + /// Return true if the type represents a struct. + bool isStruct() const { return _basetype == BASETYPE_STRUCT; } + + /// Return the index for the struct member information in StructTypeDesc, the result is invalid if `isStruct()` returns false. + uint16_t getStructIndex() const { return _structIndex; } + /// Equality operator bool operator==(TypeDesc rhs) const { @@ -143,8 +157,14 @@ class MX_GENSHADER_API TypeDesc /// If no type is found Type::NONE is returned. static TypeDesc get(const string& name); + /// Remove a type description by name, if it exists. + static void remove(const string& name); + static const string NONE_TYPE_NAME; + /// Create a Value from a string for a given typeDesc + ValuePtr createValueFromStrings(const string& value) const; + private: /// Simple constexpr hash function, good enough for the small set of short strings that /// are used for our data type names. @@ -157,6 +177,7 @@ class MX_GENSHADER_API TypeDesc uint8_t _basetype; uint8_t _semantic; uint16_t _size; + uint16_t _structIndex; }; /// @class TypeDescRegistry @@ -208,6 +229,58 @@ TYPEDESC_DEFINE_TYPE(MATERIAL, "material", TypeDesc::BASETYPE_NONE, TypeDesc::SE } // namespace Type + +/// @class StructTypeDesc +/// A type descriptor for MaterialX struct types. +/// +/// All types need to have a type descriptor registered in order for shader generators +/// to know about the type. If the type represented is of basetype=BASETYPE_STRUCT then +/// the type also needs to have an associated StructTypeDesc that describes the members +/// of the struct. +/// +class MX_GENSHADER_API StructTypeDesc +{ + public: + struct StructMemberTypeDesc + { + StructMemberTypeDesc(string name, TypeDesc typeDesc, string defaultValueStr) : + _name(name), _typeDesc(typeDesc), _defaultValueStr(defaultValueStr) + { + } + string _name; + TypeDesc _typeDesc; + string _defaultValueStr; + }; + + /// Empty constructor. + StructTypeDesc() noexcept{} + + void addMember(const string& name, TypeDesc type, string defaultValueStr); + void setTypeDesc(TypeDesc typedesc) { _typedesc = typedesc; } + + /// Return a type description by index. + static StructTypeDesc& get(unsigned int index); + static vector getStructTypeNames(); + static uint16_t emplace_back(StructTypeDesc structTypeDesc); + static void clear(); + + TypeDesc typeDesc() const { return _typedesc; } + + const string& getName() const; + + const vector& getMembers() const; + + private: + TypeDesc _typedesc; + vector _members; +}; + +class MX_GENSHADER_API StructTypeDescRegistry +{ + public: + StructTypeDescRegistry(); +}; + MATERIALX_NAMESPACE_END #endif diff --git a/source/MaterialXGraphEditor/RenderView.cpp b/source/MaterialXGraphEditor/RenderView.cpp index dbc9b4f980..92cd8f07c7 100644 --- a/source/MaterialXGraphEditor/RenderView.cpp +++ b/source/MaterialXGraphEditor/RenderView.cpp @@ -630,6 +630,9 @@ void RenderView::initContext(mx::GenContext& context) unitSystem->setUnitConverterRegistry(_unitRegistry); context.getShaderGenerator().setUnitSystem(unitSystem); context.getOptions().targetDistanceUnit = "meter"; + + // Register struct type definitions + context.getShaderGenerator().loadStructTypeDefs(_document); } void RenderView::drawContents() diff --git a/source/MaterialXRender/Util.cpp b/source/MaterialXRender/Util.cpp index 881f1b7eea..c206514412 100644 --- a/source/MaterialXRender/Util.cpp +++ b/source/MaterialXRender/Util.cpp @@ -170,7 +170,7 @@ unsigned int getUIProperties(InputPtr input, const string& target, UIProperties& else { valueString += val; - uiProperties.enumerationValues.push_back(Value::createValueFromStrings(valueString, input->getType())); + uiProperties.enumerationValues.push_back(typeDesc.createValueFromStrings(valueString)); valueString.clear(); index = 0; } @@ -318,7 +318,7 @@ void createUIPropertyGroups(DocumentPtr doc, const VariableBlock& block, UIPrope // Prepend a parent label for unlabeled node inputs. ElementPtr parent = pair.first->getParent(); - if (item.ui.uiFolder.empty() && parent && parent->isA()) + if (item.ui.uiName.empty() && parent && parent->isA()) { item.label = parent->getName() + pathSeparator + item.label; } diff --git a/source/MaterialXRenderGlsl/GlslMaterial.cpp b/source/MaterialXRenderGlsl/GlslMaterial.cpp index 788af713b2..064ab898ff 100644 --- a/source/MaterialXRenderGlsl/GlslMaterial.cpp +++ b/source/MaterialXRenderGlsl/GlslMaterial.cpp @@ -360,7 +360,7 @@ void GlslMaterial::modifyUniform(const std::string& path, ConstValuePtr value, s { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); + uniform->setValue(uniform->getType().createValueFromStrings(valueString)); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); diff --git a/source/MaterialXRenderGlsl/GlslProgram.cpp b/source/MaterialXRenderGlsl/GlslProgram.cpp index b2ca0aa66e..b63e1faecc 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.cpp +++ b/source/MaterialXRenderGlsl/GlslProgram.cpp @@ -508,7 +508,7 @@ ImagePtr GlslProgram::bindTexture(unsigned int uniformType, int uniformLocation, return nullptr; } -MaterialX::ValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList) +MaterialX::ConstValuePtr GlslProgram::findUniformValue(const string& uniformName, const GlslProgram::InputMap& uniformList) { auto uniform = uniformList.find(uniformName); if (uniform != uniformList.end()) @@ -946,47 +946,87 @@ const GlslProgram::InputMap& GlslProgram::updateUniformsList() for (size_t i = 0; i < uniforms.size(); ++i) { const ShaderPort* v = uniforms[i]; - int glType = mapTypeToOpenGLType(v->getType()); - // There is no way to match with an unnamed variable - if (v->getVariable().empty()) - { - continue; - } - - // Ignore types which are unsupported in GLSL. - if (glType == Input::INVALID_OPENGL_TYPE) - { - continue; - } + const auto& variablePath = v->getPath(); + const auto& variableUnit = v->getUnit(); + const auto& variableColorspace = v->getColorSpace(); + const auto& variableSemantic = v->getSemantic(); - auto inputIt = _uniformList.find(v->getVariable()); - if (inputIt != _uniformList.end()) + const auto populateUniformInput = + [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound] + (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue) -> void { - Input* input = inputIt->second.get(); - input->path = v->getPath(); - input->unit = v->getUnit(); - input->colorspace = v->getColorSpace(); - input->value = v->getValue(); - if (input->gltype == glType) - { - input->typeString = v->getType().getName(); - } - else + auto populateUniformInput_impl = + [this, variablePath, variableUnit, variableColorspace, variableSemantic, &errors, uniforms, &uniformTypeMismatchFound] + (TypeDesc typedesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void { - errors.push_back( - "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " - + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType().getName() - + "\". Semantic: \"" + v->getSemantic() - + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") - + "\". Unit: \"" + (!v->getUnit().empty() ? v->getUnit() : "") - + "\". Colorspace: \"" + (!v->getColorSpace().empty() ? v->getColorSpace() : "") - + "\". GLType: " + std::to_string(mapTypeToOpenGLType(v->getType())) - ); - uniformTypeMismatchFound = true; - } - } + if (!typedesc.isStruct()) + { + // Handle non-struct types + int glType = mapTypeToOpenGLType(typedesc); + + // There is no way to match with an unnamed variable + if (variableName.empty()) + { + return; + } + + // Ignore types which are unsupported in GLSL. + if (glType == Input::INVALID_OPENGL_TYPE) + { + return; + } + + auto inputIt = _uniformList.find(variableName); + if (inputIt != _uniformList.end()) + { + Input* input = inputIt->second.get(); + input->path = variablePath; + input->unit = variableUnit; + input->colorspace = variableColorspace; + input->value = variableValue; + if (input->gltype == glType) + { + input->typeString = typedesc.getName(); + } + else + { + errors.push_back( + "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + + "Name: \"" + variableName + + "\". Type: \"" + typedesc.getName() + + "\". Semantic: \"" + variableSemantic + + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "") + + "\". Unit: \"" + (!variableUnit.empty() ? variableUnit : "") + + "\". Colorspace: \"" + (!variableColorspace.empty() ? variableColorspace : "") + + "\". GLType: " + std::to_string(glType)); + uniformTypeMismatchFound = true; + } + } + } + else + { + // If we're a struct - we need to loop over each member + auto structTypeDesc = StructTypeDesc::get(typedesc.getStructIndex()); + auto aggregateValue = std::static_pointer_cast(variableValue); + + const auto& members = structTypeDesc.getMembers(); + for (size_t i = 0, n = members.size(); i < n; ++i) + { + const auto& member = members[i]; + auto memberTypeDesc = member._typeDesc; + auto memberVariableName = variableName + "." + member._name; + auto memberVariableValue = aggregateValue->getMemberValue(i); + + populateUniformInput_ref(memberTypeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref); + } + } + }; + + return populateUniformInput_impl(typedesc, variableName, variableValue, populateUniformInput_impl); + }; + + populateUniformInput(v->getType(), v->getVariable(), v->getValue()); } } @@ -1100,12 +1140,12 @@ const GlslProgram::InputMap& GlslProgram::updateAttributesList() if (string::npos != sattributeName.find(colorSet)) { string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } else if (string::npos != sattributeName.find(uvSet)) { string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } _attributeList[sattributeName] = inputPtr; diff --git a/source/MaterialXRenderGlsl/GlslProgram.h b/source/MaterialXRenderGlsl/GlslProgram.h index 7d58dbaca7..4addd7d54b 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.h +++ b/source/MaterialXRenderGlsl/GlslProgram.h @@ -102,7 +102,7 @@ class MX_RENDERGLSL_API GlslProgram string typeString; /// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during /// shader generation. - MaterialX::ValuePtr value; + MaterialX::ConstValuePtr value; /// Is this a constant bool isConstant; /// Element path (if any) @@ -223,7 +223,7 @@ class MX_RENDERGLSL_API GlslProgram // Utility to find a uniform value in an uniform list. // If uniform cannot be found a null pointer will be return. - ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); + ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); // Bind an individual texture to a program uniform location ImagePtr bindTexture(unsigned int uniformType, int uniformLocation, const FilePath& filePath, diff --git a/source/MaterialXRenderMsl/MslMaterial.mm b/source/MaterialXRenderMsl/MslMaterial.mm index 311d84acee..eb13ea7900 100644 --- a/source/MaterialXRenderMsl/MslMaterial.mm +++ b/source/MaterialXRenderMsl/MslMaterial.mm @@ -318,7 +318,7 @@ { valueString = value->getValueString(); } - uniform->setValue(Value::createValueFromStrings(valueString, uniform->getType().getName())); + uniform->setValue(uniform->getType().createValueFromStrings(valueString)); if (_doc) { ElementPtr element = _doc->getDescendant(uniform->getPath()); diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.h b/source/MaterialXRenderMsl/MslPipelineStateObject.h index b335e29af5..a823662f5f 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.h +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.h @@ -99,7 +99,7 @@ class MX_RENDERMSL_API MslProgram string typeString; /// Input value. Will only be non-empty if initialized stages with a HwShader and a value was set during /// shader generation. - MaterialX::ValuePtr value; + MaterialX::ConstValuePtr value; /// Is this a constant bool isConstant; /// Element path (if any) @@ -256,7 +256,7 @@ class MX_RENDERMSL_API MslProgram // Utility to find a uniform value in an uniform list. // If uniform cannot be found a null pointer will be return. - ValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); + ConstValuePtr findUniformValue(const string& uniformName, const InputMap& uniformList); // Bind an individual texture to a program uniform location ImagePtr bindTexture(id renderCmdEncoder, diff --git a/source/MaterialXRenderMsl/MslPipelineStateObject.mm b/source/MaterialXRenderMsl/MslPipelineStateObject.mm index 2d5685646f..470fa549b2 100644 --- a/source/MaterialXRenderMsl/MslPipelineStateObject.mm +++ b/source/MaterialXRenderMsl/MslPipelineStateObject.mm @@ -235,12 +235,12 @@ int GetStrideOfMetalType(MTLDataType type) if (_shader->hasAttribute(HW::ATTR_TRANSPARENT)) { - psoDesc.colorAttachments[0].blendingEnabled = YES; - psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; - psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; - psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; - psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; - psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + psoDesc.colorAttachments[0].blendingEnabled = YES; + psoDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; + psoDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; + psoDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + psoDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; + psoDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; psoDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; _alphaBlendingEnabled = true; @@ -265,12 +265,12 @@ int GetStrideOfMetalType(MTLDataType type) if (string::npos != sattributeName.find(colorSet)) { string setNumber = sattributeName.substr(colorSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } else if (string::npos != sattributeName.find(uvSet)) { string setNumber = sattributeName.substr(uvSet.size(), sattributeName.size()); - inputPtr->value = Value::createValueFromStrings(setNumber, getTypeString()); + inputPtr->value = Type::INTEGER.createValueFromStrings(setNumber); } _attributeList[sattributeName] = inputPtr; @@ -566,8 +566,8 @@ int GetStrideOfMetalType(MTLDataType type) return nullptr; } -MaterialX::ValuePtr MslProgram::findUniformValue(const string& uniformName, - const MslProgram::InputMap& uniformList) +MaterialX::ConstValuePtr MslProgram::findUniformValue(const string& uniformName, + const MslProgram::InputMap& uniformList) { auto uniform = uniformList.find(uniformName); if (uniform != uniformList.end()) @@ -925,31 +925,54 @@ int GetStrideOfMetalType(MTLDataType type) { if (arg.type == MTLArgumentTypeBuffer && arg.bufferDataType == MTLDataTypeStruct) { - for (MTLStructMember* member in arg.bufferStructType.members) - { - std::string uboObjectName = std::string(arg.name.UTF8String); - std::string memberName = member.name.UTF8String; - std::string uboDotMemberName = uboObjectName + "." + memberName; + const auto uboObjectName = string(arg.name.UTF8String); - InputPtr inputPtr = std::make_shared(arg.index, member.dataType, arg.bufferDataSize, EMPTY_STRING); - _uniformList[uboDotMemberName] = inputPtr; - _globalUniformNameList[memberName] = uboDotMemberName; - - if (MTLArrayType* arrayMember = member.arrayType) + const auto addUniformToList = + [this, uboObjectName] + (MTLStructMember* member, int index, int size, const string& memberNamePrefix) -> void + { + auto addUniformToList_impl = + [this, uboObjectName] + (MTLStructMember* member, int index, int size, const string& memberNamePrefix, auto& addUniformToList_ref) -> void { - for (int i = 0; i < arrayMember.arrayLength; ++i) + auto memberName = memberNamePrefix + member.name.UTF8String; + + if (MTLStructType* structMember = member.structType) { - for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + for (MTLStructMember* subMember in structMember.members) { - std::string memberNameDotSubmember = memberName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; - std::string uboDotMemberNameDotSubmemberName = uboObjectName + "." + memberNameDotSubmember; + auto namePrefix = memberName + "."; + addUniformToList_ref(subMember, subMember.argumentIndex, subMember.offset, namePrefix, addUniformToList_ref); + } + } + else + { + auto uboDotMemberName = uboObjectName + "." + memberName; + + InputPtr inputPtr = std::make_shared(index, member.dataType, size, EMPTY_STRING); + this->_uniformList[uboDotMemberName] = inputPtr; + this->_globalUniformNameList[memberName] = uboDotMemberName; - InputPtr inputPtr = std::make_shared(ArrayOfStructMember.argumentIndex, ArrayOfStructMember.dataType, ArrayOfStructMember.offset, EMPTY_STRING); - _uniformList[uboDotMemberNameDotSubmemberName] = inputPtr; - _globalUniformNameList[memberNameDotSubmember] = uboDotMemberNameDotSubmemberName; + if (MTLArrayType* arrayMember = member.arrayType) + { + for (int i = 0; i < arrayMember.arrayLength; ++i) + { + for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + { + auto namePrefix = memberName + "[" + std::to_string(i) + "]."; + addUniformToList_ref(ArrayOfStructMember, ArrayOfStructMember.argumentIndex, ArrayOfStructMember.offset, namePrefix, addUniformToList_ref); + } + } } } - } + }; + + return addUniformToList_impl(member, index, size, memberNamePrefix, addUniformToList_impl); + }; + + for (MTLStructMember* member in arg.bufferStructType.members) + { + addUniformToList(member, arg.index, arg.bufferDataSize, ""); } } @@ -1006,55 +1029,90 @@ int GetStrideOfMetalType(MTLDataType type) for (size_t i = 0; i < uniforms.size(); ++i) { const ShaderPort* v = uniforms[i]; - MTLDataType resourceType = mapTypeToMetalType(v->getType()); - - // There is no way to match with an unnamed variable - if (v->getVariable().empty()) - { - continue; - } - // Ignore types which are unsupported in MSL. - if (resourceType == MTLDataTypeNone) - { - continue; - } + const string& variablePath = v->getPath(); + const string& variableSemantic = v->getSemantic(); - auto inputIt = _uniformList.find(v->getVariable()); - if (inputIt == _uniformList.end()) + const auto populateUniformInput = + [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound] + (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue) -> void { - if (v->getType() == Type::FILENAME) + auto populateUniformInput_impl = + [this, uniforms, variablePath, variableSemantic, &errors, &uniformTypeMismatchFound] + (TypeDesc variableTypeDesc, const string& variableName, ConstValuePtr variableValue, auto& populateUniformInput_ref) -> void { - inputIt = _uniformList.find(TEXTURE_NAME(v->getVariable())); - } - else - { - inputIt = _uniformList.find(uniforms.getInstance() + "." + v->getVariable()); - } - } + // There is no way to match with an unnamed variable + if (variableName.empty()) + { + return; + } - if (inputIt != _uniformList.end()) - { - Input* input = inputIt->second.get(); - input->path = v->getPath(); - input->value = v->getValue(); - if (input->resourceType == resourceType) - { - input->typeString = v->getType().getName(); - } - else - { - errors.push_back( - "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " - + "Name: \"" + v->getVariable() - + "\". Type: \"" + v->getType().getName() - + "\". Semantic: \"" + v->getSemantic() - + "\". Value: \"" + (v->getValue() ? v->getValue()->getValueString() : "") - + "\". resourceType: " + std::to_string(mapTypeToMetalType(v->getType())) - ); - uniformTypeMismatchFound = true; - } - } + MTLDataType resourceType = mapTypeToMetalType(variableTypeDesc); + // Ignore types which are unsupported in MSL. + if (resourceType == MTLDataTypeNone) + { + return; + } + + if (!variableTypeDesc.isStruct()) + { + auto inputIt = _uniformList.find(variableName); + + if (inputIt == _uniformList.end()) { + if(variableTypeDesc == Type::FILENAME) + { + inputIt = _uniformList.find(TEXTURE_NAME(variableName)); + } + else + { + inputIt = _uniformList.find(uniforms.getInstance() + "." + variableName); + } + } + + if (inputIt != _uniformList.end()) + { + Input* input = inputIt->second.get(); + input->path = variablePath; + input->value = variableValue; + if (input->resourceType == resourceType) + { + input->typeString = variableTypeDesc.getName(); + } + else + { + errors.push_back( + "Pixel shader uniform block type mismatch [" + uniforms.getName() + "]. " + + "Name: \"" + variableName + + "\". Type: \"" + variableTypeDesc.getName() + + "\". Semantic: \"" + variableSemantic + + "\". Value: \"" + (variableValue ? variableValue->getValueString() : "") + + "\". resourceType: " + std::to_string(mapTypeToMetalType(variableTypeDesc)) + ); + uniformTypeMismatchFound = true; + } + } + } + else + { + auto structTypeDesc = StructTypeDesc::get(variableTypeDesc.getStructIndex()); + auto aggregateValue = std::static_pointer_cast(variableValue); + + const auto& members = structTypeDesc.getMembers(); + for (size_t i = 0, n = members.size(); i < n; ++i) + { + const auto& structMember = members[i]; + auto memberVariableName = variableName+"."+structMember._name; + auto memberVariableValue = aggregateValue->getMemberValue(i); + + populateUniformInput_ref(structMember._typeDesc, memberVariableName, memberVariableValue, populateUniformInput_ref); + } + } + }; + + return populateUniformInput_impl(variableTypeDesc, variableName, variableValue, populateUniformInput_impl); + }; + + populateUniformInput(v->getType(), v->getVariable(), v->getValue()); } } @@ -1231,7 +1289,7 @@ int GetStrideOfMetalType(MTLDataType type) return false; }; - auto setValue = [](MaterialX::ValuePtr value, std::vector& data, size_t offset) + auto setValue = [](MaterialX::ConstValuePtr value, std::vector& data, size_t offset) { if (value->getTypeString() == "float") { @@ -1307,7 +1365,7 @@ throw ExceptionRenderError( { if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { - MaterialX::ValuePtr value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value; + auto value = _uniformList[string(arg.name.UTF8String) + "." + member.name.UTF8String]->value; if (value) { setValue(value, uniformBufferData, member.offset); @@ -1332,39 +1390,60 @@ throw ExceptionRenderError( if (!setCommonUniform(lightHandler, cam, member.name.UTF8String, uniformBufferData, member.offset)) { - auto uniformInfo = _uniformList.find(uniformName); - if (uniformInfo != _uniformList.end()) - { - MaterialX::ValuePtr value = uniformInfo->second->value; - if (value) - { - setValue(value, uniformBufferData, member.offset); - } - } - else - { - } - } - - if (MTLArrayType* arrayMember = member.arrayType) - { - for (int i = 0; i < arrayMember.arrayLength; ++i) + const auto setUniformValue = + [this, setValue] + (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset ) -> void { - for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + auto setUniformValue_impl = + [this, setValue] + (MTLStructMember* member, const string& uniformName, std::vector& uniformBufferData, int offset, auto &setUniformValue_ref ) -> void { - string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; - - auto uniformInfo = _uniformList.find(uniformNameSubArray); - if (uniformInfo != _uniformList.end()) + if(MTLArrayType* arrayMember = member.arrayType) { - MaterialX::ValuePtr value = uniformInfo->second->value; - if (value) + for(int i = 0; i < arrayMember.arrayLength; ++i) { - setValue(value, uniformBufferData, member.offset + i * arrayMember.stride + ArrayOfStructMember.offset); + for (MTLStructMember* ArrayOfStructMember in arrayMember.elementStructType.members) + { + string uniformNameSubArray = uniformName + "[" + std::to_string(i) + "]." + ArrayOfStructMember.name.UTF8String; + auto uniformInfo = _uniformList.find(uniformNameSubArray); + if (uniformInfo != _uniformList.end()) + { + auto value = uniformInfo->second->value; + if(value) + { + setValue(value, uniformBufferData, offset + i * arrayMember.stride + ArrayOfStructMember.offset); + } + } + } } } - } - } + else if (MTLStructType* structMember = member.structType) + { + // this code does not support struct recursion yet.... + for (MTLStructMember* subMember in structMember.members) + { + string subUniformName = uniformName+"."+subMember.name.UTF8String; + setUniformValue_ref(subMember, subUniformName, uniformBufferData, offset+subMember.offset, setUniformValue_ref); + } + } + else + { + auto uniformInfo = _uniformList.find(uniformName); + if (uniformInfo != _uniformList.end()) + { + auto value = uniformInfo->second->value; + if(value) + { + setValue(value, uniformBufferData, offset); + } + } + } + }; + + return setUniformValue_impl(member, uniformName, uniformBufferData, offset, setUniformValue_impl); + }; + + setUniformValue(member, uniformName, uniformBufferData, member.offset); } } @@ -1415,14 +1494,15 @@ throw ExceptionRenderError( // A "filename" is not indicative of type, so just return a 2d sampler. return MTLDataTypeTexture; } - else if (type == Type::BSDF || - type == Type::MATERIAL || + else if (type == Type::BSDF || + type == Type::MATERIAL || type == Type::DISPLACEMENTSHADER || - type == Type::EDF || - type == Type::VDF || - type == Type::SURFACESHADER || - type == Type::LIGHTSHADER || - type == Type::VOLUMESHADER) + type == Type::EDF || + type == Type::VDF || + type == Type::SURFACESHADER || + type == Type::LIGHTSHADER || + type == Type::VOLUMESHADER || + type.isStruct()) return MTLDataTypeStruct; return MTLDataTypeNone; diff --git a/source/MaterialXTest/CMakeLists.txt b/source/MaterialXTest/CMakeLists.txt index 4835787ed8..c3fae603dc 100644 --- a/source/MaterialXTest/CMakeLists.txt +++ b/source/MaterialXTest/CMakeLists.txt @@ -96,11 +96,6 @@ endif() add_custom_command(TARGET MaterialXTest POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/../../libraries ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries) -if(MATERIALX_OSL_LEGACY_CLOSURES) - add_custom_command(TARGET MaterialXTest POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rename - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries/pbrlib/genosl/pbrlib_genosl_impl.legacy ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/libraries/pbrlib/genosl/pbrlib_genosl_impl.mtlx) -endif() if(MATERIALX_BUILD_GEN_MDL) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../source/MaterialXGenMdl/mdl/" diff --git a/source/MaterialXTest/MaterialXCore/Document.cpp b/source/MaterialXTest/MaterialXCore/Document.cpp index 94f8b98708..b593969ccb 100644 --- a/source/MaterialXTest/MaterialXCore/Document.cpp +++ b/source/MaterialXTest/MaterialXCore/Document.cpp @@ -10,8 +10,6 @@ #include #include -#include - namespace mx = MaterialX; TEST_CASE("Document", "[document]") @@ -123,16 +121,6 @@ TEST_CASE("Document", "[document]") REQUIRE(doc->validate()); } -void printDifferences(const mx::ElementEquivalenceResultVec& results, const std::string& label) -{ - for (const mx::ElementEquivalenceResult& result : results) - { - std::cout << label << ": " << "Element: " << result.path1 << - ", Element: " << result.path2 << ", Difference Type: " << result.differenceType - << ", Value: " << result.attributeName << std::endl; - } -} - TEST_CASE("Document equivalence", "[document]") { mx::DocumentPtr doc = mx::createDocument(); @@ -162,6 +150,9 @@ TEST_CASE("Document equivalence", "[document]") unsigned int index = 0; mx::ElementPtr child = doc->addNodeGraph("mygraph"); mx::NodeGraphPtr graph = child->asA(); + // Add comment block at the start of the first doc to check skipping + mx::ElementPtr comment = doc->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 1"); for (auto it = inputMap.begin(); it != inputMap.end(); ++it) { const std::string inputType = (*it).first; @@ -217,69 +208,42 @@ TEST_CASE("Document equivalence", "[document]") input->setName("input_" + inputType); } } + // Add comment blocks at end of second doc to check value and count checks + comment = doc2->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 2"); + comment = doc2->addChildOfCategory(mx::CommentElement::CATEGORY); + comment->setDocString("Comment 3"); mx::ElementEquivalenceOptions options; mx::ElementEquivalenceResultVec results; - // Check skipping all value compares - options.skipValueComparisons = true; + // Check that this fails when not performing value comparisons + options.performValueComparisons = false; bool equivalent = doc->isEquivalent(doc2, options, &results); - if (equivalent) - { - std::cout << "Unexpected skip value equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } - else - { - printDifferences(results, "Expected value differences"); - } REQUIRE(!equivalent); // Check attibute values - options.skipValueComparisons = false; + options.performValueComparisons = true; results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Unexpected value difference"); - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(equivalent); unsigned int currentPrecision = mx::Value::getFloatPrecision(); // This will compare 0.012345608 versus: 1, 0.012345611 for input10 - options.precision = 8; + options.floatPrecision = 8; equivalent = doc->isEquivalent(doc2, options); - if (equivalent) - { - std::cout << "Unexpected precision equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } - else - { - printDifferences(results, "Expected precision difference"); - } REQUIRE(!equivalent); - options.precision = currentPrecision; + options.floatPrecision = currentPrecision; // Check attribute filtering of inputs results.clear(); - options.skipAttributes = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; + options.attributeExclusionList = { mx::ValueElement::UI_MIN_ATTRIBUTE, mx::ValueElement::UI_MAX_ATTRIBUTE }; for (mx::InputPtr floatInput : floatInputs) { floatInput->setAttribute(mx::ValueElement::UI_MIN_ATTRIBUTE, "0.9"); floatInput->setAttribute(mx::ValueElement::UI_MAX_ATTRIBUTE, "100.0"); } equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Unexpected filtering differences"); - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(equivalent); for (mx::InputPtr floatInput : floatInputs) { @@ -293,16 +257,6 @@ TEST_CASE("Document equivalence", "[document]") mismatchElement->setName("mismatch_color4"); results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Expected name mismatch differences"); - } - else - { - std::cout << "Unexpected name match equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(!equivalent); mismatchElement->setName(previousName); results.clear(); @@ -320,15 +274,5 @@ TEST_CASE("Document equivalence", "[document]") nodeGraph2->setNodeDefString("ND_mygraph"); results.clear(); equivalent = doc->isEquivalent(doc2, options, &results); - if (!equivalent) - { - printDifferences(results, "Expected functional graph differences"); - } - else - { - std::cout << "Unexpected functional graph equivalence:" << std::endl; - std::cout << "Document 1: " << mx::prettyPrint(doc) << std::endl; - std::cout << "Document 2: " << mx::prettyPrint(doc2) << std::endl; - } REQUIRE(!equivalent); } diff --git a/source/MaterialXTest/MaterialXCore/Node.cpp b/source/MaterialXTest/MaterialXCore/Node.cpp index ef746bfe05..f3ce7d40de 100644 --- a/source/MaterialXTest/MaterialXCore/Node.cpp +++ b/source/MaterialXTest/MaterialXCore/Node.cpp @@ -159,12 +159,12 @@ TEST_CASE("Node", "[node]") REQUIRE(typeDef->getMembers().size() == scalarCount); // Reference the custom type. - std::string d65("400.0,82.75,500.0,109.35,600.0,90.01,700.0,71.61,800.0,59.45"); + std::string d65("{400;82.75;500;109.35;600;90.01;700;71.61;800;59.45}"); constant->setInputValue("value", d65, "spectrum"); REQUIRE(constant->getInput("value")->getType() == "spectrum"); REQUIRE(constant->getInput("value")->getValueString() == d65); - REQUIRE(constant->getInputValue("value")->isA()); - REQUIRE(constant->getInputValue("value")->asA() == d65); + REQUIRE(constant->getInputValue("value")->isA()); + REQUIRE(constant->getInputValue("value")->asA().getValueString() == d65); // Validate the document. REQUIRE(doc->validate()); diff --git a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp index de50b3671d..979320bd91 100644 --- a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp +++ b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.cpp @@ -81,7 +81,7 @@ TEST_CASE("GenShader: GLSL Implementation Check", "[genglsl]") mx::StringSet generatorSkipNodeTypes; mx::StringSet generatorSkipNodeDefs; - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 29); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs); } TEST_CASE("GenShader: GLSL Unique Names", "[genglsl]") diff --git a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h index 94f1b64f34..0e0f296ad2 100644 --- a/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h +++ b/source/MaterialXTest/MaterialXGenGlsl/GenGlsl.h @@ -51,7 +51,7 @@ class GlslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "ambientocclusion", "arrayappend", "screen", "curveadjust", "displacementshader", "volumeshader", + "screen", "displacementshader", "volumeshader", "IM_constant_", "IM_dot_", "IM_geompropvalue_boolean", "IM_geompropvalue_string", "IM_geompropvalue_filename", "IM_light_genglsl", "IM_point_light_genglsl", "IM_spot_light_genglsl", "IM_directional_light_genglsl", "IM_angle", "volumematerial", "ND_volumematerial" diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp index 2d05b1552c..4bec0016de 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp @@ -94,7 +94,7 @@ TEST_CASE("GenShader: MDL Implementation Check", "[genmdl]") mx::StringSet generatorSkipNodeDefs; - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 30); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs); } @@ -225,15 +225,9 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so moduleToTest = moduleToTest.substr(0, moduleToTest.size() - sourceCodePaths[0].getExtension().length() - 1); std::string renderExec(MATERIALX_MDL_RENDER_EXECUTABLE); - bool testMDLC = renderExec.empty(); - if (testMDLC) + std::string mdlcExec(MATERIALX_MDLC_EXECUTABLE); + if (!mdlcExec.empty()) // always run compiler { - std::string mdlcExec(MATERIALX_MDLC_EXECUTABLE); - if (mdlcExec.empty()) - { - return; - } - std::string mdlcCommand = mdlcExec; // use the same paths as the resolver @@ -264,12 +258,19 @@ void MdlShaderGeneratorTester::compileSource(const std::vector& so _logFile << "\tReturn code: " << std::to_string(returnValue) << std::endl; writeErrorCode = true; } - _logFile << "\tError: " << line << std::endl; + if (line.find(": Warning ") != std::string::npos) + { + _logFile << "\tWarning: " << line << std::endl; + } + else + { + _logFile << "\tError: " << line << std::endl; + } } CHECK(returnValue == 0); } - else + if (!renderExec.empty()) // render if renderer is availabe { std::string renderCommand = renderExec; @@ -358,6 +359,7 @@ TEST_CASE("GenShader: MDL Shader Generation", "[genmdl]") mx::FilePathVec testRootPaths; testRootPaths.push_back(searchPath.find("resources/Materials/TestSuite")); testRootPaths.push_back(searchPath.find("resources/Materials/Examples/StandardSurface")); + testRootPaths.push_back(searchPath.find("resources/Materials/Examples/UsdPreviewSurface")); const mx::FilePath logPath("genmdl_mdl_generate_test.txt"); diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h index ab92a5dacf..e51dbbd7e5 100644 --- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h +++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h @@ -76,7 +76,7 @@ class MdlShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "ambientocclusion", "arrayappend", "backfacing", "screen", "curveadjust", "displacementshader", + "backfacing", "screen", "displacementshader", "volumeshader", "IM_constant_", "IM_dot_", "IM_geomattrvalue", "IM_angle", "geompropvalue", "surfacematerial", "volumematerial", "IM_absorption_vdf_", "IM_mix_vdf_", "IM_add_vdf_", "IM_multiply_vdf", diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp index 3cab2b31b0..32baaec5f0 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp @@ -84,12 +84,7 @@ TEST_CASE("GenShader: MSL Implementation Check", "[genmsl]") mx::StringSet generatorSkipNodeTypes; mx::StringSet generatorSkipNodeDefs; - generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); - generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); - generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); - generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); - - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 33); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs); } TEST_CASE("GenShader: MSL Unique Names", "[genmsl]") diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h index 2e66e3a3a2..27a911f6d9 100644 --- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h +++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h @@ -43,8 +43,6 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester void addSkipFiles() override { - _skipFiles.insert("hair_bsdf.mtlx"); - _skipFiles.insert("hair_surfaceshader.mtlx"); } void setupDependentLibraries() override @@ -72,7 +70,7 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "ambientocclusion", "arrayappend", "backfacing", "screen", "curveadjust", "displacementshader", + "backfacing", "screen", "displacementshader", "volumeshader", "IM_constant_", "IM_dot_", "IM_geompropvalue_boolean", "IM_geompropvalue_string", "IM_geompropvalue_filename", "IM_light_genmsl", "IM_point_light_genmsl", "IM_spot_light_genmsl", "IM_directional_light_genmsl", "IM_angle", "surfacematerial", "volumematerial", "ND_surfacematerial", "ND_volumematerial", "ND_backface_util", "IM_backface_util_genmsl" diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp index 21cd12e9f2..6e613c85b8 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp @@ -89,12 +89,8 @@ TEST_CASE("GenShader: OSL Implementation Check", "[genosl]") generatorSkipNodeTypes.insert("light"); mx::StringSet generatorSkipNodeDefs; - generatorSkipNodeDefs.insert("ND_chiang_hair_roughness"); - generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color"); - generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin"); - generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf"); - GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 34); + GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs); } TEST_CASE("GenShader: OSL Unique Names", "[genosl]") diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h index b6004334c1..bb1ce5b6f9 100644 --- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h +++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h @@ -45,8 +45,6 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester void addSkipFiles() override { - _skipFiles.insert("hair_bsdf.mtlx"); - _skipFiles.insert("hair_surfaceshader.mtlx"); } // Ignore light shaders in the document for OSL @@ -65,7 +63,7 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester { whiteList = { - "ambientocclusion", "arrayappend", "backfacing", "screen", "curveadjust", "displacementshader", + "backfacing", "screen", "displacementshader", "volumeshader", "IM_constant_", "IM_dot_", "IM_geompropvalue", "IM_geompropvalueuniform", "IM_angle", "ND_backface_util" }; ShaderGeneratorTester::getImplementationWhiteList(whiteList); diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 4a8e61645a..40f89c001f 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -67,8 +67,7 @@ bool getShaderSource(mx::GenContext& context, // Check that implementations exist for all nodedefs supported per generator void checkImplementations(mx::GenContext& context, const mx::StringSet& generatorSkipNodeTypes, - const mx::StringSet& generatorSkipNodeDefs, - unsigned int expectedSkipCount) + const mx::StringSet& generatorSkipNodeDefs) { const mx::ShaderGenerator& shadergen = context.getShaderGenerator(); @@ -90,10 +89,8 @@ void checkImplementations(mx::GenContext& context, // Node types to explicitly skip temporarily. mx::StringSet skipNodeTypes = { - "ambientocclusion", "displacement", "volume", - "curveadjust", "conical_edf", "measured_edf", "absorption_vdf", @@ -268,7 +265,6 @@ void checkImplementations(mx::GenContext& context, std::cerr << (std::string("Missing list: ") + missing_str) << std::endl; } REQUIRE(missing == 0); - REQUIRE(skipped == expectedSkipCount); implDumpBuffer.close(); } @@ -649,6 +645,9 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons addColorManagement(); addUnitSystem(); + // Register struct typedefs from the library files. + _shaderGenerator->loadStructTypeDefs(_dependLib); + // Test suite setup addSkipFiles(); @@ -705,6 +704,8 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons preprocessDocument(doc); _shaderGenerator->registerShaderMetadata(doc, context); + _shaderGenerator->loadStructTypeDefs(doc); + // For each new file clear the implementation cache. // Since the new file might contain implementations with names // colliding with implementations in previous test cases. diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h index 2bac14e435..d4876a03f7 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h @@ -46,8 +46,7 @@ bool generateCode(mx::GenContext& context, const std::string& shaderName, mx::Ty // Check that implementations exist for all nodedefs supported per generator void checkImplementations(mx::GenContext& context, const mx::StringSet& generatorSkipNodeTypes, - const mx::StringSet& generatorSkipNodeDefs, - unsigned int expectedSkipCount); + const mx::StringSet& generatorSkipNodeDefs); // Utility test to check unique name generation on a shader generator void testUniqueNames(mx::GenContext& context, const std::string& stage); diff --git a/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp b/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp index 3184d892e9..05c83ae82e 100644 --- a/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp +++ b/source/MaterialXTest/MaterialXRenderOsl/GenReference.cpp @@ -65,8 +65,7 @@ TEST_CASE("GenReference: OSL Reference", "[genreference]") // Generate reference shaders. // Ignore the following nodes: const mx::StringSet ignoreNodeList = { "surfacematerial", "volumematerial", - "constant_filename", "arrayappend", - "dot_filename"}; + "constant_filename", "dot_filename"}; bool failedGeneration = false; for (const mx::NodeDefPtr& nodedef : stdlib->getNodeDefs()) diff --git a/source/MaterialXView/Editor.cpp b/source/MaterialXView/Editor.cpp index abba9ce10e..6d64c55b30 100644 --- a/source/MaterialXView/Editor.cpp +++ b/source/MaterialXView/Editor.cpp @@ -18,11 +18,11 @@ namespace class EditorColorPicker : public ng::ColorPicker { public: - EditorColorPicker(ng::Widget* parent, const ng::Color& color) : + EditorColorPicker(ng::ref parent, const ng::Color& color) : ng::ColorPicker(parent, color) { - ng::Popup* popup = this->popup(); - ng::Widget* floatGroup = new ng::Widget(popup); + ng::ref popup = this->popup(); + ng::ref floatGroup = new ng::Widget(popup); auto layout = new ng::GridLayout(ng::Orientation::Horizontal, 2, ng::Alignment::Middle, 2, 2); layout->set_col_alignment({ ng::Alignment::Fill, ng::Alignment::Fill }); @@ -60,7 +60,7 @@ class EditorColorPicker : public ng::ColorPicker protected: // Additional numeric entry / feedback widgets - ng::FloatBox* _colorWidgets[4]; + ng::ref> _colorWidgets[4]; }; } // anonymous namespace @@ -70,10 +70,6 @@ class EditorColorPicker : public ng::ColorPicker // PropertyEditor::PropertyEditor() : - _window(nullptr), - _container(nullptr), - _gridLayout2(nullptr), - _gridLayout3(nullptr), _visible(false), _fileDialogsForImages(true) { @@ -81,7 +77,7 @@ PropertyEditor::PropertyEditor() : void PropertyEditor::create(Viewer& parent) { - ng::Window* parentWindow = parent.getWindow(); + ng::ref parentWindow = parent.getWindow(); // Remove the window associated with the form. // This is done by explicitly creating and owning the window @@ -110,7 +106,7 @@ void PropertyEditor::create(Viewer& parent) _window->set_position(previousPosition); _window->set_visible(_visible); - ng::VScrollPanel* scroll_panel = new ng::VScrollPanel(_window); + ng::ref scroll_panel = new ng::VScrollPanel(_window); scroll_panel->set_fixed_height(300); _container = new ng::Widget(scroll_panel); _container->set_layout(new ng::GroupLayout(1, 1, 1, 1)); @@ -127,7 +123,7 @@ void PropertyEditor::create(Viewer& parent) } void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::string& group, - ng::Widget* container, Viewer* viewer, bool editable) + ng::ref container, Viewer* viewer, bool editable) { const mx::UIProperties& ui = item.ui; mx::ValuePtr value = item.variable->getValue(); @@ -148,9 +144,9 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st if (!group.empty()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); - ng::Label* groupLabel = new ng::Label(twoColumns, group); + ng::ref groupLabel = new ng::Label(twoColumns, group); groupLabel->set_font_size(20); groupLabel->set_font("sans-bold"); new ng::Label(twoColumns, ""); @@ -187,11 +183,11 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st const size_t valueIndex = indexInEnumeration(); if (INVALID_INDEX != valueIndex) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); - ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, { "" }); + ng::ref comboBox = new ng::ComboBox(twoColumns, { "" }); comboBox->set_enabled(editable); comboBox->set_items(enumeration); comboBox->set_selected_index(static_cast(valueIndex)); @@ -215,7 +211,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st } else { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); @@ -252,9 +248,9 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Float widget else if (value->isA()) { - ng::Widget* threeColumns = new ng::Widget(container); + ng::ref threeColumns = new ng::Widget(container); threeColumns->set_layout(_gridLayout3); - ng::FloatBox* floatBox = createFloatWidget(threeColumns, label, value->asA(), &ui, [viewer, path](float value) + ng::ref> floatBox = createFloatWidget(threeColumns, label, value->asA(), &ui, [viewer, path](float value) { mx::MaterialPtr material = viewer->getSelectedMaterial(); if (material) @@ -269,12 +265,12 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Boolean widget else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); bool v = value->asA(); new ng::Label(twoColumns, label); - ng::CheckBox* boolVar = new ng::CheckBox(twoColumns, ""); + ng::ref boolVar = new ng::CheckBox(twoColumns, ""); boolVar->set_checked(v); boolVar->set_font_size(15); boolVar->set_callback([path, viewer](bool v) @@ -290,7 +286,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Color3 input. Can map to a combo box if an enumeration else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); // Determine if there is an enumeration for this @@ -312,7 +308,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Create a combo box. The items are the enumerations in order. if (index >= 0) { - ng::ComboBox* comboBox = new ng::ComboBox(twoColumns, { "" }); + ng::ref comboBox = new ng::ComboBox(twoColumns, { "" }); comboBox->set_enabled(editable); comboBox->set_items(enumeration); comboBox->set_selected_index(index); @@ -353,7 +349,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Color4 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); new ng::Label(twoColumns, label); @@ -376,7 +372,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 2 widget else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector2 v = value->asA(); @@ -415,7 +411,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 3 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector3 v = value->asA(); @@ -470,7 +466,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st // Vec 4 input else if (value->isA()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); mx::Vector4 v = value->asA(); @@ -542,16 +538,17 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st std::string v = value->asA(); if (!v.empty()) { - ng::Widget* twoColumns = new ng::Widget(container); + ng::ref twoColumns = new ng::Widget(container); twoColumns->set_layout(_gridLayout2); if (item.variable->getType() == mx::Type::FILENAME) { new ng::Label(twoColumns, label); - ng::Button* buttonVar = new ng::Button(twoColumns, mx::FilePath(v).getBaseName()); + ng::ref buttonVar = new ng::Button(twoColumns, mx::FilePath(v).getBaseName()); buttonVar->set_enabled(editable); buttonVar->set_font_size(15); - buttonVar->set_callback([buttonVar, path, viewer]() + auto buttonVarPtr = buttonVar.get(); + buttonVar->set_callback([buttonVarPtr, path, viewer]() { mx::MaterialPtr material = viewer->getSelectedMaterial(); mx::ShaderPort* uniform = material ? material->findUniform(path) : nullptr; @@ -572,7 +569,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st if (!filename.empty()) { uniform->setValue(mx::Value::createValue(filename)); - buttonVar->set_caption(mx::FilePath(filename).getBaseName()); + buttonVarPtr->set_caption(mx::FilePath(filename).getBaseName()); viewer->perform_layout(); } } @@ -583,7 +580,7 @@ void PropertyEditor::addItemToForm(const mx::UIPropertyItem& item, const std::st else { new ng::Label(twoColumns, label); - ng::TextBox* stringVar = new ng::TextBox(twoColumns, v); + ng::ref stringVar = new ng::TextBox(twoColumns, v); stringVar->set_fixed_size({ 100, 20 }); stringVar->set_font_size(15); stringVar->set_callback([path, viewer](const std::string& v) @@ -629,14 +626,12 @@ void PropertyEditor::updateContents(Viewer* viewer) } if (!shaderName.empty() && shaderName != "surface") { - ng::Widget* twoColumns = new ng::Widget(_container); + ng::ref twoColumns = new ng::Widget(_container); twoColumns->set_layout(_gridLayout2); - ng::Widget* threeColumns = new ng::Widget(_container); - threeColumns->set_layout(_gridLayout3); - ng::Label* modelLabel = new ng::Label(twoColumns, "Shading Model"); + ng::ref modelLabel = new ng::Label(twoColumns, "Shading Model"); modelLabel->set_font_size(20); modelLabel->set_font("sans-bold"); - ng::Label* nameLabel = new ng::Label(twoColumns, shaderName); + ng::ref nameLabel = new ng::Label(twoColumns, shaderName); nameLabel->set_font_size(20); } } @@ -688,15 +683,15 @@ void PropertyEditor::updateContents(Viewer* viewer) viewer->perform_layout(); } -ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& label, float value, - const mx::UIProperties* ui, std::function callback) +ng::ref> createFloatWidget(ng::ref parent, const std::string& label, float value, + const mx::UIProperties* ui, std::function callback) { new ng::Label(parent, label); - ng::Slider* slider = new ng::Slider(parent); + ng::ref slider = new ng::Slider(parent); slider->set_value(value); - ng::FloatBox* box = new ng::FloatBox(parent, value); + ng::ref> box = new ng::FloatBox(parent, value); box->set_fixed_width(60); box->set_font_size(15); box->set_alignment(ng::TextBox::Alignment::Right); @@ -734,29 +729,31 @@ ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& la } } - slider->set_callback([box, callback](float value) + auto sliderPtr = slider.get(); + auto boxPtr = box.get(); + slider->set_callback([boxPtr, callback](float value) { - box->set_value(value); + boxPtr->set_value(value); callback(value); }); - box->set_callback([slider, callback](float value) + box->set_callback([sliderPtr, callback](float value) { - slider->set_value(value); + sliderPtr->set_value(value); callback(value); }); return box; } -ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, - const mx::UIProperties* ui, std::function callback) +ng::ref> createIntWidget(ng::ref parent, const std::string& label, int value, + const mx::UIProperties* ui, std::function callback) { new ng::Label(parent, label); - ng::Slider* slider = new ng::Slider(parent); + ng::ref slider = new ng::Slider(parent); slider->set_value((float) value); - ng::IntBox* box = new ng::IntBox(parent, value); + ng::ref> box = new ng::IntBox(parent, value); box->set_fixed_width(60); box->set_font_size(15); box->set_alignment(ng::TextBox::Alignment::Right); @@ -794,14 +791,16 @@ ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, i } } - slider->set_callback([box, callback](float value) + auto sliderPtr = slider.get(); + auto boxPtr = box.get(); + slider->set_callback([boxPtr, callback](float value) { - box->set_value((int) value); + boxPtr->set_value((int) value); callback((int) value); }); - box->set_callback([slider, callback](int value) + box->set_callback([sliderPtr, callback](int value) { - slider->set_value((float) value); + sliderPtr->set_value((float) value); callback(value); }); diff --git a/source/MaterialXView/Editor.h b/source/MaterialXView/Editor.h index b1fb4a3ade..b99f1f160c 100644 --- a/source/MaterialXView/Editor.h +++ b/source/MaterialXView/Editor.h @@ -39,7 +39,7 @@ class PropertyEditor } } - ng::Window* getWindow() + ng::ref getWindow() { return _window; } @@ -47,19 +47,19 @@ class PropertyEditor protected: void create(Viewer& parent); void addItemToForm(const mx::UIPropertyItem& item, const std::string& group, - ng::Widget* container, Viewer* viewer, bool editable); + ng::ref container, Viewer* viewer, bool editable); - ng::Window* _window; - ng::Widget* _container; - ng::GridLayout* _gridLayout2; - ng::GridLayout* _gridLayout3; + ng::ref _window; + ng::ref _container; + ng::ref _gridLayout2; + ng::ref _gridLayout3; bool _visible; bool _fileDialogsForImages; }; -ng::FloatBox* createFloatWidget(ng::Widget* parent, const std::string& label, float value, - const mx::UIProperties* ui, std::function callback = nullptr); -ng::IntBox* createIntWidget(ng::Widget* parent, const std::string& label, int value, - const mx::UIProperties* ui, std::function callback); +ng::ref> createFloatWidget(ng::ref parent, const std::string& label, float value, + const mx::UIProperties* ui, std::function callback = nullptr); +ng::ref> createIntWidget(ng::ref parent, const std::string& label, int value, + const mx::UIProperties* ui, std::function callback); #endif // MATERIALXVIEW_EDITOR_H diff --git a/source/MaterialXView/Viewer.cpp b/source/MaterialXView/Viewer.cpp index 24aea1eb42..aefdf2d401 100644 --- a/source/MaterialXView/Viewer.cpp +++ b/source/MaterialXView/Viewer.cpp @@ -158,7 +158,6 @@ Viewer::Viewer(const std::string& materialFilename, const mx::Color3& screenColor) : ng::Screen(ng::Vector2i(screenWidth, screenHeight), "MaterialXView", true, false, true, true, USE_FLOAT_BUFFER, 4, 0), - _window(nullptr), _materialFilename(materialFilename), _meshFilename(meshFilename), _envRadianceFilename(envRadianceFilename), @@ -184,11 +183,7 @@ Viewer::Viewer(const std::string& materialFilename, _shadowSoftness(1), _ambientOcclusionGain(0.6f), _selectedGeom(0), - _geomLabel(nullptr), - _geometrySelectionBox(nullptr), _selectedMaterial(0), - _materialLabel(nullptr), - _materialSelectionBox(nullptr), _identityCamera(mx::Camera::create()), _viewCamera(mx::Camera::create()), _envCamera(mx::Camera::create()), @@ -232,9 +227,6 @@ Viewer::Viewer(const std::string& materialFilename, _bakeHeight(0), _bakeDocumentPerMaterial(false), _frameTiming(false), - _timingLabel(nullptr), - _timingPanel(nullptr), - _timingText(nullptr), _avgFrameTime(0.0) { // Resolve input filenames, taking both the provided search path and @@ -295,11 +287,11 @@ void Viewer::initialize() _imageHandler->setSearchPath(_searchPath); // Initialize user interfaces. - createLoadMeshInterface(_window, "Load Mesh"); - createLoadMaterialsInterface(_window, "Load Material"); - createLoadEnvironmentInterface(_window, "Load Environment"); - createPropertyEditorInterface(_window, "Property Editor"); - createAdvancedSettings(_window); + createLoadMeshInterface((ng::ref) _window, "Load Mesh"); + createLoadMaterialsInterface((ng::ref) _window, "Load Material"); + createLoadEnvironmentInterface((ng::ref) _window, "Load Environment"); + createPropertyEditorInterface((ng::ref) _window, "Property Editor"); + createAdvancedSettings((ng::ref) _window); // Create geometry selection box. _geomLabel = new ng::Label(_window, "Select Geometry"); @@ -562,9 +554,9 @@ mx::ElementPredicate Viewer::getElementPredicate() }; } -void Viewer::createLoadMeshInterface(Widget* parent, const std::string& label) +void Viewer::createLoadMeshInterface(ng::ref parent, const std::string& label) { - ng::Button* meshButton = new ng::Button(parent, label); + ng::ref meshButton = new ng::Button(parent, label); meshButton->set_icon(FA_FOLDER); meshButton->set_tooltip("Load a new geometry in the OBJ or glTF format."); meshButton->set_callback([this]() @@ -590,9 +582,9 @@ void Viewer::createLoadMeshInterface(Widget* parent, const std::string& label) }); } -void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& label) +void Viewer::createLoadMaterialsInterface(ng::ref parent, const std::string& label) { - ng::Button* materialButton = new ng::Button(parent, label); + ng::ref materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_FOLDER); materialButton->set_tooltip("Load a material document in the MTLX format."); materialButton->set_callback([this]() @@ -608,9 +600,9 @@ void Viewer::createLoadMaterialsInterface(Widget* parent, const std::string& lab }); } -void Viewer::createLoadEnvironmentInterface(Widget* parent, const std::string& label) +void Viewer::createLoadEnvironmentInterface(ng::ref parent, const std::string& label) { - ng::Button* envButton = new ng::Button(parent, label); + ng::ref envButton = new ng::Button(parent, label); envButton->set_icon(FA_FOLDER); envButton->set_tooltip("Load a lat-long environment light in the HDR format."); envButton->set_callback([this]() @@ -634,9 +626,9 @@ void Viewer::createLoadEnvironmentInterface(Widget* parent, const std::string& l }); } -void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& label) +void Viewer::createSaveMaterialsInterface(ng::ref parent, const std::string& label) { - ng::Button* materialButton = new ng::Button(parent, label); + ng::ref materialButton = new ng::Button(parent, label); materialButton->set_icon(FA_SAVE); materialButton->set_tooltip("Save a material document in the MTLX format."); materialButton->set_callback([this]() @@ -664,9 +656,9 @@ void Viewer::createSaveMaterialsInterface(Widget* parent, const std::string& lab }); } -void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& label) +void Viewer::createPropertyEditorInterface(ng::ref parent, const std::string& label) { - ng::Button* editorButton = new ng::Button(parent, label); + ng::ref editorButton = new ng::Button(parent, label); editorButton->set_flags(ng::Button::ToggleButton); editorButton->set_tooltip("View or edit properties of the current material."); editorButton->set_change_callback([this](bool state) @@ -676,43 +668,41 @@ void Viewer::createPropertyEditorInterface(Widget* parent, const std::string& la }); } -void Viewer::createDocumentationInterface(Widget* parent, ng::VScrollPanel* scrollPanel) +void Viewer::createDocumentationInterface(ng::ref parent) { - ng::GridLayout* documentationLayout = new ng::GridLayout(ng::Orientation::Vertical, 3, - ng::Alignment::Minimum, 13, 5); + ng::ref documentationLayout = new ng::GridLayout(ng::Orientation::Vertical, 3, + ng::Alignment::Minimum, 13, 5); documentationLayout->set_row_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); - ng::Widget* documentationGroup = new ng::Widget(parent); + ng::ref documentationGroup = new ng::Widget(parent); documentationGroup->set_layout(documentationLayout); - ng::Label* documentationLabel = new ng::Label(documentationGroup, "Documentation"); + ng::ref documentationLabel = new ng::Label(documentationGroup, "Documentation"); documentationLabel->set_font_size(20); documentationLabel->set_font("sans-bold"); - ng::Button* shortcutsButton = new ng::Button(documentationGroup, "Keyboard Shortcuts"); - shortcutsButton->set_flags(ng::Button::ToggleButton); - shortcutsButton->set_icon(FA_CARET_RIGHT); - shortcutsButton->set_fixed_width(230); + _shortcutsButton = new ng::Button(documentationGroup, "Keyboard Shortcuts"); + _shortcutsButton->set_flags(ng::Button::ToggleButton); + _shortcutsButton->set_icon(FA_CARET_RIGHT); + _shortcutsButton->set_fixed_width(230); - ng::Widget* shortcutsTable = new ng::Widget(documentationGroup); - shortcutsTable->set_layout(new ng::GroupLayout(13)); - shortcutsTable->set_visible(false); + _shortcutsTable = new ng::Widget(documentationGroup); + _shortcutsTable->set_layout(new ng::GroupLayout(13)); + _shortcutsTable->set_visible(false); - // recompute layout when showing/hiding shortcuts. - shortcutsButton->set_change_callback([this, scrollPanel, shortcutsButton, - shortcutsTable](bool state) + // Recompute layout when showing/hiding shortcuts. + _shortcutsButton->set_change_callback([this](bool state) { - shortcutsTable->set_visible(state); - shortcutsButton->set_icon(state ? FA_CARET_DOWN : FA_CARET_RIGHT); - scrollPanel->set_scroll(state ? 0.73f : 1.0f); + _shortcutsButton->set_icon(state ? FA_CARET_DOWN : FA_CARET_RIGHT); + _shortcutsTable->set_visible(state); perform_layout(); }); // 2 cell layout for (key, description) pair. - ng::GridLayout* gridLayout2 = new ng::GridLayout(ng::Orientation::Horizontal, 2, - ng::Alignment::Minimum, 2, 2); + ng::ref gridLayout2 = new ng::GridLayout(ng::Orientation::Horizontal, 2, + ng::Alignment::Minimum, 2, 2); gridLayout2->set_col_alignment({ ng::Alignment::Minimum, ng::Alignment::Maximum }); - const std::vector> KEYBOARD_SHORTCUTS = + const std::array, 16> KEYBOARD_SHORTCUTS = { std::make_pair("R", "Reload the current material from file. " "Hold SHIFT to reload all standard libraries as well."), @@ -741,73 +731,73 @@ void Viewer::createDocumentationInterface(Widget* parent, ng::VScrollPanel* scro for (const auto& shortcut : KEYBOARD_SHORTCUTS) { - ng::Widget* twoColumns = new ng::Widget(shortcutsTable); + ng::ref twoColumns = new ng::Widget(_shortcutsTable); twoColumns->set_layout(gridLayout2); - ng::Label* keyLabel = new ng::Label(twoColumns, shortcut.first); + ng::ref keyLabel = new ng::Label(twoColumns, shortcut.first); keyLabel->set_font("sans-bold"); keyLabel->set_font_size(16); keyLabel->set_fixed_width(40); - ng::Label* descriptionLabel = new ng::Label(twoColumns, shortcut.second); + ng::ref descriptionLabel = new ng::Label(twoColumns, shortcut.second); descriptionLabel->set_font_size(16); descriptionLabel->set_fixed_width(160); } } -void Viewer::createAdvancedSettings(Widget* parent) +void Viewer::createAdvancedSettings(ng::ref parent) { - ng::PopupButton* advancedButton = new ng::PopupButton(parent, "Advanced Settings"); + ng::ref advancedButton = new ng::PopupButton(parent, "Advanced Settings"); advancedButton->set_icon(FA_TOOLS); advancedButton->set_chevron_icon(-1); advancedButton->set_tooltip("Asset and rendering options."); - ng::Popup* advancedPopupParent = advancedButton->popup(); + ng::ref advancedPopupParent = advancedButton->popup(); advancedPopupParent->set_layout(new ng::GroupLayout()); - ng::VScrollPanel* scrollPanel = new ng::VScrollPanel(advancedPopupParent); + ng::ref scrollPanel = new ng::VScrollPanel(advancedPopupParent); scrollPanel->set_fixed_height(500); - ng::Widget* advancedPopup = new ng::Widget(scrollPanel); + ng::ref advancedPopup = new ng::Widget(scrollPanel); advancedPopup->set_layout(new ng::BoxLayout(ng::Orientation::Vertical)); - ng::Widget* settingsGroup = new ng::Widget(advancedPopup); + ng::ref settingsGroup = new ng::Widget(advancedPopup); settingsGroup->set_layout(new ng::GroupLayout(13)); - ng::Label* viewLabel = new ng::Label(settingsGroup, "Viewing Options"); + ng::ref viewLabel = new ng::Label(settingsGroup, "Viewing Options"); viewLabel->set_font_size(20); viewLabel->set_font("sans-bold"); - ng::CheckBox* drawEnvironmentBox = new ng::CheckBox(settingsGroup, "Draw Environment"); + ng::ref drawEnvironmentBox = new ng::CheckBox(settingsGroup, "Draw Environment"); drawEnvironmentBox->set_checked(_drawEnvironment); drawEnvironmentBox->set_callback([this](bool enable) { _drawEnvironment = enable; }); - ng::CheckBox* outlineSelectedGeometryBox = new ng::CheckBox(settingsGroup, "Outline Selected Geometry"); + ng::ref outlineSelectedGeometryBox = new ng::CheckBox(settingsGroup, "Outline Selected Geometry"); outlineSelectedGeometryBox->set_checked(_outlineSelection); outlineSelectedGeometryBox->set_callback([this](bool enable) { _outlineSelection = enable; }); - ng::Label* renderLabel = new ng::Label(settingsGroup, "Render Options"); + ng::ref renderLabel = new ng::Label(settingsGroup, "Render Options"); renderLabel->set_font_size(20); renderLabel->set_font("sans-bold"); - ng::CheckBox* transparencyBox = new ng::CheckBox(settingsGroup, "Render Transparency"); + ng::ref transparencyBox = new ng::CheckBox(settingsGroup, "Render Transparency"); transparencyBox->set_checked(_renderTransparency); transparencyBox->set_callback([this](bool enable) { _renderTransparency = enable; }); - ng::CheckBox* doubleSidedBox = new ng::CheckBox(settingsGroup, "Render Double-Sided"); + ng::ref doubleSidedBox = new ng::CheckBox(settingsGroup, "Render Double-Sided"); doubleSidedBox->set_checked(_renderDoubleSided); doubleSidedBox->set_callback([this](bool enable) { _renderDoubleSided = enable; }); - ng::CheckBox* importanceSampleBox = new ng::CheckBox(settingsGroup, "Environment FIS"); + ng::ref importanceSampleBox = new ng::CheckBox(settingsGroup, "Environment FIS"); importanceSampleBox->set_checked(_genContext.getOptions().hwSpecularEnvironmentMethod == mx::SPECULAR_ENVIRONMENT_FIS); _lightHandler->setUsePrefilteredMap(_genContext.getOptions().hwSpecularEnvironmentMethod != mx::SPECULAR_ENVIRONMENT_FIS); importanceSampleBox->set_callback([this](bool enable) @@ -820,7 +810,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionBox = new ng::CheckBox(settingsGroup, "Transmission Refraction"); + ng::ref refractionBox = new ng::CheckBox(settingsGroup, "Transmission Refraction"); refractionBox->set_checked(_genContext.getOptions().hwTransmissionRenderMethod == mx::TRANSMISSION_REFRACTION); refractionBox->set_callback([this](bool enable) { @@ -831,14 +821,14 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* refractionSidedBox = new ng::CheckBox(settingsGroup, "Refraction Two-Sided"); + ng::ref refractionSidedBox = new ng::CheckBox(settingsGroup, "Refraction Two-Sided"); refractionSidedBox->set_checked(_lightHandler->getRefractionTwoSided()); refractionSidedBox->set_callback([this](bool enable) { _lightHandler->setRefractionTwoSided(enable); }); - ng::CheckBox* shaderInterfaceBox = new ng::CheckBox(settingsGroup, "Reduce Shader Interface"); + ng::ref shaderInterfaceBox = new ng::CheckBox(settingsGroup, "Reduce Shader Interface"); shaderInterfaceBox->set_checked(_genContext.getOptions().shaderInterfaceType == mx::SHADER_INTERFACE_REDUCED); shaderInterfaceBox->set_callback([this](bool enable) { @@ -846,11 +836,11 @@ void Viewer::createAdvancedSettings(Widget* parent) setShaderInterfaceType(interfaceType); }); - Widget* albedoGroup = new Widget(settingsGroup); + ng::ref albedoGroup = new Widget(settingsGroup); albedoGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(albedoGroup, "Albedo Method:"); mx::StringVec albedoOptions = { "Analytic", "Table", "MC" }; - ng::ComboBox* albedoBox = new ng::ComboBox(albedoGroup, albedoOptions); + ng::ref albedoBox = new ng::ComboBox(albedoGroup, albedoOptions); albedoBox->set_chevron_icon(-1); albedoBox->set_selected_index((int) _genContext.getOptions().hwDirectionalAlbedoMethod ); albedoBox->set_callback([this](int index) @@ -877,7 +867,7 @@ void Viewer::createAdvancedSettings(Widget* parent) } }); - Widget* sampleGroup = new Widget(settingsGroup); + ng::ref sampleGroup = new Widget(settingsGroup); sampleGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(sampleGroup, "Environment Samples:"); mx::StringVec sampleOptions; @@ -887,7 +877,7 @@ void Viewer::createAdvancedSettings(Widget* parent) sampleOptions.push_back(std::to_string(i)); m_process_events = true; } - ng::ComboBox* sampleBox = new ng::ComboBox(sampleGroup, sampleOptions); + ng::ref sampleBox = new ng::ComboBox(sampleGroup, sampleOptions); sampleBox->set_chevron_icon(-1); sampleBox->set_selected_index((int)std::log2(_lightHandler->getEnvSampleCount() / MIN_ENV_SAMPLE_COUNT) / 2); sampleBox->set_callback([this](int index) @@ -895,30 +885,30 @@ void Viewer::createAdvancedSettings(Widget* parent) _lightHandler->setEnvSampleCount(MIN_ENV_SAMPLE_COUNT * (int) std::pow(4, index)); }); - ng::Label* lightingLabel = new ng::Label(settingsGroup, "Lighting Options"); + ng::ref lightingLabel = new ng::Label(settingsGroup, "Lighting Options"); lightingLabel->set_font_size(20); lightingLabel->set_font("sans-bold"); - ng::CheckBox* directLightingBox = new ng::CheckBox(settingsGroup, "Direct Lighting"); + ng::ref directLightingBox = new ng::CheckBox(settingsGroup, "Direct Lighting"); directLightingBox->set_checked(_lightHandler->getDirectLighting()); directLightingBox->set_callback([this](bool enable) { _lightHandler->setDirectLighting(enable); }); - ng::CheckBox* indirectLightingBox = new ng::CheckBox(settingsGroup, "Indirect Lighting"); + ng::ref indirectLightingBox = new ng::CheckBox(settingsGroup, "Indirect Lighting"); indirectLightingBox->set_checked(_lightHandler->getIndirectLighting()); indirectLightingBox->set_callback([this](bool enable) { _lightHandler->setIndirectLighting(enable); }); - ng::Widget* lightRotationRow = new ng::Widget(settingsGroup); + ng::ref lightRotationRow = new ng::Widget(settingsGroup); lightRotationRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties ui; ui.uiMin = mx::Value::createValue(0.0f); ui.uiMax = mx::Value::createValue(360.0f); - ng::FloatBox* lightRotationBox = createFloatWidget(lightRotationRow, "Light Rotation:", + ng::ref> lightRotationBox = createFloatWidget(lightRotationRow, "Light Rotation:", _lightRotation, &ui, [this](float value) { _lightRotation = value; @@ -926,11 +916,11 @@ void Viewer::createAdvancedSettings(Widget* parent) }); lightRotationBox->set_editable(true); - ng::Label* shadowingLabel = new ng::Label(settingsGroup, "Shadowing Options"); + ng::ref shadowingLabel = new ng::Label(settingsGroup, "Shadowing Options"); shadowingLabel->set_font_size(20); shadowingLabel->set_font("sans-bold"); - ng::CheckBox* shadowMapBox = new ng::CheckBox(settingsGroup, "Shadow Map"); + ng::ref shadowMapBox = new ng::CheckBox(settingsGroup, "Shadow Map"); shadowMapBox->set_checked(_genContext.getOptions().hwShadowMap); shadowMapBox->set_callback([this](bool enable) { @@ -938,7 +928,7 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::CheckBox* ambientOcclusionBox = new ng::CheckBox(settingsGroup, "Ambient Occlusion"); + ng::ref ambientOcclusionBox = new ng::CheckBox(settingsGroup, "Ambient Occlusion"); ambientOcclusionBox->set_checked(_genContext.getOptions().hwAmbientOcclusion); ambientOcclusionBox->set_callback([this](bool enable) { @@ -946,23 +936,23 @@ void Viewer::createAdvancedSettings(Widget* parent) reloadShaders(); }); - ng::Widget* ambientOcclusionGainRow = new ng::Widget(settingsGroup); + ng::ref ambientOcclusionGainRow = new ng::Widget(settingsGroup); ambientOcclusionGainRow->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); - ng::FloatBox* ambientOcclusionGainBox = createFloatWidget(ambientOcclusionGainRow, "AO Gain:", + ng::ref> ambientOcclusionGainBox = createFloatWidget(ambientOcclusionGainRow, "AO Gain:", _ambientOcclusionGain, nullptr, [this](float value) { _ambientOcclusionGain = value; }); ambientOcclusionGainBox->set_editable(true); - ng::Label* sceneLabel = new ng::Label(settingsGroup, "Scene Options"); + ng::ref sceneLabel = new ng::Label(settingsGroup, "Scene Options"); sceneLabel->set_font_size(20); sceneLabel->set_font("sans-bold"); - Widget* unitGroup = new Widget(settingsGroup); + ng::ref unitGroup = new Widget(settingsGroup); unitGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(unitGroup, "Distance Unit:"); - ng::ComboBox* distanceUnitBox = new ng::ComboBox(unitGroup, _distanceUnitOptions); + ng::ref distanceUnitBox = new ng::ComboBox(unitGroup, _distanceUnitOptions); distanceUnitBox->set_fixed_size(ng::Vector2i(100, 20)); distanceUnitBox->set_chevron_icon(-1); if (_distanceUnitConverter) @@ -986,68 +976,68 @@ void Viewer::createAdvancedSettings(Widget* parent) m_process_events = true; }); - ng::Label* meshLoading = new ng::Label(settingsGroup, "Mesh Loading Options"); + ng::ref meshLoading = new ng::Label(settingsGroup, "Mesh Loading Options"); meshLoading->set_font_size(20); meshLoading->set_font("sans-bold"); - ng::CheckBox* splitUdimsBox = new ng::CheckBox(settingsGroup, "Split By UDIMs"); + ng::ref splitUdimsBox = new ng::CheckBox(settingsGroup, "Split By UDIMs"); splitUdimsBox->set_checked(_splitByUdims); splitUdimsBox->set_callback([this](bool enable) { _splitByUdims = enable; }); - ng::Label* materialLoading = new ng::Label(settingsGroup, "Material Loading Options"); + ng::ref materialLoading = new ng::Label(settingsGroup, "Material Loading Options"); materialLoading->set_font_size(20); materialLoading->set_font("sans-bold"); - ng::CheckBox* mergeMaterialsBox = new ng::CheckBox(settingsGroup, "Merge Materials"); + ng::ref mergeMaterialsBox = new ng::CheckBox(settingsGroup, "Merge Materials"); mergeMaterialsBox->set_checked(_mergeMaterials); mergeMaterialsBox->set_callback([this](bool enable) { _mergeMaterials = enable; }); - ng::CheckBox* showInputsBox = new ng::CheckBox(settingsGroup, "Show All Inputs"); + ng::ref showInputsBox = new ng::CheckBox(settingsGroup, "Show All Inputs"); showInputsBox->set_checked(_showAllInputs); showInputsBox->set_callback([this](bool enable) { _showAllInputs = enable; }); - ng::CheckBox* flattenBox = new ng::CheckBox(settingsGroup, "Flatten Subgraphs"); + ng::ref flattenBox = new ng::CheckBox(settingsGroup, "Flatten Subgraphs"); flattenBox->set_checked(_flattenSubgraphs); flattenBox->set_callback([this](bool enable) { _flattenSubgraphs = enable; }); - ng::Label* envLoading = new ng::Label(settingsGroup, "Environment Loading Options"); + ng::ref envLoading = new ng::Label(settingsGroup, "Environment Loading Options"); envLoading->set_font_size(20); envLoading->set_font("sans-bold"); - ng::CheckBox* normalizeEnvBox = new ng::CheckBox(settingsGroup, "Normalize Environment"); + ng::ref normalizeEnvBox = new ng::CheckBox(settingsGroup, "Normalize Environment"); normalizeEnvBox->set_checked(_normalizeEnvironment); normalizeEnvBox->set_callback([this](bool enable) { _normalizeEnvironment = enable; }); - ng::CheckBox* splitDirectLightBox = new ng::CheckBox(settingsGroup, "Split Direct Light"); + ng::ref splitDirectLightBox = new ng::CheckBox(settingsGroup, "Split Direct Light"); splitDirectLightBox->set_checked(_splitDirectLight); splitDirectLightBox->set_callback([this](bool enable) { _splitDirectLight = enable; }); - ng::Label* translationLabel = new ng::Label(settingsGroup, "Translation Options (T)"); + ng::ref translationLabel = new ng::Label(settingsGroup, "Translation Options (T)"); translationLabel->set_font_size(20); translationLabel->set_font("sans-bold"); - ng::Widget* targetShaderGroup = new ng::Widget(settingsGroup); + ng::ref targetShaderGroup = new ng::Widget(settingsGroup); targetShaderGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(targetShaderGroup, "Target Shader"); - ng::TextBox* targetShaderBox = new ng::TextBox(targetShaderGroup, _targetShader); + ng::ref targetShaderBox = new ng::TextBox(targetShaderGroup, _targetShader); targetShaderBox->set_callback([this](const std::string& choice) { _targetShader = choice; @@ -1056,46 +1046,46 @@ void Viewer::createAdvancedSettings(Widget* parent) targetShaderBox->set_font_size(16); targetShaderBox->set_editable(true); - ng::Label* textureLabel = new ng::Label(settingsGroup, "Texture Baking Options (B)"); + ng::ref textureLabel = new ng::Label(settingsGroup, "Texture Baking Options (B)"); textureLabel->set_font_size(20); textureLabel->set_font("sans-bold"); - ng::CheckBox* bakeHdrBox = new ng::CheckBox(settingsGroup, "Bake HDR Textures"); + ng::ref bakeHdrBox = new ng::CheckBox(settingsGroup, "Bake HDR Textures"); bakeHdrBox->set_checked(_bakeHdr); bakeHdrBox->set_callback([this](bool enable) { _bakeHdr = enable; }); - ng::CheckBox* bakeAverageBox = new ng::CheckBox(settingsGroup, "Bake Averaged Textures"); + ng::ref bakeAverageBox = new ng::CheckBox(settingsGroup, "Bake Averaged Textures"); bakeAverageBox->set_checked(_bakeAverage); bakeAverageBox->set_callback([this](bool enable) { _bakeAverage = enable; }); - ng::CheckBox* bakeOptimized = new ng::CheckBox(settingsGroup, "Optimize Baked Constants"); + ng::ref bakeOptimized = new ng::CheckBox(settingsGroup, "Optimize Baked Constants"); bakeOptimized->set_checked(_bakeOptimize); bakeOptimized->set_callback([this](bool enable) { _bakeOptimize = enable; }); - ng::CheckBox* bakeDocumentPerMaterial= new ng::CheckBox(settingsGroup, "Bake Document Per Material"); + ng::ref bakeDocumentPerMaterial= new ng::CheckBox(settingsGroup, "Bake Document Per Material"); bakeDocumentPerMaterial->set_checked(_bakeDocumentPerMaterial); bakeDocumentPerMaterial->set_callback([this](bool enable) { _bakeDocumentPerMaterial = enable; }); - ng::Label* wedgeLabel = new ng::Label(settingsGroup, "Wedge Render Options (W)"); + ng::ref wedgeLabel = new ng::Label(settingsGroup, "Wedge Render Options (W)"); wedgeLabel->set_font_size(20); wedgeLabel->set_font("sans-bold"); - ng::Widget* wedgeNameGroup = new ng::Widget(settingsGroup); + ng::ref wedgeNameGroup = new ng::Widget(settingsGroup); wedgeNameGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); new ng::Label(wedgeNameGroup, "Property Name"); - ng::TextBox* wedgeNameBox = new ng::TextBox(wedgeNameGroup, _wedgePropertyName); + ng::ref wedgeNameBox = new ng::TextBox(wedgeNameGroup, _wedgePropertyName); wedgeNameBox->set_callback([this](const std::string& choice) { _wedgePropertyName = choice; @@ -1104,12 +1094,12 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeNameBox->set_font_size(16); wedgeNameBox->set_editable(true); - ng::Widget* wedgeMinGroup = new ng::Widget(settingsGroup); + ng::ref wedgeMinGroup = new ng::Widget(settingsGroup); wedgeMinGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeProp; wedgeProp.uiSoftMin = mx::Value::createValue(0.0f); wedgeProp.uiSoftMax = mx::Value::createValue(1.0f); - ng::FloatBox* wedgeMinBox = createFloatWidget(wedgeMinGroup, "Property Min:", + ng::ref> wedgeMinBox = createFloatWidget(wedgeMinGroup, "Property Min:", _wedgePropertyMax, &wedgeProp, [this](float value) { _wedgePropertyMin = value; @@ -1117,9 +1107,9 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMinBox->set_value(0.0); wedgeMinBox->set_editable(true); - ng::Widget* wedgeMaxGroup = new ng::Widget(settingsGroup); + ng::ref wedgeMaxGroup = new ng::Widget(settingsGroup); wedgeMaxGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); - ng::FloatBox* wedgeMaxBox = createFloatWidget(wedgeMaxGroup, "Property Max:", + ng::ref> wedgeMaxBox = createFloatWidget(wedgeMaxGroup, "Property Max:", _wedgePropertyMax, &wedgeProp, [this](float value) { _wedgePropertyMax = value; @@ -1127,13 +1117,13 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeMaxBox->set_value(1.0); wedgeMaxBox->set_editable(true); - ng::Widget* wedgeCountGroup = new ng::Widget(settingsGroup); + ng::ref wedgeCountGroup = new ng::Widget(settingsGroup); wedgeCountGroup->set_layout(new ng::BoxLayout(ng::Orientation::Horizontal)); mx::UIProperties wedgeCountProp; wedgeCountProp.uiMin = mx::Value::createValue(1); wedgeCountProp.uiSoftMax = mx::Value::createValue(8); wedgeCountProp.uiStep = mx::Value::createValue(1); - ng::IntBox* wedgeCountBox = createIntWidget(wedgeCountGroup, "Image Count:", + ng::ref> wedgeCountBox = createIntWidget(wedgeCountGroup, "Image Count:", _wedgeImageCount, &wedgeCountProp, [this](int value) { _wedgeImageCount = value; @@ -1141,7 +1131,7 @@ void Viewer::createAdvancedSettings(Widget* parent) wedgeCountBox->set_value(8); wedgeCountBox->set_editable(true); - createDocumentationInterface(advancedPopup, scrollPanel); + createDocumentationInterface(advancedPopup); } void Viewer::updateGeometrySelections() @@ -1769,6 +1759,9 @@ void Viewer::initContext(mx::GenContext& context) unitSystem->setUnitConverterRegistry(_unitRegistry); context.getShaderGenerator().setUnitSystem(unitSystem); context.getOptions().targetDistanceUnit = "meter"; + + // Initialize the struct typedefs from the stdlib + context.getShaderGenerator().loadStructTypeDefs(_stdLib); } void Viewer::loadStandardLibraries() @@ -2438,7 +2431,7 @@ void Viewer::updateCameras() void Viewer::updateDisplayedProperties() { _propertyEditor.updateContents(this); - createSaveMaterialsInterface(_propertyEditor.getWindow(), "Save Material"); + createSaveMaterialsInterface((ng::ref) _propertyEditor.getWindow(), "Save Material"); perform_layout(); } diff --git a/source/MaterialXView/Viewer.h b/source/MaterialXView/Viewer.h index 08712f3c78..8f0257e1e1 100644 --- a/source/MaterialXView/Viewer.h +++ b/source/MaterialXView/Viewer.h @@ -179,7 +179,7 @@ class Viewer : public ng::Screen } // Return the underlying NanoGUI window. - ng::Window* getWindow() const + ng::ref getWindow() const { return _window; } @@ -283,13 +283,13 @@ class Viewer : public ng::Screen void updateMaterialSelectionUI(); void updateDisplayedProperties(); - void createLoadMeshInterface(Widget* parent, const std::string& label); - void createLoadMaterialsInterface(Widget* parent, const std::string& label); - void createLoadEnvironmentInterface(Widget* parent, const std::string& label); - void createSaveMaterialsInterface(Widget* parent, const std::string& label); - void createPropertyEditorInterface(Widget* parent, const std::string& label); - void createAdvancedSettings(Widget* parent); - void createDocumentationInterface(Widget* parent, ng::VScrollPanel* scrollPanel); + void createLoadMeshInterface(ng::ref parent, const std::string& label); + void createLoadMaterialsInterface(ng::ref parent, const std::string& label); + void createLoadEnvironmentInterface(ng::ref parent, const std::string& label); + void createSaveMaterialsInterface(ng::ref parent, const std::string& label); + void createPropertyEditorInterface(ng::ref parent, const std::string& label); + void createAdvancedSettings(ng::ref parent); + void createDocumentationInterface(ng::ref parent); // Return the ambient occlusion image, if any, associated with the given material. mx::ImagePtr getAmbientOcclusionImage(mx::MaterialPtr material); @@ -318,7 +318,7 @@ class Viewer : public ng::Screen void setShaderInterfaceType(mx::ShaderInterfaceType interfaceType); private: - ng::Window* _window; + ng::ref _window; RenderPipelinePtr _renderPipeline; mx::FilePath _materialFilename; @@ -380,15 +380,15 @@ class Viewer : public ng::Screen // Geometry selections std::vector _geometryList; size_t _selectedGeom; - ng::Label* _geomLabel; - ng::ComboBox* _geometrySelectionBox; + ng::ref _geomLabel; + ng::ref _geometrySelectionBox; // Material selections std::vector _materials; mx::MaterialPtr _wireMaterial; size_t _selectedMaterial; - ng::Label* _materialLabel; - ng::ComboBox* _materialSelectionBox; + ng::ref _materialLabel; + ng::ref _materialSelectionBox; PropertyEditor _propertyEditor; // Material assignments @@ -475,11 +475,15 @@ class Viewer : public ng::Screen // Frame timing bool _frameTiming; - ng::Label* _timingLabel; - ng::Widget* _timingPanel; - ng::TextBox* _timingText; + ng::ref _timingLabel; + ng::ref _timingPanel; + ng::ref _timingText; mx::ScopedTimer _frameTimer; double _avgFrameTime; + + // Documentation UI + ng::ref _shortcutsButton; + ng::ref _shortcutsTable; }; extern const mx::Vector3 DEFAULT_CAMERA_POSITION; diff --git a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp index cb70d04704..004fa0a670 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyElement.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyElement.cpp @@ -224,10 +224,10 @@ void bindPyElement(py::module& mod) .def_readwrite("attributeName", &mx::ElementEquivalenceResult::attributeName); py::class_(mod, "ElementEquivalenceOptions") - .def_readwrite("format", &mx::ElementEquivalenceOptions::format) - .def_readwrite("precision", &mx::ElementEquivalenceOptions::precision) - .def_readwrite("skipAttributes", &mx::ElementEquivalenceOptions::skipAttributes) - .def_readwrite("skipValueComparisons", &mx::ElementEquivalenceOptions::skipValueComparisons) + .def_readwrite("performValueComparisons", &mx::ElementEquivalenceOptions::performValueComparisons) + .def_readwrite("floatFormat", &mx::ElementEquivalenceOptions::floatFormat) + .def_readwrite("floatPrecision", &mx::ElementEquivalenceOptions::floatPrecision) + .def_readwrite("attributeExclusionList", &mx::ElementEquivalenceOptions::attributeExclusionList) .def(py::init<>()); py::class_(mod, "StringResolver") diff --git a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp index 501f9d5f04..c36bd6c288 100644 --- a/source/PyMaterialX/PyMaterialXCore/PyValue.cpp +++ b/source/PyMaterialX/PyMaterialXCore/PyValue.cpp @@ -6,6 +6,7 @@ #include #include +#include #define BIND_TYPE_INSTANCE(NAME, T) \ py::class_, std::shared_ptr< mx::TypedValue >, mx::Value>(mod, "TypedValue_" #NAME) \ @@ -22,7 +23,10 @@ void bindPyValue(py::module& mod) py::class_(mod, "Value") .def("getValueString", &mx::Value::getValueString) .def("getTypeString", &mx::Value::getTypeString) - .def_static("createValueFromStrings", &mx::Value::createValueFromStrings); + .def_static("createValueFromStrings", &mx::Value::createValueFromStrings, + py::arg("value"), + py::arg("type"), + py::arg("typeDefPtr") = nullptr); BIND_TYPE_INSTANCE(integer, int) BIND_TYPE_INSTANCE(boolean, bool) diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp index b952bd4651..0c8a086e58 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyShaderGenerator.cpp @@ -22,5 +22,7 @@ void bindPyShaderGenerator(py::module& mod) .def("setUnitSystem", &mx::ShaderGenerator::setUnitSystem) .def("getUnitSystem", &mx::ShaderGenerator::getUnitSystem) .def("getTokenSubstitutions", &mx::ShaderGenerator::getTokenSubstitutions) + .def("loadStructTypeDefs", &mx::ShaderGenerator::loadStructTypeDefs) + .def("clearStructTypeDefs", &mx::ShaderGenerator::clearStructTypeDefs) .def("registerShaderMetadata", &mx::ShaderGenerator::registerShaderMetadata); }