+
+
+
+
+
+
+
+
+
+
+
MaterialX Shader Editor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Capture
+
+
+
+
+
+
+
+
+
+ Preview
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Teapot
+ Shader Ball
+ Sphere
+ Plane
+ Cylinder
+ Custom...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Properties
+
+
+
+
+
+
+
+
+
+
+
+
+
MaterialX Document
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/javascript/materialxtoy/litegraph/base.js b/javascript/shader_editor/dist/litegraph/base.js
similarity index 100%
rename from javascript/materialxtoy/litegraph/base.js
rename to javascript/shader_editor/dist/litegraph/base.js
diff --git a/javascript/materialxtoy/litegraph/demos.js b/javascript/shader_editor/dist/litegraph/demos.js
similarity index 100%
rename from javascript/materialxtoy/litegraph/demos.js
rename to javascript/shader_editor/dist/litegraph/demos.js
diff --git a/javascript/materialxtoy/litegraph/input.js b/javascript/shader_editor/dist/litegraph/input.js
similarity index 100%
rename from javascript/materialxtoy/litegraph/input.js
rename to javascript/shader_editor/dist/litegraph/input.js
diff --git a/javascript/materialxtoy/litegraph/interface.js b/javascript/shader_editor/dist/litegraph/interface.js
similarity index 100%
rename from javascript/materialxtoy/litegraph/interface.js
rename to javascript/shader_editor/dist/litegraph/interface.js
diff --git a/javascript/materialxtoy/litegraph/litegraph-editor.css b/javascript/shader_editor/dist/litegraph/litegraph-editor.css
similarity index 100%
rename from javascript/materialxtoy/litegraph/litegraph-editor.css
rename to javascript/shader_editor/dist/litegraph/litegraph-editor.css
diff --git a/javascript/materialxtoy/litegraph/litegraph-editor.js b/javascript/shader_editor/dist/litegraph/litegraph-editor.js
similarity index 100%
rename from javascript/materialxtoy/litegraph/litegraph-editor.js
rename to javascript/shader_editor/dist/litegraph/litegraph-editor.js
diff --git a/javascript/materialxtoy/litegraph/litegraph.css b/javascript/shader_editor/dist/litegraph/litegraph.css
similarity index 100%
rename from javascript/materialxtoy/litegraph/litegraph.css
rename to javascript/shader_editor/dist/litegraph/litegraph.css
diff --git a/javascript/materialxtoy/litegraph/litegraph.js b/javascript/shader_editor/dist/litegraph/litegraph.js
similarity index 100%
rename from javascript/materialxtoy/litegraph/litegraph.js
rename to javascript/shader_editor/dist/litegraph/litegraph.js
diff --git a/javascript/materialxtoy/litegraph/math.js b/javascript/shader_editor/dist/litegraph/math.js
similarity index 100%
rename from javascript/materialxtoy/litegraph/math.js
rename to javascript/shader_editor/dist/litegraph/math.js
diff --git a/javascript/materialxtoy/litegraph/style.css b/javascript/shader_editor/dist/litegraph/style.css
similarity index 100%
rename from javascript/materialxtoy/litegraph/style.css
rename to javascript/shader_editor/dist/litegraph/style.css
diff --git a/javascript/materialxnode/dist/main.js b/javascript/shader_editor/dist/main.js
similarity index 95%
rename from javascript/materialxnode/dist/main.js
rename to javascript/shader_editor/dist/main.js
index 8e9324af..707cfa26 100644
--- a/javascript/materialxnode/dist/main.js
+++ b/javascript/shader_editor/dist/main.js
@@ -10,6 +10,16 @@
/******/ "use strict";
/******/ var __webpack_modules__ = ({
+/***/ "../node_editor.js":
+/*!*************************!*\
+ !*** ../node_editor.js ***!
+ \*************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ initializeNodeEditor: () => (/* binding */ initializeNodeEditor)\n/* harmony export */ });\n\r\n\r\nfunction initializeNodeEditor(materialFilename, geometryFilename, theRenderer) {\r\n\r\n // Customize what icon to show based on nodedef name prefix or nodegroup\r\n // Note that this is just a heuristic based on current nodegroup and naming \r\n // convention. Default is \"mtlx\" for MaterialX nodes.\r\n var my_icon_map = {\r\n \"gltf\": \"./Images/gltf_logo.webp\",\r\n \"usd\": \"./Images/openusd_logo.webp\",\r\n \"open_pbr\": \"./Images/openpbr_logo.webp\",\r\n \"houdini\": \"./Images/houdini_icon.webp\",\r\n \"maya\": \"./Images/maya_surfaces.webp\",\r\n \"_default_\": \"./Images/materialx_logo.webp\",\r\n \"_default_graph_\": \"./Images/nodegraph_white.svg\"\r\n };\r\n\r\n function uriExists(uri) {\r\n // Add try / catch block to handle network errors \r\n return fetch(uri)\r\n .then(response => {\r\n if (response.ok) {\r\n return Promise.resolve(true);\r\n } else {\r\n return Promise.resolve(false);\r\n }\r\n })\r\n .catch(error => {\r\n console.log('Error checking URI:', error);\r\n return Promise.resolve(false);\r\n });\r\n } \r\n\r\n function renderableItemUpdater(renderableItems) {\r\n\r\n let renderableItemSelect = document.getElementById('renderableItem');\r\n if (renderableItemSelect) {\r\n \r\n while (renderableItemSelect.firstChild) {\r\n renderableItemSelect.removeChild(renderableItemSelect.firstChild);\r\n }\r\n for (let i = 0; i < renderableItems.length; i++) {\r\n let item = renderableItems[i];\r\n let option = document.createElement('option');\r\n option.value = item;\r\n let uiitem = item;\r\n // Truncate the name so it will fit into UI.\r\n if (uiitem.length > 12)\r\n uiitem = uiitem.substring(0, 12) + '...';\r\n option.text = uiitem; \r\n renderableItemSelect.appendChild(option);\r\n } \r\n } \r\n }\r\n \r\n if (theRenderer) {\r\n var viewer = theRenderer.initializeViewer(materialFilename, geometryFilename);\r\n console.log('Setup viewer:', viewer);\r\n }\r\n else {\r\n let preview_panel = document.getElementById(\"preview_panel\");\r\n // Hide preview_panel DOM element\r\n if (preview_panel)\r\n preview_panel.style.display = 'none';\r\n }\r\n\r\n var canvas = document.getElementById('mygraphcanvas');\r\n var cmeditor = setupXMLSyntax();\r\n var cmeditor2 = setupJavascriptSyntax();\r\n var ui = {\r\n console_area: document.getElementById('console_area'),\r\n nodeTypesList: document.getElementById('nodeTypesList'),\r\n renderableItemUpdater: renderableItemUpdater,\r\n mtlxdoc: cmeditor,\r\n mtlxlib: cmeditor2,\r\n mtlxdoc_colorspace: null, // document.getElementById('mtlxdoc_colorspace'),\r\n propertypanel_content: document.getElementById('propertypanel_content'),\r\n propertypanel_icon: document.getElementById('propertypanel_icon'),\r\n icon_map: my_icon_map,\r\n };\r\n var editor = new MxShadingGraphEditor();\r\n editor.initialize(false, canvas, ui, materialFilename);\r\n\r\n function addUIHandlers() {\r\n // Add event listener to save canvas as image when button is clicked\r\n var saveCanvasButton = document.getElementById('captureGraph');\r\n saveCanvasButton.addEventListener('click', function () {\r\n var canvas = document.getElementById('mygraphcanvas');\r\n var dataURL = canvas.toDataURL('image/png');\r\n var link = document.createElement('a');\r\n link.href = dataURL;\r\n link.download = 'graph_capture.png';\r\n link.click();\r\n });\r\n\r\n // TODO: Make this a user option\r\n var auto_arrange_size = 80;\r\n\r\n // Add load materialx graph event listener\r\n var loadMaterialXDocumentFromFile = document.getElementById('loadMaterialXDocumentFromFile');\r\n loadMaterialXDocumentFromFile.addEventListener('click', function () {\r\n editor.loadGraphFromFile('mtlx', auto_arrange_size);\r\n });\r\n\r\n // Add load materialx graph from text event listener\r\n var texAreaNumber = 0;\r\n var loadMaterialXDocumentFromText = document.getElementById('loadMaterialXDocumentFromText');\r\n loadMaterialXDocumentFromText.addEventListener('click', function () {\r\n var mtlxdoc = document.getElementById('mtlxdoc').value;\r\n // Generate a name for the graph\r\n if (mtlxdoc.length > 0) {\r\n var name = 'MaterialXGraph' + texAreaNumber++;\r\n editor.loadGraphFromString('mtlx', mtlxdoc, name, auto_arrange_size);\r\n }\r\n });\r\n\r\n // Add load definitions event listener\r\n var loadMaterialXDefinitions = document.getElementById('loadMaterialXDefinitions');\r\n loadMaterialXDefinitions.addEventListener('click', function () {\r\n editor.loadDefinitionsFromFile('mtlx');\r\n });\r\n\r\n // Add clear graph event listener\r\n var clearGraphButton = document.getElementById('clearGraph');\r\n clearGraphButton.addEventListener('click', function () {\r\n editor.clearGraph();\r\n });\r\n\r\n // Add save materialx graph event listener\r\n var saveMaterialXGraph = document.getElementById('saveMaterialXGraph');\r\n saveMaterialXGraph.addEventListener('click', function () {\r\n var saveCustomLibs = document.getElementById('saveCustomLibs').checked;\r\n var saveNodePositions = document.getElementById('saveNodePositions').checked;\r\n editor.saveGraphToFile('mtlx', saveCustomLibs, saveNodePositions);\r\n });\r\n\r\n // Add save materialx graph text event listener\r\n var saveMaterialXGraphText = document.getElementById('saveMaterialXGraphText');\r\n saveMaterialXGraphText.addEventListener('click', function () {\r\n saveToStringUI();\r\n });\r\n\r\n // Add open subgraph event handler\r\n var openSubgraph = document.getElementById('openSubgraph');\r\n openSubgraph.addEventListener('click', function () {\r\n editor.openSubgraph();\r\n });\r\n\r\n // Add close subgraph event handler\r\n var closeSubgraph = document.getElementById('closeSubgraph');\r\n closeSubgraph.addEventListener('click', function () {\r\n editor.closeSubgraph();\r\n });\r\n\r\n\r\n // Add reset view event handler\r\n var resetView = document.getElementById('resetView');\r\n resetView.addEventListener('click', function () {\r\n editor.resetView();\r\n });\r\n\r\n // Add arrange graph event listener\r\n var arrangeGraphButton = document.getElementById('arrangeGraph');\r\n arrangeGraphButton.addEventListener('click', function () {\r\n editor.arrangeGraph();\r\n });\r\n\r\n // Add center node event listener\r\n var centerNodeButton = document.getElementById('centerNode');\r\n centerNodeButton.addEventListener('click', function () {\r\n editor.centerNode();\r\n });\r\n\r\n // Add collapse/expand nodes event listener\r\n var collapseNodesButton = document.getElementById('collapseNodes');\r\n collapseNodesButton.addEventListener('click', function () {\r\n editor.collapseExpandNodes(true);\r\n });\r\n var expandNodesButton = document.getElementById('expandNodes');\r\n expandNodesButton.addEventListener('click', function () {\r\n editor.collapseExpandNodes(false);\r\n });\r\n\r\n // Add copy selected event listener\r\n var copySelectedButton = document.getElementById('copySelected');\r\n copySelectedButton.addEventListener('click', function () {\r\n editor.copyToClipboard();\r\n });\r\n\r\n // Add paste selected event listener\r\n var pasteSelectedButton = document.getElementById('pasteSelected');\r\n pasteSelectedButton.addEventListener('click', function () {\r\n editor.pasteFromClipboard();\r\n });\r\n\r\n // Add create subgraph event listener\r\n var createNodeGraphButton = document.getElementById('createNodeGraph');\r\n createNodeGraphButton.addEventListener('click', function () {\r\n editor.createNodeGraph();\r\n });\r\n\r\n // Add extract subgraph event listener\r\n var extractNodeGraphButton = document.getElementById('extractNodeGraph');\r\n extractNodeGraphButton.addEventListener('click', function () {\r\n editor.extractNodeGraph();\r\n });\r\n\r\n /* \r\n // Add load serialization event listener\r\n var loadSerialization = document.getElementById('loadSerialization');\r\n loadSerialization.addEventListener('click', function () {\r\n editor.loadSerialization();\r\n });\r\n \r\n // Add download graph event listener\r\n var downloadGraph = document.getElementById('downloadGraph');\r\n downloadGraph.addEventListener('click', function () {\r\n editor.saveSerialization();\r\n }); */\r\n\r\n // Add xml to graph event listener\r\n var xmltograph = document.getElementById('xmltograph');\r\n xmltograph.addEventListener('click', function () {\r\n var name = 'MaterialXGraph' + texAreaNumber++;\r\n var mtlxdoc = document.getElementById('mtlxdoc').value;\r\n editor.loadGraphFromString('mtlx', mtlxdoc, 'MaterialXGraph', auto_arrange_size);\r\n });\r\n\r\n function updateRenderableItemUI()\r\n {\r\n let renderableItems = editor.findRenderableItems();\r\n renderableItemUpdater(renderableItems);\r\n }\r\n\r\n function saveToStringUI() {\r\n var saveCustomLibs = document.getElementById('saveCustomLibs').checked;\r\n var saveNodePositions = document.getElementById('saveNodePositions').checked;\r\n var result = editor.saveGraphToString('mtlx', saveCustomLibs, saveNodePositions);\r\n cmeditor.setValue(result);\r\n\r\n if (theRenderer) {\r\n theRenderer.updateMaterialFromText(result);\r\n updateRenderableItemUI();\r\n }\r\n }\r\n\r\n // Add graph to xml event listener\r\n var graphtoxml = document.getElementById('graphtoxml');\r\n if (graphtoxml) {\r\n graphtoxml.addEventListener('click', function () {\r\n saveToStringUI();\r\n });\r\n }\r\n\r\n var graphtoxml2 = document.getElementById('graphtoxml2');\r\n if (graphtoxml2) {\r\n graphtoxml2.addEventListener('click', function () {\r\n saveToStringUI();\r\n });\r\n }\r\n\r\n // Handle turntabe option\r\n let turntableEnabledUI = document.getElementById('turntableEnabled');\r\n if (turntableEnabledUI) {\r\n turntableEnabledUI.addEventListener('click', (e) => {\r\n // Toggle inverting the button colors no toggling danger\r\n turntableEnabledUI.classList.toggle('btn-secondary');\r\n if (theRenderer)\r\n theRenderer.toggleTurntable();\r\n });\r\n }\r\n\r\n // Handle render disabled option\r\n let disableRenderingUI = document.getElementById('disableRendering');\r\n if (disableRenderingUI) {\r\n disableRenderingUI.addEventListener('click', (e) => {\r\n // Toggle inverting the button colors\r\n disableRenderingUI.classList.toggle('btn-danger');\r\n if (theRenderer)\r\n theRenderer.toggleRendering();\r\n });\r\n }\r\n\r\n // Handle background display option\r\n let toggleBackgroundTextureUI = document.getElementById('toggleBackgroundTexture');\r\n if (toggleBackgroundTextureUI) {\r\n toggleBackgroundTextureUI.addEventListener('click', (e) => {\r\n toggleBackgroundTextureUI.classList.toggle('btn-secondary');\r\n if (theRenderer)\r\n theRenderer.toggleBackgroundTexture();\r\n });\r\n }\r\n // Handle reset camera option\r\n let resetCameraUI = document.getElementById('resetCamera');\r\n if (resetCameraUI) {\r\n resetCameraUI.addEventListener('click', (e) => {\r\n if (theRenderer)\r\n theRenderer.resetCamera();\r\n });\r\n }\r\n\r\n // Handle renderable geometry option\r\n function loadFromMenu(e) {\r\n var uiItem = e.target.value;\r\n if (uiItem == '_loadFromFile_') {\r\n // Create a file dialog to get the filename\r\n var fileInput = document.createElement('input');\r\n fileInput.type = 'file';\r\n fileInput.accept = '.glb';\r\n\r\n fileInput.onchange = function (event) {\r\n var file = event.target.files[0];\r\n if (file) {\r\n var fileURL = URL.createObjectURL(file);\r\n if (theRenderer)\r\n theRenderer.setRenderGeometry(fileURL);\r\n console.log('Change geometry to:', fileURL, 'from file:', file.name);\r\n }\r\n }\r\n fileInput.click();\r\n }\r\n else {\r\n // Convert to lowercase and remove spaces\r\n var geometryURL = uiItem.toLowerCase().replace(/\\s/g, '');\r\n var geometryPath = 'Geometry/' + geometryURL + '.glb';\r\n console.log('Change geometry to:', geometryPath);\r\n if (theRenderer)\r\n theRenderer.setRenderGeometry(geometryPath);\r\n }\r\n }\r\n\r\n // Handle geometry item changed\r\n let geometryItemSelect = document.getElementById('loadGeometry');\r\n if (geometryItemSelect) {\r\n // Add event handler for selection\r\n geometryItemSelect.addEventListener('change', (e) => {\r\n loadFromMenu(e);\r\n if (e.target.value == '_loadFromFile_')\r\n e.target.value = 'Custom Geometry'\r\n });\r\n }\r\n\r\n // Handle material selection change\r\n let renderableItemSelect = document.getElementById('renderableItem');\r\n if (renderableItemSelect) {\r\n renderableItemSelect.addEventListener('change', (e) => {\r\n let index = e.target.value;\r\n if (theRenderer)\r\n theRenderer.setRenderMaterial(index);\r\n });\r\n }\r\n\r\n // Get the canvas element and its container\r\n var canvas = document.getElementById('mygraphcanvas');\r\n var canvasContainer = document.getElementById('canvasContainer');\r\n var colContainer = document.getElementById('colContainer');\r\n\r\n // Create a new ResizeObserver\r\n var observer = new ResizeObserver(function (entries) {\r\n for (var entry of entries) {\r\n // Get the new width and height of the column\r\n var newWidth = entry.contentRect.width;\r\n var newHeight = entry.contentRect.height;\r\n\r\n // Set the canvas size to match the column\r\n canvas.width = newWidth;\r\n canvas.height = newHeight;\r\n\r\n // Mark the editor as dirty to redraw the graph.\r\n editor.setDirty();\r\n }\r\n });\r\n\r\n // Start observing the canvas container\r\n observer.observe(colContainer);\r\n\r\n }\r\n\r\n function setupJavascriptSyntax() {\r\n // Initialize CodeMirror for JS syntax highlighting\r\n const elem = document.getElementById('mtlxlib');\r\n if (!elem) {\r\n return;\r\n }\r\n var cmeditor = CodeMirror.fromTextArea(elem, {\r\n mode: 'application/javascript',\r\n lineNumbers: true,\r\n dragDrop: false,\r\n theme: 'dracula',\r\n readOnly: true\r\n });\r\n\r\n elem.value = '';\r\n cmeditor.setValue('');\r\n\r\n // Update CodeMirror whenever the textarea content changes\r\n cmeditor.on('change', () => {\r\n elem.value = cmeditor.getValue();\r\n });\r\n\r\n return cmeditor;\r\n }\r\n\r\n\r\n function setupXMLSyntax() {\r\n // Initialize CodeMirror for XML syntax highlighting\r\n const materialXTextArea = document.getElementById('mtlxdoc');\r\n var cmeditor = CodeMirror.fromTextArea(materialXTextArea, {\r\n mode: 'application/xml',\r\n lineNumbers: true,\r\n dragDrop: true,\r\n theme: 'night'\r\n });\r\n\r\n // Optional: Set an initial value for the textarea\r\n const initialXML = '';\r\n materialXTextArea.value = initialXML;\r\n cmeditor.setValue(initialXML);\r\n\r\n // Update CodeMirror whenever the textarea content changes\r\n cmeditor.on('change', (e) => {\r\n materialXTextArea.value = cmeditor.getValue();\r\n });\r\n\r\n var pasteButton = document.getElementById('mtlxdoc_paste');\r\n if (pasteButton)\r\n addPasteHandler(pasteButton, cmeditor);\r\n\r\n return cmeditor;\r\n }\r\n\r\n\r\n\r\n\r\n addUIHandlers();\r\n addCopyHandlers();\r\n}\r\n\n\n//# sourceURL=webpack://MaterialX-Shader-Editor/../node_editor.js?");
+
+/***/ }),
+
/***/ "./source/dropHandling.js":
/*!********************************!*\
!*** ./source/dropHandling.js ***!
@@ -26,7 +36,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
\**************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ findLights: () => (/* binding */ findLights),\n/* harmony export */ getLightRotation: () => (/* binding */ getLightRotation),\n/* harmony export */ getUniformValues: () => (/* binding */ getUniformValues),\n/* harmony export */ prepareEnvTexture: () => (/* binding */ prepareEnvTexture),\n/* harmony export */ registerLights: () => (/* binding */ registerLights)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n//\r\n// Copyright Contributors to the MaterialX Project\r\n// SPDX-License-Identifier: Apache-2.0\r\n//\r\n\r\n\r\n\r\n//import { getBufferFromFile } from './dropHandling.js';\r\n\r\nconst IMAGE_PROPERTY_SEPARATOR = \"_\";\r\nconst UADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"uaddressmode\";\r\nconst VADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"vaddressmode\";\r\nconst FILTER_TYPE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"filtertype\";\r\nconst IMAGE_PATH_SEPARATOR = \"/\";\r\n\r\n/**\r\n * Initialized the environment texture as MaterialX expects it\r\n * @param {THREE.Texture} texture\r\n * @param {Object} capabilities\r\n * @returns {THREE.Texture}\r\n */\r\nfunction prepareEnvTexture(texture, capabilities)\r\n{\r\n let newTexture = new three__WEBPACK_IMPORTED_MODULE_0__.DataTexture(texture.image.data, texture.image.width, texture.image.height, texture.format, texture.type);\r\n newTexture.wrapS = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n newTexture.anisotropy = capabilities.getMaxAnisotropy();\r\n newTexture.minFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearMipmapLinearFilter;\r\n newTexture.magFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n newTexture.generateMipmaps = true;\r\n newTexture.needsUpdate = true;\r\n\r\n return newTexture;\r\n}\r\n\r\n/**\r\n * Get Three uniform from MaterialX vector\r\n * @param {any} value\r\n * @param {any} dimension\r\n * @returns {THREE.Uniform}\r\n */\r\nfunction fromVector(value, dimension)\r\n{\r\n let outValue;\r\n if (value)\r\n {\r\n outValue = value.data();\r\n }\r\n else\r\n {\r\n outValue = [];\r\n for (let i = 0; i < dimension; ++i)\r\n outValue.push(0.0);\r\n }\r\n\r\n return outValue;\r\n}\r\n\r\n/**\r\n * Get Three uniform from MaterialX matrix\r\n * @param {mx.matrix} matrix\r\n * @param {mx.matrix.size} dimension\r\n */\r\nfunction fromMatrix(matrix, dimension)\r\n{\r\n let vec = [];\r\n if (matrix)\r\n {\r\n for (let i = 0; i < matrix.numRows(); ++i)\r\n {\r\n for (let k = 0; k < matrix.numColumns(); ++k)\r\n {\r\n vec.push(matrix.getItem(i, k));\r\n }\r\n }\r\n } else\r\n {\r\n for (let i = 0; i < dimension; ++i)\r\n vec.push(0.0);\r\n }\r\n\r\n return vec;\r\n}\r\n\r\nfunction loadTextureFile(uri, loader)\r\n{\r\n return new Promise((resolve, reject) =>\r\n {\r\n if (loader) \r\n {\r\n console.log(\"Load image file: \", uri); \r\n loader.load(\r\n uri,\r\n function (texture) {\r\n console.log('- Resolve texture:', texture);\r\n resolve(texture);\r\n },\r\n function (xhr) {\r\n // This function will be called while the texture is loading\r\n console.log((xhr.loaded / xhr.total) * 100 + '% loaded');\r\n },\r\n function (error) {\r\n resolve(null);\r\n // This function will be called if there is an error loading the texture\r\n //reject(new Error('Error loading texture: ' + error));\r\n }\r\n ); \r\n }\r\n });\r\n}\r\n\r\n// Function to load an image file and return a buffer using FileReader.readAsArrayBuffer()\r\nfunction getTextureBufferFromFile(filePath, textureLoader) {\r\n return new Promise((resolve, reject) => {\r\n // Create a FileReader\r\n const fileReader = new FileReader();\r\n\r\n // Event listener for the FileReader's load event\r\n //fileReader.addEventListener('load', function (event) {\r\n fileReader.onloadend = function (e)\r\n {\r\n // Get the result of the FileReader as an ArrayBuffer\r\n const buffer = event.target.result;\r\n\r\n // Convert the ArrayBuffer to a Uint8Array for examination\r\n //const uint8Array = new Uint8Array(buffer);\r\n\r\n console.log('--------- Loaded Buffer:', buffer, filePath, '---------');\r\n\r\n // Handle the obtained buffer\r\n console.log('Add texture buffer to cache:', filePath, ', ', buffer);\r\n\r\n const texture = loadTextureFile(URL.createObjectURL(new Blob([buffer])), textureLoader);\r\n //const texture = textureLoader.load(URL.createObjectURL(new Blob([buffer])));\r\n\r\n //const dataURL = 'data:image/jpeg;base64,' + btoa(String.fromCharCode.apply(null, uint8Array));\r\n //console.log('dataURL:', dataURL)\r\n //const texture = textureLoader.load(dataURL, function () {\r\n // Log the dimensions of the resulting texture\r\n // console.log('Texture dimensions:', texture.image.width, 'x', texture.image.height);\r\n //}); \r\n\r\n //const texture = textureLoader.load(texturePath);\r\n // Set address & filtering mode\r\n if (texture) {\r\n //THREE.Cache.add(filePath, texture);\r\n //setTextureParameters(texture, name, uniforms, flipY);\r\n //outValue = texture;\r\n console.log('Success: texture cached:', filePath, three__WEBPACK_IMPORTED_MODULE_0__.Cache.get(filePath));\r\n //let blah = THREE.Cache.get(texturePath);\r\n //if (blah)\r\n // console.log('blah.image.width:', blah.image.width, ', blah.image.height:', blah.image.height, ', blah.image.data:', blah.image.data, ', blah.image.data.length:', blah.image.data.length, ', blah.image.data.byteLength:', blah.image.data.byteLength, ', blah.image.data.buffer.byteLength:', blah.image.data.buffer.byteLength, ', blah.image.data.buffer:', blah.image.data.buffer);\r\n }\r\n else {\r\n console.error('Error: texture not found in cache:', filePath);\r\n }\r\n\r\n // Resolve the Promise with the obtained buffer\r\n resolve(texture);\r\n };\r\n\r\n // Event listener for errors during file reading\r\n fileReader.addEventListener('error', function (event) {\r\n result(null); // reject(new Error('Error reading file: ' + event.target.error));\r\n });\r\n\r\n // Read the content of the file as an ArrayBuffer\r\n fileReader.readAsArrayBuffer(new Blob([filePath]));\r\n });\r\n}\r\n\r\n\r\n// Function to load an image file and examine the dimensions of the loaded texture\r\nfunction examineImageFile(filePath, textureLoader) {\r\n return new Promise((resolve, reject) => {\r\n // Create a FileReader\r\n const fileReader = new FileReader();\r\n\r\n // Event listener for the FileReader's load event\r\n fileReader.addEventListener('load', function (event) {\r\n // Get the result of the FileReader as a data URL\r\n const dataURL = event.target.result;\r\n console.log('Load URL:', dataURL, filePath, '---------')\r\n\r\n // Create a texture using the data URL\r\n const texture = textureLoader.load(dataURL, function () {\r\n // Log the dimensions of the resulting texture\r\n console.log('Texture dimensions:', texture.image.width, 'x', texture.image.height);\r\n\r\n // Resolve the Promise with the loaded texture\r\n resolve(texture);\r\n });\r\n });\r\n\r\n // Event listener for errors during file reading\r\n fileReader.addEventListener('error', function (event) {\r\n reject(new Error('Error reading file: ' + event.target.error));\r\n });\r\n\r\n // Read the content of the file as a data URL\r\n fileReader.readAsDataURL(new Blob([filePath]));\r\n });\r\n}\r\n\r\n\r\n\r\n/**\r\n * Get Three uniform from MaterialX value\r\n * @param {mx.Uniform.type} type\r\n * @param {mx.Uniform.value} value\r\n * @param {mx.Uniform.name} name\r\n * @param {mx.Uniforms} uniforms\r\n * @param {THREE.textureLoader} textureLoader\r\n */\r\nfunction toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, flipY)\r\n{\r\n let outValue;\r\n switch (type)\r\n {\r\n case 'float':\r\n case 'integer':\r\n case 'boolean':\r\n outValue = value;\r\n break;\r\n case 'vector2':\r\n outValue = fromVector(value, 2);\r\n break;\r\n case 'vector3':\r\n case 'color3':\r\n outValue = fromVector(value, 3);\r\n break;\r\n case 'vector4':\r\n case 'color4':\r\n outValue = fromVector(value, 4);\r\n break;\r\n case 'matrix33':\r\n outValue = fromMatrix(value, 9);\r\n break;\r\n case 'matrix44':\r\n outValue = fromMatrix(value, 16);\r\n break;\r\n case 'filename':\r\n if (value)\r\n {\r\n let texturePath = searchPath + IMAGE_PATH_SEPARATOR + value;\r\n const textureExists = three__WEBPACK_IMPORTED_MODULE_0__.Cache.get(texturePath);\r\n if (!textureExists)\r\n {\r\n \r\n // Call the function to examine the image file\r\n /* examineImageFile(texturePath, textureLoader)\r\n .then(texture => {\r\n console.log('Add texture to cache:', texturePath, texture)\r\n setTextureParameters(texture, name, uniforms, flipY);\r\n outValue = texture; \r\n })\r\n .catch(error => {\r\n // Handle errors\r\n console.error('Error:', error);\r\n });\r\n */\r\n // Call the function to get a buffer from the file\r\n /*\r\n getTextureBufferFromFile(texturePath, textureLoader)\r\n .then(texture => {\r\n if (texture)\r\n setTextureParameters(texture, name, uniforms, flipY);\r\n outValue = texture;\r\n console.log('-- FINISHED loading: ' + texturePath)\r\n })\r\n .catch(error => {\r\n // Handle errors\r\n console.error('Error:', error);\r\n });\r\n */\r\n console.log('Image file not loaded: ', texturePath);\r\n }\r\n //else\r\n {\r\n const texture = textureLoader.load(texturePath);\r\n // Set address & filtering mode\r\n if (texture)\r\n {\r\n console.log('Loaded texture: ' + texturePath, ' searchPath: ' + searchPath + ' texture: ', texture)\r\n setTextureParameters(texture, name, uniforms, flipY);\r\n }\r\n else\r\n {\r\n console.error('Error: texture not found in cache:', texturePath);\r\n }\r\n outValue = texture;\r\n }\r\n }\r\n break;\r\n case 'samplerCube':\r\n case 'string':\r\n break;\r\n default:\r\n console.log('Value type not supported: ' + type);\r\n // struct\r\n outValue = null;//toThreeUniform(value);\r\n }\r\n\r\n return outValue;\r\n}\r\n\r\n/**\r\n * Get Three wrapping mode\r\n * @param {mx.TextureFilter.wrap} mode\r\n * @returns {THREE.Wrapping}\r\n */\r\nfunction getWrapping(mode)\r\n{\r\n let wrap;\r\n switch (mode)\r\n {\r\n case 1:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.ClampToEdgeWrapping;\r\n break;\r\n case 2:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n break;\r\n case 3:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.MirroredRepeatWrapping;\r\n break;\r\n default:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n break;\r\n }\r\n return wrap;\r\n}\r\n\r\n/**\r\n * Get Three minification filter\r\n * @param {mx.TextureFilter.minFilter} type\r\n * @param {mx.TextureFilter.generateMipmaps} generateMipmaps\r\n */\r\nfunction getMinFilter(type, generateMipmaps)\r\n{\r\n const filterType = generateMipmaps ? three__WEBPACK_IMPORTED_MODULE_0__.LinearMipMapLinearFilter : three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n if (type === 0)\r\n {\r\n filterType = generateMipmaps ? three__WEBPACK_IMPORTED_MODULE_0__.NearestMipMapNearestFilter : three__WEBPACK_IMPORTED_MODULE_0__.NearestFilter;\r\n }\r\n return filterType;\r\n}\r\n\r\n/**\r\n * Set Three texture parameters\r\n * @param {THREE.Texture} texture\r\n * @param {mx.Uniform.name} name\r\n * @param {mx.Uniforms} uniforms\r\n * @param {mx.TextureFilter.generateMipmaps} generateMipmaps\r\n */\r\nfunction setTextureParameters(texture, name, uniforms, flipY = true, generateMipmaps = true)\r\n{\r\n const idx = name.lastIndexOf(IMAGE_PROPERTY_SEPARATOR);\r\n const base = name.substring(0, idx) || name;\r\n\r\n texture.generateMipmaps = generateMipmaps;\r\n texture.wrapS = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n texture.wrapT = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n texture.magFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n texture.flipY = flipY;\r\n\r\n if (uniforms.find(base + UADDRESS_MODE_SUFFIX))\r\n {\r\n const uaddressmode = uniforms.find(base + UADDRESS_MODE_SUFFIX).getValue().getData();\r\n texture.wrapS = getWrapping(uaddressmode);\r\n }\r\n\r\n if (uniforms.find(base + VADDRESS_MODE_SUFFIX))\r\n {\r\n const vaddressmode = uniforms.find(base + VADDRESS_MODE_SUFFIX).getValue().getData();\r\n texture.wrapT = getWrapping(vaddressmode);\r\n }\r\n\r\n const filterType = uniforms.find(base + FILTER_TYPE_SUFFIX) ? uniforms.get(base + FILTER_TYPE_SUFFIX).value : -1;\r\n texture.minFilter = getMinFilter(filterType, generateMipmaps);\r\n}\r\n\r\n/**\r\n * Return the global light rotation matrix\r\n */\r\nfunction getLightRotation()\r\n{\r\n return new three__WEBPACK_IMPORTED_MODULE_0__.Matrix4().makeRotationY(Math.PI / 2);\r\n}\r\n\r\n/**\r\n * Returns all lights nodes in a MaterialX document\r\n * @param {mx.Document} doc \r\n * @returns {Array.
}\r\n */\r\nfunction findLights(doc)\r\n{\r\n let lights = [];\r\n for (let node of doc.getNodes())\r\n {\r\n if (node.getType() === \"lightshader\")\r\n lights.push(node);\r\n }\r\n return lights;\r\n}\r\n\r\n/**\r\n * Register lights in shader generation context\r\n * @param {Object} mx MaterialX Module\r\n * @param {Array.} lights Light nodes\r\n * @param {mx.GenContext} genContext Shader generation context\r\n * @returns {Array.}\r\n */\r\nfunction registerLights(mx, lights, genContext)\r\n{\r\n mx.HwShaderGenerator.unbindLightShaders(genContext);\r\n\r\n const lightTypesBound = {};\r\n const lightData = [];\r\n let lightId = 1;\r\n for (let light of lights)\r\n {\r\n let nodeDef = light.getNodeDef();\r\n let nodeName = nodeDef.getName();\r\n if (!lightTypesBound[nodeName])\r\n {\r\n lightTypesBound[nodeName] = lightId;\r\n mx.HwShaderGenerator.bindLightShader(nodeDef, lightId++, genContext);\r\n }\r\n\r\n const lightDirection = light.getValueElement(\"direction\").getValue().getData().data();\r\n const lightColor = light.getValueElement(\"color\").getValue().getData().data();\r\n const lightIntensity = light.getValueElement(\"intensity\").getValue().getData();\r\n\r\n let rotatedLightDirection = new three__WEBPACK_IMPORTED_MODULE_0__.Vector3(...lightDirection)\r\n rotatedLightDirection.transformDirection(getLightRotation())\r\n\r\n lightData.push({\r\n type: lightTypesBound[nodeName],\r\n direction: rotatedLightDirection,\r\n color: new three__WEBPACK_IMPORTED_MODULE_0__.Vector3(...lightColor),\r\n intensity: lightIntensity\r\n });\r\n }\r\n\r\n // Make sure max light count is large enough\r\n genContext.getOptions().hwMaxActiveLightSources = Math.max(genContext.getOptions().hwMaxActiveLightSources, lights.length);\r\n\r\n return lightData;\r\n}\r\n\r\n/**\r\n * Get uniform values for a shader\r\n * @param {mx.shaderStage} shaderStage\r\n * @param {THREE.TextureLoader} textureLoader\r\n */\r\nfunction getUniformValues(shaderStage, textureLoader, searchPath, flipY)\r\n{\r\n let threeUniforms = {};\r\n\r\n const uniformBlocks = Object.values(shaderStage.getUniformBlocks());\r\n uniformBlocks.forEach(uniforms =>\r\n {\r\n if (!uniforms.empty())\r\n {\r\n for (let i = 0; i < uniforms.size(); ++i)\r\n {\r\n const variable = uniforms.get(i);\r\n const value = variable.getValue()?.getData();\r\n const name = variable.getVariable();\r\n threeUniforms[name] = new three__WEBPACK_IMPORTED_MODULE_0__.Uniform(toThreeUniform(variable.getType().getName(), value, name, uniforms,\r\n textureLoader, searchPath, flipY));\r\n }\r\n }\r\n });\r\n\r\n return threeUniforms;\r\n}\r\n\n\n//# sourceURL=webpack://MaterialX-Shader-Editor/./source/helper.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ findLights: () => (/* binding */ findLights),\n/* harmony export */ getLightRotation: () => (/* binding */ getLightRotation),\n/* harmony export */ getUniformValues: () => (/* binding */ getUniformValues),\n/* harmony export */ prepareEnvTexture: () => (/* binding */ prepareEnvTexture),\n/* harmony export */ registerLights: () => (/* binding */ registerLights)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n//\r\n// Copyright Contributors to the MaterialX Project\r\n// SPDX-License-Identifier: Apache-2.0\r\n//\r\n\r\n\r\n\r\n//import { getBufferFromFile } from './dropHandling.js';\r\n\r\nconst IMAGE_PROPERTY_SEPARATOR = \"_\";\r\nconst UADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"uaddressmode\";\r\nconst VADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"vaddressmode\";\r\nconst FILTER_TYPE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"filtertype\";\r\nconst IMAGE_PATH_SEPARATOR = \"/\";\r\n\r\n/**\r\n * Initialized the environment texture as MaterialX expects it\r\n * @param {THREE.Texture} texture\r\n * @param {Object} capabilities\r\n * @returns {THREE.Texture}\r\n */\r\nfunction prepareEnvTexture(texture, capabilities)\r\n{\r\n let newTexture = new three__WEBPACK_IMPORTED_MODULE_0__.DataTexture(texture.image.data, texture.image.width, texture.image.height, texture.format, texture.type);\r\n newTexture.wrapS = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n newTexture.anisotropy = capabilities.getMaxAnisotropy();\r\n newTexture.minFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearMipmapLinearFilter;\r\n newTexture.magFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n newTexture.generateMipmaps = true;\r\n newTexture.needsUpdate = true;\r\n\r\n return newTexture;\r\n}\r\n\r\n/**\r\n * Get Three uniform from MaterialX vector\r\n * @param {any} value\r\n * @param {any} dimension\r\n * @returns {THREE.Uniform}\r\n */\r\nfunction fromVector(value, dimension)\r\n{\r\n let outValue;\r\n if (value)\r\n {\r\n outValue = value.data();\r\n }\r\n else\r\n {\r\n outValue = [];\r\n for (let i = 0; i < dimension; ++i)\r\n outValue.push(0.0);\r\n }\r\n\r\n return outValue;\r\n}\r\n\r\n/**\r\n * Get Three uniform from MaterialX matrix\r\n * @param {mx.matrix} matrix\r\n * @param {mx.matrix.size} dimension\r\n */\r\nfunction fromMatrix(matrix, dimension)\r\n{\r\n let vec = [];\r\n if (matrix)\r\n {\r\n for (let i = 0; i < matrix.numRows(); ++i)\r\n {\r\n for (let k = 0; k < matrix.numColumns(); ++k)\r\n {\r\n vec.push(matrix.getItem(i, k));\r\n }\r\n }\r\n } else\r\n {\r\n for (let i = 0; i < dimension; ++i)\r\n vec.push(0.0);\r\n }\r\n\r\n return vec;\r\n}\r\n\r\nfunction loadTextureFile(uri, loader)\r\n{\r\n return new Promise((resolve, reject) =>\r\n {\r\n if (loader) \r\n {\r\n console.log(\"Load image file: \", uri); \r\n loader.load(\r\n uri,\r\n function (texture) {\r\n console.log('- Resolve texture:', texture);\r\n resolve(texture);\r\n },\r\n function (xhr) {\r\n // This function will be called while the texture is loading\r\n console.log((xhr.loaded / xhr.total) * 100 + '% loaded');\r\n },\r\n function (error) {\r\n resolve(null);\r\n // This function will be called if there is an error loading the texture\r\n //reject(new Error('Error loading texture: ' + error));\r\n }\r\n ); \r\n }\r\n });\r\n}\r\n\r\n// Function to load an image file and return a buffer using FileReader.readAsArrayBuffer()\r\nfunction getTextureBufferFromFile(filePath, textureLoader) {\r\n return new Promise((resolve, reject) => {\r\n // Create a FileReader\r\n const fileReader = new FileReader();\r\n\r\n // Event listener for the FileReader's load event\r\n //fileReader.addEventListener('load', function (event) {\r\n fileReader.onloadend = function (e)\r\n {\r\n // Get the result of the FileReader as an ArrayBuffer\r\n const buffer = e.target.result;\r\n\r\n // Convert the ArrayBuffer to a Uint8Array for examination\r\n //const uint8Array = new Uint8Array(buffer);\r\n\r\n console.log('--------- Loaded Buffer:', buffer, filePath, '---------');\r\n\r\n // Handle the obtained buffer\r\n console.log('Add texture buffer to cache:', filePath, ', ', buffer);\r\n\r\n const texture = loadTextureFile(URL.createObjectURL(new Blob([buffer])), textureLoader);\r\n //const texture = textureLoader.load(URL.createObjectURL(new Blob([buffer])));\r\n\r\n //const dataURL = 'data:image/jpeg;base64,' + btoa(String.fromCharCode.apply(null, uint8Array));\r\n //console.log('dataURL:', dataURL)\r\n //const texture = textureLoader.load(dataURL, function () {\r\n // Log the dimensions of the resulting texture\r\n // console.log('Texture dimensions:', texture.image.width, 'x', texture.image.height);\r\n //}); \r\n\r\n //const texture = textureLoader.load(texturePath);\r\n // Set address & filtering mode\r\n if (texture) {\r\n //THREE.Cache.add(filePath, texture);\r\n //setTextureParameters(texture, name, uniforms, flipY);\r\n //outValue = texture;\r\n console.log('Success: texture cached:', filePath, three__WEBPACK_IMPORTED_MODULE_0__.Cache.get(filePath));\r\n //let blah = THREE.Cache.get(texturePath);\r\n //if (blah)\r\n // console.log('blah.image.width:', blah.image.width, ', blah.image.height:', blah.image.height, ', blah.image.data:', blah.image.data, ', blah.image.data.length:', blah.image.data.length, ', blah.image.data.byteLength:', blah.image.data.byteLength, ', blah.image.data.buffer.byteLength:', blah.image.data.buffer.byteLength, ', blah.image.data.buffer:', blah.image.data.buffer);\r\n }\r\n else {\r\n console.error('Error: texture not found in cache:', filePath);\r\n }\r\n\r\n // Resolve the Promise with the obtained buffer\r\n resolve(texture);\r\n };\r\n\r\n // Event listener for errors during file reading\r\n fileReader.addEventListener('error', function (event) {\r\n result(null); // reject(new Error('Error reading file: ' + event.target.error));\r\n });\r\n\r\n // Read the content of the file as an ArrayBuffer\r\n fileReader.readAsArrayBuffer(new Blob([filePath]));\r\n });\r\n}\r\n\r\n\r\n// Function to load an image file and examine the dimensions of the loaded texture\r\nfunction examineImageFile(filePath, textureLoader) {\r\n return new Promise((resolve, reject) => {\r\n // Create a FileReader\r\n const fileReader = new FileReader();\r\n\r\n // Event listener for the FileReader's load event\r\n fileReader.addEventListener('load', function (event) {\r\n // Get the result of the FileReader as a data URL\r\n const dataURL = event.target.result;\r\n console.log('Load URL:', dataURL, filePath, '---------')\r\n\r\n // Create a texture using the data URL\r\n const texture = textureLoader.load(dataURL, function () {\r\n // Log the dimensions of the resulting texture\r\n console.log('Texture dimensions:', texture.image.width, 'x', texture.image.height);\r\n\r\n // Resolve the Promise with the loaded texture\r\n resolve(texture);\r\n });\r\n });\r\n\r\n // Event listener for errors during file reading\r\n fileReader.addEventListener('error', function (event) {\r\n reject(new Error('Error reading file: ' + event.target.error));\r\n });\r\n\r\n // Read the content of the file as a data URL\r\n fileReader.readAsDataURL(new Blob([filePath]));\r\n });\r\n}\r\n\r\n\r\n\r\n/**\r\n * Get Three uniform from MaterialX value\r\n * @param {mx.Uniform.type} type\r\n * @param {mx.Uniform.value} value\r\n * @param {mx.Uniform.name} name\r\n * @param {mx.Uniforms} uniforms\r\n * @param {THREE.textureLoader} textureLoader\r\n */\r\nfunction toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, flipY)\r\n{\r\n let outValue = null;\r\n switch (type)\r\n {\r\n case 'float':\r\n case 'integer':\r\n case 'boolean':\r\n outValue = value;\r\n break;\r\n case 'vector2':\r\n outValue = fromVector(value, 2);\r\n break;\r\n case 'vector3':\r\n case 'color3':\r\n outValue = fromVector(value, 3);\r\n break;\r\n case 'vector4':\r\n case 'color4':\r\n outValue = fromVector(value, 4);\r\n break;\r\n case 'matrix33':\r\n outValue = fromMatrix(value, 9);\r\n break;\r\n case 'matrix44':\r\n outValue = fromMatrix(value, 16);\r\n break;\r\n case 'filename':\r\n if (value)\r\n {\r\n let texturePath = searchPath + IMAGE_PATH_SEPARATOR + value;\r\n if (value.startsWith('blob:')) \r\n {\r\n texturePath = value;\r\n console.log('Load blob URL:', texturePath);\r\n }\r\n else if (value.startsWith('http'))\r\n {\r\n texturePath = value;\r\n console.log('Load HTTP URL:', texturePath);\r\n }\r\n else if (value.startsWith('data:'))\r\n {\r\n texturePath = value;\r\n console.log('Load data URL:', texturePath);\r\n }\r\n const textureExists = three__WEBPACK_IMPORTED_MODULE_0__.Cache.get(texturePath);\r\n if (!textureExists)\r\n {\r\n \r\n // Call the function to examine the image file\r\n /* examineImageFile(texturePath, textureLoader)\r\n .then(texture => {\r\n console.log('Add texture to cache:', texturePath, texture)\r\n setTextureParameters(texture, name, uniforms, flipY);\r\n outValue = texture; \r\n })\r\n .catch(error => {\r\n // Handle errors\r\n console.error('Error:', error);\r\n });\r\n */\r\n // Call the function to get a buffer from the file\r\n /*\r\n getTextureBufferFromFile(texturePath, textureLoader)\r\n .then(texture => {\r\n if (texture)\r\n setTextureParameters(texture, name, uniforms, flipY);\r\n outValue = texture;\r\n console.log('-- FINISHED loading: ' + texturePath)\r\n })\r\n .catch(error => {\r\n // Handle errors\r\n console.error('Error:', error);\r\n });\r\n */\r\n //console.log('Image file not loaded: ', texturePath);\r\n }\r\n //else\r\n {\r\n outValue = textureLoader.load(\r\n texturePath, \r\n function (texture) {\r\n console.log('Loaded texture: ' + texturePath, texture);\r\n /* console.log('Texture image properties:');\r\n console.log('Width:', texture.image.width);\r\n console.log('Height:', texture.image.height);\r\n console.log('Format:', texture.image.format);\r\n console.log('Is Data Loaded:', texture.image.complete); // */ \r\n outValue = texture;\r\n },\r\n undefined,\r\n function (error) {\r\n console.error('Error loading texture: ', error);\r\n }); \r\n\r\n // Set address & filtering mode\r\n if (outValue)\r\n setTextureParameters(outValue, name, uniforms, flipY);\r\n }\r\n }\r\n break;\r\n case 'samplerCube':\r\n case 'string':\r\n break;\r\n default:\r\n console.log('Value type not supported: ' + type);\r\n // struct\r\n outValue = null;//toThreeUniform(value);\r\n }\r\n\r\n return outValue;\r\n}\r\n\r\n/**\r\n * Get Three wrapping mode\r\n * @param {mx.TextureFilter.wrap} mode\r\n * @returns {THREE.Wrapping}\r\n */\r\nfunction getWrapping(mode)\r\n{\r\n let wrap;\r\n switch (mode)\r\n {\r\n case 1:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.ClampToEdgeWrapping;\r\n break;\r\n case 2:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n break;\r\n case 3:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.MirroredRepeatWrapping;\r\n break;\r\n default:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n break;\r\n }\r\n return wrap;\r\n}\r\n\r\n/**\r\n * Get Three minification filter\r\n * @param {mx.TextureFilter.minFilter} type\r\n * @param {mx.TextureFilter.generateMipmaps} generateMipmaps\r\n */\r\nfunction getMinFilter(type, generateMipmaps)\r\n{\r\n const filterType = generateMipmaps ? three__WEBPACK_IMPORTED_MODULE_0__.LinearMipMapLinearFilter : three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n if (type === 0)\r\n {\r\n filterType = generateMipmaps ? three__WEBPACK_IMPORTED_MODULE_0__.NearestMipMapNearestFilter : three__WEBPACK_IMPORTED_MODULE_0__.NearestFilter;\r\n }\r\n return filterType;\r\n}\r\n\r\n/**\r\n * Set Three texture parameters\r\n * @param {THREE.Texture} texture\r\n * @param {mx.Uniform.name} name\r\n * @param {mx.Uniforms} uniforms\r\n * @param {mx.TextureFilter.generateMipmaps} generateMipmaps\r\n */\r\nfunction setTextureParameters(texture, name, uniforms, flipY = true, generateMipmaps = true)\r\n{\r\n const idx = name.lastIndexOf(IMAGE_PROPERTY_SEPARATOR);\r\n const base = name.substring(0, idx) || name;\r\n\r\n texture.generateMipmaps = generateMipmaps;\r\n texture.wrapS = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n texture.wrapT = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n texture.magFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n texture.flipY = flipY;\r\n\r\n if (uniforms.find(base + UADDRESS_MODE_SUFFIX))\r\n {\r\n const uaddressmode = uniforms.find(base + UADDRESS_MODE_SUFFIX).getValue().getData();\r\n texture.wrapS = getWrapping(uaddressmode);\r\n }\r\n\r\n if (uniforms.find(base + VADDRESS_MODE_SUFFIX))\r\n {\r\n const vaddressmode = uniforms.find(base + VADDRESS_MODE_SUFFIX).getValue().getData();\r\n texture.wrapT = getWrapping(vaddressmode);\r\n }\r\n\r\n const filterType = uniforms.find(base + FILTER_TYPE_SUFFIX) ? uniforms.get(base + FILTER_TYPE_SUFFIX).value : -1;\r\n texture.minFilter = getMinFilter(filterType, generateMipmaps);\r\n}\r\n\r\n/**\r\n * Return the global light rotation matrix\r\n */\r\nfunction getLightRotation()\r\n{\r\n return new three__WEBPACK_IMPORTED_MODULE_0__.Matrix4().makeRotationY(Math.PI / 2);\r\n}\r\n\r\n/**\r\n * Returns all lights nodes in a MaterialX document\r\n * @param {mx.Document} doc \r\n * @returns {Array.}\r\n */\r\nfunction findLights(doc)\r\n{\r\n let lights = [];\r\n for (let node of doc.getNodes())\r\n {\r\n if (node.getType() === \"lightshader\")\r\n lights.push(node);\r\n }\r\n return lights;\r\n}\r\n\r\n/**\r\n * Register lights in shader generation context\r\n * @param {Object} mx MaterialX Module\r\n * @param {Array.} lights Light nodes\r\n * @param {mx.GenContext} genContext Shader generation context\r\n * @returns {Array.}\r\n */\r\nfunction registerLights(mx, lights, genContext)\r\n{\r\n mx.HwShaderGenerator.unbindLightShaders(genContext);\r\n\r\n const lightTypesBound = {};\r\n const lightData = [];\r\n let lightId = 1;\r\n for (let light of lights)\r\n {\r\n let nodeDef = light.getNodeDef();\r\n let nodeName = nodeDef.getName();\r\n if (!lightTypesBound[nodeName])\r\n {\r\n lightTypesBound[nodeName] = lightId;\r\n mx.HwShaderGenerator.bindLightShader(nodeDef, lightId++, genContext);\r\n }\r\n\r\n const lightDirection = light.getValueElement(\"direction\").getValue().getData().data();\r\n const lightColor = light.getValueElement(\"color\").getValue().getData().data();\r\n const lightIntensity = light.getValueElement(\"intensity\").getValue().getData();\r\n\r\n let rotatedLightDirection = new three__WEBPACK_IMPORTED_MODULE_0__.Vector3(...lightDirection)\r\n rotatedLightDirection.transformDirection(getLightRotation())\r\n\r\n lightData.push({\r\n type: lightTypesBound[nodeName],\r\n direction: rotatedLightDirection,\r\n color: new three__WEBPACK_IMPORTED_MODULE_0__.Vector3(...lightColor),\r\n intensity: lightIntensity\r\n });\r\n }\r\n\r\n // Make sure max light count is large enough\r\n genContext.getOptions().hwMaxActiveLightSources = Math.max(genContext.getOptions().hwMaxActiveLightSources, lights.length);\r\n\r\n return lightData;\r\n}\r\n\r\n/**\r\n * Get uniform values for a shader\r\n * @param {mx.shaderStage} shaderStage\r\n * @param {THREE.TextureLoader} textureLoader\r\n */\r\nfunction getUniformValues(shaderStage, textureLoader, searchPath, flipY)\r\n{\r\n let threeUniforms = {};\r\n\r\n const uniformBlocks = Object.values(shaderStage.getUniformBlocks());\r\n uniformBlocks.forEach(uniforms =>\r\n {\r\n if (!uniforms.empty())\r\n {\r\n for (let i = 0; i < uniforms.size(); ++i)\r\n {\r\n const variable = uniforms.get(i);\r\n const value = variable.getValue()?.getData();\r\n const name = variable.getVariable();\r\n //console.log('fill uniform, name:', name, ', value:', value);\r\n threeUniforms[name] = new three__WEBPACK_IMPORTED_MODULE_0__.Uniform(toThreeUniform(variable.getType().getName(), value, name, uniforms,\r\n textureLoader, searchPath, flipY));\r\n }\r\n }\r\n });\r\n\r\n return threeUniforms;\r\n}\r\n\n\n//# sourceURL=webpack://MaterialX-Shader-Editor/./source/helper.js?");
/***/ }),
@@ -56,17 +66,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _ren
\**************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Editor: () => (/* binding */ Editor),\n/* harmony export */ Material: () => (/* binding */ Material),\n/* harmony export */ Scene: () => (/* binding */ Scene),\n/* harmony export */ Viewer: () => (/* binding */ Viewer)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n/* harmony import */ var three_examples_jsm_loaders_GLTFLoader__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! three/examples/jsm/loaders/GLTFLoader */ \"./node_modules/three/examples/jsm/loaders/GLTFLoader.js\");\n/* harmony import */ var three_examples_jsm_loaders_ObjLoader__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! three/examples/jsm/loaders/ObjLoader */ \"./node_modules/three/examples/jsm/loaders/ObjLoader.js\");\n/* harmony import */ var three_examples_jsm_loaders_RGBELoader_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! three/examples/jsm/loaders/RGBELoader.js */ \"./node_modules/three/examples/jsm/loaders/RGBELoader.js\");\n/* harmony import */ var _helper_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helper.js */ \"./source/helper.js\");\n/* harmony import */ var lil_gui__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! lil-gui */ \"./node_modules/lil-gui/dist/lil-gui.esm.js\");\n//\r\n// Copyright Contributors to the MaterialX Project\r\n// SPDX-License-Identifier: Apache-2.0\r\n//\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nconst ALL_GEOMETRY_SPECIFIER = \"*\";\r\nconst NO_GEOMETRY_SPECIFIER = \"\";\r\nconst DAG_PATH_SEPERATOR = \"/\";\r\n\r\n// Logging toggle\r\nvar logDetailedTime = false;\r\n\r\n/*\r\n Scene management\r\n*/\r\nclass Scene\r\n{\r\n constructor()\r\n {\r\n this._geometryURL = new URLSearchParams(document.location.search).get(\"geom\");\r\n if (!this._geometryURL)\r\n {\r\n this._geometryURL = 'Geometry/teapot.glb';\r\n }\r\n }\r\n\r\n initialize()\r\n {\r\n this._scene = new three__WEBPACK_IMPORTED_MODULE_1__.Scene();\r\n this._scene.background = new three__WEBPACK_IMPORTED_MODULE_1__.Color(this.#_backgroundColor);\r\n this._scene.background.convertSRGBToLinear();\r\n\r\n let cc = document.getElementById('webglcanvas');\r\n const aspectRatio = cc.width / cc.height;\r\n const cameraNearDist = 0.01;\r\n const cameraFarDist = 1000.0;\r\n const cameraFOV = 60.0;\r\n this._camera = new three__WEBPACK_IMPORTED_MODULE_1__.PerspectiveCamera(cameraFOV, aspectRatio, cameraNearDist, cameraFarDist);\r\n\r\n this.#_gltfLoader = new three_examples_jsm_loaders_GLTFLoader__WEBPACK_IMPORTED_MODULE_2__.GLTFLoader();\r\n this.#_objLoader = new three_examples_jsm_loaders_ObjLoader__WEBPACK_IMPORTED_MODULE_3__.OBJLoader();\r\n\r\n this.#_normalMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix3();\r\n this.#_viewProjMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4();\r\n this.#_worldViewPos = new three__WEBPACK_IMPORTED_MODULE_1__.Vector3();\r\n }\r\n\r\n // Set whether to flip UVs in V for loaded geometry\r\n setFlipGeometryV(val)\r\n {\r\n this.#_flipV = val;\r\n }\r\n\r\n // Get whether to flip UVs in V for loaded geometry\r\n getFlipGeometryV()\r\n {\r\n return this.#_flipV;\r\n }\r\n\r\n // Utility to perform geometry file load\r\n loadGeometryFile(geometryFilename, loader)\r\n {\r\n return new Promise((resolve, reject) =>\r\n {\r\n if (loader) \r\n {\r\n console.log(\"Load geometry: \", geometryFilename); \r\n loader.load(geometryFilename, data => resolve(data), null, reject);\r\n }\r\n });\r\n }\r\n\r\n //\r\n // Load in geometry specified by a given file name,\r\n // then update the scene geometry and camera.\r\n //\r\n async loadGeometry(viewer, orbitControls)\r\n {\r\n var startTime = performance.now();\r\n var geomLoadTime = startTime;\r\n\r\n var gltfData = null;\r\n if (this.getGeometryURL().endsWith('glb'))\r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_gltfLoader);\r\n else if (this.getGeometryURL().endsWith('obj'))\r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_objLoader);\r\n else \r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_gltfLoader);\r\n\r\n if (gltfData == null)\r\n {\r\n console.log(\"Failed to load geometry: \", this.getGeometryURL());\r\n return;\r\n }\r\n\r\n const scene = this.getScene();\r\n while (scene.children.length > 0)\r\n {\r\n scene.remove(scene.children[0]);\r\n }\r\n\r\n this.#_rootNode = null;\r\n const model = gltfData.scene;\r\n if (!model)\r\n {\r\n const geometry = new three__WEBPACK_IMPORTED_MODULE_1__.BoxGeometry(1, 1, 1);\r\n const material = new three__WEBPACK_IMPORTED_MODULE_1__.MeshBasicMaterial({ color: 0xdddddd });\r\n const cube = new three__WEBPACK_IMPORTED_MODULE_1__.Mesh(geometry, material);\r\n obj = new three__WEBPACK_IMPORTED_MODULE_1__.Group();\r\n obj.add(geometry);\r\n }\r\n else\r\n {\r\n this.#_rootNode = model;\r\n }\r\n scene.add(model);\r\n\r\n // Always reset controls based on camera for each load. \r\n orbitControls.reset();\r\n //console.log(\"- Scene load time: \", performance.now() - geomLoadTime, \"ms\");\r\n\r\n //console.log(\"Total geometry load time: \", performance.now() - startTime, \" ms.\");\r\n\r\n viewer.getMaterial().clearSoloMaterialUI();\r\n viewer.getMaterial().updateMaterialAssignments(viewer, viewer.getMaterial().getSoloMaterial());\r\n this.setUpdateTransforms();\r\n\r\n this.updateScene(viewer, orbitControls);\r\n }\r\n\r\n //\r\n // Update the geometry buffer, assigned materials, and camera controls.\r\n //\r\n updateScene(viewer, orbitControls)\r\n {\r\n var startUpdateSceneTime = performance.now();\r\n var uvTime = 0;\r\n var normalTime = 0;\r\n var tangentTime = 0;\r\n var streamTime = 0;\r\n var bboxTime = 0;\r\n\r\n var startBboxTime = performance.now();\r\n const bbox = new three__WEBPACK_IMPORTED_MODULE_1__.Box3().setFromObject(this._scene);\r\n const bsphere = new three__WEBPACK_IMPORTED_MODULE_1__.Sphere();\r\n bbox.getBoundingSphere(bsphere);\r\n bboxTime = performance.now() - startBboxTime;\r\n\r\n let theScene = viewer.getScene();\r\n let flipV = theScene.getFlipGeometryV();\r\n\r\n\r\n this._scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n var startUVTime = performance.now();\r\n if (!child.geometry.attributes.uv)\r\n {\r\n const posCount = child.geometry.attributes.position.count;\r\n const uvs = [];\r\n const pos = child.geometry.attributes.position.array;\r\n\r\n for (let i = 0; i < posCount; i++)\r\n {\r\n uvs.push((pos[i * 3] - bsphere.center.x) / bsphere.radius);\r\n uvs.push((pos[i * 3 + 1] - bsphere.center.y) / bsphere.radius);\r\n }\r\n\r\n child.geometry.setAttribute('uv', new three__WEBPACK_IMPORTED_MODULE_1__.BufferAttribute(new Float32Array(uvs), 2));\r\n }\r\n else if (flipV)\r\n {\r\n const uvCount = child.geometry.attributes.position.count;\r\n const uvs = child.geometry.attributes.uv.array;\r\n for (let i = 0; i < uvCount; i++)\r\n {\r\n let v = 1.0 - (uvs[i * 2 + 1]);\r\n uvs[i * 2 + 1] = v;\r\n }\r\n }\r\n uvTime += performance.now() - startUVTime;\r\n\r\n if (!child.geometry.attributes.normal)\r\n {\r\n var startNormalTime = performance.new();\r\n child.geometry.computeVertexNormals();\r\n normalTime += performance.now() - startNormalTime;\r\n }\r\n\r\n if (child.geometry.getIndex())\r\n {\r\n if (!child.geometry.attributes.tangent)\r\n {\r\n var startTangentTime = performance.now();\r\n child.geometry.computeTangents();\r\n tangentTime += performance.now() - startTangentTime;\r\n }\r\n }\r\n\r\n // Use default MaterialX naming convention.\r\n var startStreamTime = performance.now();\r\n child.geometry.attributes.i_position = child.geometry.attributes.position;\r\n child.geometry.attributes.i_normal = child.geometry.attributes.normal;\r\n child.geometry.attributes.i_tangent = child.geometry.attributes.tangent;\r\n child.geometry.attributes.i_texcoord_0 = child.geometry.attributes.uv;\r\n streamTime += performance.now() - startStreamTime;\r\n }\r\n });\r\n\r\n //console.log(\"- Stream update time: \", performance.now() - startUpdateSceneTime, \"ms\");\r\n if (logDetailedTime)\r\n {\r\n console.log(' - UV time: ', uvTime);\r\n console.log(' - Normal time: ', normalTime);\r\n console.log(' - Tangent time: ', tangentTime);\r\n console.log(' - Stream Update time: ', streamTime);\r\n console.log(' - Bounds compute time: ', bboxTime);\r\n }\r\n\r\n // Update the background\r\n this._scene.background = this.getBackground();\r\n\r\n //console.log('bounding sphere:', bsphere.center, bsphere.radius);\r\n\r\n // Fit camera to model\r\n const camera = this.getCamera();\r\n camera.position.y = bsphere.center.y;\r\n camera.position.z = bsphere.radius * 2.0;\r\n camera.updateProjectionMatrix();\r\n\r\n orbitControls.target = bsphere.center;\r\n orbitControls.update();\r\n }\r\n\r\n setUpdateTransforms(val=true)\r\n {\r\n this.#_updateTransforms = val;\r\n }\r\n\r\n getUpdateTransforms()\r\n {\r\n return this.#_updateTransforms;\r\n }\r\n\r\n updateTransforms()\r\n {\r\n // Only update on demand versus continuously.\r\n // Call setUpdateTransforms() to trigger an update here.\r\n // Required for: scene geometry, camera change and viewport resize. \r\n if (!this.#_updateTransforms)\r\n {\r\n return;\r\n }\r\n this.setUpdateTransforms(false);\r\n\r\n const scene = this.getScene();\r\n const camera = this.getCamera();\r\n scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n const uniforms = child.material.uniforms;\r\n if (uniforms)\r\n {\r\n uniforms.u_worldMatrix.value = child.matrixWorld;\r\n uniforms.u_viewProjectionMatrix.value = this.#_viewProjMat.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);\r\n\r\n if (uniforms.u_viewPosition)\r\n uniforms.u_viewPosition.value = camera.getWorldPosition(this.#_worldViewPos);\r\n\r\n if (uniforms.u_worldInverseTransposeMatrix)\r\n uniforms.u_worldInverseTransposeMatrix.value =\r\n new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4().setFromMatrix3(this.#_normalMat.getNormalMatrix(child.matrixWorld));\r\n }\r\n }\r\n });\r\n }\r\n\r\n // Determine string DAG path based on individual node names.\r\n getDagPath(node)\r\n {\r\n const rootNode = this.#_rootNode;\r\n\r\n let path = [node.name];\r\n while (node.parent)\r\n {\r\n node = node.parent;\r\n if (node)\r\n {\r\n // Stop at the root of the scene read in.\r\n if (node == rootNode)\r\n {\r\n break;\r\n }\r\n path.unshift(node.name);\r\n }\r\n }\r\n return path;\r\n }\r\n\r\n // Assign material shader to associated geometry\r\n updateMaterial(matassign)\r\n {\r\n let assigned = 0;\r\n\r\n const shader = matassign.getShader();\r\n const material = matassign.getMaterial().getName();\r\n const geometry = matassign.getGeometry();\r\n const collection = matassign.getCollection();\r\n\r\n const scene = this.getScene();\r\n const camera = this.getCamera();\r\n scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n const dagPath = this.getDagPath(child).join('/');\r\n\r\n // Note that this is a very simplistic\r\n // assignment resolve and assumes basic\r\n // regular expression name match.\r\n let matches = (geometry == ALL_GEOMETRY_SPECIFIER);\r\n if (!matches)\r\n {\r\n if (collection)\r\n {\r\n if (collection.matchesGeomString(dagPath))\r\n {\r\n matches = true;\r\n }\r\n }\r\n else\r\n {\r\n if (geometry != NO_GEOMETRY_SPECIFIER)\r\n {\r\n const paths = geometry.split(',');\r\n for (let path of paths)\r\n {\r\n if (dagPath.match(path))\r\n {\r\n matches = true;\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n if (matches)\r\n {\r\n child.material = shader;\r\n assigned++;\r\n }\r\n }\r\n });\r\n\r\n return assigned;\r\n }\r\n\r\n updateCamera()\r\n {\r\n const camera = this.getCamera();\r\n let container = document.getElementById('canvasContainer');\r\n var maxWidth = 4086;\r\n var maxHeight = 1024;\r\n var width = Math.min(container.clientWidth, maxWidth);\r\n var height = Math.min(container.clientHeight, maxHeight); \r\n\r\n camera.aspect = width / height;\r\n camera.updateProjectionMatrix();\r\n }\r\n\r\n getScene()\r\n {\r\n return this._scene;\r\n }\r\n\r\n getCamera()\r\n {\r\n return this._camera;\r\n }\r\n\r\n getGeometryURL()\r\n {\r\n return this._geometryURL;\r\n }\r\n\r\n setGeometryURL(url)\r\n {\r\n this._geometryURL = url;\r\n }\r\n\r\n setBackgroundTexture(texture)\r\n {\r\n this.#_backgroundTexture = texture;\r\n }\r\n\r\n getShowBackgroundTexture()\r\n {\r\n return this.#_showBackgroundTexture;\r\n }\r\n\r\n setShowBackgroundTexture(enable)\r\n {\r\n this.#_showBackgroundTexture = enable;\r\n }\r\n\r\n getBackground()\r\n {\r\n if (this.#_backgroundTexture && this.#_showBackgroundTexture)\r\n {\r\n return this.#_backgroundTexture;\r\n }\r\n var color = new three__WEBPACK_IMPORTED_MODULE_1__.Color(this.#_backgroundColor);\r\n color.convertSRGBToLinear();\r\n return color;\r\n }\r\n\r\n toggleBackgroundTexture()\r\n {\r\n this.#_showBackgroundTexture = !this.#_showBackgroundTexture;\r\n this._scene.background = this.getBackground();\r\n }\r\n\r\n // Geometry file\r\n #_geometryURL = '';\r\n // Geometry loaders\r\n #_gltfLoader = null;\r\n #_objLoader = null;\r\n // Flip V coordinate of texture coordinates.\r\n // Set to true to be consistent with desktop viewer.\r\n #_flipV = true;\r\n\r\n // Scene\r\n #_scene = null;\r\n\r\n // Camera\r\n #_camera = null;\r\n\r\n // Background color\r\n #_backgroundColor = 0x777777;\r\n\r\n // Background texture\r\n #_backgroundTexture = null;\r\n #_showBackgroundTexture = false;\r\n\r\n // Transform matrices\r\n #_normalMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix3();\r\n #_viewProjMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4();\r\n #_worldViewPos = new three__WEBPACK_IMPORTED_MODULE_1__.Vector3();\r\n #_updateTransforms = true;\r\n\r\n // Root node of imported scene\r\n #_rootNode = null;\r\n}\r\n\r\n/* \r\n Property editor\r\n*/\r\nclass Editor\r\n{\r\n // Initialize the editor, clearing any elements from previous materials.\r\n initialize()\r\n {\r\n Array.from(document.getElementsByClassName('lil-gui')).forEach(\r\n function (element, index, array)\r\n {\r\n if (element.className)\r\n {\r\n element.remove();\r\n }\r\n }\r\n );\r\n\r\n let parent = document.getElementById( 'webglcanvas' );\r\n //console.log('parent:', parent);\r\n this._gui = new lil_gui__WEBPACK_IMPORTED_MODULE_4__[\"default\"]( { title: \"Properties\" }, { container: parent } );\r\n //parent = this._gui.domElement;\r\n //console.log('gui parent:', parent);\r\n // Parent parent under webglcanvas\r\n //document.getElementById( 'webglcanvas' ).appendChild( parent );\r\n\r\n //this._gui = new GUI({ title: \"Property Editor\" });\r\n this._gui.close();\r\n this._gui.hide();\r\n }\r\n\r\n // Update ui properties\r\n // - Hide close button\r\n // - Update transparency so scene shows through if overlapping\r\n updateProperties(targetOpacity = 1)\r\n {\r\n // Set opacity\r\n Array.from(document.getElementsByClassName('dg')).forEach(\r\n function (element, index, array)\r\n {\r\n element.style.opacity = targetOpacity;\r\n }\r\n );\r\n }\r\n\r\n getGUI()\r\n {\r\n return this._gui;\r\n }\r\n\r\n _gui = null;\r\n}\r\n\r\nclass MaterialAssign\r\n{\r\n constructor(material, geometry, collection)\r\n {\r\n this._material = material;\r\n this._geometry = geometry;\r\n this._collection = collection;\r\n this._shader = null;\r\n this._materialUI = null;\r\n }\r\n\r\n setMaterialUI(value)\r\n {\r\n this._materialUI = value;\r\n }\r\n\r\n getMaterialUI()\r\n {\r\n return this._materialUI;\r\n }\r\n\r\n setShader(shader)\r\n {\r\n this._shader = shader;\r\n }\r\n\r\n getShader()\r\n {\r\n return this._shader;\r\n }\r\n\r\n getMaterial()\r\n {\r\n return this._material;\r\n }\r\n\r\n getGeometry()\r\n {\r\n return this._geometry;\r\n }\r\n\r\n setGeometry(value)\r\n {\r\n this._geometry = value;\r\n }\r\n\r\n getCollection()\r\n {\r\n return this._collection;\r\n }\r\n\r\n // MaterialX material node name\r\n _material;\r\n\r\n // MaterialX assignment geometry string\r\n _geometry;\r\n\r\n // MaterialX assignment collection\r\n _collection;\r\n\r\n // THREE.JS shader\r\n _shader;\r\n}\r\n\r\nclass Material\r\n{\r\n constructor()\r\n {\r\n this._materials = [];\r\n this._defaultMaterial = null;\r\n this._soloMaterial = \"\";\r\n this._shaderInterfaceType = 0;\r\n }\r\n\r\n clearMaterials()\r\n {\r\n this._materials.length = 0;\r\n this._defaultMaterial = null;\r\n this._soloMaterial = \"\";\r\n }\r\n\r\n setSoloMaterial(value)\r\n {\r\n this._soloMaterial = value;\r\n }\r\n\r\n getSoloMaterial()\r\n {\r\n return this._soloMaterial;\r\n }\r\n\r\n // If no material file is selected, we programmatically create a default material as a fallback\r\n static createFallbackMaterial(doc)\r\n {\r\n let ssNode = doc.getChild('Generated_Default_Shader');\r\n if (ssNode)\r\n {\r\n return ssNode;\r\n }\r\n const ssName = 'Generated_Default_Shader';\r\n ssNode = doc.addChildOfCategory('standard_surface', ssName);\r\n ssNode.setType('surfaceshader');\r\n const smNode = doc.addChildOfCategory('surfacematerial', 'Default');\r\n smNode.setType('material');\r\n const shaderElement = smNode.addInput('surfaceshader');\r\n shaderElement.setType('surfaceshader');\r\n shaderElement.setNodeName(ssName);\r\n\r\n return ssNode;\r\n }\r\n\r\n async loadMaterialFile(loader, materialFilename)\r\n {\r\n return new Promise((resolve, reject) =>\r\n {\r\n loader.load(materialFilename, data => resolve(data), null, reject);\r\n });\r\n }\r\n\r\n async loadMaterials(viewer, materialFilename)\r\n {\r\n const fileloader = viewer.getFileLoader();\r\n\r\n let mtlxMaterial = await viewer.getMaterial().loadMaterialFile(fileloader, materialFilename);\r\n\r\n this.loadMaterialFromString(viewer, mtlxMaterial, materialFilename);\r\n }\r\n\r\n async loadMaterialFromString(viewer, mtlxMaterial, materialFilename)\r\n {\r\n var startTime = performance.now();\r\n\r\n const mx = viewer.getMx();\r\n\r\n // Re-initialize document\r\n var startDocTime = performance.now();\r\n var doc = mx.createDocument();\r\n doc.importLibrary(viewer.getLibrary());\r\n if (!doc.validate())\r\n {\r\n console.log(\"MaterialX document validation failed.\");\r\n return;\r\n }\r\n\r\n viewer.setDocument(doc);\r\n\r\n // Load lighting setup into document\r\n doc.importLibrary(viewer.getLightRig());\r\n\r\n //console.log(\"- Material document load time: \", performance.now() - startDocTime, \"ms.\");\r\n\r\n // Set search path. Assumes images are relative to current file\r\n // location.\r\n if (!materialFilename) materialFilename = \"/\";\r\n const paths = materialFilename.split('/');\r\n paths.pop();\r\n const searchPath = paths.join('/');\r\n\r\n // Load material\r\n if (mtlxMaterial)\r\n try { \r\n await mx.readFromXmlString(doc, mtlxMaterial, searchPath);\r\n }\r\n catch (error) {\r\n console.error('Error loading material file: ', error);\r\n }\r\n else\r\n Material.createFallbackMaterial(doc);\r\n\r\n // Check if there are any looks defined in the document\r\n // If so then traverse the looks for all material assignments.\r\n // Generate code and compile for any associated surface shader\r\n // and assign to the associated geometry. If there are no looks\r\n // then the first material is found and assignment to all the\r\n // geometry.\r\n this.clearMaterials();\r\n var looks = doc.getLooks();\r\n if (looks.length)\r\n {\r\n for (let look of looks)\r\n {\r\n const materialAssigns = look.getMaterialAssigns();\r\n for (let materialAssign of materialAssigns)\r\n {\r\n let matName = materialAssign.getMaterial();\r\n if (matName)\r\n {\r\n let mat = doc.getChild(matName);\r\n var shader;\r\n if (mat)\r\n {\r\n var shaders = mx.getShaderNodes(mat);\r\n if (shaders.length)\r\n {\r\n shader = shaders[0];\r\n }\r\n }\r\n let collection = materialAssign.getCollection();\r\n let geom = materialAssign.getGeom();\r\n let newAssignment;\r\n if (collection || geom)\r\n {\r\n // Remove leading \"/\" from collection and geom for \r\n // later assignment comparison checking\r\n if (collection && collection.charAt(0) == \"/\")\r\n {\r\n collection = collection.slice(1);\r\n }\r\n if (geom && geom.charAt(0) == \"/\")\r\n {\r\n geom = geom.slice(1);\r\n }\r\n newAssignment = new MaterialAssign(shader, geom, collection);\r\n }\r\n else\r\n {\r\n newAssignment = new MaterialAssign(shader, NO_GEOMETRY_SPECIFIER, null);\r\n }\r\n\r\n if (newAssignment)\r\n {\r\n this._materials.push(newAssignment);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n else\r\n {\r\n // Search for any surface shaders. The first found\r\n // is assumed to be assigned to the entire scene\r\n // The identifier used is \"*\" to mean the entire scene. \r\n const materialNodes = doc.getMaterialNodes();\r\n let shaderList = [];\r\n let foundRenderable = false;\r\n for (let i = 0; i < materialNodes.length; ++i)\r\n {\r\n let materialNode = materialNodes[i];\r\n if (materialNode)\r\n {\r\n //console.log('Scan material: ', materialNode.getNamePath());\r\n let shaderNodes = mx.getShaderNodes(materialNode)\r\n if (shaderNodes.length > 0)\r\n {\r\n let shaderNodePath = shaderNodes[0].getNamePath()\r\n if (!shaderList.includes(shaderNodePath))\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n //console.log('-- add shader: ', shaderNodePath);\r\n shaderList.push(shaderNodePath);\r\n this._materials.push(new MaterialAssign(shaderNodes[0], assignment));\r\n }\r\n }\r\n }\r\n }\r\n const nodeGraphs = doc.getNodeGraphs();\r\n for (let i = 0; i < nodeGraphs.length; ++i)\r\n {\r\n let nodeGraph = nodeGraphs[i];\r\n if (nodeGraph)\r\n {\r\n if (nodeGraph.hasAttribute('nodedef') || nodeGraph.hasSourceUri())\r\n {\r\n continue;\r\n }\r\n // Skip any nodegraph that is connected to something downstream\r\n if (nodeGraph.getDownstreamPorts().length > 0)\r\n {\r\n continue\r\n }\r\n let outputs = nodeGraph.getOutputs();\r\n for (let j = 0; j < outputs.length; ++j)\r\n {\r\n let output = outputs[j];\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n let newMat = new MaterialAssign(output, assignment, null);\r\n this._materials.push(newMat);\r\n }\r\n }\r\n }\r\n }\r\n const outputs = doc.getOutputs();\r\n for (let i = 0; i < outputs.length; ++i)\r\n {\r\n let output = outputs[i];\r\n if (output)\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n this._materials.push(new MaterialAssign(output, assignment));\r\n }\r\n }\r\n\r\n const shaderNodes = [];\r\n for (let i = 0; i < shaderNodes.length; ++i)\r\n {\r\n let shaderNode = shaderNodes[i];\r\n let shaderNodePath = shaderNode.getNamePath()\r\n if (!shaderList.includes(shaderNodePath))\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n shaderList.push(shaderNodePath);\r\n this._materials.push(new MaterialAssign(shaderNode, assignment));\r\n }\r\n }\r\n }\r\n\r\n // Assign to default material if none found\r\n if (this._materials.length == 0)\r\n {\r\n const defaultNode = Material.createFallbackMaterial(doc);\r\n this._materials.push(new MaterialAssign(defaultNode, ALL_GEOMETRY_SPECIFIER));\r\n }\r\n\r\n // Create a new shader for each material node.\r\n // Only create the shader once even if assigned more than once.\r\n var startGenTime = performance.now();\r\n let shaderMap = new Map();\r\n let closeUI = false;\r\n for (let matassign of this._materials)\r\n {\r\n // Need to use path vs name to get a unique key.\r\n let materialName = matassign.getMaterial().getNamePath();\r\n let shader = shaderMap[materialName];\r\n if (!shader)\r\n {\r\n shader = viewer.getMaterial().generateMaterial(matassign, viewer, searchPath, closeUI);\r\n shaderMap[materialName] = shader;\r\n }\r\n matassign.setShader(shader);\r\n closeUI = true;\r\n }\r\n console.log(\"- Generate (\", this._materials.length, \") shader(s) time: \", performance.now() - startGenTime, \" ms.\",);\r\n\r\n // Update scene shader assignments\r\n this.updateMaterialAssignments(viewer, this._soloMaterial);\r\n\r\n // Mark transform update\r\n viewer.getScene().setUpdateTransforms(true);\r\n\r\n //console.log(\"Total material time: \", (performance.now() - startTime), \"ms\");\r\n }\r\n\r\n //\r\n // Update the assignments for scene objects based on the\r\n // material assignment information stored in the viewer.\r\n // Note: If none of the MaterialX assignments match the geometry\r\n // in the scene, then the first material assignment shader is assigned\r\n // to the entire scene.\r\n //\r\n async updateMaterialAssignments(viewer, soloMaterial)\r\n {\r\n console.log(\"Update material assignments. Solo=\", soloMaterial?soloMaterial:\"\");\r\n var startTime = performance.now();\r\n\r\n let assigned = 0;\r\n let assignedSolo = false;\r\n for (let matassign of this._materials)\r\n {\r\n if (matassign.getShader())\r\n {\r\n if (soloMaterial.length)\r\n {\r\n if (matassign.getMaterial().getNamePath() == soloMaterial)\r\n {\r\n let temp = matassign.getGeometry();\r\n matassign.setGeometry(ALL_GEOMETRY_SPECIFIER);\r\n assigned += viewer.getScene().updateMaterial(matassign);\r\n matassign.setGeometry(temp);\r\n assignedSolo = true;\r\n break\r\n }\r\n }\r\n else\r\n {\r\n assigned += viewer.getScene().updateMaterial(matassign);\r\n }\r\n }\r\n }\r\n if (assigned == 0 && this._materials.length)\r\n {\r\n this._defaultMaterial = new MaterialAssign(this._materials[0].getMaterial(), ALL_GEOMETRY_SPECIFIER);\r\n this._defaultMaterial.setShader(this._materials[0].getShader());\r\n viewer.getScene().updateMaterial(this._defaultMaterial);\r\n }\r\n\r\n //if (assigned > 0)\r\n //{\r\n // console.log('Material assignment time: ', performance.now() - startTime, \" ms.\");\r\n //}\r\n }\r\n\r\n // \r\n // Generate a new material for a given element\r\n //\r\n generateMaterial(matassign, viewer, searchPath, closeUI)\r\n {\r\n var elem = matassign.getMaterial();\r\n\r\n var startGenerateMat = performance.now();\r\n\r\n const mx = viewer.getMx();\r\n const textureLoader = new three__WEBPACK_IMPORTED_MODULE_1__.TextureLoader();\r\n\r\n const lights = viewer.getLights();\r\n const lightData = viewer.getLightData();\r\n const radianceTexture = viewer.getRadianceTexture();\r\n const irradianceTexture = viewer.getIrradianceTexture();\r\n const gen = viewer.getGenerator();\r\n const genContext = viewer.getGenContext();\r\n\r\n // Perform transparency check on renderable item\r\n var startTranspCheckTime = performance.now();\r\n const isTransparent = mx.isTransparentSurface(elem, gen.getTarget());\r\n genContext.getOptions().hwTransparency = isTransparent;\r\n // Always set to complete. \r\n // Can consider option to set to reduced as the parsing of large numbers of uniforms (e.g. on shading models)\r\n // can be quite expensive.\r\n //if (this._shaderInterfaceType == 0)\r\n // genContext.getOptions().shaderInterfaceType = mx.ShaderInterfaceType.SHADER_INTERFACE_REDUCED;\r\n //else\r\n genContext.getOptions().shaderInterfaceType = mx.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE;\r\n\r\n if (logDetailedTime)\r\n console.log(\" - Transparency check time: \", performance.now() - startTranspCheckTime, \"ms\");\r\n\r\n // Generate GLES code\r\n var startMTLXGenTime = performance.now();\r\n let shader = gen.generate(elem.getNamePath(), elem, genContext);\r\n if (logDetailedTime)\r\n console.log(\" - MaterialX gen time: \", performance.now() - startMTLXGenTime, \"ms\");\r\n\r\n var startUniformUpdate = performance.now();\r\n\r\n // Get shaders and uniform values\r\n let vShader = shader.getSourceCode(\"vertex\");\r\n let fShader = shader.getSourceCode(\"pixel\");\r\n\r\n let theScene = viewer.getScene();\r\n let flipV = theScene.getFlipGeometryV();\r\n let uniforms = {\r\n ...(0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getUniformValues)(shader.getStage('vertex'), textureLoader, searchPath, flipV),\r\n ...(0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getUniformValues)(shader.getStage('pixel'), textureLoader, searchPath, flipV),\r\n }\r\n\r\n Object.assign(uniforms, {\r\n u_numActiveLightSources: { value: lights.length}, //value: lights.length },\r\n u_lightData: { value: lightData },\r\n u_envMatrix: { value: (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getLightRotation)() },\r\n u_envRadiance: { value: radianceTexture },\r\n u_envRadianceMips: { value: Math.trunc(Math.log2(Math.max(radianceTexture.image.width, radianceTexture.image.height))) + 1 },\r\n u_envRadianceSamples: { value: 2 },\r\n u_envIrradiance: { value: irradianceTexture },\r\n u_refractionEnv: { value: false }\r\n });\r\n\r\n // Create Three JS Material\r\n let newMaterial = new three__WEBPACK_IMPORTED_MODULE_1__.RawShaderMaterial({\r\n uniforms: uniforms,\r\n vertexShader: vShader,\r\n fragmentShader: fShader,\r\n transparent: isTransparent,\r\n blendEquation: three__WEBPACK_IMPORTED_MODULE_1__.AddEquation,\r\n blendSrc: three__WEBPACK_IMPORTED_MODULE_1__.OneMinusSrcAlphaFactor,\r\n blendDst: three__WEBPACK_IMPORTED_MODULE_1__.SrcAlphaFactor,\r\n side: three__WEBPACK_IMPORTED_MODULE_1__.DoubleSide\r\n });\r\n\r\n if (logDetailedTime)\r\n console.log(\" - Three material update time: \", performance.now() - startUniformUpdate, \"ms\");\r\n\r\n // Update property editor\r\n //const gui = viewer.getEditor().getGUI();\r\n //this.updateEditor(matassign, shader, newMaterial, gui, closeUI, viewer);\r\n\r\n if (logDetailedTime)\r\n console.log(\"- Per material generate time: \", performance.now() - startGenerateMat, \"ms\");\r\n\r\n return newMaterial;\r\n }\r\n\r\n clearSoloMaterialUI()\r\n {\r\n for (let i = 0; i < this._materials.length; ++i)\r\n {\r\n let matassign = this._materials[i];\r\n let matUI = matassign.getMaterialUI();\r\n if (matUI)\r\n {\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n matTitle.classList.remove('peditor_material_assigned');\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n img.src = 'public/shader_ball.svg';\r\n //matTitle.classList.remove('peditor_material_unassigned');\r\n }\r\n }\r\n }\r\n\r\n static updateSoloMaterial(viewer, elemPath, materials, event)\r\n {\r\n // Prevent the event from being passed to parent folder\r\n event.stopPropagation();\r\n\r\n for (let i = 0; i < materials.length; ++i)\r\n {\r\n let matassign = materials[i];\r\n // Need to use path vs name to get a unique key.\r\n let materialName = matassign.getMaterial().getNamePath();\r\n var matUI = matassign.getMaterialUI();\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n if (materialName == elemPath)\r\n {\r\n if (this._soloMaterial == elemPath)\r\n {\r\n img.src = 'public/shader_ball.svg';\r\n matTitle.classList.remove('peditor_material_assigned');\r\n this._soloMaterial = \"\";\r\n }\r\n else\r\n {\r\n img.src = 'public/shader_ball2.svg';\r\n matTitle.classList.add('peditor_material_assigned');\r\n this._soloMaterial = elemPath;\r\n }\r\n }\r\n else\r\n {\r\n img.src = 'public/shader_ball.svg';\r\n matTitle.classList.remove('peditor_material_assigned');\r\n }\r\n }\r\n viewer.getMaterial().updateMaterialAssignments(viewer, \"\");\r\n viewer.getScene().setUpdateTransforms();\r\n }\r\n\r\n //\r\n // Update property editor for a given MaterialX element, it's shader, and\r\n // Three material\r\n //\r\n updateEditor(matassign, shader, material, gui, closeUI, viewer)\r\n {\r\n var elem = matassign.getMaterial();\r\n var materials = this._materials;\r\n\r\n const DEFAULT_MIN = 0;\r\n const DEFAULT_MAX = 100;\r\n\r\n var startTime = performance.now();\r\n\r\n const elemPath = elem.getNamePath();\r\n\r\n // Create and cache associated UI\r\n var matUI = gui.addFolder(elemPath);\r\n matassign.setMaterialUI(matUI);\r\n\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n // Add a icon to the title to allow for assigning the material to geometry\r\n // Clicking on the icon will \"solo\" the material to the geometry.\r\n // Clicking on the title will open/close the material folder.\r\n matTitle.innerHTML = \" \" + elem.getNamePath();\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n if (img)\r\n {\r\n // Add event listener to icon to call updateSoloMaterial function\r\n img.addEventListener('click', function (event)\r\n {\r\n Material.updateSoloMaterial(viewer, elemPath, materials, event);\r\n });\r\n }\r\n\r\n if (closeUI)\r\n {\r\n matUI.close();\r\n }\r\n const uniformBlocks = Object.values(shader.getStage('pixel').getUniformBlocks());\r\n var uniformToUpdate;\r\n const ignoreList = ['u_envRadianceMips', 'u_envRadianceSamples', 'u_alphaThreshold'];\r\n\r\n var folderList = new Map();\r\n folderList[elemPath] = matUI;\r\n\r\n uniformBlocks.forEach(uniforms =>\r\n {\r\n if (!uniforms.empty())\r\n {\r\n for (let i = 0; i < uniforms.size(); ++i)\r\n {\r\n const variable = uniforms.get(i);\r\n const value = variable.getValue()?.getData();\r\n let name = variable.getVariable();\r\n\r\n if (ignoreList.includes(name))\r\n {\r\n continue;\r\n }\r\n\r\n let currentFolder = matUI;\r\n let currentElemPath = variable.getPath();\r\n if (!currentElemPath || currentElemPath.length == 0)\r\n {\r\n continue;\r\n }\r\n let currentElem = elem.getDocument().getDescendant(currentElemPath);\r\n if (!currentElem)\r\n {\r\n continue;\r\n }\r\n\r\n let currentNode = null;\r\n if (currentElem.getParent() && currentElem.getParent().getNamePath() != \"\")\r\n {\r\n currentNode = currentElem.getParent();\r\n }\r\n let uiname = \"\";\r\n let nodeDefInput = null;\r\n if (currentNode)\r\n {\r\n\r\n let currentNodePath = currentNode.getNamePath();\r\n var pathSplit = currentNodePath.split('/');\r\n if (pathSplit.length)\r\n {\r\n currentNodePath = pathSplit[0];\r\n }\r\n currentFolder = folderList[currentNodePath];\r\n if (!currentFolder)\r\n {\r\n currentFolder = matUI.addFolder(currentNodePath);\r\n folderList[currentNodePath] = currentFolder;\r\n }\r\n\r\n // Check for ui attributes\r\n var nodeDef = currentNode.getNodeDef();\r\n if (nodeDef)\r\n {\r\n // Remove node name from shader uniform name for non root nodes\r\n let lookup_name = name.replace(currentNode.getName() + '_', '');\r\n nodeDefInput = nodeDef.getActiveInput(lookup_name);\r\n if (nodeDefInput)\r\n {\r\n uiname = nodeDefInput.getAttribute('uiname');\r\n let uifolderName = nodeDefInput.getAttribute('uifolder');\r\n if (uifolderName && uifolderName.length)\r\n {\r\n let newFolderName = currentNodePath + '/' + uifolderName;\r\n currentFolder = folderList[newFolderName];\r\n if (!currentFolder)\r\n {\r\n currentFolder = matUI.addFolder(uifolderName);\r\n currentFolder.domElement.classList.add('peditorfolder');\r\n folderList[newFolderName] = currentFolder;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Determine UI name to use\r\n let path = name;\r\n let interfaceName = currentElem.getAttribute(\"interfacename\");\r\n if (interfaceName && interfaceName.length)\r\n {\r\n const graph = currentNode.getParent();\r\n if (graph)\r\n {\r\n const graphInput = graph.getInput(interfaceName);\r\n if (graphInput)\r\n {\r\n let uiname = graphInput.getAttribute('uiname');\r\n if (uiname.length)\r\n {\r\n path = uiname;\r\n }\r\n else\r\n {\r\n path = graphInput.getName();\r\n }\r\n }\r\n }\r\n else\r\n {\r\n path = interfaceName;\r\n }\r\n }\r\n else\r\n {\r\n if (!uiname)\r\n {\r\n uiname = currentElem.getAttribute('uiname');\r\n }\r\n if (uiname && uiname.length)\r\n {\r\n path = uiname;\r\n }\r\n }\r\n\r\n switch (variable.getType().getName())\r\n {\r\n case 'float':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = DEFAULT_MIN;\r\n if (value < minValue)\r\n {\r\n minValue = value;\r\n }\r\n var maxValue = DEFAULT_MAX;\r\n if (value > maxValue)\r\n {\r\n maxValue = value;\r\n }\r\n var step = 0;\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = parseFloat(nodeDefInput.getAttribute('uisoftmin'));\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = parseFloat(nodeDefInput.getAttribute('uimin'));\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = parseFloat(nodeDefInput.getAttribute('uisoftmax'));\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = parseFloat(nodeDefInput.getAttribute('uimax'));\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = parseFloat(nodeDefInput.getAttribute('uistep'));\r\n }\r\n if (step == 0)\r\n {\r\n step = (maxValue - minValue) / 1000.0;\r\n }\r\n const w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'integer':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = DEFAULT_MIN;\r\n if (value < minValue)\r\n {\r\n minValue = value;\r\n }\r\n var maxValue = DEFAULT_MAX;\r\n if (value > maxValue)\r\n {\r\n maxValue = value;\r\n }\r\n var step = 0;\r\n var enumList = []\r\n var enumValues = []\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('enum'))\r\n {\r\n // Get enum and enum values attributes (if present)\r\n enumList = nodeDefInput.getAttribute('enum').split(',');\r\n if (nodeDefInput.hasAttribute('enumvalues'))\r\n {\r\n enumValues = nodeDefInput.getAttribute('enumvalues').split(',').map(Number);\r\n }\r\n }\r\n else\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = parseInt(nodeDefInput.getAttribute('uisoftmin'));\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = parseInt(nodeDefInput.getAttribute('uimin'));\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = parseInt(nodeDefInput.getAttribute('uisoftmax'));\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = parseInt(nodeDefInput.getAttribute('uimax'));\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = parseInt(nodeDefInput.getAttribute('uistep'));\r\n }\r\n }\r\n if (enumList.length == 0)\r\n {\r\n if (step == 0)\r\n {\r\n step = 1 / (maxValue - minValue);\r\n step = Math.ceil(step);\r\n if (step == 0)\r\n {\r\n step = 1;\r\n }\r\n }\r\n }\r\n if (enumList.length == 0)\r\n {\r\n let w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n else\r\n {\r\n // Map enumList strings to values\r\n // Map to 0..N if no values are specified via enumvalues attribute\r\n if (enumValues.length == 0)\r\n {\r\n for (let i = 0; i < enumList.length; ++i)\r\n {\r\n enumValues.push(i);\r\n }\r\n }\r\n const enumeration = {};\r\n enumList.forEach((str, index) =>\r\n {\r\n enumeration[str] = enumValues[index];\r\n });\r\n\r\n // Function to handle enum drop-down\r\n function handleDropdownChange(value)\r\n {\r\n if (material.uniforms[name])\r\n {\r\n material.uniforms[name].value = value;\r\n }\r\n }\r\n const defaultOption = enumList[value]; // Set the default selected option\r\n const dropdownController = currentFolder.add(enumeration, defaultOption, enumeration).name(path);\r\n dropdownController.onChange(handleDropdownChange);\r\n dropdownController.domElement.classList.add('peditoritem');\r\n }\r\n }\r\n break;\r\n\r\n case 'boolean':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n let w = currentFolder.add(material.uniforms[name], 'value').name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'vector2':\r\n case 'vector3':\r\n case 'vector4':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = [DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN];\r\n var maxValue = [DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX];\r\n var step = [0, 0, 0, 0];\r\n\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = nodeDefInput.getAttribute('uisoftmin').split(',').map(Number);\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = nodeDefInput.getAttribute('uimin').split(',').map(Number);\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = nodeDefInput.getAttribute('uisoftmax').split(',').map(Number);\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = nodeDefInput.getAttribute('uimax').split(',').map(Number);\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = nodeDefInput.getAttribute('uistep').split(',').map(Number);\r\n }\r\n for (let i = 0; i < 4; ++i)\r\n {\r\n if (step[i] == 0)\r\n {\r\n step[i] = 1 / (maxValue[i] - minValue[i]);\r\n }\r\n }\r\n\r\n const keyString = [\"x\", \"y\", \"z\", \"w\"];\r\n let vecFolder = currentFolder.addFolder(path);\r\n Object.keys(material.uniforms[name].value).forEach((key) =>\r\n {\r\n let w = vecFolder.add(material.uniforms[name].value,\r\n key, minValue[key], maxValue[key], step[key]).name(keyString[key]);\r\n w.domElement.classList.add('peditoritem');\r\n })\r\n }\r\n break;\r\n\r\n case 'color3':\r\n // Irksome way to map arrays to colors and back\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var dummy =\r\n {\r\n color: 0xFF0000\r\n };\r\n const color3 = new three__WEBPACK_IMPORTED_MODULE_1__.Color(dummy.color);\r\n color3.fromArray(material.uniforms[name].value);\r\n dummy.color = color3.getHex();\r\n let w = currentFolder.addColor(dummy, 'color').name(path)\r\n .onChange(function (value)\r\n {\r\n const color3 = new three__WEBPACK_IMPORTED_MODULE_1__.Color(value);\r\n material.uniforms[name].value.set(color3.toArray());\r\n });\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'color4':\r\n break;\r\n\r\n case 'matrix33':\r\n case 'matrix44':\r\n case 'samplerCube':\r\n case 'filename':\r\n break;\r\n case 'string':\r\n console.log('String: ', name);\r\n if (value != null)\r\n {\r\n var dummy =\r\n {\r\n thevalue: value\r\n }\r\n let item = currentFolder.add(dummy, 'thevalue');\r\n item.name(path);\r\n item.disable(true);\r\n item.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n }\r\n });\r\n\r\n if (logDetailedTime)\r\n {\r\n console.log(\" - Editor update time: \", performance.now() - startTime, \"ms\");\r\n }\r\n }\r\n\r\n // List of material assignments: { MaterialX node, geometry assignment string, and hardware shader }\r\n _materials;\r\n\r\n // Fallback material if nothing was assigned explicitly\r\n _defaultMaterial;\r\n}\r\n\r\n/*\r\n Viewer class\r\n\r\n Keeps track of local scene, and property editor as well as current MaterialX document \r\n and assocaited material, shader and lighting information.\r\n*/\r\nclass Viewer\r\n{\r\n static create()\r\n {\r\n return new Viewer();\r\n }\r\n\r\n constructor()\r\n {\r\n this.scene = new Scene();\r\n this.editor = new Editor();\r\n this.materials.push(new Material());\r\n\r\n this.fileLoader = new three__WEBPACK_IMPORTED_MODULE_1__.FileLoader();\r\n this.hdrLoader = new three_examples_jsm_loaders_RGBELoader_js__WEBPACK_IMPORTED_MODULE_5__.RGBELoader();\r\n }\r\n\r\n //\r\n // Create shader generator, generation context and \"base\" document which\r\n // contains the standard definition libraries and lighting elements.\r\n //\r\n async initialize(mtlxIn, renderer, radianceTexture, irradianceTexture, lightRigXml)\r\n {\r\n this.mx = mtlxIn;\r\n\r\n // Initialize base document\r\n this.generator = new this.mx.EsslShaderGenerator();\r\n this.genContext = new this.mx.GenContext(this.generator);\r\n\r\n this.document = this.mx.createDocument();\r\n this.stdlib = this.mx.loadStandardLibraries(this.genContext);\r\n this.document.importLibrary(this.stdlib);\r\n\r\n this.initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml);\r\n\r\n radianceTexture.mapping = three__WEBPACK_IMPORTED_MODULE_1__.EquirectangularReflectionMapping;\r\n this.getScene().setBackgroundTexture(radianceTexture);\r\n }\r\n\r\n //\r\n // Load in lighting rig document and register lights with generation context\r\n // Initialize environment lighting (IBLs).\r\n //\r\n async initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml)\r\n {\r\n // Load lighting setup into document\r\n const mx = this.getMx();\r\n this.lightRigDoc = mx.createDocument();\r\n await mx.readFromXmlString(this.lightRigDoc, lightRigXml);\r\n this.document.importLibrary(this.lightRigDoc);\r\n\r\n // Register lights with generation context\r\n this.lights = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.findLights)(this.document);\r\n this.lightData = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.registerLights)(mx, this.lights, this.genContext);\r\n\r\n this.radianceTexture = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.prepareEnvTexture)(radianceTexture, renderer.capabilities);\r\n this.irradianceTexture = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.prepareEnvTexture)(irradianceTexture, renderer.capabilities);\r\n }\r\n\r\n getEditor()\r\n {\r\n return this.editor;\r\n }\r\n\r\n getScene()\r\n {\r\n return this.scene;\r\n }\r\n\r\n getMaterial()\r\n {\r\n return this.materials[0];\r\n }\r\n\r\n getmaterials()\r\n {\r\n return this.materials;\r\n }\r\n\r\n getFileLoader()\r\n {\r\n return this.fileLoader;\r\n }\r\n\r\n getHdrLoader()\r\n {\r\n return this.hdrLoader;\r\n }\r\n\r\n setDocument(doc)\r\n {\r\n this.doc = doc;\r\n }\r\n getDocument()\r\n {\r\n return this.doc;\r\n }\r\n\r\n getLibrary()\r\n {\r\n return this.stdlib;\r\n }\r\n\r\n getLightRig()\r\n {\r\n return this.lightRigDoc;\r\n }\r\n\r\n getMx()\r\n {\r\n return this.mx;\r\n }\r\n\r\n getGenerator()\r\n {\r\n return this.generator;\r\n }\r\n\r\n getGenContext()\r\n {\r\n return this.genContext;\r\n }\r\n\r\n getLights()\r\n {\r\n return this.lights;\r\n }\r\n\r\n getLightData()\r\n {\r\n return this.lightData;\r\n }\r\n\r\n getRadianceTexture()\r\n {\r\n return this.radianceTexture;\r\n }\r\n\r\n getIrradianceTexture()\r\n {\r\n return this.irradianceTexture;\r\n }\r\n\r\n // Three scene and materials. \r\n scene = null;\r\n materials = [];\r\n\r\n // Property editor\r\n editor = null;\r\n\r\n // Utility loaders\r\n fileloader = null;\r\n hdrLoader = null;\r\n\r\n // MaterialX module, current document and support documents.\r\n mx = null;\r\n doc = null;\r\n stdlib = null;\r\n lightRigDoc = null;\r\n\r\n // MaterialX code generator and context\r\n generator = null;\r\n genContext = null;\r\n\r\n // Lighting information\r\n lights = null;\r\n lightData = null;\r\n radianceTexture = null;\r\n irradianceTexture = null;\r\n}\r\n\n\n//# sourceURL=webpack://MaterialX-Shader-Editor/./source/viewer.js?");
-
-/***/ }),
-
-/***/ "../node_editor.js":
-/*!*************************!*\
- !*** ../node_editor.js ***!
- \*************************/
-/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ initializeNodeEditor: () => (/* binding */ initializeNodeEditor)\n/* harmony export */ });\n\r\n\r\nfunction initializeNodeEditor(materialFilename, geometryFilename, theRenderer) {\r\n\r\n // Customize what icon to show based on nodedef name prefix or nodegroup\r\n // Note that this is just a heuristic based on current nodegroup and naming \r\n // convention. Default is \"mtlx\" for MaterialX nodes.\r\n var my_icon_map = {\r\n \"gltf\": \"./Images/gltf_logo.webp\",\r\n \"usd\": \"./Images/openusd_logo.webp\",\r\n \"open_pbr\": \"./Images/openpbr_logo.webp\",\r\n \"houdini\": \"./Images/houdini_icon.webp\",\r\n \"maya\": \"./Images/maya_surfaces.webp\",\r\n \"_default_\": \"./Images/materialx_logo.webp\",\r\n \"_default_graph_\": \"./Images/nodegraph_white.svg\"\r\n };\r\n\r\n function uriExists(uri) {\r\n // Add try / catch block to handle network errors \r\n return fetch(uri)\r\n .then(response => {\r\n if (response.ok) {\r\n return true;\r\n } else {\r\n return false;\r\n }\r\n })\r\n .catch(error => {\r\n console.log('Error checking URI:', error);\r\n return false;\r\n });\r\n }\r\n\r\n if (theRenderer) {\r\n var viewer = theRenderer.initializeViewer(materialFilename, geometryFilename);\r\n console.log('Setup viewer:', viewer);\r\n }\r\n else {\r\n let preview_panel = document.getElementById(\"preview_panel\");\r\n // Hide preview_panel DOM element\r\n if (preview_panel)\r\n preview_panel.style.display = 'none';\r\n }\r\n\r\n var canvas = document.getElementById('mygraphcanvas');\r\n var cmeditor = setupXMLSyntax();\r\n var cmeditor2 = setupJavascriptSyntax();\r\n var ui = {\r\n console_area: document.getElementById('console_area'),\r\n nodeTypesList: document.getElementById('nodeTypesList'),\r\n mtlxdoc: cmeditor,\r\n mtlxlib: cmeditor2,\r\n mtlxdoc_colorspace: null, // document.getElementById('mtlxdoc_colorspace'),\r\n propertypanel_content: document.getElementById('propertypanel_content'),\r\n propertypanel_icon: document.getElementById('propertypanel_icon'),\r\n icon_map: my_icon_map,\r\n };\r\n var editor = new MxShadingGraphEditor();\r\n editor.initialize(false, canvas, ui, materialFilename);\r\n\r\n function addUIHandlers() {\r\n // Add event listener to save canvas as image when button is clicked\r\n var saveCanvasButton = document.getElementById('captureGraph');\r\n saveCanvasButton.addEventListener('click', function () {\r\n var canvas = document.getElementById('mygraphcanvas');\r\n var dataURL = canvas.toDataURL('image/png');\r\n var link = document.createElement('a');\r\n link.href = dataURL;\r\n link.download = 'graph_capture.png';\r\n link.click();\r\n });\r\n\r\n // TODO: Make this a user option\r\n var auto_arrange_size = 80;\r\n\r\n // Add load materialx graph event listener\r\n var loadMaterialXDocumentFromFile = document.getElementById('loadMaterialXDocumentFromFile');\r\n loadMaterialXDocumentFromFile.addEventListener('click', function () {\r\n editor.loadGraphFromFile('mtlx', auto_arrange_size);\r\n });\r\n\r\n // Add load materialx graph from text event listener\r\n var texAreaNumber = 0;\r\n var loadMaterialXDocumentFromText = document.getElementById('loadMaterialXDocumentFromText');\r\n loadMaterialXDocumentFromText.addEventListener('click', function () {\r\n var mtlxdoc = document.getElementById('mtlxdoc').value;\r\n // Generate a name for the graph\r\n if (mtlxdoc.length > 0) {\r\n var name = 'MaterialXGraph' + texAreaNumber++;\r\n editor.loadGraphFromString('mtlx', mtlxdoc, name, auto_arrange_size);\r\n }\r\n });\r\n\r\n // Add load definitions event listener\r\n var loadMaterialXDefinitions = document.getElementById('loadMaterialXDefinitions');\r\n loadMaterialXDefinitions.addEventListener('click', function () {\r\n editor.loadDefinitionsFromFile('mtlx');\r\n });\r\n\r\n // Add clear graph event listener\r\n var clearGraphButton = document.getElementById('clearGraph');\r\n clearGraphButton.addEventListener('click', function () {\r\n editor.clearGraph();\r\n });\r\n\r\n // Add save materialx graph event listener\r\n var saveMaterialXGraph = document.getElementById('saveMaterialXGraph');\r\n saveMaterialXGraph.addEventListener('click', function () {\r\n var saveCustomLibs = document.getElementById('saveCustomLibs').checked;\r\n var saveNodePositions = document.getElementById('saveNodePositions').checked;\r\n editor.saveGraphToFile('mtlx', saveCustomLibs, saveNodePositions);\r\n });\r\n\r\n // Add save materialx graph text event listener\r\n var saveMaterialXGraphText = document.getElementById('saveMaterialXGraphText');\r\n saveMaterialXGraphText.addEventListener('click', function () {\r\n saveToStringUI();\r\n });\r\n\r\n // Add open subgraph event handler\r\n var openSubgraph = document.getElementById('openSubgraph');\r\n openSubgraph.addEventListener('click', function () {\r\n editor.openSubgraph();\r\n });\r\n\r\n // Add close subgraph event handler\r\n var closeSubgraph = document.getElementById('closeSubgraph');\r\n closeSubgraph.addEventListener('click', function () {\r\n editor.closeSubgraph();\r\n });\r\n\r\n\r\n // Add reset view event handler\r\n var resetView = document.getElementById('resetView');\r\n resetView.addEventListener('click', function () {\r\n editor.resetView();\r\n });\r\n\r\n // Add arrange graph event listener\r\n var arrangeGraphButton = document.getElementById('arrangeGraph');\r\n arrangeGraphButton.addEventListener('click', function () {\r\n editor.arrangeGraph();\r\n });\r\n\r\n // Add center node event listener\r\n var centerNodeButton = document.getElementById('centerNode');\r\n centerNodeButton.addEventListener('click', function () {\r\n editor.centerNode();\r\n });\r\n\r\n // Add collapse/expand nodes event listener\r\n var collapseNodesButton = document.getElementById('collapseNodes');\r\n collapseNodesButton.addEventListener('click', function () {\r\n editor.collapseExpandNodes(true);\r\n });\r\n var expandNodesButton = document.getElementById('expandNodes');\r\n expandNodesButton.addEventListener('click', function () {\r\n editor.collapseExpandNodes(false);\r\n });\r\n\r\n // Add copy selected event listener\r\n var copySelectedButton = document.getElementById('copySelected');\r\n copySelectedButton.addEventListener('click', function () {\r\n editor.copyToClipboard();\r\n });\r\n\r\n // Add paste selected event listener\r\n var pasteSelectedButton = document.getElementById('pasteSelected');\r\n pasteSelectedButton.addEventListener('click', function () {\r\n editor.pasteFromClipboard();\r\n });\r\n\r\n // Add create subgraph event listener\r\n var createNodeGraphButton = document.getElementById('createNodeGraph');\r\n createNodeGraphButton.addEventListener('click', function () {\r\n editor.createNodeGraph();\r\n });\r\n\r\n // Add extract subgraph event listener\r\n var extractNodeGraphButton = document.getElementById('extractNodeGraph');\r\n extractNodeGraphButton.addEventListener('click', function () {\r\n editor.extractNodeGraph();\r\n });\r\n\r\n /* \r\n // Add load serialization event listener\r\n var loadSerialization = document.getElementById('loadSerialization');\r\n loadSerialization.addEventListener('click', function () {\r\n editor.loadSerialization();\r\n });\r\n \r\n // Add download graph event listener\r\n var downloadGraph = document.getElementById('downloadGraph');\r\n downloadGraph.addEventListener('click', function () {\r\n editor.saveSerialization();\r\n }); */\r\n\r\n // Add xml to graph event listener\r\n var xmltograph = document.getElementById('xmltograph');\r\n xmltograph.addEventListener('click', function () {\r\n var name = 'MaterialXGraph' + texAreaNumber++;\r\n var mtlxdoc = document.getElementById('mtlxdoc').value;\r\n editor.loadGraphFromString('mtlx', mtlxdoc, 'MaterialXGraph', auto_arrange_size);\r\n });\r\n\r\n /* function updateRenderableItemUI(renderableItems) {\r\n let renderableItemSelect = document.getElementById('renderableItem');\r\n // Remove any previous children\r\n while (renderableItemSelect.firstChild) {\r\n renderableItemSelect.removeChild(renderableItemSelect.firstChild);\r\n }\r\n for (let i = 0; i < renderableItems.length; i++) {\r\n let item = renderableItems[i];\r\n let option = document.createElement('option');\r\n option.value = i;\r\n option.text = item; // item.getNamePath();\r\n renderableItemSelect.appendChild(option);\r\n }\r\n } */\r\n\r\n function updateRenderableItemUI()\r\n {\r\n let renderableItems = editor.findRenderableItems();\r\n\r\n // Update selection for renderables\r\n let renderableItemSelect = document.getElementById('renderableItem');\r\n while (renderableItemSelect.firstChild) {\r\n renderableItemSelect.removeChild(renderableItemSelect.firstChild);\r\n }\r\n for (let i = 0; i < renderableItems.length; i++) {\r\n let item = renderableItems[i];\r\n let option = document.createElement('option');\r\n option.value = item;\r\n let uiitem = item;\r\n // Truncate the name so it will fit into UI.\r\n if (uiitem.length > 12)\r\n uiitem = uiitem.substring(0, 12) + '...';\r\n option.text = uiitem; \r\n renderableItemSelect.appendChild(option);\r\n } \r\n }\r\n\r\n function saveToStringUI() {\r\n var saveCustomLibs = document.getElementById('saveCustomLibs').checked;\r\n var saveNodePositions = document.getElementById('saveNodePositions').checked;\r\n var result = editor.saveGraphToString('mtlx', saveCustomLibs, saveNodePositions);\r\n cmeditor.setValue(result);\r\n\r\n if (theRenderer) {\r\n theRenderer.updateMaterialFromText(result);\r\n updateRenderableItemUI();\r\n }\r\n }\r\n\r\n // Add graph to xml event listener\r\n var graphtoxml = document.getElementById('graphtoxml');\r\n if (graphtoxml) {\r\n graphtoxml.addEventListener('click', function () {\r\n saveToStringUI();\r\n });\r\n }\r\n\r\n var graphtoxml2 = document.getElementById('graphtoxml2');\r\n if (graphtoxml2) {\r\n graphtoxml2.addEventListener('click', function () {\r\n saveToStringUI();\r\n });\r\n }\r\n\r\n // Handle turntabe option\r\n let turntableEnabledUI = document.getElementById('turntableEnabled');\r\n if (turntableEnabledUI) {\r\n turntableEnabledUI.addEventListener('click', (e) => {\r\n // Toggle inverting the button colors no toggling danger\r\n turntableEnabledUI.classList.toggle('btn-secondary');\r\n if (theRenderer)\r\n theRenderer.toggleTurntable();\r\n });\r\n }\r\n\r\n // Handle render disabled option\r\n let disableRenderingUI = document.getElementById('disableRendering');\r\n if (disableRenderingUI) {\r\n disableRenderingUI.addEventListener('click', (e) => {\r\n // Toggle inverting the button colors\r\n disableRenderingUI.classList.toggle('btn-danger');\r\n if (theRenderer)\r\n theRenderer.toggleRendering();\r\n });\r\n }\r\n\r\n // Handle background display option\r\n let toggleBackgroundTextureUI = document.getElementById('toggleBackgroundTexture');\r\n if (toggleBackgroundTextureUI) {\r\n toggleBackgroundTextureUI.addEventListener('click', (e) => {\r\n toggleBackgroundTextureUI.classList.toggle('btn-secondary');\r\n if (theRenderer)\r\n theRenderer.toggleBackgroundTexture();\r\n });\r\n }\r\n // Handle reset camera option\r\n let resetCameraUI = document.getElementById('resetCamera');\r\n if (resetCameraUI) {\r\n resetCameraUI.addEventListener('click', (e) => {\r\n if (theRenderer)\r\n theRenderer.resetCamera();\r\n });\r\n }\r\n\r\n // Handle renderable geometry option\r\n function loadFromMenu(e) {\r\n var uiItem = e.target.value;\r\n if (uiItem == '_loadFromFile_') {\r\n // Create a file dialog to get the filename\r\n var fileInput = document.createElement('input');\r\n fileInput.type = 'file';\r\n fileInput.accept = '.glb';\r\n\r\n fileInput.onchange = function (event) {\r\n var file = event.target.files[0];\r\n if (file) {\r\n var fileURL = URL.createObjectURL(file);\r\n if (theRenderer)\r\n theRenderer.setRenderGeometry(fileURL);\r\n console.log('Change geometry to:', fileURL);\r\n }\r\n }\r\n fileInput.click();\r\n }\r\n else {\r\n // Convert to lowercase and remove spaces\r\n var geometryURL = uiItem.toLowerCase().replace(/\\s/g, '');\r\n var geometryPath = 'Geometry/' + geometryURL + '.glb';\r\n console.log('Change geometry to:', geometryPath);\r\n if (theRenderer)\r\n theRenderer.setRenderGeometry(geometryPath);\r\n }\r\n }\r\n\r\n // Handle geometry item changed\r\n let geometryItemSelect = document.getElementById('loadGeometry');\r\n if (geometryItemSelect) {\r\n // Add event handler for selection\r\n geometryItemSelect.addEventListener('change', (e) => {\r\n loadFromMenu(e);\r\n if (e.target.value == '_loadFromFile_')\r\n e.target.value = 'Custom Geometry'\r\n });\r\n }\r\n\r\n // Handle material selection change\r\n let renderableItemSelect = document.getElementById('renderableItem');\r\n if (renderableItemSelect) {\r\n renderableItemSelect.addEventListener('change', (e) => {\r\n let index = e.target.value;\r\n if (theRenderer)\r\n theRenderer.setRenderMaterial(index);\r\n });\r\n }\r\n\r\n // Get the canvas element and its container\r\n var canvas = document.getElementById('mygraphcanvas');\r\n var canvasContainer = document.getElementById('canvasContainer');\r\n var colContainer = document.getElementById('colContainer');\r\n\r\n // Create a new ResizeObserver\r\n var observer = new ResizeObserver(function (entries) {\r\n for (var entry of entries) {\r\n // Get the new width and height of the column\r\n var newWidth = entry.contentRect.width;\r\n var newHeight = entry.contentRect.height;\r\n\r\n // Set the canvas size to match the column\r\n canvas.width = newWidth;\r\n canvas.height = newHeight;\r\n\r\n // Mark the editor as dirty to redraw the graph.\r\n editor.setDirty();\r\n }\r\n });\r\n\r\n // Start observing the canvas container\r\n observer.observe(colContainer);\r\n\r\n }\r\n\r\n function setupJavascriptSyntax() {\r\n // Initialize CodeMirror for JS syntax highlighting\r\n const elem = document.getElementById('mtlxlib');\r\n if (!elem) {\r\n return;\r\n }\r\n var cmeditor = CodeMirror.fromTextArea(elem, {\r\n mode: 'application/javascript',\r\n lineNumbers: true,\r\n dragDrop: false,\r\n theme: 'dracula',\r\n readOnly: true\r\n });\r\n\r\n elem.value = '';\r\n cmeditor.setValue('');\r\n\r\n // Update CodeMirror whenever the textarea content changes\r\n cmeditor.on('change', () => {\r\n elem.value = cmeditor.getValue();\r\n });\r\n\r\n return cmeditor;\r\n }\r\n\r\n\r\n function setupXMLSyntax() {\r\n // Initialize CodeMirror for XML syntax highlighting\r\n const materialXTextArea = document.getElementById('mtlxdoc');\r\n var cmeditor = CodeMirror.fromTextArea(materialXTextArea, {\r\n mode: 'application/xml',\r\n lineNumbers: true,\r\n dragDrop: true,\r\n theme: 'night'\r\n });\r\n\r\n // Optional: Set an initial value for the textarea\r\n const initialXML = '';\r\n materialXTextArea.value = initialXML;\r\n cmeditor.setValue(initialXML);\r\n\r\n // Update CodeMirror whenever the textarea content changes\r\n cmeditor.on('change', (e) => {\r\n materialXTextArea.value = cmeditor.getValue();\r\n });\r\n\r\n var pasteButton = document.getElementById('mtlxdoc_paste');\r\n if (pasteButton)\r\n addPasteHandler(pasteButton, cmeditor);\r\n\r\n return cmeditor;\r\n }\r\n\r\n\r\n\r\n\r\n addUIHandlers();\r\n addCopyHandlers();\r\n}\r\n\n\n//# sourceURL=webpack://MaterialX-Shader-Editor/../node_editor.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Editor: () => (/* binding */ Editor),\n/* harmony export */ Material: () => (/* binding */ Material),\n/* harmony export */ Scene: () => (/* binding */ Scene),\n/* harmony export */ Viewer: () => (/* binding */ Viewer)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n/* harmony import */ var three_examples_jsm_loaders_GLTFLoader__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! three/examples/jsm/loaders/GLTFLoader */ \"./node_modules/three/examples/jsm/loaders/GLTFLoader.js\");\n/* harmony import */ var three_examples_jsm_loaders_ObjLoader__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! three/examples/jsm/loaders/ObjLoader */ \"./node_modules/three/examples/jsm/loaders/ObjLoader.js\");\n/* harmony import */ var three_examples_jsm_loaders_RGBELoader_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! three/examples/jsm/loaders/RGBELoader.js */ \"./node_modules/three/examples/jsm/loaders/RGBELoader.js\");\n/* harmony import */ var _helper_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helper.js */ \"./source/helper.js\");\n/* harmony import */ var lil_gui__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! lil-gui */ \"./node_modules/lil-gui/dist/lil-gui.esm.js\");\n//\r\n// Copyright Contributors to the MaterialX Project\r\n// SPDX-License-Identifier: Apache-2.0\r\n//\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nconst ALL_GEOMETRY_SPECIFIER = \"*\";\r\nconst NO_GEOMETRY_SPECIFIER = \"\";\r\nconst DAG_PATH_SEPERATOR = \"/\";\r\n\r\n// Logging toggle\r\nvar logDetailedTime = false;\r\n\r\n/*\r\n Scene management\r\n*/\r\nclass Scene\r\n{\r\n constructor()\r\n {\r\n this._geometryURL = new URLSearchParams(document.location.search).get(\"geom\");\r\n if (!this._geometryURL)\r\n {\r\n this._geometryURL = 'Geometry/teapot.glb';\r\n }\r\n }\r\n\r\n initialize()\r\n {\r\n this._scene = new three__WEBPACK_IMPORTED_MODULE_1__.Scene();\r\n this._scene.background = new three__WEBPACK_IMPORTED_MODULE_1__.Color(this.#_backgroundColor);\r\n this._scene.background.convertSRGBToLinear();\r\n\r\n let cc = document.getElementById('webglcanvas');\r\n const aspectRatio = cc.width / cc.height;\r\n const cameraNearDist = 0.01;\r\n const cameraFarDist = 1000.0;\r\n const cameraFOV = 60.0;\r\n this._camera = new three__WEBPACK_IMPORTED_MODULE_1__.PerspectiveCamera(cameraFOV, aspectRatio, cameraNearDist, cameraFarDist);\r\n\r\n this.#_gltfLoader = new three_examples_jsm_loaders_GLTFLoader__WEBPACK_IMPORTED_MODULE_2__.GLTFLoader();\r\n this.#_objLoader = new three_examples_jsm_loaders_ObjLoader__WEBPACK_IMPORTED_MODULE_3__.OBJLoader();\r\n\r\n this.#_normalMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix3();\r\n this.#_viewProjMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4();\r\n this.#_worldViewPos = new three__WEBPACK_IMPORTED_MODULE_1__.Vector3();\r\n }\r\n\r\n // Set whether to flip UVs in V for loaded geometry\r\n setFlipGeometryV(val)\r\n {\r\n this.#_flipV = val;\r\n }\r\n\r\n // Get whether to flip UVs in V for loaded geometry\r\n getFlipGeometryV()\r\n {\r\n return this.#_flipV;\r\n }\r\n\r\n // Utility to perform geometry file load\r\n loadGeometryFile(geometryFilename, loader)\r\n {\r\n return new Promise((resolve, reject) =>\r\n {\r\n if (loader) \r\n {\r\n console.log(\"Load geometry: \", geometryFilename); \r\n loader.load(geometryFilename, data => resolve(data), null, reject);\r\n }\r\n });\r\n }\r\n\r\n //\r\n // Load in geometry specified by a given file name,\r\n // then update the scene geometry and camera.\r\n //\r\n async loadGeometry(viewer, orbitControls)\r\n {\r\n var startTime = performance.now();\r\n var geomLoadTime = startTime;\r\n\r\n console.log('viewer load geometry: ', this.getGeometryURL());\r\n\r\n var gltfData = null;\r\n if (this.getGeometryURL().endsWith('glb'))\r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_gltfLoader);\r\n else if (this.getGeometryURL().endsWith('obj'))\r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_objLoader);\r\n else \r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_gltfLoader);\r\n\r\n if (gltfData == null)\r\n {\r\n console.log(\"Failed to load geometry: \", this.getGeometryURL());\r\n return;\r\n }\r\n\r\n const scene = this.getScene();\r\n while (scene.children.length > 0)\r\n {\r\n scene.remove(scene.children[0]);\r\n }\r\n\r\n this.#_rootNode = null;\r\n const model = gltfData.scene;\r\n if (!model)\r\n {\r\n const geometry = new three__WEBPACK_IMPORTED_MODULE_1__.BoxGeometry(1, 1, 1);\r\n const material = new three__WEBPACK_IMPORTED_MODULE_1__.MeshBasicMaterial({ color: 0xdddddd });\r\n const cube = new three__WEBPACK_IMPORTED_MODULE_1__.Mesh(geometry, material);\r\n obj = new three__WEBPACK_IMPORTED_MODULE_1__.Group();\r\n obj.add(geometry);\r\n }\r\n else\r\n {\r\n this.#_rootNode = model;\r\n }\r\n scene.add(model);\r\n\r\n // Always reset controls based on camera for each load. \r\n orbitControls.reset();\r\n //console.log(\"- Scene load time: \", performance.now() - geomLoadTime, \"ms\");\r\n\r\n //console.log(\"Total geometry load time: \", performance.now() - startTime, \" ms.\");\r\n\r\n viewer.getMaterial().clearSoloMaterialUI();\r\n viewer.getMaterial().updateMaterialAssignments(viewer, viewer.getMaterial().getSoloMaterial());\r\n this.setUpdateTransforms();\r\n\r\n this.updateScene(viewer, orbitControls);\r\n }\r\n\r\n //\r\n // Update the geometry buffer, assigned materials, and camera controls.\r\n //\r\n updateScene(viewer, orbitControls)\r\n {\r\n var startUpdateSceneTime = performance.now();\r\n var uvTime = 0;\r\n var normalTime = 0;\r\n var tangentTime = 0;\r\n var streamTime = 0;\r\n var bboxTime = 0;\r\n\r\n var startBboxTime = performance.now();\r\n const bbox = new three__WEBPACK_IMPORTED_MODULE_1__.Box3().setFromObject(this._scene);\r\n const bsphere = new three__WEBPACK_IMPORTED_MODULE_1__.Sphere();\r\n bbox.getBoundingSphere(bsphere);\r\n bboxTime = performance.now() - startBboxTime;\r\n\r\n let theScene = viewer.getScene();\r\n let flipV = theScene.getFlipGeometryV();\r\n\r\n\r\n this._scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n var startUVTime = performance.now();\r\n if (!child.geometry.attributes.uv)\r\n {\r\n const posCount = child.geometry.attributes.position.count;\r\n const uvs = [];\r\n const pos = child.geometry.attributes.position.array;\r\n\r\n for (let i = 0; i < posCount; i++)\r\n {\r\n uvs.push((pos[i * 3] - bsphere.center.x) / bsphere.radius);\r\n uvs.push((pos[i * 3 + 1] - bsphere.center.y) / bsphere.radius);\r\n }\r\n\r\n child.geometry.setAttribute('uv', new three__WEBPACK_IMPORTED_MODULE_1__.BufferAttribute(new Float32Array(uvs), 2));\r\n }\r\n else if (flipV)\r\n {\r\n const uvCount = child.geometry.attributes.position.count;\r\n const uvs = child.geometry.attributes.uv.array;\r\n for (let i = 0; i < uvCount; i++)\r\n {\r\n let v = 1.0 - (uvs[i * 2 + 1]);\r\n uvs[i * 2 + 1] = v;\r\n }\r\n }\r\n uvTime += performance.now() - startUVTime;\r\n\r\n if (!child.geometry.attributes.normal)\r\n {\r\n var startNormalTime = performance.new();\r\n child.geometry.computeVertexNormals();\r\n normalTime += performance.now() - startNormalTime;\r\n }\r\n\r\n if (child.geometry.getIndex())\r\n {\r\n if (!child.geometry.attributes.tangent)\r\n {\r\n var startTangentTime = performance.now();\r\n child.geometry.computeTangents();\r\n tangentTime += performance.now() - startTangentTime;\r\n }\r\n }\r\n\r\n // Use default MaterialX naming convention.\r\n var startStreamTime = performance.now();\r\n child.geometry.attributes.i_position = child.geometry.attributes.position;\r\n child.geometry.attributes.i_normal = child.geometry.attributes.normal;\r\n child.geometry.attributes.i_tangent = child.geometry.attributes.tangent;\r\n child.geometry.attributes.i_texcoord_0 = child.geometry.attributes.uv;\r\n streamTime += performance.now() - startStreamTime;\r\n }\r\n });\r\n\r\n //console.log(\"- Stream update time: \", performance.now() - startUpdateSceneTime, \"ms\");\r\n if (logDetailedTime)\r\n {\r\n console.log(' - UV time: ', uvTime);\r\n console.log(' - Normal time: ', normalTime);\r\n console.log(' - Tangent time: ', tangentTime);\r\n console.log(' - Stream Update time: ', streamTime);\r\n console.log(' - Bounds compute time: ', bboxTime);\r\n }\r\n\r\n // Update the background\r\n this._scene.background = this.getBackground();\r\n\r\n //console.log('bounding sphere:', bsphere.center, bsphere.radius);\r\n\r\n // Fit camera to model\r\n const camera = this.getCamera();\r\n camera.position.y = bsphere.center.y;\r\n camera.position.z = bsphere.radius * 2.0;\r\n camera.updateProjectionMatrix();\r\n\r\n orbitControls.target = bsphere.center;\r\n orbitControls.update();\r\n }\r\n\r\n setUpdateTransforms(val=true)\r\n {\r\n this.#_updateTransforms = val;\r\n }\r\n\r\n getUpdateTransforms()\r\n {\r\n return this.#_updateTransforms;\r\n }\r\n\r\n updateTransforms()\r\n {\r\n // Only update on demand versus continuously.\r\n // Call setUpdateTransforms() to trigger an update here.\r\n // Required for: scene geometry, camera change and viewport resize. \r\n if (!this.#_updateTransforms)\r\n {\r\n return;\r\n }\r\n this.setUpdateTransforms(false);\r\n\r\n const scene = this.getScene();\r\n const camera = this.getCamera();\r\n scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n const uniforms = child.material.uniforms;\r\n if (uniforms)\r\n {\r\n uniforms.u_worldMatrix.value = child.matrixWorld;\r\n uniforms.u_viewProjectionMatrix.value = this.#_viewProjMat.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);\r\n\r\n if (uniforms.u_viewPosition)\r\n uniforms.u_viewPosition.value = camera.getWorldPosition(this.#_worldViewPos);\r\n\r\n if (uniforms.u_worldInverseTransposeMatrix)\r\n uniforms.u_worldInverseTransposeMatrix.value =\r\n new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4().setFromMatrix3(this.#_normalMat.getNormalMatrix(child.matrixWorld));\r\n }\r\n }\r\n });\r\n }\r\n\r\n // Determine string DAG path based on individual node names.\r\n getDagPath(node)\r\n {\r\n const rootNode = this.#_rootNode;\r\n\r\n let path = [node.name];\r\n while (node.parent)\r\n {\r\n node = node.parent;\r\n if (node)\r\n {\r\n // Stop at the root of the scene read in.\r\n if (node == rootNode)\r\n {\r\n break;\r\n }\r\n path.unshift(node.name);\r\n }\r\n }\r\n return path;\r\n }\r\n\r\n // Assign material shader to associated geometry\r\n updateMaterial(matassign)\r\n {\r\n let assigned = 0;\r\n\r\n const shader = matassign.getShader();\r\n const material = matassign.getMaterial().getName();\r\n const geometry = matassign.getGeometry();\r\n const collection = matassign.getCollection();\r\n\r\n const scene = this.getScene();\r\n const camera = this.getCamera();\r\n scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n const dagPath = this.getDagPath(child).join('/');\r\n\r\n // Note that this is a very simplistic\r\n // assignment resolve and assumes basic\r\n // regular expression name match.\r\n let matches = (geometry == ALL_GEOMETRY_SPECIFIER);\r\n if (!matches)\r\n {\r\n if (collection)\r\n {\r\n if (collection.matchesGeomString(dagPath))\r\n {\r\n matches = true;\r\n }\r\n }\r\n else\r\n {\r\n if (geometry != NO_GEOMETRY_SPECIFIER)\r\n {\r\n const paths = geometry.split(',');\r\n for (let path of paths)\r\n {\r\n if (dagPath.match(path))\r\n {\r\n matches = true;\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n if (matches)\r\n {\r\n child.material = shader;\r\n assigned++;\r\n }\r\n }\r\n });\r\n\r\n return assigned;\r\n }\r\n\r\n updateCamera()\r\n {\r\n const camera = this.getCamera();\r\n let container = document.getElementById('canvasContainer');\r\n var maxWidth = 4086;\r\n var maxHeight = 1024;\r\n var width = Math.min(container.clientWidth, maxWidth);\r\n var height = Math.min(container.clientHeight, maxHeight); \r\n\r\n camera.aspect = width / height;\r\n camera.updateProjectionMatrix();\r\n }\r\n\r\n getScene()\r\n {\r\n return this._scene;\r\n }\r\n\r\n getCamera()\r\n {\r\n return this._camera;\r\n }\r\n\r\n getGeometryURL()\r\n {\r\n return this._geometryURL;\r\n }\r\n\r\n setGeometryURL(url)\r\n {\r\n this._geometryURL = url;\r\n }\r\n\r\n setBackgroundTexture(texture)\r\n {\r\n this.#_backgroundTexture = texture;\r\n }\r\n\r\n getShowBackgroundTexture()\r\n {\r\n return this.#_showBackgroundTexture;\r\n }\r\n\r\n setShowBackgroundTexture(enable)\r\n {\r\n this.#_showBackgroundTexture = enable;\r\n }\r\n\r\n getBackground()\r\n {\r\n if (this.#_backgroundTexture && this.#_showBackgroundTexture)\r\n {\r\n return this.#_backgroundTexture;\r\n }\r\n var color = new three__WEBPACK_IMPORTED_MODULE_1__.Color(this.#_backgroundColor);\r\n color.convertSRGBToLinear();\r\n return color;\r\n }\r\n\r\n toggleBackgroundTexture()\r\n {\r\n this.#_showBackgroundTexture = !this.#_showBackgroundTexture;\r\n this._scene.background = this.getBackground();\r\n }\r\n\r\n // Geometry file\r\n #_geometryURL = '';\r\n // Geometry loaders\r\n #_gltfLoader = null;\r\n #_objLoader = null;\r\n // Flip V coordinate of texture coordinates.\r\n // Set to true to be consistent with desktop viewer.\r\n #_flipV = true;\r\n\r\n // Scene\r\n #_scene = null;\r\n\r\n // Camera\r\n #_camera = null;\r\n\r\n // Background color\r\n #_backgroundColor = 0x777777;\r\n\r\n // Background texture\r\n #_backgroundTexture = null;\r\n #_showBackgroundTexture = false;\r\n\r\n // Transform matrices\r\n #_normalMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix3();\r\n #_viewProjMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4();\r\n #_worldViewPos = new three__WEBPACK_IMPORTED_MODULE_1__.Vector3();\r\n #_updateTransforms = true;\r\n\r\n // Root node of imported scene\r\n #_rootNode = null;\r\n}\r\n\r\n/* \r\n Property editor\r\n*/\r\nclass Editor\r\n{\r\n // Initialize the editor, clearing any elements from previous materials.\r\n initialize()\r\n {\r\n Array.from(document.getElementsByClassName('lil-gui')).forEach(\r\n function (element, index, array)\r\n {\r\n if (element.className)\r\n {\r\n element.remove();\r\n }\r\n }\r\n );\r\n\r\n let parent = document.getElementById( 'webglcanvas' );\r\n //console.log('parent:', parent);\r\n this._gui = new lil_gui__WEBPACK_IMPORTED_MODULE_4__[\"default\"]( { title: \"Properties\" }, { container: parent } );\r\n //parent = this._gui.domElement;\r\n //console.log('gui parent:', parent);\r\n // Parent parent under webglcanvas\r\n //document.getElementById( 'webglcanvas' ).appendChild( parent );\r\n\r\n //this._gui = new GUI({ title: \"Property Editor\" });\r\n this._gui.close();\r\n this._gui.hide();\r\n }\r\n\r\n // Update ui properties\r\n // - Hide close button\r\n // - Update transparency so scene shows through if overlapping\r\n updateProperties(targetOpacity = 1)\r\n {\r\n // Set opacity\r\n Array.from(document.getElementsByClassName('dg')).forEach(\r\n function (element, index, array)\r\n {\r\n element.style.opacity = targetOpacity;\r\n }\r\n );\r\n }\r\n\r\n getGUI()\r\n {\r\n return this._gui;\r\n }\r\n\r\n _gui = null;\r\n}\r\n\r\nclass MaterialAssign\r\n{\r\n constructor(material, geometry, collection)\r\n {\r\n this._material = material;\r\n this._geometry = geometry;\r\n this._collection = collection;\r\n this._shader = null;\r\n this._materialUI = null;\r\n }\r\n\r\n setMaterialUI(value)\r\n {\r\n this._materialUI = value;\r\n }\r\n\r\n getMaterialUI()\r\n {\r\n return this._materialUI;\r\n }\r\n\r\n setShader(shader)\r\n {\r\n this._shader = shader;\r\n }\r\n\r\n getShader()\r\n {\r\n return this._shader;\r\n }\r\n\r\n getMaterial()\r\n {\r\n return this._material;\r\n }\r\n\r\n getGeometry()\r\n {\r\n return this._geometry;\r\n }\r\n\r\n setGeometry(value)\r\n {\r\n this._geometry = value;\r\n }\r\n\r\n getCollection()\r\n {\r\n return this._collection;\r\n }\r\n\r\n // MaterialX material node name\r\n _material;\r\n\r\n // MaterialX assignment geometry string\r\n _geometry;\r\n\r\n // MaterialX assignment collection\r\n _collection;\r\n\r\n // THREE.JS shader\r\n _shader;\r\n}\r\n\r\nclass Material\r\n{\r\n constructor()\r\n {\r\n this._materials = [];\r\n this._defaultMaterial = null;\r\n this._soloMaterial = \"\";\r\n this._shaderInterfaceType = 0;\r\n }\r\n\r\n clearMaterials()\r\n {\r\n this._materials.length = 0;\r\n this._defaultMaterial = null;\r\n this._soloMaterial = \"\";\r\n }\r\n\r\n setSoloMaterial(value)\r\n {\r\n this._soloMaterial = value;\r\n }\r\n\r\n getSoloMaterial()\r\n {\r\n return this._soloMaterial;\r\n }\r\n\r\n // Create a fallback material\r\n static createFallbackMaterial(doc)\r\n {\r\n let ssNode = doc.getChild('Generated_Default_Shader');\r\n if (ssNode)\r\n {\r\n return ssNode;\r\n }\r\n const ssName = 'Generated_Default_Shader';\r\n ssNode = doc.addChildOfCategory('surface_unlit', ssName);\r\n ssNode.setType('surfaceshader');\r\n const smNode = doc.addChildOfCategory('surfacematerial', 'Default');\r\n smNode.setType('material'); \r\n const shaderElement = smNode.addInput('surfaceshader');\r\n shaderElement.setType('surfaceshader');\r\n shaderElement.setNodeName(ssName);\r\n\r\n return ssNode;\r\n }\r\n\r\n async loadMaterialFile(loader, materialFilename)\r\n {\r\n return new Promise((resolve, reject) =>\r\n {\r\n loader.load(materialFilename, data => resolve(data), null, reject);\r\n });\r\n }\r\n\r\n async loadMaterials(viewer, materialFilename)\r\n {\r\n const fileloader = viewer.getFileLoader();\r\n\r\n let mtlxMaterial = await viewer.getMaterial().loadMaterialFile(fileloader, materialFilename);\r\n\r\n this.loadMaterialFromString(viewer, mtlxMaterial, materialFilename);\r\n }\r\n\r\n async loadMaterialFromString(viewer, mtlxMaterial, materialFilename)\r\n {\r\n var startTime = performance.now();\r\n\r\n const mx = viewer.getMx();\r\n\r\n // Re-initialize document\r\n var startDocTime = performance.now();\r\n var doc = mx.createDocument();\r\n doc.importLibrary(viewer.getLibrary());\r\n if (!doc.validate())\r\n {\r\n console.log(\"MaterialX document validation failed.\");\r\n return;\r\n }\r\n\r\n viewer.setDocument(doc);\r\n\r\n // Load lighting setup into document\r\n doc.importLibrary(viewer.getLightRig());\r\n\r\n //console.log(\"- Material document load time: \", performance.now() - startDocTime, \"ms.\");\r\n\r\n // Set search path. Assumes images are relative to current file\r\n // location.\r\n if (!materialFilename) materialFilename = \"/\";\r\n const paths = materialFilename.split('/');\r\n paths.pop();\r\n const searchPath = '/javascript/shader_editor/dist';\r\n console.log('> Global search path = ', searchPath);\r\n\r\n // Load material\r\n if (mtlxMaterial)\r\n try { \r\n await mx.readFromXmlString(doc, mtlxMaterial, searchPath);\r\n }\r\n catch (error) {\r\n console.log('Error loading material file: ', error);\r\n }\r\n else\r\n Material.createFallbackMaterial(doc);\r\n\r\n // Check if there are any looks defined in the document\r\n // If so then traverse the looks for all material assignments.\r\n // Generate code and compile for any associated surface shader\r\n // and assign to the associated geometry. If there are no looks\r\n // then the first material is found and assignment to all the\r\n // geometry.\r\n this.clearMaterials();\r\n var looks = doc.getLooks();\r\n if (looks.length)\r\n {\r\n for (let look of looks)\r\n {\r\n const materialAssigns = look.getMaterialAssigns();\r\n for (let materialAssign of materialAssigns)\r\n {\r\n let matName = materialAssign.getMaterial();\r\n if (matName)\r\n {\r\n let mat = doc.getChild(matName);\r\n var shader;\r\n if (mat)\r\n {\r\n var shaders = mx.getShaderNodes(mat);\r\n if (shaders.length)\r\n {\r\n shader = shaders[0];\r\n }\r\n }\r\n let collection = materialAssign.getCollection();\r\n let geom = materialAssign.getGeom();\r\n let newAssignment;\r\n if (collection || geom)\r\n {\r\n // Remove leading \"/\" from collection and geom for \r\n // later assignment comparison checking\r\n if (collection && collection.charAt(0) == \"/\")\r\n {\r\n collection = collection.slice(1);\r\n }\r\n if (geom && geom.charAt(0) == \"/\")\r\n {\r\n geom = geom.slice(1);\r\n }\r\n newAssignment = new MaterialAssign(shader, geom, collection);\r\n }\r\n else\r\n {\r\n newAssignment = new MaterialAssign(shader, NO_GEOMETRY_SPECIFIER, null);\r\n }\r\n\r\n if (newAssignment)\r\n {\r\n this._materials.push(newAssignment);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n else\r\n {\r\n // Search for any surface shaders. The first found\r\n // is assumed to be assigned to the entire scene\r\n // The identifier used is \"*\" to mean the entire scene. \r\n const materialNodes = doc.getMaterialNodes();\r\n let shaderList = [];\r\n let foundRenderable = false;\r\n for (let i = 0; i < materialNodes.length; ++i)\r\n {\r\n let materialNode = materialNodes[i];\r\n if (materialNode)\r\n {\r\n //console.log('Scan material: ', materialNode.getNamePath());\r\n let shaderNodes = mx.getShaderNodes(materialNode)\r\n if (shaderNodes.length > 0)\r\n {\r\n let shaderNodePath = shaderNodes[0].getNamePath()\r\n if (!shaderList.includes(shaderNodePath))\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n //console.log('-- add shader: ', shaderNodePath);\r\n shaderList.push(shaderNodePath);\r\n this._materials.push(new MaterialAssign(shaderNodes[0], assignment));\r\n }\r\n }\r\n }\r\n }\r\n const nodeGraphs = doc.getNodeGraphs();\r\n for (let i = 0; i < nodeGraphs.length; ++i)\r\n {\r\n let nodeGraph = nodeGraphs[i];\r\n if (nodeGraph)\r\n {\r\n if (nodeGraph.hasAttribute('nodedef') || nodeGraph.hasSourceUri())\r\n {\r\n continue;\r\n }\r\n // Skip any nodegraph that is connected to something downstream\r\n if (nodeGraph.getDownstreamPorts().length > 0)\r\n {\r\n continue\r\n }\r\n let outputs = nodeGraph.getOutputs();\r\n for (let j = 0; j < outputs.length; ++j)\r\n {\r\n let output = outputs[j];\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n let newMat = new MaterialAssign(output, assignment, null);\r\n this._materials.push(newMat);\r\n }\r\n }\r\n }\r\n }\r\n const outputs = doc.getOutputs();\r\n for (let i = 0; i < outputs.length; ++i)\r\n {\r\n let output = outputs[i];\r\n if (output)\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n this._materials.push(new MaterialAssign(output, assignment));\r\n }\r\n }\r\n\r\n const shaderNodes = [];\r\n for (let i = 0; i < shaderNodes.length; ++i)\r\n {\r\n let shaderNode = shaderNodes[i];\r\n let shaderNodePath = shaderNode.getNamePath()\r\n if (!shaderList.includes(shaderNodePath))\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n shaderList.push(shaderNodePath);\r\n this._materials.push(new MaterialAssign(shaderNode, assignment));\r\n }\r\n }\r\n }\r\n\r\n // Assign to default material if none found\r\n if (this._materials.length == 0)\r\n {\r\n const defaultNode = Material.createFallbackMaterial(doc);\r\n this._materials.push(new MaterialAssign(defaultNode, ALL_GEOMETRY_SPECIFIER));\r\n }\r\n\r\n // Create a new shader for each material node.\r\n // Only create the shader once even if assigned more than once.\r\n var startGenTime = performance.now();\r\n let shaderMap = new Map();\r\n let closeUI = false;\r\n for (let matassign of this._materials)\r\n {\r\n // Need to use path vs name to get a unique key.\r\n let materialName = matassign.getMaterial().getNamePath();\r\n let shader = shaderMap[materialName];\r\n if (!shader)\r\n {\r\n shader = viewer.getMaterial().generateMaterial(matassign, viewer, searchPath, closeUI);\r\n shaderMap[materialName] = shader;\r\n }\r\n matassign.setShader(shader);\r\n closeUI = true;\r\n }\r\n console.log(\"- Generate (\", this._materials.length, \") shader(s) time: \", performance.now() - startGenTime, \" ms.\",);\r\n\r\n // Update scene shader assignments\r\n this.updateMaterialAssignments(viewer, this._soloMaterial);\r\n\r\n // Mark transform update\r\n viewer.getScene().setUpdateTransforms(true);\r\n\r\n //console.log(\"Total material time: \", (performance.now() - startTime), \"ms\");\r\n }\r\n\r\n //\r\n // Update the assignments for scene objects based on the\r\n // material assignment information stored in the viewer.\r\n // Note: If none of the MaterialX assignments match the geometry\r\n // in the scene, then the first material assignment shader is assigned\r\n // to the entire scene.\r\n //\r\n async updateMaterialAssignments(viewer, soloMaterial)\r\n {\r\n console.log(\"Update material assignments. Solo=\", soloMaterial?soloMaterial:\"\");\r\n var startTime = performance.now();\r\n\r\n let assigned = 0;\r\n let assignedSolo = false;\r\n for (let matassign of this._materials)\r\n {\r\n if (matassign.getShader())\r\n {\r\n if (soloMaterial.length)\r\n {\r\n if (matassign.getMaterial().getNamePath() == soloMaterial)\r\n {\r\n let temp = matassign.getGeometry();\r\n matassign.setGeometry(ALL_GEOMETRY_SPECIFIER);\r\n assigned += viewer.getScene().updateMaterial(matassign);\r\n matassign.setGeometry(temp);\r\n assignedSolo = true;\r\n break\r\n }\r\n }\r\n else\r\n {\r\n assigned += viewer.getScene().updateMaterial(matassign);\r\n }\r\n }\r\n }\r\n if (assigned == 0 && this._materials.length)\r\n {\r\n this._defaultMaterial = new MaterialAssign(this._materials[0].getMaterial(), ALL_GEOMETRY_SPECIFIER);\r\n this._defaultMaterial.setShader(this._materials[0].getShader());\r\n viewer.getScene().updateMaterial(this._defaultMaterial);\r\n }\r\n\r\n //if (assigned > 0)\r\n //{\r\n // console.log('Material assignment time: ', performance.now() - startTime, \" ms.\");\r\n //}\r\n }\r\n\r\n // \r\n // Generate a new material for a given element\r\n //\r\n generateMaterial(matassign, viewer, searchPath, closeUI)\r\n {\r\n var elem = matassign.getMaterial();\r\n\r\n var startGenerateMat = performance.now();\r\n\r\n const mx = viewer.getMx();\r\n const textureLoader = new three__WEBPACK_IMPORTED_MODULE_1__.TextureLoader();\r\n\r\n const lights = viewer.getLights();\r\n const lightData = viewer.getLightData();\r\n const radianceTexture = viewer.getRadianceTexture();\r\n const irradianceTexture = viewer.getIrradianceTexture();\r\n const gen = viewer.getGenerator();\r\n const genContext = viewer.getGenContext();\r\n\r\n // Perform transparency check on renderable item\r\n var startTranspCheckTime = performance.now();\r\n const isTransparent = mx.isTransparentSurface(elem, gen.getTarget());\r\n genContext.getOptions().hwTransparency = isTransparent;\r\n // Always set to complete. \r\n // Can consider option to set to reduced as the parsing of large numbers of uniforms (e.g. on shading models)\r\n // can be quite expensive.\r\n //if (this._shaderInterfaceType == 0)\r\n // genContext.getOptions().shaderInterfaceType = mx.ShaderInterfaceType.SHADER_INTERFACE_REDUCED;\r\n //else\r\n genContext.getOptions().shaderInterfaceType = mx.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE;\r\n\r\n if (logDetailedTime)\r\n console.log(\" - Transparency check time: \", performance.now() - startTranspCheckTime, \"ms\");\r\n\r\n // Generate GLES code\r\n var startMTLXGenTime = performance.now();\r\n let shader = gen.generate(elem.getNamePath(), elem, genContext);\r\n if (logDetailedTime)\r\n console.log(\" - MaterialX gen time: \", performance.now() - startMTLXGenTime, \"ms\");\r\n\r\n var startUniformUpdate = performance.now();\r\n\r\n // Get shaders and uniform values\r\n let vShader = shader.getSourceCode(\"vertex\");\r\n let fShader = shader.getSourceCode(\"pixel\");\r\n\r\n let theScene = viewer.getScene();\r\n let flipV = theScene.getFlipGeometryV();\r\n let uniforms = {\r\n ...(0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getUniformValues)(shader.getStage('vertex'), textureLoader, searchPath, flipV),\r\n ...(0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getUniformValues)(shader.getStage('pixel'), textureLoader, searchPath, flipV),\r\n }\r\n\r\n Object.assign(uniforms, {\r\n u_numActiveLightSources: { value: lights.length}, //value: lights.length },\r\n u_lightData: { value: lightData },\r\n u_envMatrix: { value: (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getLightRotation)() },\r\n u_envRadiance: { value: radianceTexture },\r\n u_envRadianceMips: { value: Math.trunc(Math.log2(Math.max(radianceTexture.image.width, radianceTexture.image.height))) + 1 },\r\n u_envRadianceSamples: { value: 2 },\r\n u_envIrradiance: { value: irradianceTexture },\r\n u_refractionEnv: { value: false }\r\n });\r\n\r\n // Create Three JS Material\r\n let newMaterial = new three__WEBPACK_IMPORTED_MODULE_1__.RawShaderMaterial({\r\n uniforms: uniforms,\r\n vertexShader: vShader,\r\n fragmentShader: fShader,\r\n transparent: isTransparent,\r\n blendEquation: three__WEBPACK_IMPORTED_MODULE_1__.AddEquation,\r\n blendSrc: three__WEBPACK_IMPORTED_MODULE_1__.OneMinusSrcAlphaFactor,\r\n blendDst: three__WEBPACK_IMPORTED_MODULE_1__.SrcAlphaFactor,\r\n side: three__WEBPACK_IMPORTED_MODULE_1__.DoubleSide\r\n });\r\n\r\n console.log('new material:', newMaterial);\r\n\r\n if (logDetailedTime)\r\n console.log(\" - Three material update time: \", performance.now() - startUniformUpdate, \"ms\");\r\n\r\n // Update property editor\r\n //const gui = viewer.getEditor().getGUI();\r\n //this.updateEditor(matassign, shader, newMaterial, gui, closeUI, viewer);\r\n\r\n if (logDetailedTime)\r\n console.log(\"- Per material generate time: \", performance.now() - startGenerateMat, \"ms\");\r\n\r\n return newMaterial;\r\n }\r\n\r\n clearSoloMaterialUI()\r\n {\r\n for (let i = 0; i < this._materials.length; ++i)\r\n {\r\n let matassign = this._materials[i];\r\n let matUI = matassign.getMaterialUI();\r\n if (matUI)\r\n {\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n matTitle.classList.remove('peditor_material_assigned');\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n img.src = 'public/shader_ball.svg';\r\n //matTitle.classList.remove('peditor_material_unassigned');\r\n }\r\n }\r\n }\r\n\r\n static updateSoloMaterial(viewer, elemPath, materials, event)\r\n {\r\n // Prevent the event from being passed to parent folder\r\n event.stopPropagation();\r\n\r\n for (let i = 0; i < materials.length; ++i)\r\n {\r\n let matassign = materials[i];\r\n // Need to use path vs name to get a unique key.\r\n let materialName = matassign.getMaterial().getNamePath();\r\n var matUI = matassign.getMaterialUI();\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n if (materialName == elemPath)\r\n {\r\n if (this._soloMaterial == elemPath)\r\n {\r\n img.src = 'public/shader_ball.svg';\r\n matTitle.classList.remove('peditor_material_assigned');\r\n this._soloMaterial = \"\";\r\n }\r\n else\r\n {\r\n img.src = 'public/shader_ball2.svg';\r\n matTitle.classList.add('peditor_material_assigned');\r\n this._soloMaterial = elemPath;\r\n }\r\n }\r\n else\r\n {\r\n img.src = 'public/shader_ball.svg';\r\n matTitle.classList.remove('peditor_material_assigned');\r\n }\r\n }\r\n viewer.getMaterial().updateMaterialAssignments(viewer, \"\");\r\n viewer.getScene().setUpdateTransforms();\r\n }\r\n\r\n //\r\n // Update property editor for a given MaterialX element, it's shader, and\r\n // Three material\r\n //\r\n updateEditor(matassign, shader, material, gui, closeUI, viewer)\r\n {\r\n var elem = matassign.getMaterial();\r\n var materials = this._materials;\r\n\r\n const DEFAULT_MIN = 0;\r\n const DEFAULT_MAX = 100;\r\n\r\n var startTime = performance.now();\r\n\r\n const elemPath = elem.getNamePath();\r\n\r\n // Create and cache associated UI\r\n var matUI = gui.addFolder(elemPath);\r\n matassign.setMaterialUI(matUI);\r\n\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n // Add a icon to the title to allow for assigning the material to geometry\r\n // Clicking on the icon will \"solo\" the material to the geometry.\r\n // Clicking on the title will open/close the material folder.\r\n matTitle.innerHTML = \" \" + elem.getNamePath();\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n if (img)\r\n {\r\n // Add event listener to icon to call updateSoloMaterial function\r\n img.addEventListener('click', function (event)\r\n {\r\n Material.updateSoloMaterial(viewer, elemPath, materials, event);\r\n });\r\n }\r\n\r\n if (closeUI)\r\n {\r\n matUI.close();\r\n }\r\n const uniformBlocks = Object.values(shader.getStage('pixel').getUniformBlocks());\r\n var uniformToUpdate;\r\n const ignoreList = ['u_envRadianceMips', 'u_envRadianceSamples', 'u_alphaThreshold'];\r\n\r\n var folderList = new Map();\r\n folderList[elemPath] = matUI;\r\n\r\n uniformBlocks.forEach(uniforms =>\r\n {\r\n if (!uniforms.empty())\r\n {\r\n for (let i = 0; i < uniforms.size(); ++i)\r\n {\r\n const variable = uniforms.get(i);\r\n const value = variable.getValue()?.getData();\r\n let name = variable.getVariable();\r\n\r\n if (ignoreList.includes(name))\r\n {\r\n continue;\r\n }\r\n\r\n let currentFolder = matUI;\r\n let currentElemPath = variable.getPath();\r\n if (!currentElemPath || currentElemPath.length == 0)\r\n {\r\n continue;\r\n }\r\n let currentElem = elem.getDocument().getDescendant(currentElemPath);\r\n if (!currentElem)\r\n {\r\n continue;\r\n }\r\n\r\n let currentNode = null;\r\n if (currentElem.getParent() && currentElem.getParent().getNamePath() != \"\")\r\n {\r\n currentNode = currentElem.getParent();\r\n }\r\n let uiname = \"\";\r\n let nodeDefInput = null;\r\n if (currentNode)\r\n {\r\n\r\n let currentNodePath = currentNode.getNamePath();\r\n var pathSplit = currentNodePath.split('/');\r\n if (pathSplit.length)\r\n {\r\n currentNodePath = pathSplit[0];\r\n }\r\n currentFolder = folderList[currentNodePath];\r\n if (!currentFolder)\r\n {\r\n currentFolder = matUI.addFolder(currentNodePath);\r\n folderList[currentNodePath] = currentFolder;\r\n }\r\n\r\n // Check for ui attributes\r\n var nodeDef = currentNode.getNodeDef();\r\n if (nodeDef)\r\n {\r\n // Remove node name from shader uniform name for non root nodes\r\n let lookup_name = name.replace(currentNode.getName() + '_', '');\r\n nodeDefInput = nodeDef.getActiveInput(lookup_name);\r\n if (nodeDefInput)\r\n {\r\n uiname = nodeDefInput.getAttribute('uiname');\r\n let uifolderName = nodeDefInput.getAttribute('uifolder');\r\n if (uifolderName && uifolderName.length)\r\n {\r\n let newFolderName = currentNodePath + '/' + uifolderName;\r\n currentFolder = folderList[newFolderName];\r\n if (!currentFolder)\r\n {\r\n currentFolder = matUI.addFolder(uifolderName);\r\n currentFolder.domElement.classList.add('peditorfolder');\r\n folderList[newFolderName] = currentFolder;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Determine UI name to use\r\n let path = name;\r\n let interfaceName = currentElem.getAttribute(\"interfacename\");\r\n if (interfaceName && interfaceName.length)\r\n {\r\n const graph = currentNode.getParent();\r\n if (graph)\r\n {\r\n const graphInput = graph.getInput(interfaceName);\r\n if (graphInput)\r\n {\r\n let uiname = graphInput.getAttribute('uiname');\r\n if (uiname.length)\r\n {\r\n path = uiname;\r\n }\r\n else\r\n {\r\n path = graphInput.getName();\r\n }\r\n }\r\n }\r\n else\r\n {\r\n path = interfaceName;\r\n }\r\n }\r\n else\r\n {\r\n if (!uiname)\r\n {\r\n uiname = currentElem.getAttribute('uiname');\r\n }\r\n if (uiname && uiname.length)\r\n {\r\n path = uiname;\r\n }\r\n }\r\n\r\n switch (variable.getType().getName())\r\n {\r\n case 'float':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = DEFAULT_MIN;\r\n if (value < minValue)\r\n {\r\n minValue = value;\r\n }\r\n var maxValue = DEFAULT_MAX;\r\n if (value > maxValue)\r\n {\r\n maxValue = value;\r\n }\r\n var step = 0;\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = parseFloat(nodeDefInput.getAttribute('uisoftmin'));\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = parseFloat(nodeDefInput.getAttribute('uimin'));\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = parseFloat(nodeDefInput.getAttribute('uisoftmax'));\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = parseFloat(nodeDefInput.getAttribute('uimax'));\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = parseFloat(nodeDefInput.getAttribute('uistep'));\r\n }\r\n if (step == 0)\r\n {\r\n step = (maxValue - minValue) / 1000.0;\r\n }\r\n const w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'integer':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = DEFAULT_MIN;\r\n if (value < minValue)\r\n {\r\n minValue = value;\r\n }\r\n var maxValue = DEFAULT_MAX;\r\n if (value > maxValue)\r\n {\r\n maxValue = value;\r\n }\r\n var step = 0;\r\n var enumList = []\r\n var enumValues = []\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('enum'))\r\n {\r\n // Get enum and enum values attributes (if present)\r\n enumList = nodeDefInput.getAttribute('enum').split(',');\r\n if (nodeDefInput.hasAttribute('enumvalues'))\r\n {\r\n enumValues = nodeDefInput.getAttribute('enumvalues').split(',').map(Number);\r\n }\r\n }\r\n else\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = parseInt(nodeDefInput.getAttribute('uisoftmin'));\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = parseInt(nodeDefInput.getAttribute('uimin'));\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = parseInt(nodeDefInput.getAttribute('uisoftmax'));\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = parseInt(nodeDefInput.getAttribute('uimax'));\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = parseInt(nodeDefInput.getAttribute('uistep'));\r\n }\r\n }\r\n if (enumList.length == 0)\r\n {\r\n if (step == 0)\r\n {\r\n step = 1 / (maxValue - minValue);\r\n step = Math.ceil(step);\r\n if (step == 0)\r\n {\r\n step = 1;\r\n }\r\n }\r\n }\r\n if (enumList.length == 0)\r\n {\r\n let w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n else\r\n {\r\n // Map enumList strings to values\r\n // Map to 0..N if no values are specified via enumvalues attribute\r\n if (enumValues.length == 0)\r\n {\r\n for (let i = 0; i < enumList.length; ++i)\r\n {\r\n enumValues.push(i);\r\n }\r\n }\r\n const enumeration = {};\r\n enumList.forEach((str, index) =>\r\n {\r\n enumeration[str] = enumValues[index];\r\n });\r\n\r\n // Function to handle enum drop-down\r\n function handleDropdownChange(value)\r\n {\r\n if (material.uniforms[name])\r\n {\r\n material.uniforms[name].value = value;\r\n }\r\n }\r\n const defaultOption = enumList[value]; // Set the default selected option\r\n const dropdownController = currentFolder.add(enumeration, defaultOption, enumeration).name(path);\r\n dropdownController.onChange(handleDropdownChange);\r\n dropdownController.domElement.classList.add('peditoritem');\r\n }\r\n }\r\n break;\r\n\r\n case 'boolean':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n let w = currentFolder.add(material.uniforms[name], 'value').name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'vector2':\r\n case 'vector3':\r\n case 'vector4':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = [DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN];\r\n var maxValue = [DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX];\r\n var step = [0, 0, 0, 0];\r\n\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = nodeDefInput.getAttribute('uisoftmin').split(',').map(Number);\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = nodeDefInput.getAttribute('uimin').split(',').map(Number);\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = nodeDefInput.getAttribute('uisoftmax').split(',').map(Number);\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = nodeDefInput.getAttribute('uimax').split(',').map(Number);\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = nodeDefInput.getAttribute('uistep').split(',').map(Number);\r\n }\r\n for (let i = 0; i < 4; ++i)\r\n {\r\n if (step[i] == 0)\r\n {\r\n step[i] = 1 / (maxValue[i] - minValue[i]);\r\n }\r\n }\r\n\r\n const keyString = [\"x\", \"y\", \"z\", \"w\"];\r\n let vecFolder = currentFolder.addFolder(path);\r\n Object.keys(material.uniforms[name].value).forEach((key) =>\r\n {\r\n let w = vecFolder.add(material.uniforms[name].value,\r\n key, minValue[key], maxValue[key], step[key]).name(keyString[key]);\r\n w.domElement.classList.add('peditoritem');\r\n })\r\n }\r\n break;\r\n\r\n case 'color3':\r\n // Irksome way to map arrays to colors and back\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var dummy =\r\n {\r\n color: 0xFF0000\r\n };\r\n const color3 = new three__WEBPACK_IMPORTED_MODULE_1__.Color(dummy.color);\r\n color3.fromArray(material.uniforms[name].value);\r\n dummy.color = color3.getHex();\r\n let w = currentFolder.addColor(dummy, 'color').name(path)\r\n .onChange(function (value)\r\n {\r\n const color3 = new three__WEBPACK_IMPORTED_MODULE_1__.Color(value);\r\n material.uniforms[name].value.set(color3.toArray());\r\n });\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'color4':\r\n break;\r\n\r\n case 'matrix33':\r\n case 'matrix44':\r\n case 'samplerCube':\r\n case 'filename':\r\n break;\r\n case 'string':\r\n console.log('String: ', name);\r\n if (value != null)\r\n {\r\n var dummy =\r\n {\r\n thevalue: value\r\n }\r\n let item = currentFolder.add(dummy, 'thevalue');\r\n item.name(path);\r\n item.disable(true);\r\n item.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n }\r\n });\r\n\r\n if (logDetailedTime)\r\n {\r\n console.log(\" - Editor update time: \", performance.now() - startTime, \"ms\");\r\n }\r\n }\r\n\r\n // List of material assignments: { MaterialX node, geometry assignment string, and hardware shader }\r\n _materials;\r\n\r\n // Fallback material if nothing was assigned explicitly\r\n _defaultMaterial;\r\n}\r\n\r\n/*\r\n Viewer class\r\n\r\n Keeps track of local scene, and property editor as well as current MaterialX document \r\n and assocaited material, shader and lighting information.\r\n*/\r\nclass Viewer\r\n{\r\n static create()\r\n {\r\n return new Viewer();\r\n }\r\n\r\n constructor()\r\n {\r\n this.scene = new Scene();\r\n this.editor = new Editor();\r\n this.materials.push(new Material());\r\n\r\n this.fileLoader = new three__WEBPACK_IMPORTED_MODULE_1__.FileLoader();\r\n this.hdrLoader = new three_examples_jsm_loaders_RGBELoader_js__WEBPACK_IMPORTED_MODULE_5__.RGBELoader();\r\n }\r\n\r\n //\r\n // Create shader generator, generation context and \"base\" document which\r\n // contains the standard definition libraries and lighting elements.\r\n //\r\n async initialize(mtlxIn, renderer, radianceTexture, irradianceTexture, lightRigXml)\r\n {\r\n this.mx = mtlxIn;\r\n\r\n // Initialize base document\r\n this.generator = new this.mx.EsslShaderGenerator();\r\n this.genContext = new this.mx.GenContext(this.generator);\r\n\r\n this.document = this.mx.createDocument();\r\n this.stdlib = this.mx.loadStandardLibraries(this.genContext);\r\n this.document.importLibrary(this.stdlib);\r\n\r\n this.initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml);\r\n\r\n radianceTexture.mapping = three__WEBPACK_IMPORTED_MODULE_1__.EquirectangularReflectionMapping;\r\n this.getScene().setBackgroundTexture(radianceTexture);\r\n }\r\n\r\n //\r\n // Load in lighting rig document and register lights with generation context\r\n // Initialize environment lighting (IBLs).\r\n //\r\n async initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml)\r\n {\r\n // Load lighting setup into document\r\n const mx = this.getMx();\r\n this.lightRigDoc = mx.createDocument();\r\n await mx.readFromXmlString(this.lightRigDoc, lightRigXml);\r\n this.document.importLibrary(this.lightRigDoc);\r\n\r\n // Register lights with generation context\r\n this.lights = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.findLights)(this.document);\r\n this.lightData = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.registerLights)(mx, this.lights, this.genContext);\r\n\r\n this.radianceTexture = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.prepareEnvTexture)(radianceTexture, renderer.capabilities);\r\n this.irradianceTexture = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.prepareEnvTexture)(irradianceTexture, renderer.capabilities);\r\n }\r\n\r\n getEditor()\r\n {\r\n return this.editor;\r\n }\r\n\r\n getScene()\r\n {\r\n return this.scene;\r\n }\r\n\r\n getMaterial()\r\n {\r\n return this.materials[0];\r\n }\r\n\r\n getmaterials()\r\n {\r\n return this.materials;\r\n }\r\n\r\n getFileLoader()\r\n {\r\n return this.fileLoader;\r\n }\r\n\r\n getHdrLoader()\r\n {\r\n return this.hdrLoader;\r\n }\r\n\r\n setDocument(doc)\r\n {\r\n this.doc = doc;\r\n }\r\n getDocument()\r\n {\r\n return this.doc;\r\n }\r\n\r\n getLibrary()\r\n {\r\n return this.stdlib;\r\n }\r\n\r\n getLightRig()\r\n {\r\n return this.lightRigDoc;\r\n }\r\n\r\n getMx()\r\n {\r\n return this.mx;\r\n }\r\n\r\n getGenerator()\r\n {\r\n return this.generator;\r\n }\r\n\r\n getGenContext()\r\n {\r\n return this.genContext;\r\n }\r\n\r\n getLights()\r\n {\r\n return this.lights;\r\n }\r\n\r\n getLightData()\r\n {\r\n return this.lightData;\r\n }\r\n\r\n getRadianceTexture()\r\n {\r\n return this.radianceTexture;\r\n }\r\n\r\n getIrradianceTexture()\r\n {\r\n return this.irradianceTexture;\r\n }\r\n\r\n // Three scene and materials. \r\n scene = null;\r\n materials = [];\r\n\r\n // Property editor\r\n editor = null;\r\n\r\n // Utility loaders\r\n fileloader = null;\r\n hdrLoader = null;\r\n\r\n // MaterialX module, current document and support documents.\r\n mx = null;\r\n doc = null;\r\n stdlib = null;\r\n lightRigDoc = null;\r\n\r\n // MaterialX code generator and context\r\n generator = null;\r\n genContext = null;\r\n\r\n // Lighting information\r\n lights = null;\r\n lightData = null;\r\n radianceTexture = null;\r\n irradianceTexture = null;\r\n}\r\n\n\n//# sourceURL=webpack://MaterialX-Shader-Editor/./source/viewer.js?");
/***/ }),
diff --git a/javascript/materialxnode/dist/public/favicon.ico b/javascript/shader_editor/dist/public/favicon.ico
similarity index 100%
rename from javascript/materialxnode/dist/public/favicon.ico
rename to javascript/shader_editor/dist/public/favicon.ico
diff --git a/javascript/materialxnode/dist/public/shader_ball.svg b/javascript/shader_editor/dist/public/shader_ball.svg
similarity index 100%
rename from javascript/materialxnode/dist/public/shader_ball.svg
rename to javascript/shader_editor/dist/public/shader_ball.svg
diff --git a/javascript/materialxnode/dist/public/shader_ball2.svg b/javascript/shader_editor/dist/public/shader_ball2.svg
similarity index 100%
rename from javascript/materialxnode/dist/public/shader_ball2.svg
rename to javascript/shader_editor/dist/public/shader_ball2.svg
diff --git a/javascript/materialxtoy/ui_helpers.js b/javascript/shader_editor/dist/ui_helpers.js
similarity index 100%
rename from javascript/materialxtoy/ui_helpers.js
rename to javascript/shader_editor/dist/ui_helpers.js
diff --git a/javascript/shader_utilities/dist/Geometry/boombox.glb b/javascript/shader_utilities/dist/Geometry/boombox.glb
new file mode 100644
index 00000000..fea64585
Binary files /dev/null and b/javascript/shader_utilities/dist/Geometry/boombox.glb differ
diff --git a/javascript/viewer/dist/Geometry/cloth.glb b/javascript/shader_utilities/dist/Geometry/cloth.glb
similarity index 100%
rename from javascript/viewer/dist/Geometry/cloth.glb
rename to javascript/shader_utilities/dist/Geometry/cloth.glb
diff --git a/javascript/viewer/dist/Geometry/cylinder.glb b/javascript/shader_utilities/dist/Geometry/cylinder.glb
similarity index 100%
rename from javascript/viewer/dist/Geometry/cylinder.glb
rename to javascript/shader_utilities/dist/Geometry/cylinder.glb
diff --git a/javascript/viewer/dist/Geometry/glTF.glb b/javascript/shader_utilities/dist/Geometry/glTF.glb
similarity index 100%
rename from javascript/viewer/dist/Geometry/glTF.glb
rename to javascript/shader_utilities/dist/Geometry/glTF.glb
diff --git a/javascript/viewer/dist/Geometry/plane.glb b/javascript/shader_utilities/dist/Geometry/plane.glb
similarity index 100%
rename from javascript/viewer/dist/Geometry/plane.glb
rename to javascript/shader_utilities/dist/Geometry/plane.glb
diff --git a/javascript/viewer/dist/Geometry/shaderball.glb b/javascript/shader_utilities/dist/Geometry/shaderball.glb
similarity index 100%
rename from javascript/viewer/dist/Geometry/shaderball.glb
rename to javascript/shader_utilities/dist/Geometry/shaderball.glb
diff --git a/javascript/viewer/dist/Geometry/sphere.glb b/javascript/shader_utilities/dist/Geometry/sphere.glb
similarity index 100%
rename from javascript/viewer/dist/Geometry/sphere.glb
rename to javascript/shader_utilities/dist/Geometry/sphere.glb
diff --git a/javascript/viewer/dist/Geometry/teapot.glb b/javascript/shader_utilities/dist/Geometry/teapot.glb
similarity index 100%
rename from javascript/viewer/dist/Geometry/teapot.glb
rename to javascript/shader_utilities/dist/Geometry/teapot.glb
diff --git a/javascript/shader_utilities/dist/Images/boombox/BoomBox_baseColor.png b/javascript/shader_utilities/dist/Images/boombox/BoomBox_baseColor.png
new file mode 100644
index 00000000..992429df
Binary files /dev/null and b/javascript/shader_utilities/dist/Images/boombox/BoomBox_baseColor.png differ
diff --git a/javascript/shader_utilities/dist/Images/boombox/BoomBox_emissive.png b/javascript/shader_utilities/dist/Images/boombox/BoomBox_emissive.png
new file mode 100644
index 00000000..315a4994
Binary files /dev/null and b/javascript/shader_utilities/dist/Images/boombox/BoomBox_emissive.png differ
diff --git a/javascript/shader_utilities/dist/Images/boombox/BoomBox_normal.png b/javascript/shader_utilities/dist/Images/boombox/BoomBox_normal.png
new file mode 100644
index 00000000..19d7afbe
Binary files /dev/null and b/javascript/shader_utilities/dist/Images/boombox/BoomBox_normal.png differ
diff --git a/javascript/shader_utilities/dist/Images/boombox/BoomBox_occlusionRoughnessMetallic.png b/javascript/shader_utilities/dist/Images/boombox/BoomBox_occlusionRoughnessMetallic.png
new file mode 100644
index 00000000..4370d609
Binary files /dev/null and b/javascript/shader_utilities/dist/Images/boombox/BoomBox_occlusionRoughnessMetallic.png differ
diff --git a/javascript/materialxtoy/resources/Images/brass_color.jpg b/javascript/shader_utilities/dist/Images/brass_color.jpg
similarity index 100%
rename from javascript/materialxtoy/resources/Images/brass_color.jpg
rename to javascript/shader_utilities/dist/Images/brass_color.jpg
diff --git a/javascript/materialxtoy/resources/Images/brass_roughness.jpg b/javascript/shader_utilities/dist/Images/brass_roughness.jpg
similarity index 100%
rename from javascript/materialxtoy/resources/Images/brass_roughness.jpg
rename to javascript/shader_utilities/dist/Images/brass_roughness.jpg
diff --git a/javascript/materialxtoy/resources/Images/brick_base_gray.jpg b/javascript/shader_utilities/dist/Images/brick_base_gray.jpg
similarity index 100%
rename from javascript/materialxtoy/resources/Images/brick_base_gray.jpg
rename to javascript/shader_utilities/dist/Images/brick_base_gray.jpg
diff --git a/javascript/materialxtoy/resources/Images/brick_dirt_mask.jpg b/javascript/shader_utilities/dist/Images/brick_dirt_mask.jpg
similarity index 100%
rename from javascript/materialxtoy/resources/Images/brick_dirt_mask.jpg
rename to javascript/shader_utilities/dist/Images/brick_dirt_mask.jpg
diff --git a/javascript/materialxtoy/resources/Images/brick_mask.jpg b/javascript/shader_utilities/dist/Images/brick_mask.jpg
similarity index 100%
rename from javascript/materialxtoy/resources/Images/brick_mask.jpg
rename to javascript/shader_utilities/dist/Images/brick_mask.jpg
diff --git a/javascript/materialxtoy/resources/Images/brick_normal.jpg b/javascript/shader_utilities/dist/Images/brick_normal.jpg
similarity index 100%
rename from javascript/materialxtoy/resources/Images/brick_normal.jpg
rename to javascript/shader_utilities/dist/Images/brick_normal.jpg
diff --git a/javascript/materialxtoy/resources/Images/brick_roughness.jpg b/javascript/shader_utilities/dist/Images/brick_roughness.jpg
similarity index 100%
rename from javascript/materialxtoy/resources/Images/brick_roughness.jpg
rename to javascript/shader_utilities/dist/Images/brick_roughness.jpg
diff --git a/javascript/materialxtoy/resources/Images/brick_variation_mask.jpg b/javascript/shader_utilities/dist/Images/brick_variation_mask.jpg
similarity index 100%
rename from javascript/materialxtoy/resources/Images/brick_variation_mask.jpg
rename to javascript/shader_utilities/dist/Images/brick_variation_mask.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/bishop_black_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/bishop_black_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/bishop_black_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/bishop_black_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/bishop_black_normal.jpg b/javascript/shader_utilities/dist/Images/chess_set/bishop_black_normal.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/bishop_black_normal.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/bishop_black_normal.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/bishop_black_roughness.jpg b/javascript/shader_utilities/dist/Images/chess_set/bishop_black_roughness.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/bishop_black_roughness.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/bishop_black_roughness.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/bishop_shared_metallic.jpg b/javascript/shader_utilities/dist/Images/chess_set/bishop_shared_metallic.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/bishop_shared_metallic.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/bishop_shared_metallic.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/bishop_white_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/bishop_white_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/bishop_white_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/bishop_white_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/bishop_white_normal.jpg b/javascript/shader_utilities/dist/Images/chess_set/bishop_white_normal.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/bishop_white_normal.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/bishop_white_normal.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/bishop_white_roughness.jpg b/javascript/shader_utilities/dist/Images/chess_set/bishop_white_roughness.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/bishop_white_roughness.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/bishop_white_roughness.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/castle_black_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/castle_black_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/castle_black_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/castle_black_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/castle_shared_metallic.jpg b/javascript/shader_utilities/dist/Images/chess_set/castle_shared_metallic.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/castle_shared_metallic.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/castle_shared_metallic.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/castle_shared_normal.jpg b/javascript/shader_utilities/dist/Images/chess_set/castle_shared_normal.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/castle_shared_normal.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/castle_shared_normal.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/castle_shared_roughness.jpg b/javascript/shader_utilities/dist/Images/chess_set/castle_shared_roughness.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/castle_shared_roughness.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/castle_shared_roughness.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/castle_white_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/castle_white_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/castle_white_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/castle_white_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/chessboard_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/chessboard_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/chessboard_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/chessboard_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/chessboard_metallic.jpg b/javascript/shader_utilities/dist/Images/chess_set/chessboard_metallic.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/chessboard_metallic.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/chessboard_metallic.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/chessboard_normal.jpg b/javascript/shader_utilities/dist/Images/chess_set/chessboard_normal.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/chessboard_normal.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/chessboard_normal.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/chessboard_roughness.jpg b/javascript/shader_utilities/dist/Images/chess_set/chessboard_roughness.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/chessboard_roughness.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/chessboard_roughness.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/king_black_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/king_black_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/king_black_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/king_black_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/king_black_normal.jpg b/javascript/shader_utilities/dist/Images/chess_set/king_black_normal.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/king_black_normal.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/king_black_normal.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/king_black_roughness.jpg b/javascript/shader_utilities/dist/Images/chess_set/king_black_roughness.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/king_black_roughness.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/king_black_roughness.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/king_shared_metallic.jpg b/javascript/shader_utilities/dist/Images/chess_set/king_shared_metallic.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/king_shared_metallic.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/king_shared_metallic.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/king_shared_scattering.jpg b/javascript/shader_utilities/dist/Images/chess_set/king_shared_scattering.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/king_shared_scattering.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/king_shared_scattering.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/king_white_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/king_white_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/king_white_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/king_white_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/king_white_normal.jpg b/javascript/shader_utilities/dist/Images/chess_set/king_white_normal.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/king_white_normal.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/king_white_normal.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/king_white_roughness.jpg b/javascript/shader_utilities/dist/Images/chess_set/king_white_roughness.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/king_white_roughness.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/king_white_roughness.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/knight_black_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/knight_black_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/knight_black_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/knight_black_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/knight_black_normal.jpg b/javascript/shader_utilities/dist/Images/chess_set/knight_black_normal.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/knight_black_normal.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/knight_black_normal.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/knight_black_roughness.jpg b/javascript/shader_utilities/dist/Images/chess_set/knight_black_roughness.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/knight_black_roughness.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/knight_black_roughness.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/knight_white_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/knight_white_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/knight_white_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/knight_white_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/knight_white_normal.jpg b/javascript/shader_utilities/dist/Images/chess_set/knight_white_normal.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/knight_white_normal.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/knight_white_normal.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/knight_white_roughness.jpg b/javascript/shader_utilities/dist/Images/chess_set/knight_white_roughness.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/knight_white_roughness.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/knight_white_roughness.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/pawn_black_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/pawn_black_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/pawn_black_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/pawn_black_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_metallic.jpg b/javascript/shader_utilities/dist/Images/chess_set/pawn_shared_metallic.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_metallic.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/pawn_shared_metallic.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_normal.jpg b/javascript/shader_utilities/dist/Images/chess_set/pawn_shared_normal.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_normal.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/pawn_shared_normal.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_roughness.jpg b/javascript/shader_utilities/dist/Images/chess_set/pawn_shared_roughness.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/pawn_shared_roughness.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/pawn_shared_roughness.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/pawn_white_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/pawn_white_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/pawn_white_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/pawn_white_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/queen_black_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/queen_black_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/queen_black_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/queen_black_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/queen_black_normal.jpg b/javascript/shader_utilities/dist/Images/chess_set/queen_black_normal.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/queen_black_normal.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/queen_black_normal.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/queen_black_roughness.jpg b/javascript/shader_utilities/dist/Images/chess_set/queen_black_roughness.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/queen_black_roughness.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/queen_black_roughness.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/queen_shared_metallic.jpg b/javascript/shader_utilities/dist/Images/chess_set/queen_shared_metallic.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/queen_shared_metallic.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/queen_shared_metallic.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/queen_shared_scattering.jpg b/javascript/shader_utilities/dist/Images/chess_set/queen_shared_scattering.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/queen_shared_scattering.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/queen_shared_scattering.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/queen_white_base_color.jpg b/javascript/shader_utilities/dist/Images/chess_set/queen_white_base_color.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/queen_white_base_color.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/queen_white_base_color.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/queen_white_normal.jpg b/javascript/shader_utilities/dist/Images/chess_set/queen_white_normal.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/queen_white_normal.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/queen_white_normal.jpg
diff --git a/resources/Materials/Examples/StandardSurface/chess_set/queen_white_roughness.jpg b/javascript/shader_utilities/dist/Images/chess_set/queen_white_roughness.jpg
similarity index 100%
rename from resources/Materials/Examples/StandardSurface/chess_set/queen_white_roughness.jpg
rename to javascript/shader_utilities/dist/Images/chess_set/queen_white_roughness.jpg
diff --git a/javascript/viewer/dist/Images/clipboard.svg b/javascript/shader_utilities/dist/Images/clipboard.svg
similarity index 100%
rename from javascript/viewer/dist/Images/clipboard.svg
rename to javascript/shader_utilities/dist/Images/clipboard.svg
diff --git a/javascript/viewer/dist/Images/clipboard_white.svg b/javascript/shader_utilities/dist/Images/clipboard_white.svg
similarity index 100%
rename from javascript/viewer/dist/Images/clipboard_white.svg
rename to javascript/shader_utilities/dist/Images/clipboard_white.svg
diff --git a/javascript/materialxtoy/resources/Images/cloth.bmp b/javascript/shader_utilities/dist/Images/cloth.bmp
similarity index 100%
rename from javascript/materialxtoy/resources/Images/cloth.bmp
rename to javascript/shader_utilities/dist/Images/cloth.bmp
diff --git a/javascript/materialxtoy/resources/Images/cloth.gif b/javascript/shader_utilities/dist/Images/cloth.gif
similarity index 100%
rename from javascript/materialxtoy/resources/Images/cloth.gif
rename to javascript/shader_utilities/dist/Images/cloth.gif
diff --git a/javascript/materialxtoy/resources/Images/cloth.jpg b/javascript/shader_utilities/dist/Images/cloth.jpg
similarity index 100%
rename from javascript/materialxtoy/resources/Images/cloth.jpg
rename to javascript/shader_utilities/dist/Images/cloth.jpg
diff --git a/javascript/materialxtoy/resources/Images/cloth.png b/javascript/shader_utilities/dist/Images/cloth.png
similarity index 100%
rename from javascript/materialxtoy/resources/Images/cloth.png
rename to javascript/shader_utilities/dist/Images/cloth.png
diff --git a/javascript/materialxtoy/resources/Images/cloth.tga b/javascript/shader_utilities/dist/Images/cloth.tga
similarity index 100%
rename from javascript/materialxtoy/resources/Images/cloth.tga
rename to javascript/shader_utilities/dist/Images/cloth.tga
diff --git a/javascript/viewer/dist/Images/copy-regular.svg b/javascript/shader_utilities/dist/Images/copy-regular.svg
similarity index 100%
rename from javascript/viewer/dist/Images/copy-regular.svg
rename to javascript/shader_utilities/dist/Images/copy-regular.svg
diff --git a/javascript/materialxtoy/resources/Images/greysphere_calibration.png b/javascript/shader_utilities/dist/Images/greysphere_calibration.png
similarity index 100%
rename from javascript/materialxtoy/resources/Images/greysphere_calibration.png
rename to javascript/shader_utilities/dist/Images/greysphere_calibration.png
diff --git a/javascript/materialxtoy/resources/Images/grid.png b/javascript/shader_utilities/dist/Images/grid.png
similarity index 100%
rename from javascript/materialxtoy/resources/Images/grid.png
rename to javascript/shader_utilities/dist/Images/grid.png
diff --git a/javascript/materialxtoy/resources/Images/mesh_wire_norm.png b/javascript/shader_utilities/dist/Images/mesh_wire_norm.png
similarity index 100%
rename from javascript/materialxtoy/resources/Images/mesh_wire_norm.png
rename to javascript/shader_utilities/dist/Images/mesh_wire_norm.png
diff --git a/javascript/materialxtoy/resources/Images/plain_heightmap.png b/javascript/shader_utilities/dist/Images/plain_heightmap.png
similarity index 100%
rename from javascript/materialxtoy/resources/Images/plain_heightmap.png
rename to javascript/shader_utilities/dist/Images/plain_heightmap.png
diff --git a/javascript/materialxtoy/resources/Images/wood_color.jpg b/javascript/shader_utilities/dist/Images/wood_color.jpg
similarity index 100%
rename from javascript/materialxtoy/resources/Images/wood_color.jpg
rename to javascript/shader_utilities/dist/Images/wood_color.jpg
diff --git a/javascript/materialxtoy/resources/Images/wood_roughness.jpg b/javascript/shader_utilities/dist/Images/wood_roughness.jpg
similarity index 100%
rename from javascript/materialxtoy/resources/Images/wood_roughness.jpg
rename to javascript/shader_utilities/dist/Images/wood_roughness.jpg
diff --git a/javascript/viewer/dist/JsMaterialXCore.js b/javascript/shader_utilities/dist/JsMaterialXCore.js
similarity index 100%
rename from javascript/viewer/dist/JsMaterialXCore.js
rename to javascript/shader_utilities/dist/JsMaterialXCore.js
diff --git a/javascript/viewer/dist/JsMaterialXCore.wasm b/javascript/shader_utilities/dist/JsMaterialXCore.wasm
similarity index 100%
rename from javascript/viewer/dist/JsMaterialXCore.wasm
rename to javascript/shader_utilities/dist/JsMaterialXCore.wasm
diff --git a/javascript/viewer/dist/JsMaterialXGenShader.data b/javascript/shader_utilities/dist/JsMaterialXGenShader.data
similarity index 100%
rename from javascript/viewer/dist/JsMaterialXGenShader.data
rename to javascript/shader_utilities/dist/JsMaterialXGenShader.data
diff --git a/javascript/viewer/dist/JsMaterialXGenShader.js b/javascript/shader_utilities/dist/JsMaterialXGenShader.js
similarity index 100%
rename from javascript/viewer/dist/JsMaterialXGenShader.js
rename to javascript/shader_utilities/dist/JsMaterialXGenShader.js
diff --git a/javascript/viewer/dist/JsMaterialXGenShader.wasm b/javascript/shader_utilities/dist/JsMaterialXGenShader.wasm
similarity index 100%
rename from javascript/viewer/dist/JsMaterialXGenShader.wasm
rename to javascript/shader_utilities/dist/JsMaterialXGenShader.wasm
diff --git a/javascript/shader_utilities/dist/JsMaterialXNodeEditor.js b/javascript/shader_utilities/dist/JsMaterialXNodeEditor.js
new file mode 100644
index 00000000..241f050e
--- /dev/null
+++ b/javascript/shader_utilities/dist/JsMaterialXNodeEditor.js
@@ -0,0 +1,3445 @@
+
+// Globals
+var ne_mx = null;
+var doc = null;
+var stdlib = null;
+var customlibs = [];
+var customDocLibs = [];
+var graph = null;
+var graphcanvas = null;
+
+// Base Class for Graph Handler
+class MxGraphHandler
+{
+ constructor(id, extension)
+ {
+ // Identifier
+ this.id = id;
+ // Extension
+ this.extension = extension;
+ // Editor
+ this.editor = null;
+
+ this.DEFAULT_COLOR_SPACE = 'lin_rec709';
+ this.DEFAULT_UNIT = 'meter';
+ this.activeColorSpace = this.DEFAULT_COLOR_SPACE;
+ this.activeUnit = this.DEFAULT_UNIT;
+ }
+
+ setActiveColorSpace(colorSpace)
+ {
+ if (colorSpace && colorSpace.length > 0)
+ this.activeColorSpace = colorSpace;
+ else
+ this.activeColorSpace = this.DEFAULT_COLOR_SPACE;
+ }
+
+ setActiveUnit(unit)
+ {
+ if (unit && unit.length > 0)
+ this.activeUnit = unit;
+ else
+ this.activeUnit = this.DEFAULT_UNIT;
+ }
+
+ getActiveColorSpace()
+ {
+ return this.activeColorSpace;
+ }
+
+ getActiveUnit()
+ {
+ return this.activeUnit;
+ }
+
+ getExtension()
+ {
+ return this.extension;
+ }
+
+ initialize(editor)
+ {
+ this.editor = editor;
+ }
+
+ createValidName(name)
+ {
+ return name;
+ }
+
+ getDefaultValue(value, _type)
+ {
+ if (_type === 'string' || _type === 'filename') {
+ value = "'" + value + "'";
+ }
+ else if (this.isArray(_type)) {
+ if (value.length == 0) {
+ if (_type === 'color3')
+ value = "[0.0, 0.0, 0.0]";
+ else if (_type === 'color4')
+ value = "[0.0, 0.0, 0.0, 0.0]";
+ else if (_type === 'vector2')
+ value = "[0.0, 0.0]";
+ else if (_type === 'vector3')
+ value = "[0.0, 0.0, 0.0]";
+ else if (_type === 'vector4')
+ value = "[0.0, 0.0, 0.0, 0.0]";
+ else if (_type === 'matrix33')
+ value = "[1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]";
+ else if (_type === 'matrix44')
+ value = "[1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]";
+ }
+ else {
+ value = "[" + value + "]";
+ }
+ }
+ else if (_type === 'integer') {
+ if (value.length == 0) {
+ value = 0;
+ }
+ }
+ else if (_type === 'float') {
+ if (value.length == 0) {
+ value = 0.0;
+ }
+ }
+ else if (_type === 'boolean') {
+ if (value)
+ value = 'true';
+ else
+ value = 'false';
+ }
+
+ if (value.length == 0) {
+ //console.log('No value for input:', _name, 'type:', _type, 'value:', value);=
+ value = "''";
+ }
+ return value;
+ }
+
+ /*
+ getDefaultValueRaw(value, _type) {
+ if (_type === 'integer' || _type === 'float') {
+ if (value.length == 0) {
+ value = 0;
+ }
+ }
+ else if (_type === 'string' || _type === 'filename') {
+ //value = value + "'";
+ }
+ else if (isArray(_type)) {
+ if (value.length == 0) {
+ if (_type === 'color3')
+ value = [0.0, 0.0, 0.0];
+ else if (_type === 'color4')
+ value = [0.0, 0.0, 0.0, 0.0];
+ else if (_type === 'vector2')
+ value = [0.0, 0.0];
+ else if (_type === 'vector3')
+ value = [0.0, 0.0, 0.0];
+ else if (_type === 'vector4')
+ value = [0.0, 0.0, 0.0, 0.0];
+ else if (_type === 'matrix33')
+ value = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0];
+ else if (_type === 'matrix44')
+ value = [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0];
+ }
+ else {
+ value = [value];
+ }
+ }
+
+ if (value.length == 0) {
+ //console.log('No value for input:', _name, 'type:', _type, 'value:', value);
+ value = "";
+ }
+ return value;
+ }
+ */
+};
+
+class MxMaterialXHandler extends MxGraphHandler {
+ constructor(id, extension)
+ {
+ super(id, extension);
+ }
+
+ loadMaterialX() {
+ return new Promise((resolve, reject) => {
+ MaterialX().then((ne_mtlx) => {
+ // Save the MaterialX instance to the global variable
+ ne_mx = ne_mtlx;
+ resolve();
+ }).catch((error) => {
+ reject(error);
+ });
+ });
+ }
+
+ loadDefaultDocument(editor, materialFilename) {
+
+ function loadInitialText(filePath, handler) {
+ try {
+ fetch(filePath)
+ .then(response => response.blob())
+ .then(blob => {
+ const reader = new FileReader();
+ reader.onload = function (e) {
+ console.log('Loaded startup document:', filePath);
+ editor.loadGraphFromString('mtlx', e.target.result, filePath, 80);
+ }
+ reader.readAsText(blob);
+ })
+ } catch (error) {
+ console.error('Error loading file %s:' % filePath, error);
+ }
+ }
+
+ loadInitialText(materialFilename, this);
+ }
+
+ // Initialize the MaterialX handler for the given editor
+ initialize(editor, materialFilename)
+ {
+ super.initialize(editor);
+
+ if (!ne_mx) {
+
+ this.loadMaterialX().then(() => {
+
+ // Additional logic after MaterialX is loaded
+ editor.debugOutput("Loaded MaterialX version:" + ne_mx.getVersionString(), 0, true);
+ doc = ne_mx.createDocument();
+
+ var generator = new ne_mx.EsslShaderGenerator();
+ var genContext = new ne_mx.GenContext(generator);
+ stdlib = ne_mx.loadStandardLibraries(genContext);
+ editor.debugOutput('Loaded standard libraries definitions:' + stdlib.getNodeDefs().length, 0, false);
+
+ var definitionsList = [];
+ var result = this.createLiteGraphDefinitions(stdlib, false, true, definitionsList, 'mtlx', MxShadingGraphEditor.theEditor);
+ var textarea = editor.ui.mtlxlib;
+ if (textarea)
+ {
+ //console.log('set value', result);
+ textarea.setValue(result);
+ }
+
+ editor.clearNodeTypes();
+ try {
+ eval(result);
+ } catch (e) {
+ editor.debugOutput('Error evaluating source: ' + e, 2, false);
+ }
+
+ var nodeTypes = LiteGraph.registered_node_types;
+ var i = 0;
+ for (var typeName in nodeTypes) {
+ i++;
+ }
+ editor.debugOutput("Registered node types:" + definitionsList.length, 0, false);
+
+ editor.displayNodeTypes();
+
+ if (materialFilename.length> 0)
+ {
+ this.loadDefaultDocument(editor, materialFilename);
+ }
+
+ editor.updatePropertyPanel(null);
+
+ }).catch((error) => {
+ editor.debugOutput("Error on initialization:" + error, 2);
+ });
+ }
+ }
+
+ findRenderableItems(graph) {
+
+ let mdoc = this.saveGraphToDocument(graph, false, false);
+ if (!mdoc) {
+ console.log('Failed to save graph to document');
+ return;
+ }
+ return this.findRenderableItemsInDoc(mdoc);
+ }
+
+ findRenderableItemsInDoc(mdoc) {
+
+ const materialNodes = mdoc.getMaterialNodes();
+ let shaderList = [];
+ let renderableItems = [];
+
+ for (let i = 0; i < materialNodes.length; ++i) {
+ let materialNode = materialNodes[i];
+ if (materialNode) {
+ //console.log('Scan material: ', materialNode.getNamePath());
+ let shaderNodes = ne_mx.getShaderNodes(materialNode)
+ if (shaderNodes.length > 0) {
+ let shaderNodePath = shaderNodes[0].getNamePath()
+ if (!shaderList.includes(shaderNodePath)) {
+ //console.log('-- add shader: ', shaderNodePath);
+ shaderList.push(shaderNodePath);
+ renderableItems.push(shaderNodePath);
+ }
+ }
+ }
+ }
+ const nodeGraphs = mdoc.getNodeGraphs();
+ for (let i = 0; i < nodeGraphs.length; ++i) {
+ let nodeGraph = nodeGraphs[i];
+ if (nodeGraph) {
+ if (nodeGraph.hasAttribute('nodedef') || nodeGraph.hasSourceUri()) {
+ continue;
+ }
+ // Skip any nodegraph that is connected to something downstream
+ if (nodeGraph.getDownstreamPorts().length > 0) {
+ continue
+ }
+ let outputs = nodeGraph.getOutputs();
+ for (let j = 0; j < outputs.length; ++j) {
+ let output = outputs[j];
+ {
+ //let newMat = new MaterialAssign(output, assignment, null);
+ renderableItems.push(output.getNamePath());
+ }
+ }
+ }
+ }
+ const outputs = mdoc.getOutputs();
+ for (let i = 0; i < outputs.length; ++i) {
+ let output = outputs[i];
+ if (output) {
+ renderableItems.push(output.getNamePath());
+ }
+ }
+
+ /*
+ const allNodes = mdoc.getNodes();
+ console.log('All Nodes:', allNodes.length, allNodes);
+ for (let i = 0; i < allNodes.length; ++i) {
+ let node = allNodes[i];
+ if (node) {
+ if (node.getType() == 'surfaceshader') {
+ let shaderNodePath = node.getNamePath()
+ if (!shaderList.includes(shaderNodePath)) {
+ console.log('========================= Node:', node.getNamePath(), node.getCategory(), node.getType());
+ let assignment = NO_GEOMETRY_SPECIFIER;
+ if (foundRenderable == false) {
+ assignment = ALL_GEOMETRY_SPECIFIER;
+ foundRenderable = true;
+ }
+ shaderList.push(shaderNodePath);
+ // Create a dummy surface material
+ let surfaceMaterial = mdoc.addChildOfCategory('surfacematerial', shaderNodePath + '_material');
+ let sm_input = surfaceMaterial.addInput('surfaceshader', 'surfaceshader');
+ sm_input.setValueString(shaderNodePath, 'surfaceshader');
+ renderableItems.push(shaderNodePath);
+ console.log('Add dummy material:', ne_mx.prettyPrint(surfaceMaterial));
+ }
+ }
+ }
+
+ } */
+
+ return renderableItems;
+ }
+
+
+ buildMetaData(colorSpace, unit, unitType, uiname, uimin, uimax, uifolder, _type)
+ {
+ // Create a struct with the metadata names as key and value
+ var metaData = {};
+ metaData['colorspace'] = colorSpace;
+ metaData['unit'] = unit;
+ metaData['unittype'] = unitType;
+ metaData['uiname'] = uiname;
+ if (_type == 'vector2' || _type == 'vector3' || _type == 'vector4' || _type == 'matrix33' || _type == 'matrix44') {
+ if (uimin) {
+ uimin = uimin.split(',').map(Number);
+ }
+ if (uimax)
+ {
+ uimax = uimax.split(',').map(Number);
+ }
+ }
+ metaData['uimin'] = uimin;
+ metaData['uimax'] = uimax;
+ metaData['uifolder'] = uifolder;
+
+ // Return struct in an array
+ return metaData;
+ }
+
+ createLiteGraphDefinitions(doc, debug, addInputOutputs, definitionsList, libraryPrefix='mtlx',
+ editor, icon='')
+ {
+ //var ctor_code = "function loadMaterialXDefinitions(){\n";
+
+ var ctor_code = ""
+
+ console.log('Creating LiteGraph definitions from MaterialX document:', doc);
+
+ // Get the node definitions from the MaterialX document
+ var nodeDefs = doc.getNodeDefs();
+
+ if (debug)
+ ctor_code += "console.log('Loading MaterialX Definitions...');\n";
+
+ var TMAP = {}
+ TMAP['float'] = 'float';
+ TMAP['color3'] = 'color3';
+ TMAP['color4'] = 'color4';
+ TMAP['vector2'] = 'vector2';
+ TMAP['vector3'] = 'vector3';
+ TMAP['vector4'] = 'vector4';
+ TMAP['matrix33'] = 'matrix33';
+ TMAP['matrix44'] = 'matrix44';
+ TMAP['integer'] = 'integer';
+ TMAP['string'] = 'string';
+ TMAP['boolean'] = 'boolean';
+ TMAP['filename'] = 'filename';
+ TMAP['BSDF'] = 'BSDF';
+ TMAP['EDF'] = 'EDF';
+ TMAP['VDF'] = 'VDF';
+ TMAP['surfaceshader'] = 'surfaceshader';
+ TMAP['volumeshader'] = 'volumeshader';
+ TMAP['displacementshader'] = 'displacementshader';
+ TMAP['lightshader'] = 'lightshader';
+ TMAP['material'] = 'material';
+ TMAP['vector2array'] = 'vector2array';
+
+ var CMAP = {}
+ CMAP['integer'] = "#A32";
+ CMAP['float'] = "#161";
+ CMAP['vector2'] = "#265";
+ CMAP['vector3'] = "#465";
+ CMAP['vector4'] = "#275";
+ CMAP['color3'] = "#37A";
+ CMAP['color4'] = "#69A";
+ CMAP['matrix33'] = "#333";
+ CMAP['matrix44'] = "#444";
+ CMAP['string'] = "#395";
+ CMAP['filename'] = "#888";
+ CMAP['boolean'] = "#060";
+ /*
+ CMAP['float'] = "#753";
+ CMAP['color3'] = "#679";
+ CMAP['color4'] = "#899";
+ CMAP['vector2'] = "#A32";
+ CMAP['vector3'] = "#A76";
+ CMAP['vector4'] = "#A98";
+ CMAP['matrix33'] = "#333";
+ CMAP['matrix44'] = "#444";
+ CMAP['integer'] = "#A32";
+ CMAP['string'] = "#888";
+ CMAP['boolean'] = "#48A";
+ CMAP['filename'] = "#58E";
+ */
+ /*
+ float: "#753",
+ vector2: "#A32",
+ vector3: "#A76",
+ vector4: "#A98",
+ color3: "#679",
+ color4: "#899",
+ matrix33: "#333",
+ matrix44: "#444",
+ string: "#888",
+ filename: "#58E",
+ boolean: "#48A", */
+
+ var inputTypes = ['float', 'color3', 'color4', 'vector2', 'vector3', 'vector4', 'matrix33', 'matrix44', 'integer', 'string', 'boolean', 'filename', 'BSDF', 'EDF', 'VDF', 'surfaceshader', 'volumeshader', 'displacementshader', 'lightshader', 'material', 'vector2array'];
+ var outputTypes = ['float', 'color3', 'color4', 'vector2', 'vector3', 'vector4', 'matrix33', 'matrix44', 'integer', 'string', 'boolean', 'filename', 'BSDF', 'EDF', 'VDF', 'surfaceshader', 'volumeshader', 'displacementshader', 'lightshader', 'material', 'vector2array'];
+
+ // TODO: Support tokens
+ var supporTokens = false;
+ if (supporTokens)
+ {
+ inputTypes.push('token');
+ TMAP['token'] = 'string';
+ }
+
+ const INPUT_ND = 'ND_input_';
+ const OUTPUT_ND = 'ND_output_';
+ const INPUT_NODE_STRING = 'input';
+ const OUTPUT_NODE_STRING = 'output';
+ const LIBRARY_ICON = editor.ui.icon_map['_default_'];
+
+ // Register inputs (which have no nodedef)
+ if (addInputOutputs)
+ {
+ for (var _type of inputTypes) {
+ var id = libraryPrefix + '/input/input_' + _type;
+ var functionName = ne_mx.createValidName(id);
+ var titleName = 'input_' + _type;
+ ctor_code += "\n// MaterialX node type: " + id + "\n//\n";
+ ctor_code += "function " + functionName + "() {\n";
+ {
+ ctor_code += " this.nodedef_icon = '" + LIBRARY_ICON + "';\n";
+ ctor_code += " this.nodedef_name = '" + INPUT_ND + _type + "';\n";
+ ctor_code += " this.nodedef_node = '" + INPUT_NODE_STRING + "';\n";
+ ctor_code += " this.nodedef_type = '" + _type + "';\n";
+ ctor_code += " this.nodedef_group = '" + INPUT_NODE_STRING + "';\n";
+ if (_type == 'token')
+ _type = 'string';
+ ctor_code += " this.addInput('in', '" + TMAP[_type] + "');\n";
+ var value = this.getDefaultValue('', _type);
+ var metaData = this.buildMetaData('', '', '', '', null, null, '', null);
+ metaData = JSON.stringify(metaData);
+ ctor_code += " this.addProperty('in', " + value + ", '" + _type + "'," + metaData + ");\n";
+ ctor_code += " this.addOutput('out', '" + TMAP[_type] + "');\n";
+
+ ctor_code += " this.title = '" + titleName + "';\n"
+ var desc = '"MaterialX:' + id + '"';
+ ctor_code += " this.desc = " + desc + ";\n";
+
+ var onNodeCreated = "function() {\n";
+ onNodeCreated += " //console.log('Node created:', this);\n";
+ onNodeCreated += " }";
+ ctor_code += " this.onNodeCreated = " + onNodeCreated + "\n";
+ var onRemoved = "function() {\n";
+ onRemoved += " //console.log('Node removed:', this);\n";
+ onRemoved += " }";
+ ctor_code += " this.onRemoved = " + onRemoved + "\n";
+
+ ctor_code += " this.color = '#004C94';\n";
+ ctor_code += " this.bgcolor = '#000';\n";
+ if (_type in CMAP)
+ {
+ ctor_code += " this.boxcolor = '" + CMAP[_type] + "';\n";
+ }
+ ctor_code += " this.shape = LiteGraph.ROUND_SHAPE;\n";
+
+ ctor_code += " this.onExecute = function() {\n";
+ ctor_code += " console.log('Executing node: ', this);\n";
+ ctor_code += " }\n";
+ }
+ ctor_code += "}\n"
+ ctor_code += "LiteGraph.registerNodeType('" + id + "', " + functionName + ");\n";
+ }
+
+ // Register outputs (which have no nodedef)
+ for (var _type of outputTypes) {
+ var id = libraryPrefix + '/output/output_' + _type;
+ var functionName = ne_mx.createValidName(id);
+ var titleName = 'output_' + _type;
+ ctor_code += "\n// MaterialX node type: " + id + "\n//\n";
+ ctor_code += "function " + functionName + "() {\n";
+ {
+ ctor_code += " this.title = '" + titleName + "';\n"
+ var desc = '"MaterialX Node :' + id + '"';
+ ctor_code += " this.desc = " + desc + ";\n";
+
+ ctor_code += " this.nodedef_icon = '" + LIBRARY_ICON + "';\n";
+ ctor_code += " this.nodedef_name = '" + OUTPUT_ND + + _type + "';\n";
+ ctor_code += " this.nodedef_node = '" + OUTPUT_NODE_STRING + "';\n";
+ ctor_code += " this.nodedef_type = '" + _type + "';\n";
+ ctor_code += " this.nodedef_group = '" + OUTPUT_NODE_STRING + "';\n";
+ ctor_code += " this.addInput('in', '" + TMAP[_type] + "');\n";
+ var value = this.getDefaultValue('', _type);
+ ctor_code += " this.addProperty('in', " + value + ", '" + _type + "');\n";
+ ctor_code += " this.addOutput('out', '" + TMAP[_type] + "');\n";
+
+ var onNodeCreated = "function() {\n";
+ onNodeCreated += " //console.log('Node created:', this);\n";
+ onNodeCreated += " }";
+ ctor_code += " this.onNodeCreated = " + onNodeCreated + "\n";
+ var onRemoved = "function() {\n";
+ onRemoved += " //console.log('Node removed:', this);\n";
+ onRemoved += " }";
+ ctor_code += " this.onRemoved = " + onRemoved + "\n";
+
+ ctor_code += " this.color = '#004C94';\n";
+ ctor_code += " this.bgcolor = '#000';\n";
+ if (_type in CMAP)
+ {
+ ctor_code += " this.boxcolor = '" + CMAP[_type] + "';\n";
+ }
+ ctor_code += " this.shape = LiteGraph.ROUND_SHAPE;\n";
+
+ ctor_code += " this.onExecute = function() {\n";
+ ctor_code += " console.log('Executing node:', this);\n";
+ ctor_code += " }\n";
+ }
+ ctor_code += "}\n"
+ ctor_code += "LiteGraph.registerNodeType('" + id + "', " + functionName + ");\n";
+ definitionsList.push(id);
+ }
+ }
+
+ // Iterate over all node definitions
+ for (var nodeDef of nodeDefs) {
+
+ var nodeDefName = nodeDef.getName();
+ var id = libraryPrefix + '/' + nodeDef.getNodeGroup() + '/' + nodeDefName;
+ id = id.replace('ND_', '');
+ var functionName = ne_mx.createValidName(id);
+ var nodeType = nodeDef.getType();
+ var titleName = nodeDef.getNodeString() + "_" + nodeType;
+ var swatchLocation = 'https://materialx.nanmucreative.com/resources/mtlx/nodedef_materials/';
+ var outputs = nodeDef.getActiveOutputs();
+ var outputName = outputs[0].getName(); // TODO: Handle swatch for multiple outputs
+ var swatchId = swatchLocation + 'material_' + nodeDefName + '_' + outputName + '_genglsl.png';
+ swatchId = swatchId.replace('ND_', '');
+ if (debug)
+ console.log('\n--- Registering node type:', id, '----');
+
+ ctor_code += "\n// MaterialX node type: " + id + "\n//\n";
+ ctor_code += "function " + functionName + "() {\n";
+ {
+ var nodeGroup = nodeDef.getNodeGroup();
+ var nodeString = nodeDef.getNodeString();
+ var theIcon = icon;
+ if (theIcon.length == 0)
+ {
+ for (var key in editor.ui.icon_map)
+ {
+ if (nodeString.toLowerCase().startsWith(key.toLowerCase()))
+ {
+ theIcon = editor.ui.icon_map[key];
+ //console.log('set icon:', theIcon, 'for:', key, nodeString);
+ break;
+ }
+ else if (nodeGroup.toLowerCase().startsWith(key.toLowerCase()))
+ {
+ theIcon = editor.ui.icon_map[key];
+ //console.log('set icon:', theIcon, 'for:', key, nodeGroup);
+ break;
+ }
+ }
+ }
+
+ ctor_code += " this.nodedef_icon = '" + theIcon + "';\n";
+ ctor_code += " this.nodedef_name = '" + nodeDefName + "';\n";
+ ctor_code += " this.nodedef_type = '" + nodeType + "';\n";
+ ctor_code += " this.nodedef_node = '" + nodeString + "';\n";
+ ctor_code += " this.nodedef_href = 'https://materialx.nanmucreative.com/documents/definitions/" + nodeString + ".html';\n";
+ ctor_code += " this.nodedef_swatch = '" + swatchId + "';\n";
+ ctor_code += " this.nodedef_group = '" + nodeGroup + "';\n";
+
+ for (var input of nodeDef.getActiveInputs()) {
+ var _name = input.getName();
+ var _type = input.getType();
+ if (_type in TMAP)
+ _type = TMAP[_type];
+ else
+ console.log('Unmappable type:', _type)
+ ctor_code += " this.addInput('" + _name + "','" + _type + "');\n";
+
+ var value = input.getValueString();
+ value = this.getDefaultValue(value, _type);
+ var uiname = input.getAttribute('uiname');
+ var uimin = input.getAttribute('uimin');
+ if (uimin.length == 0)
+ {
+ uimin = null;
+ }
+ var uimax = input.getAttribute('uimax');
+ if (uimax.length == 0)
+ {
+ uimax = null;
+ }
+ var uifolder = input.getAttribute('uifolder');
+ var metaData = this.buildMetaData('', '', '', uiname, uimin, uimax, uifolder, _type);
+ metaData = JSON.stringify(metaData);
+ ctor_code += " this.addProperty('" + _name + "', " + value + ", '" + _type + "'," + metaData + ");\n";
+ }
+ for (var output of nodeDef.getActiveOutputs()) {
+ var _name = output.getName();
+ var _type = output.getType();
+ if (_type in TMAP)
+ _type = TMAP[_type];
+ else
+ console.log('Unmappable type:', _type)
+ //if(_type && _type.constructor === String)
+ // _type = '"'+_type+'"';
+ ctor_code += " this.addOutput('" + _name + "','" + _type + "');\n";
+ }
+
+ ctor_code += " this.title = '" + titleName + "';\n"
+ var desc = '"MaterialX:' + id + '"';
+ ctor_code += " this.desc = " + desc + ";\n";
+
+ var onNodeCreated = "function() {\n";
+ onNodeCreated += " //console.log('Node created:', this);\n";
+ onNodeCreated += "}";
+ ctor_code += " this.onNodeCreated = " + onNodeCreated + "\n";
+ var onRemoved = "function() {\n";
+ onRemoved += " //console.log('Node removed:', this);\n";
+ onRemoved += " }";
+ ctor_code += " this.onRemoved = " + onRemoved + "\n";
+
+ // Set the background color to slate grey
+ ctor_code += " this.bgcolor = '#111';\n";
+ //console.log('Node group:', nodeGroup, nodeDefName);
+ if (nodeGroup == 'conditional')
+ {
+ //console.log('Cond Node group:', nodeGroup)
+ ctor_code += " this.color = '#532200';\n";
+ ctor_code += " this.title_text_color = '#000';\n";
+ ctor_code += " this.shape = LiteGraph.CARD_SHAPE;\n";
+ }
+
+ else if (nodeString != 'convert' &&
+ (nodeGroup == 'shader' || nodeType == 'surfaceshader' || nodeType == 'volumshader' || nodeType == 'displacementshader'))
+ {
+ ctor_code += " this.color = '#232';\n";
+ ctor_code += " this.shape = LiteGraph.ROUND_SHAPE;\n";
+ }
+ else if (nodeGroup == 'material')
+ {
+ ctor_code += " this.color = '#151';\n";
+ ctor_code += " this.shape = LiteGraph.BOX_SHAPE;\n";
+ }
+ else
+ {
+ ctor_code += " this.color = '#222';\n";
+ ctor_code += " this.shape = LiteGraph.ROUND_SHAPE;\n";
+ }
+ if (nodeType in CMAP)
+ {
+ ctor_code += " this.boxcolor = '" + CMAP[nodeType] + "';\n";
+ }
+ }
+ ctor_code += "}\n"
+
+ // Register the node type
+ ctor_code += functionName + ".nodedef_name = '" + nodeDefName + "';\n";
+ ctor_code += functionName + ".nodedef_node = '" + nodeString + "';\n";
+ ctor_code += functionName + ".nodedef_href = 'https://materialx.nanmucreative.com/documents/definitions/" + nodeString + ".html';\n";
+
+ ctor_code += "LiteGraph.registerNodeType(" + "'" + id + "'," + functionName + ");\n";
+ definitionsList.push(id);
+ if (debug)
+ ctor_code += "console.log('Registered node type:', '" + id + "');\n";
+ }
+
+ //ctor_code += "}\n";
+ return ctor_code;
+ }
+
+ validateDocument(doc)
+ {
+ var errors = {};
+ var valid = doc.validate(errors);
+ if (!valid) {
+ this.editor.debugOutput('Failed to validate document:\n' + errors.message, 2);
+ }
+ }
+
+ saveGraphToDocument(graph, writeCustomLibs = true, saveNodePositions = false)
+ {
+ if (!ne_mx) {
+ this.editor.debugOutput("MaterialX is not initialized", 2);
+ return;
+ }
+
+ var outputDoc = ne_mx.createDocument();
+
+ if (!stdlib) {
+ var generator = new ne_mx.EsslShaderGenerator();
+ var genContext = new ne_mx.GenContext(generator);
+ stdlib = ne_mx.loadStandardLibraries(genContext);
+ }
+
+ // Handle top level
+ this.writeGraphToDocument(outputDoc, graph, saveNodePositions);
+
+ if (writeCustomLibs)
+ {
+ console.log('Write custom libraries:', customlibs.length);
+ for (var customlib of customlibs)
+ {
+ outputDoc.importLibrary(customlib[1]);
+ }
+ console.log('Write document custom definitions:', customDocLibs.length);
+ for (var customDocLib of customDocLibs)
+ {
+ outputDoc.importLibrary(customDocLib[1]);
+ }
+ }
+
+ // TODO: Add in another other globals
+ outputDoc.setColorSpace(this.getActiveColorSpace());
+ outputDoc.removeAttribute('fileprefix');
+
+ this.validateDocument(outputDoc);
+
+ return outputDoc;
+ }
+
+ saveGraphToString(graph, writeCustomLibs = true, saveNodePositions = false) {
+ if (!ne_mx) {
+ this.editor.debugOutput("MaterialX is not initialized", 2);
+ return;
+ }
+
+ var outputDoc = this.saveGraphToDocument(graph, writeCustomLibs, saveNodePositions);
+ if (!outputDoc) {
+ this.editor.debugOutput("Failed to save graph to document", 2);
+ return;
+ }
+
+ const writeOptions = new ne_mx.XmlWriteOptions();
+ writeOptions.writeXIncludeEnable = false;
+ var data = '';
+ try {
+ data = ne_mx.writeToXmlString(outputDoc, writeOptions);
+ } catch (e) {
+ this.editor.debugOutput("Failed to write graph:" + e, 2);
+ }
+ return data;
+ }
+
+ saveGraphToFile(graph, saveCustomLibs = true, saveNodePositions = false) {
+ var data = this.saveGraphToString(graph, saveCustomLibs, saveNodePositions);
+ if (!data) {
+ return;
+ }
+
+ var blob = new Blob([data], { type: "text/plain" });
+ var url = URL.createObjectURL(blob);
+ var a = document.createElement("a");
+ a.href = url;
+ a.download = "output_graph.mtlx";
+ a.click();
+ }
+
+ writeGraphToDocument(mltxgraph, graph, saveNodePositions = false) {
+
+ var debug = false;
+
+ if (debug)
+ console.log('***** START Scan Graph:', graph.title);
+ for (var node of graph._nodes) {
+ if (node.type == 'graph/subgraph') {
+ var subgraph = node.subgraph;
+ //var subgraphNode = mltxgraph.addNodeGraph(node.title);
+ var subgraphNode = mltxgraph.addChildOfCategory('nodegraph', node.title);
+ if (debug)
+ console.log('---->>> Scan NodeGraph:', node.title);
+ this.writeGraphToDocument(subgraphNode, subgraph, saveNodePositions);
+ continue;
+ }
+
+ if (debug)
+ console.log('---->>> Scan Node:', node.title);
+
+ var nodeDefName = node.nodedef_name;
+ /* if (!nodeDefName)
+ {
+ this.editor.debugOutput('Failed to find nodeDef for:' + node.title, 1);
+ continue;
+ } */
+
+ //var nodeTypes = LiteGraph.registered_node_types;
+ //var nodeType = nodeTypes[node.type];
+ var nodedefName = node.nodedef_name;
+ var nodedef = null;
+ var nodeElement = null;
+ //if (nodeType) {
+ // nodedefName = nodeType.nodedef_name;
+ // nodedef = stdlib.getNodeDef(nodedefName);
+ //}
+
+ //if (nodedef) {
+ // nodeElement = mltxgraph.addNodeInstance(nodedef, name)
+ // nodeElement.setName(node.title);
+ //}
+ //else
+ {
+ if (nodedefName) {
+ nodeElement = mltxgraph.addChildOfCategory(node.nodedef_node, node.nodedef_type);
+ nodeElement.setType(node.nodedef_type);
+ if (saveNodePositions)
+ {
+ // TODO: Get properly remapping for xpos, ypos.
+ nodeElement.setAttribute('xpos', JSON.stringify(node.pos[0]));
+ nodeElement.setAttribute('ypos', JSON.stringify(node.pos[1]));
+ }
+ if (debug)
+ console.log('** Create node:', nodeElement.getNamePath(), nodeElement.getType());
+ nodeElement.setName(node.title);
+ }
+ }
+
+ if (nodeElement) {
+ if (debug)
+ console.log('-> Write Node:', graph.title + '/' + node.title, ' --> ', nodeElement.getNamePath());
+ }
+ else {
+ console.log('Skip writing :', node.title);
+ //this.editor.debugOutput('No nodedef for:' + node.title + 'Nodetype: ' + node.type, 0);
+ continue;
+ }
+
+ // Add inputs
+ var properties = node.properties;
+
+ var node_inputs = node.inputs;
+ var isInputNode = false;
+ var isOutputNode = false;
+ if (nodeElement.getCategory() == 'input') {
+ isInputNode = true;
+ node_inputs = [node];
+ }
+ else if (nodeElement.getCategory() == 'output') {
+ isOutputNode = true;
+ node_inputs = [node];
+ }
+ if (node_inputs) {
+
+ var inputs = node_inputs;
+ for (var i in inputs) {
+ var input = inputs[i];
+ if (debug)
+ console.log('---- Write port:', input);
+
+ var inputName = input.name;
+ var inputType = input.type;
+ if (nodeElement.getCategory() == 'input' ||
+ nodeElement.getCategory() == 'output') {
+ inputName = 'in';
+ inputType = node.nodedef_type;
+ }
+
+ //var inputType = input.type;
+ var inputElement = null;
+ var nodeToCheck = node;
+ var inputNode = null;
+ var inputLink = null;
+ if (isInputNode && node.graph._subgraph_node)
+ {
+ nodeToCheck = node.graph._subgraph_node;
+ for (var i=0; i 1 && inputLinkOutput) {
+ inputElement.setOutputString(inputLinkOutput.name);
+ }
+ }
+ else {
+ //var upstream_nodeType = nodeTypes[inputNode.type];
+ //if (upstream_nodeType)
+ {
+ if (inputNode.nodedef_node == 'input') {
+ inputElement.setInterfaceName(inputNode.title);
+ }
+ else {
+ inputElement.setNodeName(inputNode.title);
+ // TODO: Need to check that upstream has > 1 output.
+ // Put up an issue that this is really annoying to
+ // disallow an explicit output in validation !!!
+ if (numInputOutputs > 1 && inputNode.nodedef_node != 'output') {
+ // Set output string if there was an output link.
+ if (inputLinkOutput) {
+ inputElement.setOutputString(inputLinkOutput.name);
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ var inputValue = node.properties[inputName];
+ if (inputValue == null) {
+ console.log('Cannot find property value for input:', inputName);
+ }
+ else {
+ var origValue = inputValue;
+ //var inputType = propInfo.type;
+ if (inputType in ['float', 'integer', 'vector2', 'vector3', 'vector4',
+ 'matrix33', 'matrix44', 'color3', 'color4']) {
+ inputValue = '"' + parseFloat(inputValue) + '"';
+ }
+ else if (inputType === 'boolean') {
+ if (inputValue === 'true')
+ inputValue = 'true';
+ else
+ inputValue = 'false';
+ }
+ else {
+ inputValue = inputValue.toString();
+ }
+ //console.log('Write input:', inputElement, node, inputName, origValue, inputValue, inputType);
+ if (nodeElement.getCategory() != 'input' &&
+ nodeElement.getCategory() != 'output') {
+ inputElement = nodeElement.getInput(inputName);
+ if (!inputElement)
+ inputElement = nodeElement.addInput(inputName, inputType);
+ else {
+ // TODO: Seems that c+paste adds same input > once ???
+ console.log('Error> Trying add input more than once:', inputName, ' to node: ', nodeElement.getNamePath());
+ }
+ }
+ else {
+ inputElement = nodeElement;
+ }
+ inputElement.setValueString(inputValue, inputType);
+ }
+ }
+
+ if (inputElement)
+ {
+ var propInfo = null;
+ var skip_attributes = [];
+ if (isInputNode || isOutputNode) {
+ if (input.properties_info) {
+ skip_attributes = ['name', 'type', 'value', 'default_value'];
+ propInfo = input.properties_info[0];
+ }
+ }
+ else {
+ if (node.properties_info) {
+ skip_attributes = ['name', 'type', 'value', 'default_value', 'uimin', 'uimax', 'uiname', 'uifolder'];
+ propInfo = node.properties_info[i];
+ }
+ }
+ if (propInfo)
+ {
+ //console.log('Scan propinfo:', propInfo, 'for input:', inputElement.getNamePath(), 'prop_info:', propInfo);
+
+ // Write node_properties metadata to input
+ for (var propAttribute in propInfo)
+ {
+ if (skip_attributes.includes(propAttribute))
+ continue;
+
+ //console.log('-- scan attrib:', propAttribute);
+ var propAttributeValue = propInfo[propAttribute];
+ if (propAttributeValue && propAttributeValue.length > 0)
+ {
+ //console.log('---- save attribute:', propAttribute, propAttributeValue, 'on input:', inputElement.getNamePath());
+ inputElement.setAttribute(propAttribute, propAttributeValue);
+ }
+ }
+ }
+ }
+ }
+
+ if (debug)
+ console.log('---- END Write inputs:', node.inputs);
+ }
+
+ // Add outputs
+ if (node.outputs) {
+ /*
+ var outputs = node.outputs;
+ for (var i in outputs)
+ {
+ var output = outputs[i];
+ var outputName = output.name;
+ var outputType = output.type;
+ var outputElement = nodeElement.addOutput(outputName, outputType);
+ }
+ */
+ }
+
+ if (debug)
+ console.log('---> End write node', node.title);
+ }
+
+ if (debug)
+ console.log('***** END Scan Graph:', graph.title);
+ }
+
+ isArray(_type) {
+ var ARRAY_TYPES = ['color3', 'color4', 'vector2', 'vector3', 'vector4', 'matrix33', 'matrix44'];
+ if (ARRAY_TYPES.includes(_type)) {
+ return true;
+ }
+ return false;
+ }
+
+ buildConnections(editor, node, lg_node, explicitInputs, graph, parentGraph) {
+
+ var nodeInputs = [];
+ var isOutput = (node.getCategory() == 'output');
+ var isInput = (node.getCategory() == 'input');
+ if (isOutput || isInput) {
+ nodeInputs = [node];
+ }
+ else {
+ nodeInputs = node.getInputs();
+ }
+ for (var input of nodeInputs) {
+
+ var _name = ''
+
+ if (!isOutput && !isInput) {
+ _name = input.getName();
+ explicitInputs.push(_name);
+ }
+
+ var nodeName = input.getNodeName();
+ var nodeGraphName = input.getNodeGraphString();
+ var inputInterfaceName = input.getInterfaceName();
+ var outputName = input.getOutputString();
+
+ if (nodeName.length ||
+ nodeGraphName.length ||
+ inputInterfaceName.length ||
+ outputName.length) {
+
+ //console.log('Test connection on input:', input.getNamePath(), 'nodeName:[ ', nodeName,
+ // '] nodeGraphName:[', nodeGraphName,
+ // '] inputInterfaceName:[', inputInterfaceName,
+ // ']outputName:[', outputName, ']');
+
+ var target_node = lg_node;
+ var target_slot = null;
+ if (!isOutput && !isInput)
+ target_slot = target_node.findInputSlot(_name);
+ else
+ target_slot = 0;
+ var source_node = null;
+ var source_slot = 0;
+ var source_name = nodeName;
+ if (nodeGraphName.length) {
+ source_name = nodeGraphName;
+ }
+ if (inputInterfaceName.length) {
+ source_name = inputInterfaceName;
+ }
+
+ var graphToCheck = graph;
+ if (isInput && graph._subgraph_node)
+ {
+ target_node = graph._subgraph_node;
+ target_slot = target_node.findInputSlot(lg_node.title);
+ // Go up to parent graph
+ graphToCheck = parentGraph;
+ //console.log(' go up to parent graph:', graphToCheck,
+ // 'from:', graph, 'subgraph:', graph._subgraph_node,
+ //'target_node:', target_node.title, 'target_slot:', target_slot);
+
+ // Need to scan parent graph here if interfacename and input
+ /* for (var p = 0; p < parentGraph._nodes.length; ++p) {
+ console.log('local check graph node title', parentGraph._nodes[p].title, source_name);
+ if (parentGraph._nodes[p].title == source_name) {
+ source_node = parentGraph._nodes[p];
+ break;
+ }
+ } */
+ }
+ source_node = graphToCheck.findNodeByTitle(source_name);
+ if (source_node) {
+ if (outputName) {
+ var outputSlot = source_node.findOutputSlot(outputName);
+ if (outputSlot >= 0) {
+ source_slot = outputSlot;
+ }
+ else {
+ editor.debugOutput('Failed to find output slot:' + outputName, 1);
+ }
+ var linkInfo = source_node.connect(source_slot, target_node, target_slot);
+ if (!linkInfo)
+ {
+ editor.debugOutput('Failed to connect:' + source_node.title + '.' + outputName, '->', target_node.title + '.' + _name), 1, false;
+ }
+ }
+ //console.log('CONNECT START: source[', source_node.title, '.', source_slot,
+ // '] --> target[:', target_node.title, ".", target_slot);
+ var linkInfo = null;
+ if (source_slot == null || target_slot == null || target_node == null)
+ {
+ console.warning('Cannot connect!')
+ }
+ else
+ {
+ linkInfo = source_node.connect(source_slot, target_node, target_slot);
+ }
+ if (!linkInfo)
+ {
+ editor.debugOutput('Failed to connect:' + source_node.title + '.' + outputName, '->', target_node.title + '.' + _name, 1);
+ }
+ //console.log('CONNECT END: source[', source_node.title, '.', source_slot,
+ // '] --> target[:', target_node.title, ".", target_slot);
+ }
+ else {
+ console.log('Failed to find node ', source_name, 'in graph:', graphToCheck);
+ this.editor.debugOutput('Failed to find source node: ' + source_node + "." +
+ source_name, '->', lg_node.title + "." + _name, 2);
+ }
+ }
+ else {
+ var _value = input.getResolvedValueString(); // input.getValueString();
+ if (_value.length > 0) {
+ if (this.isArray(input.getType())) {
+ // split by commas or spaces
+ let valueArray = _value.split(/[\s,]+/);
+ _value = valueArray;
+ }
+
+ //console.log('-- Value Input:',
+ //lg_node.title + "." + _name, 'value:', _value);
+ lg_node.setProperty(_name, _value);
+ }
+ }
+
+ var property_info = lg_node.getPropertyInfo(_name);
+ this.loadInputMetaData(input, property_info);
+ }
+ }
+
+ loadInputMetaData(input, property_info)
+ {
+ if (input && property_info) {
+
+ // Load in basic meta-data
+ var colorspace = input.getColorSpace();
+ if (colorspace.length > 0)
+ property_info['colorspace'] = colorspace;
+
+ var unit = input.getUnit();
+ if (unit.length > 0)
+ property_info['unit'] = unit;
+
+ var uiname = input.getAttribute('uiname');
+ if (uiname.length > 0)
+ property_info['uiname'] = uiname;
+
+ var uimin = input.getAttribute('uimin');
+ if (uimin.length > 0)
+ property_info['uimin'] = uimin;
+
+ var uimax = input.getAttribute('uimax');
+ if (uimax.length > 0)
+ property_info['uimax'] = uimax;
+
+ var uifolder = input.getAttribute('uifolder');
+ if (uifolder.length > 0)
+ property_info['uifolder'] = uifolder;
+
+ var basicMetaData = ['colorspace', 'unit', 'uiname', 'uimin', 'uimax', 'uifolder', 'name', 'type', 'output', 'nodename', 'nodegraph'];
+ for (var attrName of input.getAttributeNames())
+ {
+ if (!basicMetaData.includes(attrName)) {
+ property_info[attrName] = input.getAttribute(attrName);
+ }
+ }
+
+ //console.log('load input metadata for:', input.getNamePath(), property_info);
+ }
+ }
+
+ buildGraphFromDoc(doc, editor, auto_arrange) {
+ var debug = false;
+
+ //console.log('Build graph from doc. auto_arrange: ', auto_arrange);
+ if (!ne_mx) {
+ editor.debugOutput("MaterialX is not initialized", 2);
+ return;
+ }
+
+ editor.clearGraph();
+
+ // Don't try and update the graph while building it
+ editor.monitorGraph(graph, false);
+
+ // Index here is index into litegraph nodes
+ var mtlxNodes = [];
+ var mtlxNodeDefs = [];
+
+ for (var interfaceInput of doc.getInputs()) {
+ var _type = interfaceInput.getType();
+ var id = 'mtlx/input/input_' + _type;
+
+ var lg_node = LiteGraph.createNode(id);
+ if (lg_node) {
+ lg_node.title = interfaceInput.getName();
+ if (debug)
+ console.log('Add top level input:', lg_node.title, 'to graph', graph);
+
+ var _value = interfaceInput.getValueString();
+ if (_value && _value.length > 0) {
+ if (this.isArray(interfaceInput.getType())) {
+ _value = "[" + _value + "]"
+ _value = JSON.parse(_value);
+ }
+ lg_node.setProperty('in', _value);
+ }
+
+ var xpos = interfaceInput.getAttribute('xpos');
+ var ypos = interfaceInput.getAttribute('ypos');
+ if (xpos.length > 0 && ypos.length > 0)
+ {
+ ;//lg_node.pos[0] = xpos;
+ ;//lg_node.pos[1] = ypos;
+ }
+ //lg_node.flags.collapsed = false;
+
+ // Make sure size is updated
+ lg_node.setSize(lg_node.computeSize());
+
+ graph.add(lg_node);
+
+ //mtlxNodes.push([interfaceInput, lg_node, graph]);
+ }
+ }
+
+ for (var interfaceOutput of doc.getOutputs()) {
+ var _type = interfaceOutput.getType()
+ var id = 'mtlx/output/output_' + _type;
+
+ var lg_node = LiteGraph.createNode(id);
+ if (lg_node) {
+ lg_node.title = interfaceOutput.getName();
+ graph.add(lg_node);
+ if (debug)
+ {
+ console.log('Add graph output:', lg_node.title);
+ }
+
+ // Make sure size is updated
+ lg_node.setSize(lg_node.computeSize());
+
+ var xpos = interfaceOutput.getAttribute('xpos');
+ var ypos = interfaceOutput.getAttribute('ypos');
+ if (xpos.length > 0 && ypos.length > 0)
+ ;//lg_node.pos = [xpos, ypos];
+
+ mtlxNodes.push([interfaceOutput, lg_node, graph]);
+ }
+ }
+
+ for (var node of doc.getNodes()) {
+ var nodeDef = node.getNodeDef();
+ if (!nodeDef) {
+ editor.debugOutput('Skip node w/o nodedef:' + node.getName(), 1)
+ continue;
+ }
+
+ // mtlx/pbr/gltf_pbr_surfaceshader
+ var id = 'mtlx/' + nodeDef.getNodeGroup() + '/' + nodeDef.getName();
+ id = id.replace('ND_', '');
+ if (debug)
+ console.log('Load node:', node.getName(), ' -> ', id);
+
+ var lg_node = LiteGraph.createNode(id);
+ if (lg_node) {
+ //console.log('LiteGraph node:', lg_node);
+ lg_node.title = node.getName();
+
+ graph.add(lg_node);
+
+ // Make sure size is updated
+ lg_node.setSize(lg_node.computeSize());
+
+ var xpos = node.getAttribute('xpos');
+ var ypos = node.getAttribute('ypos');
+ if (xpos.length > 0 && ypos.length > 0)
+ ;//lg_node.pos = [xpos, ypos];
+
+ mtlxNodes.push([node, lg_node, graph]);
+ mtlxNodeDefs.push(nodeDef);
+ }
+ else {
+ editor.debugOutput('Failed to create node:' + node.getName(), 2);
+ }
+ }
+
+ for (var nodegraph of doc.getNodeGraphs()) {
+ if (nodegraph.hasSourceUri()) {
+ continue;
+ }
+ var nodedefAttrib = nodegraph.getAttribute('nodedef');
+ if (nodedefAttrib && nodedefAttrib.length > 0)
+ {
+ console.log('Skip loading in functional graph:', nodegraph.getName(), 'nodedef:', nodedefAttrib);
+ continue;
+ }
+ if (debug)
+ console.log('Create nodegraph:', nodegraph.getName());
+
+ var title = nodegraph.getName();
+ var subgraphNode = LiteGraph.createNode("graph/subgraph", title);
+ //var subgraph = new LiteGraph.LGraph();
+ //subgraphNode._subgraph_node = subgraph;
+ //subgraphNode.bgcolor = "#112";
+ subgraphNode.bgImageUrl = "./Images/nodegraph.png";
+
+ var mtlxSubGraphNodes = [];
+ for (var interfaceInput of nodegraph.getInputs()) {
+ var _type = interfaceInput.getType();
+ var id = 'mtlx/input/input_' + _type;
+
+ var lg_node = LiteGraph.createNode(id);
+ if (lg_node) {
+ lg_node.title = interfaceInput.getName();
+ this.loadInputMetaData(interfaceInput, lg_node.properties_info[0]);
+ subgraphNode.subgraph.add(lg_node);
+
+ if (debug)
+ console.log('-------- Add subgraph input:', lg_node.title, lg_node);
+
+ subgraphNode.addInput(interfaceInput.getName(), _type);
+ subgraphNode.subgraph.addInput(interfaceInput.getName(), _type);
+
+ var _value = interfaceInput.getValueString();
+ if (_value && _value.length > 0) {
+ if (this.isArray(interfaceInput.getType())) {
+ _value = "[" + _value + "]"
+ _value = JSON.parse(_value);
+ }
+ lg_node.setProperty('in', _value);
+ }
+
+ // Make sure size is updated
+ lg_node.setSize(lg_node.computeSize());
+
+ var xpos = nodegraph.getAttribute('xpos');
+ var ypos = nodegraph.getAttribute('ypos');
+ if (xpos.length > 0 && ypos.length > 0)
+ ; // lg_node.pos = [xpos, ypos];
+
+ mtlxSubGraphNodes.push([interfaceInput, lg_node, graph]);
+ }
+ }
+
+ for (var interfaceOutput of nodegraph.getOutputs()) {
+ var _type = interfaceOutput.getType()
+ var id = 'mtlx/output/output_' + _type;
+
+ var lg_node = LiteGraph.createNode(id);
+ if (lg_node) {
+ lg_node.title = interfaceOutput.getName();
+ subgraphNode.subgraph.add(lg_node);
+ if (debug)
+ console.log('Add subgraph output:', lg_node.title);
+
+ subgraphNode.addOutput(interfaceOutput.getName(), _type);
+ subgraphNode.subgraph.addOutput(interfaceOutput.getName(), _type);
+
+ // Make sure size is updated
+ lg_node.setSize(lg_node.computeSize());
+
+ var xpos = interfaceOutput.getAttribute('xpos');
+ var ypos = interfaceOutput.getAttribute('ypos');
+ if (xpos.length > 0 && ypos.length > 0)
+ ; // lg_node.pos = [xpos, ypos];
+
+ mtlxSubGraphNodes.push([interfaceOutput, lg_node, graph]);
+ }
+ }
+
+
+ for (var node of nodegraph.getNodes()) {
+ var nodeDef = node.getNodeDef();
+ if (!nodeDef) {
+ editor.debugOutput('Skip node w/o nodedef:' + node.getName(), 1)
+ continue;
+ }
+
+ // mtlx/pbr/gltf_pbr_surfaceshader
+ var id = 'mtlx/' + nodeDef.getNodeGroup() + '/' + nodeDef.getName();
+ id = id.replace('ND_', '');
+
+ var lg_node = LiteGraph.createNode(id);
+ lg_node.title = node.getName();
+ subgraphNode.subgraph.add(lg_node);
+ if (debug)
+ console.log('Add subgraph node:', lg_node.title);
+
+ // Make sure size is updated
+ lg_node.setSize(lg_node.computeSize());
+
+ var xpos = node.getAttribute('xpos');
+ var ypos = node.getAttribute('ypos');
+ if (xpos.length > 0 && ypos.length > 0)
+ ; // lg_node.pos = [xpos, ypos];
+
+ mtlxSubGraphNodes.push([node, lg_node, graph]);
+ }
+
+ for (var item of mtlxSubGraphNodes) {
+ var node = item[0];
+ var lg_node = item[1];
+ var parentGraph = item[2];
+ var explicitInputs = [];
+
+ // Make sure size is updated
+ lg_node.setSize(lg_node.computeSize());
+
+ //console.log('Build connections for subgraog node:', lg_node.title);
+ this.buildConnections(editor, node, lg_node, explicitInputs, subgraphNode.subgraph, parentGraph);
+ }
+
+ if (debug)
+ console.log('Add subgraph:', subgraphNode.title);
+
+ if (auto_arrange > 0)
+ {
+ subgraphNode.subgraph.arrange(auto_arrange);
+ }
+
+ graph.add(subgraphNode);
+
+ }
+
+ // Build top level connections last after top level nodes
+ // and nodegraph have been added.
+ var itemCount = 0;
+ for (var item of mtlxNodes) {
+ var node = item[0];
+ var lg_node = item[1];
+
+ // Keep track of explicit inputs
+ var explicitInputs = [];
+ //console.log('Build connections for:', lg_node.title);
+ this.buildConnections(editor, node, lg_node, explicitInputs, graph, null);
+
+ if (lg_node.nodedef_node == 'input' || lg_node.nodedef_node == 'output')
+ {
+ continue;
+ }
+
+ var removeInputs = [];
+ var nodeDef = mtlxNodeDefs[itemCount];
+ if (nodeDef)
+ {
+ for (var nodeDefInput of nodeDef.getActiveInputs()) {
+ var _name = nodeDefInput.getName();
+ if (!explicitInputs.includes(_name)) {
+ removeInputs.push(_name);
+ }
+ }
+ for (var _name of removeInputs) {
+ var slot = lg_node.findInputSlot(_name);
+ //console.log('Remove input:', _name, ' on: ', lg_node);
+ lg_node.removeInput(slot);
+ }
+
+ // Make sure size is updated
+ lg_node.setSize(lg_node.computeSize());
+ }
+ itemCount++;
+ }
+
+ editor.monitorGraph(graph, true);
+
+ if (auto_arrange > 0)
+ {
+ graph.arrange(auto_arrange);
+ }
+
+ graph.setDirtyCanvas(true, true);
+ graphcanvas.setDirty(true, true);
+ }
+
+ loadDefinitionsFromFile()
+ {
+ var that = this;
+
+ // Load mtlx document from disk
+ var input = document.createElement("input");
+ input.type = "file";
+ input.accept = ".mtlx";
+ input.onchange = function (e) {
+ var file = e.target.files[0];
+ console.log('Loading definitions from file: ' + file.name);
+
+ if (ne_mx) {
+ // Load the content from the specified file (replace this with actual loading logic)
+
+ const reader = new FileReader();
+ reader.readAsText(file, 'UTF-8');
+
+ reader.onload = function (e) {
+ // Display the contents of the file in the output div
+ let fileContents = e.target.result;
+ //console.log(fileContents);
+
+ (async () => {
+ try {
+ const readOptions = new ne_mx.XmlReadOptions();
+ readOptions.readXIncludes = false;
+ var customLib = ne_mx.createDocument();
+
+ await ne_mx.readFromXmlString(customLib, fileContents, '', readOptions);
+
+ // Create JS from custom library
+ try {
+ console.log('Create custom library definitions')
+ var iconName = '';
+ var scanForIcon = false;
+ if (scanForIcon)
+ {
+ // Icon name is filename with webp as extension
+ var iconName = file.name.replace(/\.[^/.]+$/, ".webp");
+ // Check if iconName file exists
+ var iconExists = await that.editor.uriExists(iconName);
+ if (!iconExists) {
+ iconName = '';
+ }
+ }
+ var definitionsList = [];
+ var result = that.createLiteGraphDefinitions(customLib, false, false, definitionsList , 'mtlx', that.editor, iconName);
+ if (result)
+ {
+ eval(result);
+ var definitionsListString = definitionsList.join(', ');
+ that.editor.debugOutput("Registered custom node types: [" + definitionsListString + "]", 0, false);
+ that.editor.displayNodeTypes();
+ }
+ } catch (e) {
+ console.log('Error evaluating source:', e);
+ }
+
+
+ // Keep track of libraries loaded by filename.
+ customlibs.push([file.name, customLib]);
+
+ } catch (error) {
+ that.editor.debugOutput('Error reading definitions:' + error, 2, false);
+ }
+ })();
+
+ };
+
+ } else {
+ that.editor.debugOutput("MaterialX is not initialized", 2);
+ }
+
+ //customlibs
+ };
+ input.click();
+ }
+
+ loadFromString(fileContents, fileName, auto_arrange)
+ {
+ if (!ne_mx) {
+ console.log('MaterialX is not initialized');
+ return;
+ }
+
+ (async () => {
+ try {
+ const readOptions = new ne_mx.XmlReadOptions();
+ readOptions.readXIncludes = false;
+
+ doc.clearContent();
+
+ doc.importLibrary(stdlib);
+ for (var item of customlibs) {
+ console.log('Import custom library:', item[0]);
+ doc.importLibrary(item[1]);
+ }
+ var loadDoc = ne_mx.createDocument();
+ await ne_mx.readFromXmlString(loadDoc, fileContents, '', readOptions);
+
+ // Check if nodedef is not in existingDefs
+ //
+ var customLib = ne_mx.createDocument();
+ customLib.copyContentFrom(loadDoc);
+ var keepChildren = [];
+ var existingDefs = []
+ var saveCustomLib = false;
+ doc.getNodeDefs().forEach(def => { existingDefs.push(def.getName()); });
+ for (var nodedef of loadDoc.getNodeDefs()) {
+ var nodedefName = nodedef.getName();
+ if (!existingDefs.includes(nodedefName)) {
+ keepChildren.push(nodedef.getName());
+ saveCustomLib = true;
+ }
+ }
+ for (var ng of loadDoc.getNodeGraphs()) {
+ if (ng.getAttribute('nodedef') && ng.getAttribute('nodedef').length > 0) {
+ saveCustomLib = true;
+ keepChildren.push(ng.getName());
+ }
+ }
+
+ if (saveCustomLib) {
+
+ for (var child of customLib.getChildren()) {
+ if (!keepChildren.includes(child.getName())) {
+ console.log('Remove child:', child.getName());
+ customLib.removeChild(child.getName());
+ }
+ }
+
+ var additionDefs = [];
+ var result = this.createLiteGraphDefinitions(customLib, true, false, additionDefs, 'mtlx', MxShadingGraphEditor.theEditor);
+ try {
+ eval(result);
+ console.log('Loaded local definitions: ', additionDefs);
+ } catch (e) {
+ console.log('Error evaluating source:', e);
+ }
+ }
+
+ doc.copyContentFrom(loadDoc);
+ this.validateDocument(doc);
+ this.buildGraphFromDoc(doc, MxShadingGraphEditor.theEditor, auto_arrange);
+
+ // Must do this after build as build will clear customDocLibs array
+ if (saveCustomLib) {
+ customDocLibs.push([fileName, customLib]);
+ }
+
+ var documentColorSace = doc.getColorSpace();
+ this.setActiveColorSpace(documentColorSace);
+ documentColorSace = this.getActiveColorSpace();
+ //console.log('Document colorspace:', documentColorSace);
+ var csArea = MxShadingGraphEditor.theEditor.ui.mtlxdoc_colorspace;
+ if (csArea)
+ csArea.innerHTML = documentColorSace;
+ MxShadingGraphEditor.theEditor.updatePropertyPanel(null);
+
+ // Cleanup document, and get up-to-date contents after any possible upgrade.
+ loadDoc.removeAttribute('fileprefix');
+ fileContents = ne_mx.writeToXmlString(loadDoc);
+
+ this.validateDocument(loadDoc);
+
+ MxShadingGraphEditor.theEditor.debugOutput('Loaded document: "' + fileName + '"', 0, false);
+
+ // Update mtlx text area
+ let textArea = MxShadingGraphEditor.theEditor.ui.mtlxdoc;
+ if (!textArea) {
+ MxShadingGraphEditor.theEditor.debugOutput('Failed to find text area for mtlxdoc', 2, false);
+ }
+ else {
+ textArea.setValue(fileContents);
+ }
+
+ // Update render items in UI
+ let renderableItemUpdater = MxShadingGraphEditor.theEditor.ui.renderableItemUpdater;
+ if (renderableItemUpdater) {
+ let renderableItems = this.findRenderableItemsInDoc(doc);
+ if (!renderableItems || renderableItems.length == 0) {
+ MxShadingGraphEditor.theEditor.debugOutput('No renderable items found in graph: ' + fileName, 1, false);
+ }
+ renderableItemUpdater(renderableItems);
+ }
+
+ } catch (error) {
+ MxShadingGraphEditor.theEditor.debugOutput('Error reading document: ' + fileName + '. Error: ' + error, 2, false);
+ }
+ })();
+ }
+
+ loadFromFile(file, fileName, editor, auto_arrange) {
+ var debug = false;
+
+ if (ne_mx)
+ {
+ if (!this.loadMaterialXLibraries())
+ return;
+
+ // Load the content from the specified file (replace this with actual loading logic)
+
+ const reader = new FileReader();
+ reader.readAsText(file, 'UTF-8');
+ reader.accept = '.mtlx';
+
+ var that = this;
+ reader.onload = function (e) {
+ // Display the contents of the file in the output div
+ let fileContents = e.target.result;
+
+ that.loadFromString(fileContents, fileName, auto_arrange);
+ };
+
+ } else {
+ editor.debugOutput("MaterialX is not initialized", 2, false);
+ }
+ }
+
+ loadMaterialXLibraries() {
+ if (stdlib)
+ return stdlib;
+
+ if (!ne_mx) {
+ MxShadingGraphEditor.theEditor.debugOutput("MaterialX is not initialized", 2);
+ return null;
+ }
+
+ var generator = new ne_mx.EsslShaderGenerator();
+ var genContext = new ne_mx.GenContext(generator);
+ {
+ stdlib = ne_mx.loadStandardLibraries(genContext);
+ console.log('Loaded standard libraries:', stdlib.getNodeDefs().length);
+ }
+
+ return stdlib;
+ }
+
+ // Create a valid MaterialX name
+ createValidName(name, msg=null)
+ {
+ if (name.length == 0) {
+ if (msg)
+ {
+ msg = 'Setting empty name as "blank"';
+ }
+ name = "blank";
+ }
+
+ // Get list of all names in graph.
+ var graph = graphcanvas.graph;
+ var nodes = graph._nodes;
+ var nodenames = [];
+ for (var node of nodes) {
+ nodenames.push(node.title);
+ }
+ //console.log('Current graph nodes:', nodenames);
+
+ name = ne_mx.createValidName(name);
+
+ if (!nodenames.includes(name)) {
+ return name;
+ }
+
+ // Get starting number and root name
+ var rootName = name;
+ var i = 1;
+ var number = name.match(/\d+$/);
+ if (number) {
+ i = (parseInt(number) + 1)
+ rootName = name.slice(0, -number[0].length);
+ }
+
+ var valid_name = rootName + i.toString();
+ while (nodenames.includes(valid_name)) {
+ i++;
+ valid_name = rootName + i.toString();
+ }
+ return valid_name;
+ }
+};
+
+class MxShadingGraphEditor {
+ //
+ // This class is a wrapper around the LiteGraph library to provide a MaterialX node editor.
+ // It is designed to work with the MaterialX JavaScript API.
+ //
+ // List of methods:
+ // - constructor
+ // - setUI
+ // - setDirty
+ // - debugOutput
+ // - arrangeGraph
+ // - resetView
+ // - clearGraph
+ // - saveSerialization
+ // - loadSerialization
+ // - saveGraph
+ // - saveGraphToString
+ // - ladDefinitions
+ // - loadGraph
+ // - loadGraphFromString
+ // - rgbToHex
+ // - createButtonWithImageAndText
+ // - openImageDialog
+ // - updatePropertyPanel
+ //
+ constructor() {
+ if (!MxShadingGraphEditor.theEditor)
+ {
+ MxShadingGraphEditor.theEditor = this;
+ this.handler = new MxMaterialXHandler('MaterialX Handler', 'mtlx');
+ console.log('Create new editor', MxShadingGraphEditor.theEditor, ' and handler: ', this.handler);
+ }
+ return MxShadingGraphEditor.theEditor;
+ }
+
+ setUI(ui) {
+ this.ui = ui;
+ }
+
+ setDirty()
+ {
+ if (graphcanvas)
+ {
+ graphcanvas.setDirty(true, true);
+ //graphcanvas.resize();
+ }
+ }
+
+ debugOutput(text, severity, clear = null) {
+ var console_area = MxShadingGraphEditor.theEditor.ui.console_area;
+ if (!console_area) {
+ console.error('No console area found!');
+ return;
+ }
+ if (severity === 2) {
+ text = '> Error: ' + text
+ }
+ else if (severity === 1) {
+ text = '> Warning: ' + text
+ }
+ else {
+ if (text.length)
+ text = '> ' + text;
+ }
+
+ //if (clear) {
+ // console_area.value = text + '\n';
+ //}
+ //else
+ {
+ console_area.value = console_area.value + text + '\n';
+ }
+ // Scroll to latest entry.
+ console_area.scrollTop = console_area.scrollHeight;
+ }
+
+ arrangeGraph() {
+ // This does not track the current subgraph.
+ if (graphcanvas) {
+ graphcanvas.graph.arrange(80);
+ }
+ }
+
+ openSubgraph()
+ {
+ var selected = graphcanvas.selected_nodes;
+ for (var s in selected) {
+ var node = selected[s];
+ if (node.type == 'graph/subgraph') {
+ console.log('Open subgraph', node.title );
+ graphcanvas.openSubgraph(node.subgraph);
+ break;
+ }
+ }
+ }
+
+ closeSubgraph()
+ {
+ if (graphcanvas) {
+ graphcanvas.closeSubgraph();
+ }
+ }
+
+ resetView() {
+ if (graphcanvas) {
+ graphcanvas.ds.reset();
+ graphcanvas.setDirty(true, true);
+ }
+ }
+
+ clearGraph() {
+ //localStorage.setItem(
+ // "litegrapheditor_clipboard", ""
+ //);
+
+ this.handler.activeColorSpace = this.handler.DEFAULT_COLOR_SPACE;
+ this.handler.activeUnits = this.handler.DEFAULT_UNITS;
+ MxShadingGraphEditor.theEditor.updatePropertyPanel(null);
+ MxShadingGraphEditor.theEditor.debugOutput('', 0, false);
+ this.updatePropertyPanel(null);
+ if (graphcanvas) {
+ // Set back to top graph
+ graphcanvas.setGraph(graph);
+ graphcanvas.graph.clear();
+ graphcanvas.ds.reset();
+ graphcanvas.setDirty(true, true);
+ }
+ //console.log('Clear graph', customDocLibs);
+ customDocLibs = [];
+ }
+
+ saveSerialization() {
+ var data = JSON.stringify(graph.serialize(), null, 2);
+ var blob = new Blob([data], { type: "text/plain" });
+ var url = URL.createObjectURL(blob);
+ var a = document.createElement("a");
+ a.href = url;
+ a.download = "my_lite_graph.json";
+ a.click();
+ }
+
+ loadSerialization() {
+ MxShadingGraphEditor.theEditor.clearGraph();
+
+ var input = document.createElement("input");
+ input.type = "file";
+ input.accept = ".json";
+ input.onchange = function (e) {
+ var file = e.target.files[0];
+ var reader = new FileReader();
+ reader.onload = function (event) {
+ var data = JSON.parse(event.target.result);
+ graph.configure(data);
+ };
+ reader.readAsText(file);
+ };
+ input.click();
+ }
+
+ saveGraphToFile(extension, saveCustomLibs, saveNodePositions)
+ {
+ if (extension == 'mtlx')
+ this.handler.saveGraphToFile(graph, saveCustomLibs, saveNodePositions);
+ }
+
+ saveGraphToString(extension, saveCustomLibs, saveNodePositions)
+ {
+ if (extension == 'mtlx')
+ return this.handler.saveGraphToString(graph, saveCustomLibs, saveNodePositions);
+ return '';
+ }
+
+ loadDefinitionsFromFile(extension)
+ {
+ if (extension == 'mtlx')
+ {
+ this.handler.loadDefinitionsFromFile();
+ }
+ }
+
+ loadGraphFromFile(extension, auto_arrange) {
+
+ if (extension != this.handler.getExtension())
+ {
+ this.debugOutput('Unsupported extension for loading graph', 2, false);
+ return;
+ }
+
+ // Load document from disk. TODO: handle other extensions
+ var input = document.createElement("input");
+ input.type = "file";
+ input.accept = "." + this.handler.getExtension();
+ console.log('Accept:', input.accept);
+ input.onchange = function (e) {
+ var file = e.target.files[0];
+ console.log('Loading file: ' + file.name);
+ MxShadingGraphEditor.theEditor.handler.loadFromFile(file, file.name, MxShadingGraphEditor.theEditor, auto_arrange);
+ };
+ input.click();
+ }
+
+ findRenderableItems() {
+ return this.handler.findRenderableItems(graph);
+ }
+
+ loadGraphFromString(extension, content, fileName, auto_arrange)
+ {
+ if (extension != this.handler.getExtension())
+ {
+ this.debugOutput('Unsupported extension for loading graph', 2, false);
+ return;
+ }
+
+ // TODO: handle other extensions
+ if (content.length > 0)
+ this.handler.loadFromString(content, fileName, auto_arrange);
+ else
+ MxShadingGraphEditor.theEditor.debugOutput('No content to load', 2, false);
+ }
+
+ rgbToHex(rgb) {
+ if (!rgb) {
+ console.log('rgbToHex empty !', rgb);
+ return "#000000";
+ }
+ return '#' + rgb.map(x => {
+ var hex = Math.round(x * 255).toString(16);
+ return hex.length === 1 ? '0' + hex : hex;
+ }).join('');
+ }
+
+ createButtonWithImageAndText(imageSrc, text, id) {
+ // Create image element
+ var img = document.createElement("img");
+ img.id = id + "_img";
+ img.src = imageSrc;
+ img.classList.add("img-fluid");
+
+ // Create text element
+ var span = document.createElement("span");
+ span.id = id + "_text";
+ span.textContent = " " + text;
+
+ // Create button element
+ var button = document.createElement("button");
+ button.id = id;
+ button.classList.add("btn", "btn-sm", "btn-outline-secondary", "form-control", "form-control-sm");
+ button.appendChild(img);
+ button.appendChild(span);
+
+ return button;
+ }
+
+
+ openImageDialog(theNode, updateProp, wantURI) {
+ //console.log('updateImageDialog', theNode, updateProp, wantURI);
+
+ // Dynamically create a file input element
+ var fileInput = document.createElement('input');
+ fileInput.type = 'file';
+ fileInput.accept = 'image/*'; // Accept any image file
+ fileInput.style.display = 'none';
+ document.body.appendChild(fileInput);
+
+ fileInput.click();
+
+ // TODO : Cache the fileURI on the node so can display without loading...
+ fileInput.addEventListener('change', function () {
+ var fileURI = fileInput.value.split('\\').pop(); // Get the filename without the full path
+ var file = fileInput.files[0];
+ //if (wantURI)
+ fileURI = URL.createObjectURL(file);
+
+ var updateElementId = '__pp:' + updateProp;
+ var textInput = document.getElementById(updateElementId);
+ //console.log('New filename:', fileURI, 'updateElementId:', updateElementId, 'updateProp:', updateProp);
+ textInput.value = fileURI;
+ theNode.properties[updateProp] = fileURI;
+
+ var propertypanel_preview = document.getElementById('propertypanel_preview');
+ if (propertypanel_preview)
+ {
+ propertypanel_preview.src = URL.createObjectURL(file);
+ propertypanel_preview.style.display = "block";
+ }
+
+ var previewImage = false;
+ if (previewImage) {
+ if (propertypanel_preview) {
+ var reader = new FileReader();
+ reader.onload = function (event) {
+ propertypanel_preview.src = event.target.result;
+ };
+
+ // Read the file as a data URL (base64 encoded string)
+ reader.readAsDataURL(file);
+
+ propertypanel_preview.style.display = "block";
+ }
+ }
+
+ document.body.removeChild(fileInput);
+ });
+ }
+
+ uriExists(uri) {
+ // Add try / catch block to handle network errors
+ return fetch(uri)
+ .then(response => {
+ if (response.ok) {
+ return Promise.resolve(true);
+ } else {
+ return Promise.resolve(false);
+ }
+ })
+ .catch(error => {
+ console.log('Error checking URI:', error);
+ return Promise.resolve(false);
+ });
+ }
+
+ updatePropertyPanel(node) {
+ //console.log('Update Panel For:', node);
+ var propertypanelcontent = MxShadingGraphEditor.theEditor.ui.propertypanel_content;
+ if (!propertypanelcontent) {
+ console.error('No property panel content widget found!');
+ return;
+ }
+ // Delete all children
+ while (propertypanelcontent.firstChild) {
+ propertypanelcontent.removeChild(propertypanelcontent.firstChild);
+ }
+
+ // Update icon
+ var panelIcon = MxShadingGraphEditor.theEditor.ui.propertypanel_icon;
+ if (node && node.nodedef_icon) {
+ //if (panelIcon.src != node.nodedef_icon)
+ panelIcon.src = node.nodedef_icon;
+ }
+ else {
+ if (!node)
+ panelIcon.src = this.ui.icon_map['_default_graph_'];
+ else
+ panelIcon.src = this.ui.icon_map['_default_'];
+ }
+
+ propertypanelcontent.innerHTML = "";
+
+ if (!node && graphcanvas.graph._subgraph_node)
+ {
+ node = graphcanvas.graph._subgraph_node;
+ console.log('In subgraph but no node deleted. Select subgram node', node)
+ }
+ else if (!node && !graphcanvas.graph._is_subgraph) {
+ var docInfo = [ ['Colorspace', this.handler.activeColorSpace],
+ ['Units', this.handler.activeUnit ]];
+
+ for (var item of docInfo) {
+
+ var elem = document.createElement("div");
+ elem.className = "row px-1 py-0";
+ var label = document.createElement("div");
+ label.className = "col py-0 col-form-label-sm text-left";
+ label.innerHTML = "" + item[0] + " ";
+ elem.appendChild(label);
+
+ var inputCol = document.createElement("div");
+ inputCol.className = "col text-left";
+ var nameInput = document.createElement("input");
+ nameInput.type = "text";
+ nameInput.value = item[1];
+ nameInput.className = "form-control form-control-sm";
+ nameInput.disabled = true;
+ elem.appendChild(inputCol);
+ inputCol.appendChild(nameInput);
+
+ propertypanelcontent.appendChild(elem);
+ }
+ return;
+ }
+
+ var _category = node.nodedef_node;
+ var _type = node.nodedef_type;
+
+ var isNodeGraph = node.type == 'graph/subgraph';
+ if (isNodeGraph) {
+ _category = 'nodegraph';
+ if (node.outputs) {
+ if (node.outputs.length > 1) {
+ _type = 'multi';
+ }
+ else if (node.outputs.length > 0) {
+ _type = node.outputs[0].type;
+ }
+ }
+ else {
+ _type = '';
+ }
+ }
+ else {
+ if (_category == 'surfacematerial') {
+ _type = '';
+ }
+ }
+
+ var elem = document.createElement("div");
+ elem.className = "row px-1 py-0";
+ var label = document.createElement("div");
+ label.className = "col-4 py-0 col-form-label-sm text-left";
+ label.innerHTML = "" + _category;
+ if (_type.length > 0) {
+ label.innerHTML += ' ' + _type;
+ }
+ label.innerHTML += " ";
+
+ var inputCol = document.createElement("div");
+ inputCol.className = "col text-left";
+ var nameInput = document.createElement("input");
+ nameInput.type = "text";
+ nameInput.value = node.title;
+ nameInput.className = "form-control form-control-sm";
+ nameInput.onchange = function (e) {
+ var oldTitle = node.title;
+ node.title = MxShadingGraphEditor.theEditor.handler.createValidName(e.target.value);
+ e.target.value = node.title;
+ //console.log('node.graph._is_subgraph:', node)
+ if (node.graph._is_subgraph) {
+ if (node.nodedef_node == 'input') {
+ //console.log('Rename subgraph input:');
+ node.graph.renameInput(oldTitle, node.title);
+ }
+ else if (node.nodedef_node == 'output') {
+ //console.log('Rename subgraph output:');
+ node.graph.renameOutput(oldTitle, node.title);
+ }
+ }
+
+ // Note: there is a custom size fo subgraphs.
+ node.setSize(node.computeSize());
+ node.setDirtyCanvas(true, true);
+ }
+ inputCol.appendChild(nameInput);
+
+ // TODO: Preview image
+ if (node.nodedef_node != 'input' && node.nodedef_node != 'output'
+ && node.type != 'graph/subgraph') {
+ var imagePreview = document.createElement("img");
+ imagePreview.src = "./Images/no_image.png";
+ var previewSet = false;
+ //console.log('Check for preview:', node.nodedef_swatch, 'category:', _category)
+ imagePreview.style.display = "none";
+ imagePreview.src = "./Images/no_image.png";
+ /* if (node.nodedef_swatch &&
+ (_type == 'BSDF' || _type == 'EDF' || _type == 'surfaceshader'))
+ {
+ this.uriExists(node.nodedef_swatch)
+ .then(exists => {
+ if (exists) {
+ previewSet = true;
+ imagePreview.style.display = "block";
+ imagePreview.src = node.nodedef_swatch;
+ }
+ });
+ } */
+ imagePreview.id = "propertypanel_preview";
+ imagePreview.className = "img-fluid form-control form-control-sm";
+ inputCol.appendChild(imagePreview);
+ }
+
+ elem.appendChild(label);
+ elem.appendChild(inputCol);
+ propertypanelcontent.appendChild(elem);
+
+ // TODO: Add toggle for showing/hiding all inputs
+ var addShow = false;
+ if (addShow) {
+ var elem = document.createElement("div");
+ elem.className = "row px-1 py-0";
+
+ var label = document.createElement("div");
+ label.className = "col-12 col-form-label-sm";
+ label.innerHTML = "All Inputs: ";
+ elem.appendChild(label);
+ var input = document.createElement("input");
+ input.type = "checkbox";
+ label.appendChild(input);
+
+ var showAll = false;
+ if (node.showAllInputs) {
+ showAll = node.showAllInputs;
+ }
+ input.checked = showAll;
+ input.onclick = function (e) {
+ var show = e.target.checked;
+ node.showAllInputs = show;
+
+ // Need to keep all old + new inputs in order. Easiest
+ // is to keep a list of all inputs, remove old and add new.
+ for (var index in node.properties_info) {
+ var propInfo = node.properties_info[index];
+ var found = false;
+ for (var i = 0; i < node.inputs.length; ++i) {
+ if (node.inputs[i].name == propInfo.name) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ console.log('Add missing input:', propInfo.name, propInfo.default_value, propInfo.type);
+ //node.addInput(propInfo.name, propInfo.type);
+ //node.addProperty(propInfo.name, propInfo.value, propInfo.type);
+ }
+ }
+ }
+
+ if (current_details)
+ current_details.appendChild(elem);
+ else
+ propertypanelcontent.appendChild(elem);
+ }
+
+ var hr = document.createElement("hr");
+ hr.classList.add("my-1");
+ propertypanelcontent.appendChild(hr);
+
+ var current_details = null;
+ var first_details = true;
+ var nodeInputs = node.inputs
+
+ var targetNodes = [];
+ for (var i in nodeInputs) {
+ var nodeInput = nodeInputs[i];
+ var inputName = nodeInput.name;
+ var nodeInputLink = nodeInput.link;
+ var uiName = inputName;
+ var uimin = null;
+ var uimax = null;
+ var colorspace = '';
+ var units = '';
+
+ //console.log('Scan input:', inputName, ' on node: ', node.graph);
+
+ var property_info = node.getPropertyInfo(inputName);
+ //console.log('1. get property info for i: ', inputName, 'info: ', property_info)
+
+ var skipInterorConnectedInput = false;
+ if (node.graph._is_subgraph)
+ {
+ // Find input on subgraph node
+ //console.log('Check subgraph for link:', node.graph)
+ var sg_node = node.graph._subgraph_node;
+ if (sg_node)
+ {
+ //console.log('Check for input on sg node', sg_node, node.title);
+ var slot = sg_node.findInputSlot(node.title);
+ if (slot != null)
+ {
+ if (sg_node.inputs)
+ {
+ //property_info = sg_node.properties_info[slot];
+ var slotInput = sg_node.inputs[slot];
+ //console.log('check slot: ', slotInput.link);
+ if (slotInput != null && slotInput.link != null)
+ {
+ skipInterorConnectedInput = true;
+ }
+ }
+ else
+ {
+ console.log('Error: no subgraph node inputs for subgraph input!', sg_node, node.title);
+ }
+ }
+ }
+ }
+
+ if (skipInterorConnectedInput)
+ {
+ console.log('Skip interior connected input: ', nodeInput);
+ continue;
+ }
+
+ //console.log('Property info:', property_info, ' for input:', inputName);
+ if (property_info)
+ {
+ if (property_info.colorspace)
+ {
+ colorspace = property_info.colorspace;
+ }
+ if (property_info.unit)
+ {
+ units = property_info.unit;
+ }
+ if (property_info.uiname)
+ {
+ uiName = property_info.uiname;
+ }
+ if (property_info.uimin)
+ {
+ uimin = property_info.uimin;
+ }
+ if (property_info.uimax)
+ {
+ uimax = property_info.uimax;
+ }
+ if (property_info.uifolder && property_info.uifolder.length > 0)
+ {
+ // Create a details element
+ if (current_details == null || current_details.id != property_info.uifolder)
+ {
+ //console.log('Create new details:', property_info.uifolder);
+ current_details = document.createElement("details");
+ current_details.id = property_info.uifolder;
+ current_details.open = first_details;
+ current_details.classList.add('w-100', 'p-1', 'border', 'border-secondary', 'rounded', 'my-1');
+ first_details = false;
+ var summary = document.createElement('summary')
+ summary.innerHTML = property_info.uifolder;
+ //summary.classList.add('btn', 'btn-sm', 'btn-outline-secondary', 'btn-block');
+ current_details.appendChild(summary);
+
+ propertypanelcontent.appendChild(current_details);
+ }
+ else
+ {
+ //current_details = null;
+ }
+ }
+ else {
+ current_details = null;
+ }
+ //console.log('2. uiName:', uiName, 'uimin:', uimin, 'uimax:', uimax, 'uiFolder:', property_info.uifolder);
+ }
+ else {
+ current_details = null;
+ }
+
+ var elem = null;
+
+ // Check if there is a link
+ if (nodeInputLink) {
+ let upstreamLink = null;
+
+ let nodegraph = node.graph;
+ let link = nodegraph.links[nodeInputLink];
+ //console.log('link:', link);
+ let linkId = link && link.origin_id;
+ let linkNode = linkId && nodegraph.getNodeById(linkId);
+ if (linkNode) {
+
+
+ //console.log('linkNode:', linkNode);
+ let linkSlot = link.origin_slot;
+ //console.log('linkSlot:', linkSlot);
+ let linkOutput = linkNode.outputs[linkSlot];
+ //console.log('linkOutput:', linkOutput);
+ upstreamLink = linkNode.title + '.' + linkOutput.name;
+ //console.log('upstreamLink:', upstreamLink);
+
+ let id = "__pp:" + inputName;
+ let buttonText = upstreamLink;
+ // Truncate long names
+ if (buttonText.length > 15) {
+ buttonText = buttonText.substring(0, 15) + "...";
+ }
+ let input = this.createButtonWithImageAndText("./Images/arrow_up_white.svg", buttonText, id);
+
+ //var input = document.createElement("div");
+ //input.id = "__pp:" + inputName;
+ //input.type = "text";
+ //input.value = upstreamLink;
+ //input.disabled = true;
+ //input.className = "btn form-control form-control-sm";
+ //input.style = "background-color: #252";
+ input.onclick = function (e) {
+
+ var inputName = e.target.id;
+ inputName = inputName.replace('__pp:', '');
+ inputName = inputName.replace('_text', '');
+ inputName = inputName.replace('_img', '');
+ console.log('Clicked traversal button:', inputName);
+
+ console.log('Jump to node:', linkNode.title);
+ graphcanvas.selectNodes([linkNode]);
+ //node.setDirtyCanvas(true, true);
+ MxShadingGraphEditor.theEditor.updatePropertyPanel(linkNode);
+ node.setDirtyCanvas(true, true);
+ }
+
+ // Add new row
+ elem = document.createElement("div");
+ elem.className = "row px-1 py-0";
+
+ input.id = "__pp:" + inputName;
+
+ var label = document.createElement("div");
+ label.className = "col-4 p-0 col-form-label-sm text-end";
+ label.innerHTML = uiName;
+ label.for = input.id;
+ elem.appendChild(label);
+
+ // form-control
+ if (useFormControl) {
+ input.classList.add("form-control");
+ }
+ input.classList.add("form-control-sm");
+ // Disable if don't want interaction.
+ if (!graphcanvas.allow_interaction)
+ input.disabled = true;
+
+ var propvalue = document.createElement("div");
+ propvalue.className = "col p-1";
+ propvalue.appendChild(input);
+
+ elem.appendChild(propvalue);
+ }
+ }
+
+ else {
+
+ targetNodes[i] = node;
+ let targetNode = targetNodes[i];
+ var propertyKey = inputName;
+
+ var property = targetNode.properties[inputName];
+ if (property == null) {
+ if (isNodeGraph)
+ {
+ var subgraph = targetNode.subgraph;
+ if (subgraph)
+ {
+ //console.log('Find node by title', inputName, ' in subgraph', subgraph._nodes);
+ var subNode = subgraph.findNodeByTitle(inputName);
+ if (subNode)
+ {
+ targetNodes[i] = subNode;
+ propertyKey = 'in';
+ property = targetNodes[i].properties['in'];
+ //console.log('Route to subgraph target node:', targetNode, targetNode.title, '. ', inputName, ' = ', JSON.stringify(property), 'propkey=', propertyKey);
+ }
+ }
+ }
+ if (property == null)
+ {
+ console.log('Update: Cannot find property value for input:', inputName);
+ continue;
+ }
+ }
+ else {
+ //console.log('handle propery value: ', property, 'for input', input);
+ }
+
+ // Add new row
+ elem = document.createElement("div");
+ elem.className = "row px-1 py-0";
+
+ var input = null;
+ var input_btn = null;
+ var colorspace_unit_btn = null;
+ var useFormControl = true;
+
+ // TODO: Clean this up to be a drop-down and only apply to numbers / colors
+ if (colorspace.length > 0) {
+ /*
+ // Create drop-down menu
+ /*
+ colorspace_unit_btn = document.createElement("div");
+ colorspace_unit_btn.classList.add("dropdown");
+ var dropdownButton = document.createElement("button");
+ dropdownButton.classList.add("btn", "btn-sm", "btn-outline-secondary", "dropdown-toggle");
+ dropdownButton.type = "button";
+ dropdownButton.id = "dropdownMenuButton";
+ dropdownButton.setAttribute("data-bs-toggle", "dropdown");
+ dropdownButton.setAttribute("aria-expanded", "false");
+ dropdownButton.innerHTML = "+";
+ var dropdownMenu = document.createElement("ul");
+ dropdownMenu.classList.add("dropdown-menu");
+ dropdownMenu.setAttribute("aria-labelledby", "dropdownMenuButton");
+ var dropdownItem = document.createElement("li");
+ dropdownItem.classList.add("dropdown-item");
+ dropdownItem.innerHTML = colorspace;
+ dropdownMenu.appendChild(dropdownItem);
+ colorspace_unit_btn.appendChild(dropdownMenu);
+ */
+ colorspace_unit_btn = document.createElement("button");
+ colorspace_unit_btn.classList.add("btn", "py-0", "btn-sm", "btn-outline-secondary");
+ colorspace_unit_btn.innerHTML = colorspace;
+
+ console.log('Show MetaData Colorspace:', colorspace, ' for input:', inputName, ' on node:', node.title)
+ }
+ else if (units.length > 0) {
+ colorspace_unit_btn = document.createElement("button");
+ colorspace_unit_btn.classList.add("btn", "py-0", "btn-sm", "btn-outline-secondary");
+ colorspace_unit_btn.innerHTML = units;
+ console.log('Show MetaData Units:', units, ' for input:', inputName, ' on node:', node.title)
+ }
+
+ var proptype = nodeInput.type;
+ if (proptype == 'float' || proptype == 'integer') {
+ var isFloat = proptype == 'float';
+ input = document.createElement("input");
+ input.type = 'number';
+ input.value = property;
+ if (uimin)
+ {
+ input.min = uimin;
+ }
+ if (uimax)
+ {
+ input.max = uimax;
+ }
+ if (input.min && input.max && isFloat)
+ {
+ input.step = uimax - uimin / 100.0;
+ }
+ input.setAttribute('propertyKey', propertyKey);
+ let theNode = targetNodes[i];
+ input.onchange = function (e) {
+ var pi = e.target.getAttribute('propertyKey');
+ var val = parseFloat(e.target.value);
+ theNode.properties[pi] = val;
+ console.log('Update scalar property:', pi, parseFloat(e.target.value), theNode.title, theNode.properties)
+ }
+ }
+ else if (proptype == 'string' || proptype == 'filename') {
+ input = document.createElement("input");
+ input.type = "text";
+ if (proptype == 'filename') {
+ var propertypanel_preview = document.getElementById('propertypanel_preview');
+ var curImage = property;
+ if (curImage && propertypanel_preview) {
+ this.uriExists(curImage)
+ .then(exists => {
+ if (exists) {
+ propertypanel_preview.src = curImage;
+ propertypanel_preview.style.display = "block";
+ } else {
+ //propertypanel_preview.style.display = "none";
+ propertypanel_preview.src = "./Images/no_image.png";
+ propertypanel_preview.style.display = "block";
+ MxShadingGraphEditor.theEditor.debugOutput('Image does not exist: ' + curImage, 1);
+ }
+ });
+ }
+
+ input_btn = document.createElement("button");
+ input_btn.classList.add("btn", "btn-sm", "btn-outline-secondary");
+ input_btn.innerHTML = "+";
+ input_btn.setAttribute('propertyKey', propertyKey);
+ var fileId = "__pp:" + inputName;
+ let theNode = targetNodes[i];
+ input_btn.onclick = function (e) {
+ var pi = e.target.getAttribute('propertyKey');
+ console.log('pi:', pi);
+ MxShadingGraphEditor.theEditor.openImageDialog(theNode, pi, false);
+ }
+ }
+ input.value = property;
+ input.setAttribute('propertyKey', propertyKey);
+ let theNode = targetNodes[i];
+ input.onchange = function (e) {
+ var pi = e.target.getAttribute('propertyKey');
+ theNode.properties[pi] = e.target.value;
+ console.log('Update string property:', pi, theNode.properties[pi])
+ }
+ }
+ else if (proptype == 'boolean') {
+ //console.log('Add Boolean property:', property);
+ input = document.createElement("input");
+ input.type = "checkbox";
+ input.classList = "form-check-input";
+ //input.style.width = "10%";
+ //input.style.height = "50%";
+ useFormControl = false;
+ input.checked = property;
+ input.setAttribute('propertyKey', propertyKey);
+ let theNode = targetNodes[i];
+ input.onchange = function (e) {
+ var pi = e.target.getAttribute('propertyKey');
+ theNode.properties[pi] = e.target.checked;
+ console.log('Update boolean property:', pi, theNode.properties[pi]);
+ }
+ }
+
+ else if (proptype == 'vector2' || proptype == 'vector3' || proptype == 'vector4') {
+ // Find index of proptype in ['vector2', 'vector3', 'vector4' ]
+ var vector_size = ['vector2', 'vector3', 'vector4'].indexOf(proptype) + 2;
+ var input = document.createElement("div");
+ useFormControl = false;
+
+ input.className = "row py-1 ps-2";
+ {
+ //console.log('Vector property:[', 0, '] = ', property[0], proptype)
+ var subinput = document.createElement("input");
+ subinput.type = 'number';
+ subinput.classList.add("form-control");
+ subinput.classList.add("form-control-sm");
+ subinput.value = property[0];
+ if (uimin) {
+ subinput.min = uimin[0];
+ }
+ if (uimax) {
+ subinput.max = uimax[0];
+ }
+ if (uimin && uimax) {
+ subinput.step = (uimax[0] - uimin[0]) / 100.0;
+ }
+ subinput.setAttribute('propertyKey', propertyKey);
+ let theNode = targetNodes[i];
+ subinput.onchange = function (e) {
+ var pi = e.target.getAttribute('propertyKey');
+ var value = parseFloat(e.target.value);
+ theNode.properties[pi][0] = value;
+ }
+ input.appendChild(subinput);
+ }
+ {
+ //console.log('Vector property:[', 1, '] = ', property[0], proptype)
+ var subinput = document.createElement("input");
+ subinput.type = 'number';
+ subinput.value = property[1];
+ if (uimin) {
+ subinput.min = uimin[1];
+ }
+ if (uimax) {
+ subinput.max = uimax[1];
+ }
+ if (uimin && uimax) {
+ subinput.step = (uimax[1] - uimin[1]) / 100.0;
+ }
+ subinput.setAttribute('propertyKey', propertyKey);
+ subinput.classList.add("form-control");
+ subinput.classList.add("form-control-sm");
+ let theNode = targetNodes[i];
+ subinput.onchange = function (e) {
+ var pi = e.target.getAttribute('propertyKey');
+ var value = parseFloat(e.target.value);
+ theNode.properties[pi][1] = value;
+ console.log('Update Vector property:"', pi, '"', 1, parseFloat(e.target.value), theNode.properties[pi])
+ }
+ input.appendChild(subinput);
+ }
+ if (vector_size > 2) {
+ //console.log('Vector property:[', 2, '] = ', property[0], proptype)
+ var subinput = document.createElement("input");
+ subinput.type = 'number';
+ if (uimin) {
+ subinput.min = uimin[2];
+ }
+ if (uimax) {
+ subinput.max = uimax[2];
+ }
+ if (uimin && uimax) {
+ subinput.step = (uimax[2] - uimin[2]) / 100.0;
+ }
+ subinput.value = property[2];
+ subinput.setAttribute('propertyKey', propertyKey);
+ subinput.classList.add("form-control");
+ subinput.classList.add("form-control-sm");
+ let theNode = targetNodes[i];
+ subinput.onchange = function (e) {
+ var pi = e.target.getAttribute('propertyKey');
+ var value = parseFloat(e.target.value);
+ theNode.properties[pi][2] = value;
+ console.log('Update Vector property:"', pi, '"', 2, parseFloat(e.target.value), theNode.properties[pi])
+ }
+ input.appendChild(subinput);
+ }
+ if (vector_size > 3) {
+ //console.log('Vector property:[', 3, '] = ', property[0], proptype)
+ var subinput = document.createElement("input");
+ subinput.type = 'number';
+ if (uimin) {
+ subinput.min = uimin[3];
+ }
+ if (uimax) {
+ subinput.max = uimax[3];
+ }
+ if (uimin && uimax) {
+ subinput.step = (uimax[3] - uimin[3]) / 100.0;
+ }
+ subinput.value = property[3];
+ subinput.setAttribute('propertyKey', propertyKey);
+ subinput.classList.add("form-control");
+ subinput.classList.add("form-control-sm");
+ let theNode = targetNodes[i];
+ subinput.onchange = function (e) {
+ var pi = e.target.getAttribute('propertyKey');
+ var value = parseFloat(e.target.value);
+ theNode.properties[pi][3] = value;
+ console.log('Update Vector property:"', pi, '"', 3, parseFloat(e.target.value), theNode.properties[pi])
+ }
+ input.appendChild(subinput);
+ }
+ }
+ else if (proptype == 'color3' || proptype == 'color4') {
+ input = document.createElement("input");
+ input.type = "color";
+ //console.log('set color property:', rgbToHex(property));
+ input.value = this.rgbToHex(property);
+ input.setAttribute('propertyKey', propertyKey);
+ let theNode = targetNodes[i];
+ input.onchange = function (e) {
+ // Convert hex to rgb in 0..1 range
+ var hex = e.target.value;
+ var rgb = [0, 0, 0];
+ rgb[0] = parseInt(hex.substring(1, 3), 16) / 255.0;
+ rgb[1] = parseInt(hex.substring(3, 5), 16) / 255.0;
+ rgb[2] = parseInt(hex.substring(5, 7), 16) / 255.0;
+
+ var pi = e.target.getAttribute('propertyKey');
+ theNode.properties[pi] = rgb;
+ console.log('set color property:', theNode.title, theNode.properties[pi], 'key=', pi, rgb, e.target.value);
+ }
+ }
+ else {
+ input = document.createElement("input");
+ input.type = "text";
+ input.value = property;
+ var propertyKey = inputName;
+ let theNode = targetNodes[i];
+ input.onchange = function (e) {
+ theNode.properties[propertyKey] = e.target.value;
+ }
+ }
+ /*
+ TODO: Handle enumerations
+ else if (proptype == 'enum') {
+ var input = document.createElement("select");
+ for (var j in nodes.inputs[i].values) {
+ var option = document.createElement("option");
+ option.value = j;
+ option.innerHTML = nodes.inputs[i].values[j];
+ input.appendChild(option);
+ }
+ input.value = property;
+ input.onchange = function (e) {
+ targetNode.properties[i] = e.target.value;
+ }
+ } */
+
+ if (input) {
+ input.id = "__pp:" + inputName;
+ //console.log('> Add input:', input.id);
+
+ var label = document.createElement("div");
+ label.className = "col-4 p-0 col-form-label-sm text-end font-small";
+ label.innerHTML = uiName;
+ label.for = input.id;
+ elem.appendChild(label);
+
+ // form-control
+ if (useFormControl) {
+ input.classList.add("form-control");
+ }
+ input.classList.add("form-control-sm");
+ // Disable if don't want interaction.
+ if (!graphcanvas.allow_interaction)
+ input.disabled = true;
+
+ var propvalue = document.createElement("div");
+ propvalue.className = "col py-0";
+ propvalue.appendChild(input);
+
+ if (input_btn) {
+ var propbutton = document.createElement("div");
+ propbutton.className = "col-1 py-0";
+ //console.log('Add input button:', input_btn);
+ propbutton.appendChild(input_btn);
+ elem.appendChild(propbutton);
+ }
+ if (colorspace_unit_btn) {
+ //console.log('Add cs / unit button:', input_btn);
+ var propbutton = document.createElement("div");
+ propbutton.className = "col col-form-label-sm font-small";
+ var details = document.createElement("details");
+ var summary = document.createElement('summary')
+ if (colorspace.length > 0)
+ summary.innerHTML = "Colorspace";
+ else if (units.length > 0)
+ summary.innerHTML = "Units";
+ details.appendChild(summary);
+ details.appendChild(colorspace_unit_btn);
+ propbutton.appendChild(details);
+ propvalue.appendChild(propbutton);
+ }
+ elem.appendChild(propvalue);
+ }
+ }
+ //elem.innerHTML = "" + i + " : " + property;
+ if (elem) {
+ if (current_details) {
+ //console.log('3a. append child to details:', current_details.id, elem, inputName);
+ current_details.appendChild(elem);
+ }
+ else {
+ propertypanelcontent.appendChild(elem);
+ //console.log('3b. append child to parent content:', elem, inputName);
+ }
+ }
+ }
+ }
+
+ onConnectOutput(slot, input_type, input, target_node, target_slot)
+ {
+ console.log('**** Connect output');
+ console.log(' - slot:', slot);
+ console.log(' - input type: ', input_type)
+ console.log(' - input:', input);
+ console.log(' - target_node', target_node);
+ console.log(' - target slot', target_slot);
+ }
+
+ onConnectInput(target_slot, output_type, output, source, slot)
+ {
+ console.log('**** Node connection changed');
+ console.log(' - target_slot:', target_slot);
+ console.log(' - output_type: ', output_type)
+ console.log(' - output:', output);
+ console.log(' - source', source);
+ console.log(' - source slot', slot);
+ }
+
+ monitorGraph(theGraph, monitor) {
+ if (!theGraph)
+ return;
+
+ theGraph.onConnectionChange = null;
+ theGraph.onNodeAdded = null;
+ theGraph.onNodeRemoved = null;
+
+ if (monitor) {
+
+ var that = this;
+ //console.log('Monitor connection change:', theGraph.title);
+ theGraph.onConnectionChange = function (node)
+ {
+ //console.log('On connection change:', node.title, node);
+ var selected = graphcanvas.selected_nodes;
+ for (var s in selected) {
+ console.log('update selected node:', selected[s].title);
+ that.updatePropertyPanel(selected[s]);
+ break;
+ }
+ }
+
+ //console.log('Monitor graph add:', theGraph.title);
+ theGraph.onNodeAdded = function (node) {
+
+ node.onConnectOutput = MxShadingGraphEditor.theEditor.onConnectOutput;
+
+ if (node.type == 'graph/subgraph') {
+ // Use MaterialX naming for subgraphs
+ //node.title = 'nodegraph';
+ //console.log('Monitor new subgraph node for connection change:', node.title, node);
+ node.onConnectInput = MxShadingGraphEditor.theEditor.onConnectInput;
+ //node.onConnectionChange = function (node) {
+ // console.log('**** Subgraph connection changed');
+ //}
+
+ //MxShadingGraphEditor.theEditor.monitorGraph(node.subgraph, monitor);
+
+ // Scan the subgraph for any nodes which are not in the node inputs list.
+ var node_subgraph = node.subgraph;
+ var node_graph = node.graph;
+ if (node_subgraph)
+ {
+ //console.log('** Scan subgraph: ', node_subgraph)
+ for (var i in node_subgraph._nodes)
+ {
+ let theNode = node_subgraph._nodes[i];
+ //console.log('*** scan subgrapn node: ', theNode.title)
+ if (!node_graph.findNodeByTitle(theNode.title))
+ {
+ if (theNode.nodedef_node == 'input') {
+ console.log('-0-0-0 add input', theNode.title)
+ node.addInput(theNode.title, theNode.nodedef_type);
+ console.log('--> Promote input node to subgraph node.', theNode.title);
+ }
+ else if (theNode.nodedef_node == 'output') {
+ console.log('--> Promote output node to subgraph node.', theNode.title);
+ node.addOutput(theNode.title, theNode.nodedef_type);
+ }
+ }
+ }
+ }
+ }
+
+ node.title = MxShadingGraphEditor.theEditor.handler.createValidName(node.title)
+ node.setSize(node.computeSize());
+ //console.log('-> Node Added:', node, '. Type:', node.type, '. Graph:', node.graph._2458graph);
+
+ // Expose node as an input or output on the subgraph
+ var is_subgraph = node.graph._is_subgraph;;
+ if (is_subgraph) {
+
+ if (node.nodedef_node == 'input') {
+ console.log('Adding input node to subgraph.', node.title, node.graph);
+ node.graph.addInput(node.title, node.nodedef_type);
+ }
+ else if (node.nodedef_node == 'output') {
+ console.log('Adding output node to subgraph.');
+ node.graph.addOutput(node.title, node.nodedef_type);
+ }
+ }
+
+ if (node.type == 'graph/subgraph') {
+ MxShadingGraphEditor.theEditor.monitorGraph(node.subgraph, monitor);
+ }
+ }
+
+ //console.log('Monitor graph remove:', theGraph.title);
+ theGraph.onNodeRemoved = function (node) {
+ //console.log('-> Node Removed:', node, '. Type:', node.type, '. Graph:', graphcanvas.graph);
+ /* This is too late the graph reference has already been removed */
+ var is_subgraph = graphcanvas.graph._is_subgraph;
+ if (is_subgraph) {
+ if (node.nodedef_node == 'input') {
+ console.log('Removing input node from subgraph.');
+ graphcanvas.graph.removeInput(node.title);
+ }
+ else if (node.nodedef_node == 'output') {
+ console.log('Removing output node from subgraph.');
+ graphcanvas.graph.removeOutput(node.title);
+ }
+ }
+ }
+ }
+
+
+ for (var i in theGraph._nodes) {
+ var node = theGraph._nodes[i];
+ if (node.type == 'graph/subgraph') {
+ //console.log('Monitor node:', node.title);
+ this.monitorGraph(node.subgraph, monitor);
+ node.onConnectInput = MxShadingGraphEditor.theEditor.onConnectInput;
+ //node.onConnectionChange = function (node) {
+ // console.log('**** Subgraph connection changed');
+ //}
+ }
+ }
+ }
+
+ initializeLiteGraph(canvas)
+ {
+ // Initialize Litegraph
+ graph = new LiteGraph.LGraph();
+ graphcanvas = new LiteGraph.LGraphCanvas(canvas, graph);
+ graphcanvas.onShowNodePanel = function (node) {
+ ; // Making this a no-op as will not use the default panel
+ }
+ graphcanvas.onNodeSelected = function (node) {
+ console.log('Selected node:', node.title, node);
+ MxShadingGraphEditor.theEditor.updatePropertyPanel(node);
+ }
+ graphcanvas.onNodeDeselected = function (node) {
+ //console.log('Node Deselected:', node);
+ MxShadingGraphEditor.theEditor.updatePropertyPanel(null);
+ }
+
+ // Todo: Move this to application site and expose settings to use.
+ graphcanvas.default_connection_color_byTypeOff = {
+ integer: "#A32",
+ float: "#161",
+ vector2: "#265",
+ vector3: "#465",
+ vector4: "#275",
+ color3: "#37A",
+ color4: "#69A",
+ matrix33: "#555",
+ matrix44: "#666",
+ string: "#395",
+ filename: "#888",
+ boolean: "#060",
+ };
+
+ graphcanvas.default_connection_color_byType = {
+ integer: "#D52",
+ float: "#1D1",
+ vector2: "#4D4",
+ vector3: "#7D7",
+ vector4: "#9D9",
+ color3: "#4AF",
+ color4: "#6CF",
+ matrix33: "#AAA",
+ matrix44: "#BBB",
+ string: "#3F4",
+ filename: "#FFF",
+ boolean: "#0F0",
+ };
+ /* float: "#666",
+ vector3: "#888",
+ color3: "#89A",
+ vector4: "#99B",
+ color4: "#9AC",
+ matrix33: "#9BD",
+ matrix44: "#9CE",
+ string: "#9DF",
+ filename: "#9EF",
+ boolean: "#AF0",
+ }; */
+
+ //console.log('Setup graph canvas:', graphcanvas);
+
+ graphcanvas.resize();
+
+ this.monitorGraph(graph, true);
+ graph.arrange(80);
+
+ // Run the graph
+ //graph.runStep();
+
+ // Enable interaction
+ //graphcanvas.hide_unconnected = false;
+ graphcanvas.allow_interaction = true;
+ graphcanvas.allow_dragnodes = true;
+ graphcanvas.allow_searchbox = true;
+ graphcanvas.render_connections_arrows = true;
+ graphcanvas.clear_background_color = "#222223";
+ graphcanvas.max_zoom = 0.25;
+ graphcanvas.connections_width = 2;
+ graphcanvas.render_canvas_border = false;
+ graphcanvas.align_to_grid = false;
+ graphcanvas.render_connection_arrows = false;
+ graphcanvas.render_curved_connections = true;
+ //graphcanvas.background_image = null;
+
+ // Turn off HUD
+ graphcanvas.show_info = false;
+
+ // Ad event handler to call centerOnNode with f key press within the canvas area
+ canvas.addEventListener("keydown", function (e) {
+ if (e.key === "f") {
+ MxShadingGraphEditor.theEditor.centerNode();
+ }
+ });
+
+ // Ad event handler to call array with l key press within the canvas area
+ canvas.addEventListener("keydown", function (e) {
+ if (e.key === "l") {
+ MxShadingGraphEditor.theEditor.arrangeGraph();
+ }
+ });
+
+ }
+
+ centerNode() {
+ var selected = graphcanvas.selected_nodes;
+ for (var s in selected) {
+ //console.log('Focus on', selected[s]);
+ graphcanvas.centerOnNode(selected[s]);
+ break;
+ }
+ }
+
+ clearNodeTypes() {
+ LiteGraph.searchbox_extras = [];
+ var nodeTypes = LiteGraph.registered_node_types;
+ for (var typeName in nodeTypes) {
+ if (typeName !== "graph/subgraph") {
+ console.log('Removing node type:', LiteGraph.getNodeType(typeName));
+ LiteGraph.unregisterNodeType(typeName);
+ }
+ }
+ }
+
+ collapseNode(node, collapse) {
+ if (node.constructor.collapsable === false) {
+ return false;
+ }
+ if (node.flags.collapsed != collapse) {
+ node.flags.collapsed = collapse;
+ return true;
+ }
+ return false;
+ }
+
+ collapseExpandNodes(collapse) {
+ var curGraph = graphcanvas.graph;
+
+ var selected_nodes = graphcanvas.selected_nodes;
+ console.log('Selected nodes:', selected_nodes);
+ var modified = false;
+ if (selected_nodes) {
+ for (var i in selected_nodes) {
+ var node = selected_nodes[i];
+ console.log('Collapse/Expand:', node.title, collapse);
+ if (this.collapseNode(node, collapse))
+ modified = true;
+ }
+ }
+ if (!modified)
+ {
+ var nodes = curGraph._nodes;
+ for (var i in nodes) {
+ var node = nodes[i];
+ if (this.collapseNode(node, collapse))
+ modified = true;
+ }
+ }
+
+ if (modified)
+ {
+ graph._version++;
+ graph.setDirtyCanvas(true, true);
+ }
+ }
+
+ copyToClipboard() {
+ graphcanvas.copyToClipboard();
+ }
+
+ pasteFromClipboard() {
+ graphcanvas.pasteFromClipboard();
+ }
+
+ extractNodeGraph() {
+ var selected = graphcanvas.selected_nodes;
+ if (selected.length == 0) {
+ console.log('No nodes selected.');
+ return;
+ }
+
+ var subgraphsSelected = []
+ for (var i in selected) {
+ var node = selected[i];
+ if (node.type == 'graph/subgraph') {
+ subgraphsSelected.push(node);
+ }
+ }
+ if (subgraphsSelected.length == 0) {
+ console.log('No subgraphs selected.');
+ return;
+ }
+
+ // Select subgraph nodes
+ var subGraph = subgraphsSelected[0];
+ var subGraphNodes = subGraph.subgraph._nodes;
+ for (var i in subGraphNodes) {
+ var node = subGraphNodes[i];
+ console.log('Select subgraph node:', node.title);
+ }
+
+ graphcanvas.openSubgraph(subGraph.subgraph);
+ graphcanvas.selectNodes(subGraphNodes);
+ // Copy the selected nodes to the clipboard
+ graphcanvas.copyToClipboard();
+
+ // Paste the copied nodes into the graph
+ graphcanvas.closeSubgraph();
+ graphcanvas.pasteFromClipboard();
+ }
+
+ createNodeGraph() {
+ // Disallow testing for now.
+ if (graphcanvas.graph._is_subgraph)
+ {
+ this.debugOutput('Cannot create nest subgraphs.', 1);
+ return;
+ }
+
+ // Check for selected nodes
+ var selected = graphcanvas.selected_nodes;
+ if (selected.length == 0) {
+ console.log('No nodes selected.');
+ return;
+ }
+
+ // Copy the selected nodes to the clipboard
+ graphcanvas.copyToClipboard();
+
+ // Create a new graph/subgraph node
+ var node = LiteGraph.createNode('graph/subgraph');
+ graph.add(node);
+ node.title = MxShadingGraphEditor.theEditor.handler.createValidName('group');
+ // Open subgraph
+ graphcanvas.openSubgraph(node.subgraph);
+ // Paste the copied nodes into the subgraph
+ graphcanvas.pasteFromClipboard();
+
+ node.subgraph.arrange(80);
+ graphcanvas.ds.reset();
+ graphcanvas.setDirty(true, true);
+ }
+
+ displayNodeTypes() {
+ // Get the list of available node types
+ var nodeTypes = LiteGraph.registered_node_types;
+
+ // Get the list container
+ var nodeList = this.ui.nodeTypesList;
+ if (!nodeList) {
+ return;
+ }
+
+ // Clear all children of nodeList
+ while (nodeList.firstChild) {
+ nodeList.removeChild(nodeList.firstChild);
+ }
+
+ // Iterate over the node types and add them to the list
+ for (var typeName in nodeTypes) {
+
+ var rowItem = document.createElement("tr");
+
+ var cellItem = document.createElement("td");
+ cellItem.textContent = typeName;
+ rowItem.appendChild(cellItem);
+
+ cellItem = document.createElement("td");
+ var nodeDefString = '';
+ var nodeDefName = nodeTypes[typeName].nodedef_name;
+ var nodeDefNode = nodeTypes[typeName].nodedef_node
+ var nodeDefHref = nodeTypes[typeName].nodedef_href;
+ if (nodeDefName) {
+ if (nodeDefNode)
+ {
+ var link = document.createElement("a");
+ link.target = "_blank";
+ link.href = nodeDefHref;
+ link.textContent = nodeDefNode + " ( " + nodeDefName + " )";
+ cellItem.appendChild(link);
+ }
+ else
+ {
+ cellItem.textContent = nodeDefName;
+ }
+ }
+ else {
+ cellItem.textContent = nodeDefString;
+ }
+ rowItem.appendChild(cellItem);
+
+ nodeList.appendChild(rowItem);
+ }
+ }
+
+
+ initialize(createMode, canvas, ui, materialFilename) {
+
+ this.setUI(ui);
+ this.initializeLiteGraph(canvas);
+ this.handler.initialize(MxShadingGraphEditor.theEditor, materialFilename);
+ }
+}
+
+/*
+document.addEventListener('DOMContentLoaded', () {
+ console.log('Setup property panel event handlers...')
+ var panel1 = document.getElementById('propertypanelcontent');
+ //var panel2 = document.getElementById('panel2');
+ var isDraggingPanel1 = false;
+ //var isDraggingPanel2 = false;
+ var offsetX1, offsetY1, offsetX2, offsetY2;
+
+ panel1.addEventListener('mousedown', (e) {
+ console.log('mousedown:', e.target.id);
+ isDraggingPanel1 = true;
+ var rect = panel1.getBoundingClientRect();
+ offsetX1 = e.clientX - rect.left;
+ offsetY1 = e.clientY - rect.top;
+ e.stopPropagation();
+ });
+
+
+ document.addEventListener('mousemove', (e) {
+ if (isDraggingPanel1) {
+ handleDragging(panel1, offsetX1, offsetY1, e);
+ }
+ });
+
+ document.addEventListener('mouseup', () {
+ isDraggingPanel1 = false;
+ //isDraggingPanel2 = false;
+ });
+
+ handleDragging(panel, offsetX, offsetY, e) {
+ var canvas = document.getElementById('graphcanvas');
+ var canvasRect = canvas.getBoundingClientRect();
+ var canvasLeft = canvasRect.left + window.pageXOffset;
+ var canvasTop = canvasRect.top + window.pageYOffset;
+ var canvasRight = canvasLeft + canvas.width;
+ var canvasBottom = canvasTop + canvas.height;
+
+ var x = e.clientX - offsetX;
+ var y = e.clientY - offsetY;
+
+ x = Math.min(Math.max(canvasLeft, x), canvasRight - panel.offsetWidth);
+ y = Math.min(Math.max(canvasTop, y), canvasBottom - panel.offsetHeight);
+
+ panel.style.left = x - canvasLeft + 'px';
+ panel.style.top = y - canvasTop + 'px';
+ }
+}); */
diff --git a/javascript/viewer/dist/Lights/environment_map.mtlx b/javascript/shader_utilities/dist/Lights/environment_map.mtlx
similarity index 100%
rename from javascript/viewer/dist/Lights/environment_map.mtlx
rename to javascript/shader_utilities/dist/Lights/environment_map.mtlx
diff --git a/javascript/viewer/dist/Lights/irradiance/san_giuseppe_bridge.hdr b/javascript/shader_utilities/dist/Lights/irradiance/san_giuseppe_bridge.hdr
similarity index 100%
rename from javascript/viewer/dist/Lights/irradiance/san_giuseppe_bridge.hdr
rename to javascript/shader_utilities/dist/Lights/irradiance/san_giuseppe_bridge.hdr
diff --git a/javascript/viewer/dist/Lights/irradiance/san_giuseppe_bridge_split.hdr b/javascript/shader_utilities/dist/Lights/irradiance/san_giuseppe_bridge_split.hdr
similarity index 100%
rename from javascript/viewer/dist/Lights/irradiance/san_giuseppe_bridge_split.hdr
rename to javascript/shader_utilities/dist/Lights/irradiance/san_giuseppe_bridge_split.hdr
diff --git a/javascript/viewer/dist/Lights/san_giuseppe_bridge.hdr b/javascript/shader_utilities/dist/Lights/san_giuseppe_bridge.hdr
similarity index 100%
rename from javascript/viewer/dist/Lights/san_giuseppe_bridge.hdr
rename to javascript/shader_utilities/dist/Lights/san_giuseppe_bridge.hdr
diff --git a/javascript/viewer/dist/Lights/san_giuseppe_bridge_split.hdr b/javascript/shader_utilities/dist/Lights/san_giuseppe_bridge_split.hdr
similarity index 100%
rename from javascript/viewer/dist/Lights/san_giuseppe_bridge_split.hdr
rename to javascript/shader_utilities/dist/Lights/san_giuseppe_bridge_split.hdr
diff --git a/javascript/viewer/dist/Lights/san_giuseppe_bridge_split.mtlx b/javascript/shader_utilities/dist/Lights/san_giuseppe_bridge_split.mtlx
similarity index 100%
rename from javascript/viewer/dist/Lights/san_giuseppe_bridge_split.mtlx
rename to javascript/shader_utilities/dist/Lights/san_giuseppe_bridge_split.mtlx
diff --git a/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_baseColor.png b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_baseColor.png
new file mode 100644
index 00000000..992429df
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_baseColor.png differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_emissive.png b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_emissive.png
new file mode 100644
index 00000000..315a4994
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_emissive.png differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_normal.png b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_normal.png
new file mode 100644
index 00000000..19d7afbe
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_normal.png differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_occlusionRoughnessMetallic.png b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_occlusionRoughnessMetallic.png
new file mode 100644
index 00000000..4370d609
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/boombox/BoomBox_occlusionRoughnessMetallic.png differ
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox.md b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox.md
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox.md
diff --git a/javascript/materialxnode/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox.mtlx b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox.mtlx
similarity index 94%
rename from javascript/materialxnode/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox.mtlx
index 72d23a8c..34052699 100644
--- a/javascript/materialxnode/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox.mtlx
+++ b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox.mtlx
@@ -1,5 +1,5 @@
-
+
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox_connections.json b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_boombox_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint.md b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint.md
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint.md
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint.mtlx b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint_connections.json b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_carpaint_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_default.md b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_default.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_default.md
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_default.md
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_default_connections.json b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_default_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_default_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_default_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_glass.md b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_glass.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_glass.md
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_glass.md
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_glass.mtlx b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_glass.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_glass.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_glass.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_glass_connections.json b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_glass_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_glass_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_glass_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_gold.md b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_gold.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_gold.md
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_gold.md
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_gold.mtlx b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_gold.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_gold.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_gold.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_gold_connections.json b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_gold_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_gold_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_gold_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic.md b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic.md
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic.md
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic.mtlx b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic_connections.json b/javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/GltfPbr/gltf_pbr_plastic_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_aluminum_brushed.mtlx b/javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_aluminum_brushed.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_aluminum_brushed.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_aluminum_brushed.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_carpaint.mtlx b/javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_carpaint.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_carpaint.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_carpaint.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_default.mtlx b/javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_default.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_default.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_default.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_glass.mtlx b/javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_glass.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_glass.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_glass.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_honey.mtlx b/javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_honey.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_honey.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_honey.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_ketchup.mtlx b/javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_ketchup.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_ketchup.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_ketchup.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_lightbulb.mtlx b/javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_lightbulb.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_lightbulb.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_lightbulb.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_pearl.mtlx b/javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_pearl.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_pearl.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_pearl.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_soapbubble.mtlx b/javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_soapbubble.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_soapbubble.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_soapbubble.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_velvet.mtlx b/javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_velvet.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/OpenPBR/open_pbr_velvet.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/OpenPBR/open_pbr_velvet.mtlx
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_black_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_black_base_color.jpg
new file mode 100644
index 00000000..b74cbc50
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_black_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_black_normal.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_black_normal.jpg
new file mode 100644
index 00000000..f205522e
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_black_normal.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_black_roughness.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_black_roughness.jpg
new file mode 100644
index 00000000..b6fafcf2
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_black_roughness.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_shared_metallic.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_shared_metallic.jpg
new file mode 100644
index 00000000..d58c8a9d
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_shared_metallic.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_white_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_white_base_color.jpg
new file mode 100644
index 00000000..bdd10f05
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_white_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_white_normal.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_white_normal.jpg
new file mode 100644
index 00000000..e7e825fe
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_white_normal.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_white_roughness.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_white_roughness.jpg
new file mode 100644
index 00000000..91ff237e
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/bishop_white_roughness.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_black_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_black_base_color.jpg
new file mode 100644
index 00000000..101fb07f
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_black_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_shared_metallic.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_shared_metallic.jpg
new file mode 100644
index 00000000..98ebcb2b
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_shared_metallic.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_shared_normal.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_shared_normal.jpg
new file mode 100644
index 00000000..4e6e5a93
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_shared_normal.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_shared_roughness.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_shared_roughness.jpg
new file mode 100644
index 00000000..6d67f883
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_shared_roughness.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_white_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_white_base_color.jpg
new file mode 100644
index 00000000..92cccfdf
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/castle_white_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_base_color.jpg
new file mode 100644
index 00000000..73ad4112
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_metallic.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_metallic.jpg
new file mode 100644
index 00000000..8e54561e
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_metallic.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_normal.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_normal.jpg
new file mode 100644
index 00000000..d02f3dc1
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_normal.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_roughness.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_roughness.jpg
new file mode 100644
index 00000000..9639d245
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/chessboard_roughness.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_black_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_black_base_color.jpg
new file mode 100644
index 00000000..5b0cd472
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_black_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_black_normal.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_black_normal.jpg
new file mode 100644
index 00000000..61983b3b
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_black_normal.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_black_roughness.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_black_roughness.jpg
new file mode 100644
index 00000000..3a81b206
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_black_roughness.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_shared_metallic.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_shared_metallic.jpg
new file mode 100644
index 00000000..9fc424a6
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_shared_metallic.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_shared_scattering.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_shared_scattering.jpg
new file mode 100644
index 00000000..be5468f4
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_shared_scattering.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_white_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_white_base_color.jpg
new file mode 100644
index 00000000..abe33ebe
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_white_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_white_normal.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_white_normal.jpg
new file mode 100644
index 00000000..65e868d4
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_white_normal.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_white_roughness.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_white_roughness.jpg
new file mode 100644
index 00000000..5bbace7f
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/king_white_roughness.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_black_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_black_base_color.jpg
new file mode 100644
index 00000000..68b9d920
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_black_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_black_normal.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_black_normal.jpg
new file mode 100644
index 00000000..223a038b
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_black_normal.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_black_roughness.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_black_roughness.jpg
new file mode 100644
index 00000000..111fccf6
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_black_roughness.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_white_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_white_base_color.jpg
new file mode 100644
index 00000000..e7d34b23
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_white_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_white_normal.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_white_normal.jpg
new file mode 100644
index 00000000..be398eea
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_white_normal.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_white_roughness.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_white_roughness.jpg
new file mode 100644
index 00000000..2201a35e
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/knight_white_roughness.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_black_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_black_base_color.jpg
new file mode 100644
index 00000000..f4280f07
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_black_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_shared_metallic.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_shared_metallic.jpg
new file mode 100644
index 00000000..cd0d5a67
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_shared_metallic.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_shared_normal.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_shared_normal.jpg
new file mode 100644
index 00000000..26448089
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_shared_normal.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_shared_roughness.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_shared_roughness.jpg
new file mode 100644
index 00000000..fd964619
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_shared_roughness.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_white_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_white_base_color.jpg
new file mode 100644
index 00000000..d9908093
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/pawn_white_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_black_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_black_base_color.jpg
new file mode 100644
index 00000000..3e4207c5
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_black_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_black_normal.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_black_normal.jpg
new file mode 100644
index 00000000..76158911
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_black_normal.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_black_roughness.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_black_roughness.jpg
new file mode 100644
index 00000000..8c146f05
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_black_roughness.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_shared_metallic.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_shared_metallic.jpg
new file mode 100644
index 00000000..5f82821e
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_shared_metallic.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_shared_scattering.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_shared_scattering.jpg
new file mode 100644
index 00000000..efecb700
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_shared_scattering.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_white_base_color.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_white_base_color.jpg
new file mode 100644
index 00000000..89d6825e
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_white_base_color.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_white_normal.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_white_normal.jpg
new file mode 100644
index 00000000..54238c0b
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_white_normal.jpg differ
diff --git a/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_white_roughness.jpg b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_white_roughness.jpg
new file mode 100644
index 00000000..f8a981ed
Binary files /dev/null and b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/chess_set/queen_white_roughness.jpg differ
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/gooch_shade.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/gooch_shade.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/gooch_shade.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/gooch_shade.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/gooch_shade.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/gooch_shade.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/gooch_shade.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/gooch_shade.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/gooch_shade_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/gooch_shade_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/gooch_shade_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/gooch_shade_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled.mtlx
similarity index 94%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled.mtlx
index bc59bf17..89abdf3a 100644
--- a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled.mtlx
+++ b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled.mtlx
@@ -1,5 +1,5 @@
-
+
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled_graph.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled_graph.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled_graph.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brass_tiled_graph.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural.mtlx
similarity index 98%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural.mtlx
index 1d6f6da6..27476f42 100644
--- a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural.mtlx
+++ b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural.mtlx
@@ -1,5 +1,5 @@
-
+
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_brick_procedural_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_carpaint.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_carpaint.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_carpaint.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_carpaint.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_carpaint.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_carpaint.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_carpaint.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_carpaint.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_carpaint_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_carpaint_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_carpaint_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_carpaint_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chess_set.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chess_set.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chess_set.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chess_set.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx
similarity index 99%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx
index 96e8a658..7fb96c37 100644
--- a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx
+++ b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chess_set.mtlx
@@ -1,5 +1,5 @@
-
+
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chess_set_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chess_set_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chess_set_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chess_set_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chrome.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chrome.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chrome.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chrome.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chrome.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chrome.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chrome.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chrome.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chrome_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chrome_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_chrome_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_chrome_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_copper.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_copper.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_copper.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_copper.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_copper.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_copper.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_copper.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_copper.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_copper_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_copper_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_copper_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_copper_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_default.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_default.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_default.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_default.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_default.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_default.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_default.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_default.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_default_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_default_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_default_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_default_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_glass_tinted_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_gold.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_gold.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_gold.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_gold.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_gold.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_gold.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_gold.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_gold.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_gold_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_gold_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_gold_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_gold_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_greysphere.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_greysphere.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_greysphere.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_greysphere.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.md
diff --git a/javascript/materialxnode/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.mtlx
similarity index 94%
rename from javascript/materialxnode/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.mtlx
index 9e3ada7c..79e39088 100644
--- a/javascript/materialxnode/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.mtlx
+++ b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration.mtlx
@@ -1,5 +1,5 @@
-
+
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_calibration_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_greysphere_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_jade.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_jade.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_jade.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_jade.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_jade.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_jade.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_jade.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_jade.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_jade_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_jade_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_jade_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_jade_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_look_wood_tiled.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_look_wood_tiled.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_look_wood_tiled.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_look_wood_tiled.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid_graph.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid_graph.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid_graph.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_marble_solid_graph.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_metal_brushed_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_plastic.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_plastic.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_plastic.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_plastic.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_plastic.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_plastic.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_plastic.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_plastic.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_plastic_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_plastic_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_plastic_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_plastic_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_thin_film.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_thin_film.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_thin_film.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_thin_film.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_thin_film.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_thin_film.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_thin_film.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_thin_film.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_thin_film_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_thin_film_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_thin_film_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_thin_film_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_velvet.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_velvet.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_velvet.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_velvet.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_velvet.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_velvet.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_velvet.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_velvet.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_velvet_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_velvet_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_velvet_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_velvet_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled.mtlx
similarity index 95%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled.mtlx
index c030aa94..339f2147 100644
--- a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled.mtlx
+++ b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled.mtlx
@@ -1,6 +1,6 @@
-
+
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/standard_surface_wood_tiled_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/toon_shade.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/toon_shade.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/toon_shade.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/toon_shade.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/toon_shade.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/toon_shade.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/toon_shade.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/toon_shade.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/toon_shade_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/toon_shade_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/toon_shade_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/toon_shade_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon2.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon2.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon2.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon2.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon2.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon2.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon2.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon2.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon2_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon2_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon2_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon2_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon2_graph.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon2_graph.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon2_graph.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon2_graph.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/unity_polygon_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unity_polygon_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/unlitshader_default.md b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unlitshader_default.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/unlitshader_default.md
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unlitshader_default.md
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/unlitshader_default.mtlx b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unlitshader_default.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/unlitshader_default.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unlitshader_default.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/StandardSurface/unlitshader_default_connections.json b/javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unlitshader_default_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/StandardSurface/unlitshader_default_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/StandardSurface/unlitshader_default_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.md b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.md
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.md
diff --git a/javascript/materialxnode/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.mtlx b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.mtlx
similarity index 94%
rename from javascript/materialxnode/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.mtlx
index 59562e4a..e108eb80 100644
--- a/javascript/materialxnode/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.mtlx
+++ b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled.mtlx
@@ -1,6 +1,6 @@
-
+
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled_connections.json b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_brass_tiled_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.md b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.md
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.md
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.mtlx b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint_connections.json b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_carpaint_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.md b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.md
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.md
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default_connections.json b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_default_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.md b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.md
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.md
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.mtlx b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass_connections.json b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_glass_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.md b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.md
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.md
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.mtlx b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold_connections.json b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_gold_connections.json
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.md b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.md
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.md
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.md
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.mtlx b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.mtlx
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.mtlx
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic.mtlx
diff --git a/javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic_connections.json b/javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic_connections.json
similarity index 100%
rename from javascript/viewer/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic_connections.json
rename to javascript/shader_utilities/dist/Materials/Examples/UsdPreviewSurface/usd_preview_surface_plastic_connections.json
diff --git a/javascript/viewer/dist/index.html b/javascript/shader_utilities/dist/index.html
similarity index 98%
rename from javascript/viewer/dist/index.html
rename to javascript/shader_utilities/dist/index.html
index 65011257..b0e2cd5b 100644
--- a/javascript/viewer/dist/index.html
+++ b/javascript/shader_utilities/dist/index.html
@@ -384,7 +384,7 @@ Document Visualization
for (let i = 0; i < materialNodes.length; ++i) {
let materialNode = materialNodes[i];
if (materialNode) {
- console.log('Scan material: ', materialNode.getNamePath());
+ //console.log('Scan material: ', materialNode.getNamePath());
let shaderNodes = mmx.getShaderNodes(materialNode)
if (shaderNodes.length > 0) {
let shaderNodePath = shaderNodes[0].getNamePath()
@@ -471,16 +471,19 @@ Document Visualization
//console.log('----------- Renderable Items:', renderableItems);
// Update selection for renderables
let renderableItemSelect = document.getElementById('renderableItem');
- // Remove any previous children
- while (renderableItemSelect.firstChild) {
- renderableItemSelect.removeChild(renderableItemSelect.firstChild);
- }
- for (let i = 0; i < renderableItems.length; i++) {
- let item = renderableItems[i];
- let option = document.createElement('option');
- option.value = i;
- option.text = item; // item.getNamePath();
- renderableItemSelect.appendChild(option);
+ if (renderableItemSelect)
+ {
+ // Remove any previous children
+ while (renderableItemSelect.firstChild) {
+ renderableItemSelect.removeChild(renderableItemSelect.firstChild);
+ }
+ for (let i = 0; i < renderableItems.length; i++) {
+ let item = renderableItems[i];
+ let option = document.createElement('option');
+ option.value = i;
+ option.text = item; // item.getNamePath();
+ renderableItemSelect.appendChild(option);
+ }
}
return renderableItems;
diff --git a/javascript/viewer/dist/index_out.html b/javascript/shader_utilities/dist/index_out.html
similarity index 97%
rename from javascript/viewer/dist/index_out.html
rename to javascript/shader_utilities/dist/index_out.html
index 3f8478b1..f48dd467 100644
--- a/javascript/viewer/dist/index_out.html
+++ b/javascript/shader_utilities/dist/index_out.html
@@ -226,11 +226,13 @@ Utilities
@@ -582,7 +584,7 @@ Document Visualization
for (let i = 0; i < materialNodes.length; ++i) {
let materialNode = materialNodes[i];
if (materialNode) {
- console.log('Scan material: ', materialNode.getNamePath());
+ //console.log('Scan material: ', materialNode.getNamePath());
let shaderNodes = mmx.getShaderNodes(materialNode)
if (shaderNodes.length > 0) {
let shaderNodePath = shaderNodes[0].getNamePath()
@@ -669,16 +671,19 @@ Document Visualization
//console.log('----------- Renderable Items:', renderableItems);
// Update selection for renderables
let renderableItemSelect = document.getElementById('renderableItem');
- // Remove any previous children
- while (renderableItemSelect.firstChild) {
- renderableItemSelect.removeChild(renderableItemSelect.firstChild);
- }
- for (let i = 0; i < renderableItems.length; i++) {
- let item = renderableItems[i];
- let option = document.createElement('option');
- option.value = i;
- option.text = item; // item.getNamePath();
- renderableItemSelect.appendChild(option);
+ if (renderableItemSelect)
+ {
+ // Remove any previous children
+ while (renderableItemSelect.firstChild) {
+ renderableItemSelect.removeChild(renderableItemSelect.firstChild);
+ }
+ for (let i = 0; i < renderableItems.length; i++) {
+ let item = renderableItems[i];
+ let option = document.createElement('option');
+ option.value = i;
+ option.text = item; // item.getNamePath();
+ renderableItemSelect.appendChild(option);
+ }
}
return renderableItems;
diff --git a/javascript/viewer/dist/main.js b/javascript/shader_utilities/dist/main.js
similarity index 96%
rename from javascript/viewer/dist/main.js
rename to javascript/shader_utilities/dist/main.js
index 062e8aaf..ab135700 100644
--- a/javascript/viewer/dist/main.js
+++ b/javascript/shader_utilities/dist/main.js
@@ -26,7 +26,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
\**************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ findLights: () => (/* binding */ findLights),\n/* harmony export */ getLightRotation: () => (/* binding */ getLightRotation),\n/* harmony export */ getUniformValues: () => (/* binding */ getUniformValues),\n/* harmony export */ prepareEnvTexture: () => (/* binding */ prepareEnvTexture),\n/* harmony export */ registerLights: () => (/* binding */ registerLights)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n//\r\n// Copyright Contributors to the MaterialX Project\r\n// SPDX-License-Identifier: Apache-2.0\r\n//\r\n\r\n\r\n\r\n//import { getBufferFromFile } from './dropHandling.js';\r\n\r\nconst IMAGE_PROPERTY_SEPARATOR = \"_\";\r\nconst UADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"uaddressmode\";\r\nconst VADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"vaddressmode\";\r\nconst FILTER_TYPE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"filtertype\";\r\nconst IMAGE_PATH_SEPARATOR = \"/\";\r\n\r\n/**\r\n * Initialized the environment texture as MaterialX expects it\r\n * @param {THREE.Texture} texture\r\n * @param {Object} capabilities\r\n * @returns {THREE.Texture}\r\n */\r\nfunction prepareEnvTexture(texture, capabilities)\r\n{\r\n let newTexture = new three__WEBPACK_IMPORTED_MODULE_0__.DataTexture(texture.image.data, texture.image.width, texture.image.height, texture.format, texture.type);\r\n newTexture.wrapS = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n newTexture.anisotropy = capabilities.getMaxAnisotropy();\r\n newTexture.minFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearMipmapLinearFilter;\r\n newTexture.magFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n newTexture.generateMipmaps = true;\r\n newTexture.needsUpdate = true;\r\n\r\n return newTexture;\r\n}\r\n\r\n/**\r\n * Get Three uniform from MaterialX vector\r\n * @param {any} value\r\n * @param {any} dimension\r\n * @returns {THREE.Uniform}\r\n */\r\nfunction fromVector(value, dimension)\r\n{\r\n let outValue;\r\n if (value)\r\n {\r\n outValue = value.data();\r\n }\r\n else\r\n {\r\n outValue = [];\r\n for (let i = 0; i < dimension; ++i)\r\n outValue.push(0.0);\r\n }\r\n\r\n return outValue;\r\n}\r\n\r\n/**\r\n * Get Three uniform from MaterialX matrix\r\n * @param {mx.matrix} matrix\r\n * @param {mx.matrix.size} dimension\r\n */\r\nfunction fromMatrix(matrix, dimension)\r\n{\r\n let vec = [];\r\n if (matrix)\r\n {\r\n for (let i = 0; i < matrix.numRows(); ++i)\r\n {\r\n for (let k = 0; k < matrix.numColumns(); ++k)\r\n {\r\n vec.push(matrix.getItem(i, k));\r\n }\r\n }\r\n } else\r\n {\r\n for (let i = 0; i < dimension; ++i)\r\n vec.push(0.0);\r\n }\r\n\r\n return vec;\r\n}\r\n\r\nfunction loadTextureFile(uri, loader)\r\n{\r\n return new Promise((resolve, reject) =>\r\n {\r\n if (loader) \r\n {\r\n console.log(\"Load image file: \", uri); \r\n loader.load(\r\n uri,\r\n function (texture) {\r\n console.log('- Resolve texture:', texture);\r\n resolve(texture);\r\n },\r\n function (xhr) {\r\n // This function will be called while the texture is loading\r\n console.log((xhr.loaded / xhr.total) * 100 + '% loaded');\r\n },\r\n function (error) {\r\n resolve(null);\r\n // This function will be called if there is an error loading the texture\r\n //reject(new Error('Error loading texture: ' + error));\r\n }\r\n ); \r\n }\r\n });\r\n}\r\n\r\n// Function to load an image file and return a buffer using FileReader.readAsArrayBuffer()\r\nfunction getTextureBufferFromFile(filePath, textureLoader) {\r\n return new Promise((resolve, reject) => {\r\n // Create a FileReader\r\n const fileReader = new FileReader();\r\n\r\n // Event listener for the FileReader's load event\r\n //fileReader.addEventListener('load', function (event) {\r\n fileReader.onloadend = function (e)\r\n {\r\n // Get the result of the FileReader as an ArrayBuffer\r\n const buffer = event.target.result;\r\n\r\n // Convert the ArrayBuffer to a Uint8Array for examination\r\n //const uint8Array = new Uint8Array(buffer);\r\n\r\n console.log('--------- Loaded Buffer:', buffer, filePath, '---------');\r\n\r\n // Handle the obtained buffer\r\n console.log('Add texture buffer to cache:', filePath, ', ', buffer);\r\n\r\n const texture = loadTextureFile(URL.createObjectURL(new Blob([buffer])), textureLoader);\r\n //const texture = textureLoader.load(URL.createObjectURL(new Blob([buffer])));\r\n\r\n //const dataURL = 'data:image/jpeg;base64,' + btoa(String.fromCharCode.apply(null, uint8Array));\r\n //console.log('dataURL:', dataURL)\r\n //const texture = textureLoader.load(dataURL, function () {\r\n // Log the dimensions of the resulting texture\r\n // console.log('Texture dimensions:', texture.image.width, 'x', texture.image.height);\r\n //}); \r\n\r\n //const texture = textureLoader.load(texturePath);\r\n // Set address & filtering mode\r\n if (texture) {\r\n //THREE.Cache.add(filePath, texture);\r\n //setTextureParameters(texture, name, uniforms, flipY);\r\n //outValue = texture;\r\n console.log('Success: texture cached:', filePath, three__WEBPACK_IMPORTED_MODULE_0__.Cache.get(filePath));\r\n //let blah = THREE.Cache.get(texturePath);\r\n //if (blah)\r\n // console.log('blah.image.width:', blah.image.width, ', blah.image.height:', blah.image.height, ', blah.image.data:', blah.image.data, ', blah.image.data.length:', blah.image.data.length, ', blah.image.data.byteLength:', blah.image.data.byteLength, ', blah.image.data.buffer.byteLength:', blah.image.data.buffer.byteLength, ', blah.image.data.buffer:', blah.image.data.buffer);\r\n }\r\n else {\r\n console.error('Error: texture not found in cache:', filePath);\r\n }\r\n\r\n // Resolve the Promise with the obtained buffer\r\n resolve(texture);\r\n };\r\n\r\n // Event listener for errors during file reading\r\n fileReader.addEventListener('error', function (event) {\r\n result(null); // reject(new Error('Error reading file: ' + event.target.error));\r\n });\r\n\r\n // Read the content of the file as an ArrayBuffer\r\n fileReader.readAsArrayBuffer(new Blob([filePath]));\r\n });\r\n}\r\n\r\n\r\n// Function to load an image file and examine the dimensions of the loaded texture\r\nfunction examineImageFile(filePath, textureLoader) {\r\n return new Promise((resolve, reject) => {\r\n // Create a FileReader\r\n const fileReader = new FileReader();\r\n\r\n // Event listener for the FileReader's load event\r\n fileReader.addEventListener('load', function (event) {\r\n // Get the result of the FileReader as a data URL\r\n const dataURL = event.target.result;\r\n console.log('Load URL:', dataURL, filePath, '---------')\r\n\r\n // Create a texture using the data URL\r\n const texture = textureLoader.load(dataURL, function () {\r\n // Log the dimensions of the resulting texture\r\n console.log('Texture dimensions:', texture.image.width, 'x', texture.image.height);\r\n\r\n // Resolve the Promise with the loaded texture\r\n resolve(texture);\r\n });\r\n });\r\n\r\n // Event listener for errors during file reading\r\n fileReader.addEventListener('error', function (event) {\r\n reject(new Error('Error reading file: ' + event.target.error));\r\n });\r\n\r\n // Read the content of the file as a data URL\r\n fileReader.readAsDataURL(new Blob([filePath]));\r\n });\r\n}\r\n\r\n\r\n\r\n/**\r\n * Get Three uniform from MaterialX value\r\n * @param {mx.Uniform.type} type\r\n * @param {mx.Uniform.value} value\r\n * @param {mx.Uniform.name} name\r\n * @param {mx.Uniforms} uniforms\r\n * @param {THREE.textureLoader} textureLoader\r\n */\r\nfunction toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, flipY)\r\n{\r\n let outValue;\r\n switch (type)\r\n {\r\n case 'float':\r\n case 'integer':\r\n case 'boolean':\r\n outValue = value;\r\n break;\r\n case 'vector2':\r\n outValue = fromVector(value, 2);\r\n break;\r\n case 'vector3':\r\n case 'color3':\r\n outValue = fromVector(value, 3);\r\n break;\r\n case 'vector4':\r\n case 'color4':\r\n outValue = fromVector(value, 4);\r\n break;\r\n case 'matrix33':\r\n outValue = fromMatrix(value, 9);\r\n break;\r\n case 'matrix44':\r\n outValue = fromMatrix(value, 16);\r\n break;\r\n case 'filename':\r\n if (value)\r\n {\r\n let texturePath = searchPath + IMAGE_PATH_SEPARATOR + value;\r\n const textureExists = three__WEBPACK_IMPORTED_MODULE_0__.Cache.get(texturePath);\r\n if (!textureExists)\r\n {\r\n \r\n // Call the function to examine the image file\r\n /* examineImageFile(texturePath, textureLoader)\r\n .then(texture => {\r\n console.log('Add texture to cache:', texturePath, texture)\r\n setTextureParameters(texture, name, uniforms, flipY);\r\n outValue = texture; \r\n })\r\n .catch(error => {\r\n // Handle errors\r\n console.error('Error:', error);\r\n });\r\n */\r\n // Call the function to get a buffer from the file\r\n /*\r\n getTextureBufferFromFile(texturePath, textureLoader)\r\n .then(texture => {\r\n if (texture)\r\n setTextureParameters(texture, name, uniforms, flipY);\r\n outValue = texture;\r\n console.log('-- FINISHED loading: ' + texturePath)\r\n })\r\n .catch(error => {\r\n // Handle errors\r\n console.error('Error:', error);\r\n });\r\n */\r\n console.log('Image file not loaded: ', texturePath);\r\n }\r\n //else\r\n {\r\n const texture = textureLoader.load(texturePath);\r\n // Set address & filtering mode\r\n if (texture)\r\n {\r\n console.log('Loaded texture: ' + texturePath, ' searchPath: ' + searchPath + ' texture: ', texture)\r\n setTextureParameters(texture, name, uniforms, flipY);\r\n }\r\n else\r\n {\r\n console.error('Error: texture not found in cache:', texturePath);\r\n }\r\n outValue = texture;\r\n }\r\n }\r\n break;\r\n case 'samplerCube':\r\n case 'string':\r\n break;\r\n default:\r\n console.log('Value type not supported: ' + type);\r\n // struct\r\n outValue = null;//toThreeUniform(value);\r\n }\r\n\r\n return outValue;\r\n}\r\n\r\n/**\r\n * Get Three wrapping mode\r\n * @param {mx.TextureFilter.wrap} mode\r\n * @returns {THREE.Wrapping}\r\n */\r\nfunction getWrapping(mode)\r\n{\r\n let wrap;\r\n switch (mode)\r\n {\r\n case 1:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.ClampToEdgeWrapping;\r\n break;\r\n case 2:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n break;\r\n case 3:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.MirroredRepeatWrapping;\r\n break;\r\n default:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n break;\r\n }\r\n return wrap;\r\n}\r\n\r\n/**\r\n * Get Three minification filter\r\n * @param {mx.TextureFilter.minFilter} type\r\n * @param {mx.TextureFilter.generateMipmaps} generateMipmaps\r\n */\r\nfunction getMinFilter(type, generateMipmaps)\r\n{\r\n const filterType = generateMipmaps ? three__WEBPACK_IMPORTED_MODULE_0__.LinearMipMapLinearFilter : three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n if (type === 0)\r\n {\r\n filterType = generateMipmaps ? three__WEBPACK_IMPORTED_MODULE_0__.NearestMipMapNearestFilter : three__WEBPACK_IMPORTED_MODULE_0__.NearestFilter;\r\n }\r\n return filterType;\r\n}\r\n\r\n/**\r\n * Set Three texture parameters\r\n * @param {THREE.Texture} texture\r\n * @param {mx.Uniform.name} name\r\n * @param {mx.Uniforms} uniforms\r\n * @param {mx.TextureFilter.generateMipmaps} generateMipmaps\r\n */\r\nfunction setTextureParameters(texture, name, uniforms, flipY = true, generateMipmaps = true)\r\n{\r\n const idx = name.lastIndexOf(IMAGE_PROPERTY_SEPARATOR);\r\n const base = name.substring(0, idx) || name;\r\n\r\n texture.generateMipmaps = generateMipmaps;\r\n texture.wrapS = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n texture.wrapT = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n texture.magFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n texture.flipY = flipY;\r\n\r\n if (uniforms.find(base + UADDRESS_MODE_SUFFIX))\r\n {\r\n const uaddressmode = uniforms.find(base + UADDRESS_MODE_SUFFIX).getValue().getData();\r\n texture.wrapS = getWrapping(uaddressmode);\r\n }\r\n\r\n if (uniforms.find(base + VADDRESS_MODE_SUFFIX))\r\n {\r\n const vaddressmode = uniforms.find(base + VADDRESS_MODE_SUFFIX).getValue().getData();\r\n texture.wrapT = getWrapping(vaddressmode);\r\n }\r\n\r\n const filterType = uniforms.find(base + FILTER_TYPE_SUFFIX) ? uniforms.get(base + FILTER_TYPE_SUFFIX).value : -1;\r\n texture.minFilter = getMinFilter(filterType, generateMipmaps);\r\n}\r\n\r\n/**\r\n * Return the global light rotation matrix\r\n */\r\nfunction getLightRotation()\r\n{\r\n return new three__WEBPACK_IMPORTED_MODULE_0__.Matrix4().makeRotationY(Math.PI / 2);\r\n}\r\n\r\n/**\r\n * Returns all lights nodes in a MaterialX document\r\n * @param {mx.Document} doc \r\n * @returns {Array.}\r\n */\r\nfunction findLights(doc)\r\n{\r\n let lights = [];\r\n for (let node of doc.getNodes())\r\n {\r\n if (node.getType() === \"lightshader\")\r\n lights.push(node);\r\n }\r\n return lights;\r\n}\r\n\r\n/**\r\n * Register lights in shader generation context\r\n * @param {Object} mx MaterialX Module\r\n * @param {Array.} lights Light nodes\r\n * @param {mx.GenContext} genContext Shader generation context\r\n * @returns {Array.}\r\n */\r\nfunction registerLights(mx, lights, genContext)\r\n{\r\n mx.HwShaderGenerator.unbindLightShaders(genContext);\r\n\r\n const lightTypesBound = {};\r\n const lightData = [];\r\n let lightId = 1;\r\n for (let light of lights)\r\n {\r\n let nodeDef = light.getNodeDef();\r\n let nodeName = nodeDef.getName();\r\n if (!lightTypesBound[nodeName])\r\n {\r\n lightTypesBound[nodeName] = lightId;\r\n mx.HwShaderGenerator.bindLightShader(nodeDef, lightId++, genContext);\r\n }\r\n\r\n const lightDirection = light.getValueElement(\"direction\").getValue().getData().data();\r\n const lightColor = light.getValueElement(\"color\").getValue().getData().data();\r\n const lightIntensity = light.getValueElement(\"intensity\").getValue().getData();\r\n\r\n let rotatedLightDirection = new three__WEBPACK_IMPORTED_MODULE_0__.Vector3(...lightDirection)\r\n rotatedLightDirection.transformDirection(getLightRotation())\r\n\r\n lightData.push({\r\n type: lightTypesBound[nodeName],\r\n direction: rotatedLightDirection,\r\n color: new three__WEBPACK_IMPORTED_MODULE_0__.Vector3(...lightColor),\r\n intensity: lightIntensity\r\n });\r\n }\r\n\r\n // Make sure max light count is large enough\r\n genContext.getOptions().hwMaxActiveLightSources = Math.max(genContext.getOptions().hwMaxActiveLightSources, lights.length);\r\n\r\n return lightData;\r\n}\r\n\r\n/**\r\n * Get uniform values for a shader\r\n * @param {mx.shaderStage} shaderStage\r\n * @param {THREE.TextureLoader} textureLoader\r\n */\r\nfunction getUniformValues(shaderStage, textureLoader, searchPath, flipY)\r\n{\r\n let threeUniforms = {};\r\n\r\n const uniformBlocks = Object.values(shaderStage.getUniformBlocks());\r\n uniformBlocks.forEach(uniforms =>\r\n {\r\n if (!uniforms.empty())\r\n {\r\n for (let i = 0; i < uniforms.size(); ++i)\r\n {\r\n const variable = uniforms.get(i);\r\n const value = variable.getValue()?.getData();\r\n const name = variable.getVariable();\r\n threeUniforms[name] = new three__WEBPACK_IMPORTED_MODULE_0__.Uniform(toThreeUniform(variable.getType().getName(), value, name, uniforms,\r\n textureLoader, searchPath, flipY));\r\n }\r\n }\r\n });\r\n\r\n return threeUniforms;\r\n}\r\n\n\n//# sourceURL=webpack://MaterialX-Swatch-Viewer/./source/helper.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ findLights: () => (/* binding */ findLights),\n/* harmony export */ getLightRotation: () => (/* binding */ getLightRotation),\n/* harmony export */ getUniformValues: () => (/* binding */ getUniformValues),\n/* harmony export */ prepareEnvTexture: () => (/* binding */ prepareEnvTexture),\n/* harmony export */ registerLights: () => (/* binding */ registerLights)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n//\r\n// Copyright Contributors to the MaterialX Project\r\n// SPDX-License-Identifier: Apache-2.0\r\n//\r\n\r\n\r\n\r\n//import { getBufferFromFile } from './dropHandling.js';\r\n\r\nconst IMAGE_PROPERTY_SEPARATOR = \"_\";\r\nconst UADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"uaddressmode\";\r\nconst VADDRESS_MODE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"vaddressmode\";\r\nconst FILTER_TYPE_SUFFIX = IMAGE_PROPERTY_SEPARATOR + \"filtertype\";\r\nconst IMAGE_PATH_SEPARATOR = \"/\";\r\n\r\n/**\r\n * Initialized the environment texture as MaterialX expects it\r\n * @param {THREE.Texture} texture\r\n * @param {Object} capabilities\r\n * @returns {THREE.Texture}\r\n */\r\nfunction prepareEnvTexture(texture, capabilities)\r\n{\r\n let newTexture = new three__WEBPACK_IMPORTED_MODULE_0__.DataTexture(texture.image.data, texture.image.width, texture.image.height, texture.format, texture.type);\r\n newTexture.wrapS = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n newTexture.anisotropy = capabilities.getMaxAnisotropy();\r\n newTexture.minFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearMipmapLinearFilter;\r\n newTexture.magFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n newTexture.generateMipmaps = true;\r\n newTexture.needsUpdate = true;\r\n\r\n return newTexture;\r\n}\r\n\r\n/**\r\n * Get Three uniform from MaterialX vector\r\n * @param {any} value\r\n * @param {any} dimension\r\n * @returns {THREE.Uniform}\r\n */\r\nfunction fromVector(value, dimension)\r\n{\r\n let outValue;\r\n if (value)\r\n {\r\n outValue = value.data();\r\n }\r\n else\r\n {\r\n outValue = [];\r\n for (let i = 0; i < dimension; ++i)\r\n outValue.push(0.0);\r\n }\r\n\r\n return outValue;\r\n}\r\n\r\n/**\r\n * Get Three uniform from MaterialX matrix\r\n * @param {mx.matrix} matrix\r\n * @param {mx.matrix.size} dimension\r\n */\r\nfunction fromMatrix(matrix, dimension)\r\n{\r\n let vec = [];\r\n if (matrix)\r\n {\r\n for (let i = 0; i < matrix.numRows(); ++i)\r\n {\r\n for (let k = 0; k < matrix.numColumns(); ++k)\r\n {\r\n vec.push(matrix.getItem(i, k));\r\n }\r\n }\r\n } else\r\n {\r\n for (let i = 0; i < dimension; ++i)\r\n vec.push(0.0);\r\n }\r\n\r\n return vec;\r\n}\r\n\r\nfunction loadTextureFile(uri, loader)\r\n{\r\n return new Promise((resolve, reject) =>\r\n {\r\n if (loader) \r\n {\r\n console.log(\"Load image file: \", uri); \r\n loader.load(\r\n uri,\r\n function (texture) {\r\n console.log('- Resolve texture:', texture);\r\n resolve(texture);\r\n },\r\n function (xhr) {\r\n // This function will be called while the texture is loading\r\n console.log((xhr.loaded / xhr.total) * 100 + '% loaded');\r\n },\r\n function (error) {\r\n resolve(null);\r\n // This function will be called if there is an error loading the texture\r\n //reject(new Error('Error loading texture: ' + error));\r\n }\r\n ); \r\n }\r\n });\r\n}\r\n\r\n// Function to load an image file and return a buffer using FileReader.readAsArrayBuffer()\r\nfunction getTextureBufferFromFile(filePath, textureLoader) {\r\n return new Promise((resolve, reject) => {\r\n // Create a FileReader\r\n const fileReader = new FileReader();\r\n\r\n // Event listener for the FileReader's load event\r\n //fileReader.addEventListener('load', function (event) {\r\n fileReader.onloadend = function (e)\r\n {\r\n // Get the result of the FileReader as an ArrayBuffer\r\n const buffer = e.target.result;\r\n\r\n // Convert the ArrayBuffer to a Uint8Array for examination\r\n //const uint8Array = new Uint8Array(buffer);\r\n\r\n console.log('--------- Loaded Buffer:', buffer, filePath, '---------');\r\n\r\n // Handle the obtained buffer\r\n console.log('Add texture buffer to cache:', filePath, ', ', buffer);\r\n\r\n const texture = loadTextureFile(URL.createObjectURL(new Blob([buffer])), textureLoader);\r\n //const texture = textureLoader.load(URL.createObjectURL(new Blob([buffer])));\r\n\r\n //const dataURL = 'data:image/jpeg;base64,' + btoa(String.fromCharCode.apply(null, uint8Array));\r\n //console.log('dataURL:', dataURL)\r\n //const texture = textureLoader.load(dataURL, function () {\r\n // Log the dimensions of the resulting texture\r\n // console.log('Texture dimensions:', texture.image.width, 'x', texture.image.height);\r\n //}); \r\n\r\n //const texture = textureLoader.load(texturePath);\r\n // Set address & filtering mode\r\n if (texture) {\r\n //THREE.Cache.add(filePath, texture);\r\n //setTextureParameters(texture, name, uniforms, flipY);\r\n //outValue = texture;\r\n console.log('Success: texture cached:', filePath, three__WEBPACK_IMPORTED_MODULE_0__.Cache.get(filePath));\r\n //let blah = THREE.Cache.get(texturePath);\r\n //if (blah)\r\n // console.log('blah.image.width:', blah.image.width, ', blah.image.height:', blah.image.height, ', blah.image.data:', blah.image.data, ', blah.image.data.length:', blah.image.data.length, ', blah.image.data.byteLength:', blah.image.data.byteLength, ', blah.image.data.buffer.byteLength:', blah.image.data.buffer.byteLength, ', blah.image.data.buffer:', blah.image.data.buffer);\r\n }\r\n else {\r\n console.error('Error: texture not found in cache:', filePath);\r\n }\r\n\r\n // Resolve the Promise with the obtained buffer\r\n resolve(texture);\r\n };\r\n\r\n // Event listener for errors during file reading\r\n fileReader.addEventListener('error', function (event) {\r\n result(null); // reject(new Error('Error reading file: ' + event.target.error));\r\n });\r\n\r\n // Read the content of the file as an ArrayBuffer\r\n fileReader.readAsArrayBuffer(new Blob([filePath]));\r\n });\r\n}\r\n\r\n\r\n// Function to load an image file and examine the dimensions of the loaded texture\r\nfunction examineImageFile(filePath, textureLoader) {\r\n return new Promise((resolve, reject) => {\r\n // Create a FileReader\r\n const fileReader = new FileReader();\r\n\r\n // Event listener for the FileReader's load event\r\n fileReader.addEventListener('load', function (event) {\r\n // Get the result of the FileReader as a data URL\r\n const dataURL = event.target.result;\r\n console.log('Load URL:', dataURL, filePath, '---------')\r\n\r\n // Create a texture using the data URL\r\n const texture = textureLoader.load(dataURL, function () {\r\n // Log the dimensions of the resulting texture\r\n console.log('Texture dimensions:', texture.image.width, 'x', texture.image.height);\r\n\r\n // Resolve the Promise with the loaded texture\r\n resolve(texture);\r\n });\r\n });\r\n\r\n // Event listener for errors during file reading\r\n fileReader.addEventListener('error', function (event) {\r\n reject(new Error('Error reading file: ' + event.target.error));\r\n });\r\n\r\n // Read the content of the file as a data URL\r\n fileReader.readAsDataURL(new Blob([filePath]));\r\n });\r\n}\r\n\r\n\r\n\r\n/**\r\n * Get Three uniform from MaterialX value\r\n * @param {mx.Uniform.type} type\r\n * @param {mx.Uniform.value} value\r\n * @param {mx.Uniform.name} name\r\n * @param {mx.Uniforms} uniforms\r\n * @param {THREE.textureLoader} textureLoader\r\n */\r\nfunction toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, flipY)\r\n{\r\n let outValue = null;\r\n switch (type)\r\n {\r\n case 'float':\r\n case 'integer':\r\n case 'boolean':\r\n outValue = value;\r\n break;\r\n case 'vector2':\r\n outValue = fromVector(value, 2);\r\n break;\r\n case 'vector3':\r\n case 'color3':\r\n outValue = fromVector(value, 3);\r\n break;\r\n case 'vector4':\r\n case 'color4':\r\n outValue = fromVector(value, 4);\r\n break;\r\n case 'matrix33':\r\n outValue = fromMatrix(value, 9);\r\n break;\r\n case 'matrix44':\r\n outValue = fromMatrix(value, 16);\r\n break;\r\n case 'filename':\r\n if (value)\r\n {\r\n let texturePath = searchPath + IMAGE_PATH_SEPARATOR + value;\r\n if (value.startsWith('blob:')) \r\n {\r\n texturePath = value;\r\n console.log('Load blob URL:', texturePath);\r\n }\r\n else if (value.startsWith('http'))\r\n {\r\n texturePath = value;\r\n console.log('Load HTTP URL:', texturePath);\r\n }\r\n else if (value.startsWith('data:'))\r\n {\r\n texturePath = value;\r\n console.log('Load data URL:', texturePath);\r\n }\r\n else\r\n {\r\n console.log('Load image file:', texturePath);\r\n }\r\n const textureExists = three__WEBPACK_IMPORTED_MODULE_0__.Cache.get(texturePath);\r\n if (!textureExists)\r\n {\r\n \r\n // Call the function to examine the image file\r\n /* examineImageFile(texturePath, textureLoader)\r\n .then(texture => {\r\n console.log('Add texture to cache:', texturePath, texture)\r\n setTextureParameters(texture, name, uniforms, flipY);\r\n outValue = texture; \r\n })\r\n .catch(error => {\r\n // Handle errors\r\n console.error('Error:', error);\r\n });\r\n */\r\n // Call the function to get a buffer from the file\r\n /*\r\n getTextureBufferFromFile(texturePath, textureLoader)\r\n .then(texture => {\r\n if (texture)\r\n setTextureParameters(texture, name, uniforms, flipY);\r\n outValue = texture;\r\n console.log('-- FINISHED loading: ' + texturePath)\r\n })\r\n .catch(error => {\r\n // Handle errors\r\n console.error('Error:', error);\r\n });\r\n */\r\n //console.log('Image file not loaded: ', texturePath);\r\n }\r\n //else\r\n {\r\n outValue = textureLoader.load(\r\n texturePath, \r\n function (texture) {\r\n console.log('Loaded texture: ' + texturePath, texture);\r\n /* console.log('Texture image properties:');\r\n console.log('Width:', texture.image.width);\r\n console.log('Height:', texture.image.height);\r\n console.log('Format:', texture.image.format);\r\n console.log('Is Data Loaded:', texture.image.complete); // */ \r\n outValue = texture;\r\n },\r\n undefined,\r\n function (error) {\r\n console.error('Error loading texture: ', error);\r\n }); \r\n\r\n // Set address & filtering mode\r\n if (outValue)\r\n setTextureParameters(outValue, name, uniforms, flipY);\r\n }\r\n }\r\n break;\r\n case 'samplerCube':\r\n case 'string':\r\n break;\r\n default:\r\n console.log('Value type not supported: ' + type);\r\n // struct\r\n outValue = null;//toThreeUniform(value);\r\n }\r\n\r\n return outValue;\r\n}\r\n\r\n/**\r\n * Get Three wrapping mode\r\n * @param {mx.TextureFilter.wrap} mode\r\n * @returns {THREE.Wrapping}\r\n */\r\nfunction getWrapping(mode)\r\n{\r\n let wrap;\r\n switch (mode)\r\n {\r\n case 1:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.ClampToEdgeWrapping;\r\n break;\r\n case 2:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n break;\r\n case 3:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.MirroredRepeatWrapping;\r\n break;\r\n default:\r\n wrap = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n break;\r\n }\r\n return wrap;\r\n}\r\n\r\n/**\r\n * Get Three minification filter\r\n * @param {mx.TextureFilter.minFilter} type\r\n * @param {mx.TextureFilter.generateMipmaps} generateMipmaps\r\n */\r\nfunction getMinFilter(type, generateMipmaps)\r\n{\r\n const filterType = generateMipmaps ? three__WEBPACK_IMPORTED_MODULE_0__.LinearMipMapLinearFilter : three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n if (type === 0)\r\n {\r\n filterType = generateMipmaps ? three__WEBPACK_IMPORTED_MODULE_0__.NearestMipMapNearestFilter : three__WEBPACK_IMPORTED_MODULE_0__.NearestFilter;\r\n }\r\n return filterType;\r\n}\r\n\r\n/**\r\n * Set Three texture parameters\r\n * @param {THREE.Texture} texture\r\n * @param {mx.Uniform.name} name\r\n * @param {mx.Uniforms} uniforms\r\n * @param {mx.TextureFilter.generateMipmaps} generateMipmaps\r\n */\r\nfunction setTextureParameters(texture, name, uniforms, flipY = true, generateMipmaps = true)\r\n{\r\n const idx = name.lastIndexOf(IMAGE_PROPERTY_SEPARATOR);\r\n const base = name.substring(0, idx) || name;\r\n\r\n texture.generateMipmaps = generateMipmaps;\r\n texture.wrapS = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n texture.wrapT = three__WEBPACK_IMPORTED_MODULE_0__.RepeatWrapping;\r\n texture.magFilter = three__WEBPACK_IMPORTED_MODULE_0__.LinearFilter;\r\n texture.flipY = flipY;\r\n\r\n if (uniforms.find(base + UADDRESS_MODE_SUFFIX))\r\n {\r\n const uaddressmode = uniforms.find(base + UADDRESS_MODE_SUFFIX).getValue().getData();\r\n texture.wrapS = getWrapping(uaddressmode);\r\n }\r\n\r\n if (uniforms.find(base + VADDRESS_MODE_SUFFIX))\r\n {\r\n const vaddressmode = uniforms.find(base + VADDRESS_MODE_SUFFIX).getValue().getData();\r\n texture.wrapT = getWrapping(vaddressmode);\r\n }\r\n\r\n const filterType = uniforms.find(base + FILTER_TYPE_SUFFIX) ? uniforms.get(base + FILTER_TYPE_SUFFIX).value : -1;\r\n texture.minFilter = getMinFilter(filterType, generateMipmaps);\r\n}\r\n\r\n/**\r\n * Return the global light rotation matrix\r\n */\r\nfunction getLightRotation()\r\n{\r\n return new three__WEBPACK_IMPORTED_MODULE_0__.Matrix4().makeRotationY(Math.PI / 2);\r\n}\r\n\r\n/**\r\n * Returns all lights nodes in a MaterialX document\r\n * @param {mx.Document} doc \r\n * @returns {Array.}\r\n */\r\nfunction findLights(doc)\r\n{\r\n let lights = [];\r\n for (let node of doc.getNodes())\r\n {\r\n if (node.getType() === \"lightshader\")\r\n lights.push(node);\r\n }\r\n return lights;\r\n}\r\n\r\n/**\r\n * Register lights in shader generation context\r\n * @param {Object} mx MaterialX Module\r\n * @param {Array.} lights Light nodes\r\n * @param {mx.GenContext} genContext Shader generation context\r\n * @returns {Array.}\r\n */\r\nfunction registerLights(mx, lights, genContext)\r\n{\r\n mx.HwShaderGenerator.unbindLightShaders(genContext);\r\n\r\n const lightTypesBound = {};\r\n const lightData = [];\r\n let lightId = 1;\r\n for (let light of lights)\r\n {\r\n let nodeDef = light.getNodeDef();\r\n let nodeName = nodeDef.getName();\r\n if (!lightTypesBound[nodeName])\r\n {\r\n lightTypesBound[nodeName] = lightId;\r\n mx.HwShaderGenerator.bindLightShader(nodeDef, lightId++, genContext);\r\n }\r\n\r\n const lightDirection = light.getValueElement(\"direction\").getValue().getData().data();\r\n const lightColor = light.getValueElement(\"color\").getValue().getData().data();\r\n const lightIntensity = light.getValueElement(\"intensity\").getValue().getData();\r\n\r\n let rotatedLightDirection = new three__WEBPACK_IMPORTED_MODULE_0__.Vector3(...lightDirection)\r\n rotatedLightDirection.transformDirection(getLightRotation())\r\n\r\n lightData.push({\r\n type: lightTypesBound[nodeName],\r\n direction: rotatedLightDirection,\r\n color: new three__WEBPACK_IMPORTED_MODULE_0__.Vector3(...lightColor),\r\n intensity: lightIntensity\r\n });\r\n }\r\n\r\n // Make sure max light count is large enough\r\n genContext.getOptions().hwMaxActiveLightSources = Math.max(genContext.getOptions().hwMaxActiveLightSources, lights.length);\r\n\r\n return lightData;\r\n}\r\n\r\n/**\r\n * Get uniform values for a shader\r\n * @param {mx.shaderStage} shaderStage\r\n * @param {THREE.TextureLoader} textureLoader\r\n */\r\nfunction getUniformValues(shaderStage, textureLoader, searchPath, flipY)\r\n{\r\n let threeUniforms = {};\r\n\r\n const uniformBlocks = Object.values(shaderStage.getUniformBlocks());\r\n uniformBlocks.forEach(uniforms =>\r\n {\r\n if (!uniforms.empty())\r\n {\r\n for (let i = 0; i < uniforms.size(); ++i)\r\n {\r\n const variable = uniforms.get(i);\r\n const value = variable.getValue()?.getData();\r\n const name = variable.getVariable();\r\n //console.log('fill uniform, name:', name, ', value:', value);\r\n threeUniforms[name] = new three__WEBPACK_IMPORTED_MODULE_0__.Uniform(toThreeUniform(variable.getType().getName(), value, name, uniforms,\r\n textureLoader, searchPath, flipY));\r\n }\r\n }\r\n });\r\n\r\n return threeUniforms;\r\n}\r\n\n\n//# sourceURL=webpack://MaterialX-Swatch-Viewer/./source/helper.js?");
/***/ }),
@@ -46,7 +46,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var thre
\**************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Editor: () => (/* binding */ Editor),\n/* harmony export */ Material: () => (/* binding */ Material),\n/* harmony export */ Scene: () => (/* binding */ Scene),\n/* harmony export */ Viewer: () => (/* binding */ Viewer)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n/* harmony import */ var three_examples_jsm_loaders_GLTFLoader__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! three/examples/jsm/loaders/GLTFLoader */ \"./node_modules/three/examples/jsm/loaders/GLTFLoader.js\");\n/* harmony import */ var three_examples_jsm_loaders_ObjLoader__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! three/examples/jsm/loaders/ObjLoader */ \"./node_modules/three/examples/jsm/loaders/ObjLoader.js\");\n/* harmony import */ var three_examples_jsm_loaders_RGBELoader_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! three/examples/jsm/loaders/RGBELoader.js */ \"./node_modules/three/examples/jsm/loaders/RGBELoader.js\");\n/* harmony import */ var _helper_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helper.js */ \"./source/helper.js\");\n/* harmony import */ var lil_gui__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! lil-gui */ \"./node_modules/lil-gui/dist/lil-gui.esm.js\");\n//\r\n// Copyright Contributors to the MaterialX Project\r\n// SPDX-License-Identifier: Apache-2.0\r\n//\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nconst ALL_GEOMETRY_SPECIFIER = \"*\";\r\nconst NO_GEOMETRY_SPECIFIER = \"\";\r\nconst DAG_PATH_SEPERATOR = \"/\";\r\n\r\n// Logging toggle\r\nvar logDetailedTime = false;\r\n\r\n/*\r\n Scene management\r\n*/\r\nclass Scene\r\n{\r\n constructor()\r\n {\r\n this._geometryURL = new URLSearchParams(document.location.search).get(\"geom\");\r\n if (!this._geometryURL)\r\n {\r\n this._geometryURL = 'Geometry/teapot.glb';\r\n }\r\n }\r\n\r\n initialize()\r\n {\r\n this._scene = new three__WEBPACK_IMPORTED_MODULE_1__.Scene();\r\n this._scene.background = new three__WEBPACK_IMPORTED_MODULE_1__.Color(this.#_backgroundColor);\r\n this._scene.background.convertSRGBToLinear();\r\n\r\n let cc = document.getElementById('webglcanvas');\r\n console.log('cc: ', cc)\r\n const aspectRatio = cc.width / cc.height;\r\n const cameraNearDist = 0.01;\r\n const cameraFarDist = 1000.0;\r\n const cameraFOV = 60.0;\r\n this._camera = new three__WEBPACK_IMPORTED_MODULE_1__.PerspectiveCamera(cameraFOV, aspectRatio, cameraNearDist, cameraFarDist);\r\n\r\n this.#_gltfLoader = new three_examples_jsm_loaders_GLTFLoader__WEBPACK_IMPORTED_MODULE_2__.GLTFLoader();\r\n this.#_objLoader = new three_examples_jsm_loaders_ObjLoader__WEBPACK_IMPORTED_MODULE_3__.OBJLoader();\r\n\r\n this.#_normalMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix3();\r\n this.#_viewProjMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4();\r\n this.#_worldViewPos = new three__WEBPACK_IMPORTED_MODULE_1__.Vector3();\r\n }\r\n\r\n // Set whether to flip UVs in V for loaded geometry\r\n setFlipGeometryV(val)\r\n {\r\n this.#_flipV = val;\r\n }\r\n\r\n // Get whether to flip UVs in V for loaded geometry\r\n getFlipGeometryV()\r\n {\r\n return this.#_flipV;\r\n }\r\n\r\n // Utility to perform geometry file load\r\n loadGeometryFile(geometryFilename, loader)\r\n {\r\n return new Promise((resolve, reject) =>\r\n {\r\n if (loader) \r\n {\r\n console.log(\"Load geometry: \", geometryFilename); \r\n loader.load(geometryFilename, data => resolve(data), null, reject);\r\n }\r\n });\r\n }\r\n\r\n //\r\n // Load in geometry specified by a given file name,\r\n // then update the scene geometry and camera.\r\n //\r\n async loadGeometry(viewer, orbitControls)\r\n {\r\n var startTime = performance.now();\r\n var geomLoadTime = startTime;\r\n\r\n var gltfData = null;\r\n if (this.getGeometryURL().endsWith('glb'))\r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_gltfLoader);\r\n else if (this.getGeometryURL().endsWith('obj'))\r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_objLoader);\r\n else \r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_gltfLoader);\r\n\r\n if (gltfData == null)\r\n {\r\n console.log(\"Failed to load geometry: \", this.getGeometryURL());\r\n return;\r\n }\r\n\r\n const scene = this.getScene();\r\n while (scene.children.length > 0)\r\n {\r\n scene.remove(scene.children[0]);\r\n }\r\n\r\n this.#_rootNode = null;\r\n const model = gltfData.scene;\r\n if (!model)\r\n {\r\n const geometry = new three__WEBPACK_IMPORTED_MODULE_1__.BoxGeometry(1, 1, 1);\r\n const material = new three__WEBPACK_IMPORTED_MODULE_1__.MeshBasicMaterial({ color: 0xdddddd });\r\n const cube = new three__WEBPACK_IMPORTED_MODULE_1__.Mesh(geometry, material);\r\n obj = new three__WEBPACK_IMPORTED_MODULE_1__.Group();\r\n obj.add(geometry);\r\n }\r\n else\r\n {\r\n this.#_rootNode = model;\r\n }\r\n scene.add(model);\r\n\r\n // Always reset controls based on camera for each load. \r\n orbitControls.reset();\r\n console.log(\"- Scene load time: \", performance.now() - geomLoadTime, \"ms\");\r\n\r\n console.log(\"Total geometry load time: \", performance.now() - startTime, \" ms.\");\r\n\r\n viewer.getMaterial().clearSoloMaterialUI();\r\n viewer.getMaterial().updateMaterialAssignments(viewer, viewer.getMaterial().getSoloMaterial());\r\n this.setUpdateTransforms();\r\n\r\n this.updateScene(viewer, orbitControls);\r\n }\r\n\r\n //\r\n // Update the geometry buffer, assigned materials, and camera controls.\r\n //\r\n updateScene(viewer, orbitControls)\r\n {\r\n var startUpdateSceneTime = performance.now();\r\n var uvTime = 0;\r\n var normalTime = 0;\r\n var tangentTime = 0;\r\n var streamTime = 0;\r\n var bboxTime = 0;\r\n\r\n var startBboxTime = performance.now();\r\n const bbox = new three__WEBPACK_IMPORTED_MODULE_1__.Box3().setFromObject(this._scene);\r\n const bsphere = new three__WEBPACK_IMPORTED_MODULE_1__.Sphere();\r\n bbox.getBoundingSphere(bsphere);\r\n bboxTime = performance.now() - startBboxTime;\r\n\r\n let theScene = viewer.getScene();\r\n let flipV = theScene.getFlipGeometryV();\r\n\r\n\r\n this._scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n var startUVTime = performance.now();\r\n if (!child.geometry.attributes.uv)\r\n {\r\n const posCount = child.geometry.attributes.position.count;\r\n const uvs = [];\r\n const pos = child.geometry.attributes.position.array;\r\n\r\n for (let i = 0; i < posCount; i++)\r\n {\r\n uvs.push((pos[i * 3] - bsphere.center.x) / bsphere.radius);\r\n uvs.push((pos[i * 3 + 1] - bsphere.center.y) / bsphere.radius);\r\n }\r\n\r\n child.geometry.setAttribute('uv', new three__WEBPACK_IMPORTED_MODULE_1__.BufferAttribute(new Float32Array(uvs), 2));\r\n }\r\n else if (flipV)\r\n {\r\n const uvCount = child.geometry.attributes.position.count;\r\n const uvs = child.geometry.attributes.uv.array;\r\n for (let i = 0; i < uvCount; i++)\r\n {\r\n let v = 1.0 - (uvs[i * 2 + 1]);\r\n uvs[i * 2 + 1] = v;\r\n }\r\n }\r\n uvTime += performance.now() - startUVTime;\r\n\r\n if (!child.geometry.attributes.normal)\r\n {\r\n var startNormalTime = performance.new();\r\n child.geometry.computeVertexNormals();\r\n normalTime += performance.now() - startNormalTime;\r\n }\r\n\r\n if (child.geometry.getIndex())\r\n {\r\n if (!child.geometry.attributes.tangent)\r\n {\r\n var startTangentTime = performance.now();\r\n child.geometry.computeTangents();\r\n tangentTime += performance.now() - startTangentTime;\r\n }\r\n }\r\n\r\n // Use default MaterialX naming convention.\r\n var startStreamTime = performance.now();\r\n child.geometry.attributes.i_position = child.geometry.attributes.position;\r\n child.geometry.attributes.i_normal = child.geometry.attributes.normal;\r\n child.geometry.attributes.i_tangent = child.geometry.attributes.tangent;\r\n child.geometry.attributes.i_texcoord_0 = child.geometry.attributes.uv;\r\n streamTime += performance.now() - startStreamTime;\r\n }\r\n });\r\n\r\n console.log(\"- Stream update time: \", performance.now() - startUpdateSceneTime, \"ms\");\r\n if (logDetailedTime)\r\n {\r\n console.log(' - UV time: ', uvTime);\r\n console.log(' - Normal time: ', normalTime);\r\n console.log(' - Tangent time: ', tangentTime);\r\n console.log(' - Stream Update time: ', streamTime);\r\n console.log(' - Bounds compute time: ', bboxTime);\r\n }\r\n\r\n // Update the background\r\n this._scene.background = this.getBackground();\r\n\r\n //console.log('bounding sphere:', bsphere.center, bsphere.radius);\r\n\r\n // Fit camera to model\r\n const camera = this.getCamera();\r\n camera.position.y = bsphere.center.y;\r\n camera.position.z = bsphere.radius * 2.0;\r\n camera.updateProjectionMatrix();\r\n\r\n orbitControls.target = bsphere.center;\r\n orbitControls.update();\r\n }\r\n\r\n setUpdateTransforms()\r\n {\r\n this.#_updateTransforms = true;\r\n }\r\n\r\n updateTransforms()\r\n {\r\n // Only update on demand versus continuously.\r\n // Call setUpdateTransforms() to trigger an update here.\r\n // Required for: scene geometry, camera change and viewport resize. \r\n if (!this.#_updateTransforms)\r\n {\r\n return;\r\n }\r\n this.#_updateTransforms = false;\r\n\r\n const scene = this.getScene();\r\n const camera = this.getCamera();\r\n scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n const uniforms = child.material.uniforms;\r\n if (uniforms)\r\n {\r\n uniforms.u_worldMatrix.value = child.matrixWorld;\r\n uniforms.u_viewProjectionMatrix.value = this.#_viewProjMat.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);\r\n\r\n if (uniforms.u_viewPosition)\r\n uniforms.u_viewPosition.value = camera.getWorldPosition(this.#_worldViewPos);\r\n\r\n if (uniforms.u_worldInverseTransposeMatrix)\r\n uniforms.u_worldInverseTransposeMatrix.value =\r\n new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4().setFromMatrix3(this.#_normalMat.getNormalMatrix(child.matrixWorld));\r\n }\r\n }\r\n });\r\n }\r\n\r\n // Determine string DAG path based on individual node names.\r\n getDagPath(node)\r\n {\r\n const rootNode = this.#_rootNode;\r\n\r\n let path = [node.name];\r\n while (node.parent)\r\n {\r\n node = node.parent;\r\n if (node)\r\n {\r\n // Stop at the root of the scene read in.\r\n if (node == rootNode)\r\n {\r\n break;\r\n }\r\n path.unshift(node.name);\r\n }\r\n }\r\n return path;\r\n }\r\n\r\n // Assign material shader to associated geometry\r\n updateMaterial(matassign)\r\n {\r\n let assigned = 0;\r\n\r\n const shader = matassign.getShader();\r\n const material = matassign.getMaterial().getName();\r\n const geometry = matassign.getGeometry();\r\n const collection = matassign.getCollection();\r\n\r\n const scene = this.getScene();\r\n const camera = this.getCamera();\r\n scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n const dagPath = this.getDagPath(child).join('/');\r\n\r\n // Note that this is a very simplistic\r\n // assignment resolve and assumes basic\r\n // regular expression name match.\r\n let matches = (geometry == ALL_GEOMETRY_SPECIFIER);\r\n if (!matches)\r\n {\r\n if (collection)\r\n {\r\n if (collection.matchesGeomString(dagPath))\r\n {\r\n matches = true;\r\n }\r\n }\r\n else\r\n {\r\n if (geometry != NO_GEOMETRY_SPECIFIER)\r\n {\r\n const paths = geometry.split(',');\r\n for (let path of paths)\r\n {\r\n if (dagPath.match(path))\r\n {\r\n matches = true;\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n if (matches)\r\n {\r\n child.material = shader;\r\n assigned++;\r\n }\r\n }\r\n });\r\n\r\n return assigned;\r\n }\r\n\r\n updateCamera()\r\n {\r\n const camera = this.getCamera();\r\n let container = document.getElementById('canvasContainer');\r\n var maxWidth = 4086;\r\n var maxHeight = 1024;\r\n var width = Math.min(container.clientWidth, maxWidth);\r\n var height = Math.min(container.clientHeight, maxHeight); \r\n\r\n camera.aspect = width / height;\r\n camera.updateProjectionMatrix();\r\n }\r\n\r\n getScene()\r\n {\r\n return this._scene;\r\n }\r\n\r\n getCamera()\r\n {\r\n return this._camera;\r\n }\r\n\r\n getGeometryURL()\r\n {\r\n return this._geometryURL;\r\n }\r\n\r\n setGeometryURL(url)\r\n {\r\n this._geometryURL = url;\r\n }\r\n\r\n setBackgroundTexture(texture)\r\n {\r\n this.#_backgroundTexture = texture;\r\n }\r\n\r\n getShowBackgroundTexture()\r\n {\r\n return this.#_showBackgroundTexture;\r\n }\r\n\r\n setShowBackgroundTexture(enable)\r\n {\r\n this.#_showBackgroundTexture = enable;\r\n }\r\n\r\n getBackground()\r\n {\r\n if (this.#_backgroundTexture && this.#_showBackgroundTexture)\r\n {\r\n return this.#_backgroundTexture;\r\n }\r\n var color = new three__WEBPACK_IMPORTED_MODULE_1__.Color(this.#_backgroundColor);\r\n color.convertSRGBToLinear();\r\n return color;\r\n }\r\n\r\n toggleBackgroundTexture()\r\n {\r\n this.#_showBackgroundTexture = !this.#_showBackgroundTexture;\r\n this._scene.background = this.getBackground();\r\n }\r\n\r\n // Geometry file\r\n #_geometryURL = '';\r\n // Geometry loaders\r\n #_gltfLoader = null;\r\n #_objLoader = null;\r\n // Flip V coordinate of texture coordinates.\r\n // Set to true to be consistent with desktop viewer.\r\n #_flipV = true;\r\n\r\n // Scene\r\n #_scene = null;\r\n\r\n // Camera\r\n #_camera = null;\r\n\r\n // Background color\r\n #_backgroundColor = 0xAcAdBB;\r\n\r\n // Background texture\r\n #_backgroundTexture = null;\r\n #_showBackgroundTexture = false;\r\n\r\n // Transform matrices\r\n #_normalMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix3();\r\n #_viewProjMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4();\r\n #_worldViewPos = new three__WEBPACK_IMPORTED_MODULE_1__.Vector3();\r\n #_updateTransforms = true;\r\n\r\n // Root node of imported scene\r\n #_rootNode = null;\r\n}\r\n\r\n/* \r\n Property editor\r\n*/\r\nclass Editor\r\n{\r\n // Initialize the editor, clearing any elements from previous materials.\r\n initialize()\r\n {\r\n Array.from(document.getElementsByClassName('lil-gui')).forEach(\r\n function (element, index, array)\r\n {\r\n if (element.className)\r\n {\r\n element.remove();\r\n }\r\n }\r\n );\r\n\r\n let parent = document.getElementById( 'webglcanvas' );\r\n //console.log('parent:', parent);\r\n this._gui = new lil_gui__WEBPACK_IMPORTED_MODULE_4__[\"default\"]( { title: \"Properties\" }, { container: parent } );\r\n //parent = this._gui.domElement;\r\n //console.log('gui parent:', parent);\r\n // Parent parent under webglcanvas\r\n //document.getElementById( 'webglcanvas' ).appendChild( parent );\r\n\r\n //this._gui = new GUI({ title: \"Property Editor\" });\r\n this._gui.close();\r\n this._gui.hide();\r\n }\r\n\r\n // Update ui properties\r\n // - Hide close button\r\n // - Update transparency so scene shows through if overlapping\r\n updateProperties(targetOpacity = 1)\r\n {\r\n // Set opacity\r\n Array.from(document.getElementsByClassName('dg')).forEach(\r\n function (element, index, array)\r\n {\r\n element.style.opacity = targetOpacity;\r\n }\r\n );\r\n }\r\n\r\n getGUI()\r\n {\r\n return this._gui;\r\n }\r\n\r\n _gui = null;\r\n}\r\n\r\nclass MaterialAssign\r\n{\r\n constructor(material, geometry, collection)\r\n {\r\n this._material = material;\r\n this._geometry = geometry;\r\n this._collection = collection;\r\n this._shader = null;\r\n this._materialUI = null;\r\n }\r\n\r\n setMaterialUI(value)\r\n {\r\n this._materialUI = value;\r\n }\r\n\r\n getMaterialUI()\r\n {\r\n return this._materialUI;\r\n }\r\n\r\n setShader(shader)\r\n {\r\n this._shader = shader;\r\n }\r\n\r\n getShader()\r\n {\r\n return this._shader;\r\n }\r\n\r\n getMaterial()\r\n {\r\n return this._material;\r\n }\r\n\r\n getGeometry()\r\n {\r\n return this._geometry;\r\n }\r\n\r\n setGeometry(value)\r\n {\r\n this._geometry = value;\r\n }\r\n\r\n getCollection()\r\n {\r\n return this._collection;\r\n }\r\n\r\n // MaterialX material node name\r\n _material;\r\n\r\n // MaterialX assignment geometry string\r\n _geometry;\r\n\r\n // MaterialX assignment collection\r\n _collection;\r\n\r\n // THREE.JS shader\r\n _shader;\r\n}\r\n\r\nclass Material\r\n{\r\n constructor()\r\n {\r\n this._materials = [];\r\n this._defaultMaterial = null;\r\n this._soloMaterial = \"\";\r\n this._shaderInterfaceType = 0;\r\n }\r\n\r\n clearMaterials()\r\n {\r\n this._materials.length = 0;\r\n this._defaultMaterial = null;\r\n this._soloMaterial = \"\";\r\n }\r\n\r\n setSoloMaterial(value)\r\n {\r\n this._soloMaterial = value;\r\n }\r\n\r\n getSoloMaterial()\r\n {\r\n return this._soloMaterial;\r\n }\r\n\r\n // If no material file is selected, we programmatically create a default material as a fallback\r\n static createFallbackMaterial(doc)\r\n {\r\n let ssNode = doc.getChild('Generated_Default_Shader');\r\n if (ssNode)\r\n {\r\n return ssNode;\r\n }\r\n const ssName = 'Generated_Default_Shader';\r\n ssNode = doc.addChildOfCategory('standard_surface', ssName);\r\n ssNode.setType('surfaceshader');\r\n const smNode = doc.addChildOfCategory('surfacematerial', 'Default');\r\n smNode.setType('material');\r\n const shaderElement = smNode.addInput('surfaceshader');\r\n shaderElement.setType('surfaceshader');\r\n shaderElement.setNodeName(ssName);\r\n\r\n return ssNode;\r\n }\r\n\r\n async loadMaterialFile(loader, materialFilename)\r\n {\r\n return new Promise((resolve, reject) =>\r\n {\r\n loader.load(materialFilename, data => resolve(data), null, reject);\r\n });\r\n }\r\n\r\n async loadMaterials(viewer, materialFilename)\r\n {\r\n const fileloader = viewer.getFileLoader();\r\n\r\n let mtlxMaterial = await viewer.getMaterial().loadMaterialFile(fileloader, materialFilename);\r\n\r\n this.loadMaterialFromString(viewer, mtlxMaterial, materialFilename);\r\n }\r\n\r\n async loadMaterialFromString(viewer, mtlxMaterial, materialFilename)\r\n {\r\n var startTime = performance.now();\r\n\r\n const mx = viewer.getMx();\r\n\r\n // Re-initialize document\r\n var startDocTime = performance.now();\r\n var doc = mx.createDocument();\r\n doc.importLibrary(viewer.getLibrary());\r\n if (!doc.validate())\r\n {\r\n console.log(\"MaterialX document validation failed.\");\r\n return;\r\n }\r\n\r\n viewer.setDocument(doc);\r\n\r\n // Load lighting setup into document\r\n doc.importLibrary(viewer.getLightRig());\r\n\r\n console.log(\"- Material document load time: \", performance.now() - startDocTime, \"ms.\");\r\n\r\n // Set search path. Assumes images are relative to current file\r\n // location.\r\n if (!materialFilename) materialFilename = \"/\";\r\n const paths = materialFilename.split('/');\r\n paths.pop();\r\n const searchPath = paths.join('/');\r\n\r\n // Load material\r\n if (mtlxMaterial)\r\n try { \r\n await mx.readFromXmlString(doc, mtlxMaterial, searchPath);\r\n }\r\n catch (error) {\r\n console.error('Error loading material file: ', error);\r\n }\r\n else\r\n Material.createFallbackMaterial(doc);\r\n\r\n // Check if there are any looks defined in the document\r\n // If so then traverse the looks for all material assignments.\r\n // Generate code and compile for any associated surface shader\r\n // and assign to the associated geometry. If there are no looks\r\n // then the first material is found and assignment to all the\r\n // geometry.\r\n this.clearMaterials();\r\n var looks = doc.getLooks();\r\n if (looks.length)\r\n {\r\n for (let look of looks)\r\n {\r\n const materialAssigns = look.getMaterialAssigns();\r\n for (let materialAssign of materialAssigns)\r\n {\r\n let matName = materialAssign.getMaterial();\r\n if (matName)\r\n {\r\n let mat = doc.getChild(matName);\r\n var shader;\r\n if (mat)\r\n {\r\n var shaders = mx.getShaderNodes(mat);\r\n if (shaders.length)\r\n {\r\n shader = shaders[0];\r\n }\r\n }\r\n let collection = materialAssign.getCollection();\r\n let geom = materialAssign.getGeom();\r\n let newAssignment;\r\n if (collection || geom)\r\n {\r\n // Remove leading \"/\" from collection and geom for \r\n // later assignment comparison checking\r\n if (collection && collection.charAt(0) == \"/\")\r\n {\r\n collection = collection.slice(1);\r\n }\r\n if (geom && geom.charAt(0) == \"/\")\r\n {\r\n geom = geom.slice(1);\r\n }\r\n newAssignment = new MaterialAssign(shader, geom, collection);\r\n }\r\n else\r\n {\r\n newAssignment = new MaterialAssign(shader, NO_GEOMETRY_SPECIFIER, null);\r\n }\r\n\r\n if (newAssignment)\r\n {\r\n this._materials.push(newAssignment);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n else\r\n {\r\n // Search for any surface shaders. The first found\r\n // is assumed to be assigned to the entire scene\r\n // The identifier used is \"*\" to mean the entire scene. \r\n const materialNodes = doc.getMaterialNodes();\r\n let shaderList = [];\r\n let foundRenderable = false;\r\n for (let i = 0; i < materialNodes.length; ++i)\r\n {\r\n let materialNode = materialNodes[i];\r\n if (materialNode)\r\n {\r\n console.log('Scan material: ', materialNode.getNamePath());\r\n let shaderNodes = mx.getShaderNodes(materialNode)\r\n if (shaderNodes.length > 0)\r\n {\r\n let shaderNodePath = shaderNodes[0].getNamePath()\r\n if (!shaderList.includes(shaderNodePath))\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n console.log('-- add shader: ', shaderNodePath);\r\n shaderList.push(shaderNodePath);\r\n this._materials.push(new MaterialAssign(shaderNodes[0], assignment));\r\n }\r\n }\r\n }\r\n }\r\n const nodeGraphs = doc.getNodeGraphs();\r\n for (let i = 0; i < nodeGraphs.length; ++i)\r\n {\r\n let nodeGraph = nodeGraphs[i];\r\n if (nodeGraph)\r\n {\r\n if (nodeGraph.hasAttribute('nodedef') || nodeGraph.hasSourceUri())\r\n {\r\n continue;\r\n }\r\n // Skip any nodegraph that is connected to something downstream\r\n if (nodeGraph.getDownstreamPorts().length > 0)\r\n {\r\n continue\r\n }\r\n let outputs = nodeGraph.getOutputs();\r\n for (let j = 0; j < outputs.length; ++j)\r\n {\r\n let output = outputs[j];\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n let newMat = new MaterialAssign(output, assignment, null);\r\n this._materials.push(newMat);\r\n }\r\n }\r\n }\r\n }\r\n const outputs = doc.getOutputs();\r\n for (let i = 0; i < outputs.length; ++i)\r\n {\r\n let output = outputs[i];\r\n if (output)\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n this._materials.push(new MaterialAssign(output, assignment));\r\n }\r\n }\r\n\r\n const shaderNodes = [];\r\n for (let i = 0; i < shaderNodes.length; ++i)\r\n {\r\n let shaderNode = shaderNodes[i];\r\n let shaderNodePath = shaderNode.getNamePath()\r\n if (!shaderList.includes(shaderNodePath))\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n shaderList.push(shaderNodePath);\r\n this._materials.push(new MaterialAssign(shaderNode, assignment));\r\n }\r\n }\r\n }\r\n\r\n // Assign to default material if none found\r\n if (this._materials.length == 0)\r\n {\r\n const defaultNode = Material.createFallbackMaterial(doc);\r\n this._materials.push(new MaterialAssign(defaultNode, ALL_GEOMETRY_SPECIFIER));\r\n }\r\n\r\n // Create a new shader for each material node.\r\n // Only create the shader once even if assigned more than once.\r\n var startGenTime = performance.now();\r\n let shaderMap = new Map();\r\n let closeUI = false;\r\n for (let matassign of this._materials)\r\n {\r\n // Need to use path vs name to get a unique key.\r\n let materialName = matassign.getMaterial().getNamePath();\r\n let shader = shaderMap[materialName];\r\n if (!shader)\r\n {\r\n shader = viewer.getMaterial().generateMaterial(matassign, viewer, searchPath, closeUI);\r\n shaderMap[materialName] = shader;\r\n }\r\n matassign.setShader(shader);\r\n closeUI = true;\r\n }\r\n console.log(\"- Generate (\", this._materials.length, \") shader(s) time: \", performance.now() - startGenTime, \" ms.\",);\r\n\r\n // Update scene shader assignments\r\n this.updateMaterialAssignments(viewer, this._soloMaterial);\r\n\r\n // Mark transform update\r\n viewer.getScene().setUpdateTransforms();\r\n\r\n console.log(\"Total material time: \", (performance.now() - startTime), \"ms\");\r\n }\r\n\r\n //\r\n // Update the assignments for scene objects based on the\r\n // material assignment information stored in the viewer.\r\n // Note: If none of the MaterialX assignments match the geometry\r\n // in the scene, then the first material assignment shader is assigned\r\n // to the entire scene.\r\n //\r\n async updateMaterialAssignments(viewer, soloMaterial)\r\n {\r\n console.log(\"Update material assignments. Solo=\", soloMaterial);\r\n var startTime = performance.now();\r\n\r\n let assigned = 0;\r\n let assignedSolo = false;\r\n for (let matassign of this._materials)\r\n {\r\n if (matassign.getShader())\r\n {\r\n if (soloMaterial.length)\r\n {\r\n if (matassign.getMaterial().getNamePath() == soloMaterial)\r\n {\r\n let temp = matassign.getGeometry();\r\n matassign.setGeometry(ALL_GEOMETRY_SPECIFIER);\r\n assigned += viewer.getScene().updateMaterial(matassign);\r\n matassign.setGeometry(temp);\r\n assignedSolo = true;\r\n break\r\n }\r\n }\r\n else\r\n {\r\n assigned += viewer.getScene().updateMaterial(matassign);\r\n }\r\n }\r\n }\r\n if (assigned == 0 && this._materials.length)\r\n {\r\n this._defaultMaterial = new MaterialAssign(this._materials[0].getMaterial(), ALL_GEOMETRY_SPECIFIER);\r\n this._defaultMaterial.setShader(this._materials[0].getShader());\r\n viewer.getScene().updateMaterial(this._defaultMaterial);\r\n }\r\n\r\n if (assigned > 0)\r\n {\r\n console.log('Material assignment time: ', performance.now() - startTime, \" ms.\");\r\n }\r\n }\r\n\r\n // \r\n // Generate a new material for a given element\r\n //\r\n generateMaterial(matassign, viewer, searchPath, closeUI)\r\n {\r\n var elem = matassign.getMaterial();\r\n\r\n var startGenerateMat = performance.now();\r\n\r\n const mx = viewer.getMx();\r\n const textureLoader = new three__WEBPACK_IMPORTED_MODULE_1__.TextureLoader();\r\n\r\n const lights = viewer.getLights();\r\n const lightData = viewer.getLightData();\r\n const radianceTexture = viewer.getRadianceTexture();\r\n const irradianceTexture = viewer.getIrradianceTexture();\r\n const gen = viewer.getGenerator();\r\n const genContext = viewer.getGenContext();\r\n\r\n // Perform transparency check on renderable item\r\n var startTranspCheckTime = performance.now();\r\n const isTransparent = mx.isTransparentSurface(elem, gen.getTarget());\r\n genContext.getOptions().hwTransparency = isTransparent;\r\n // Always set to complete. \r\n // Can consider option to set to reduced as the parsing of large numbers of uniforms (e.g. on shading models)\r\n // can be quite expensive.\r\n if (this._shaderInterfaceType == 0)\r\n genContext.getOptions().shaderInterfaceType = mx.ShaderInterfaceType.SHADER_INTERFACE_REDUCED;\r\n else\r\n genContext.getOptions().shaderInterfaceType = mx.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE;\r\n\r\n if (logDetailedTime)\r\n console.log(\" - Transparency check time: \", performance.now() - startTranspCheckTime, \"ms\");\r\n\r\n // Generate GLES code\r\n var startMTLXGenTime = performance.now();\r\n let shader = gen.generate(elem.getNamePath(), elem, genContext);\r\n if (logDetailedTime)\r\n console.log(\" - MaterialX gen time: \", performance.now() - startMTLXGenTime, \"ms\");\r\n\r\n var startUniformUpdate = performance.now();\r\n\r\n // Get shaders and uniform values\r\n let vShader = shader.getSourceCode(\"vertex\");\r\n let fShader = shader.getSourceCode(\"pixel\");\r\n\r\n let theScene = viewer.getScene();\r\n let flipV = theScene.getFlipGeometryV();\r\n let uniforms = {\r\n ...(0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getUniformValues)(shader.getStage('vertex'), textureLoader, searchPath, flipV),\r\n ...(0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getUniformValues)(shader.getStage('pixel'), textureLoader, searchPath, flipV),\r\n }\r\n\r\n Object.assign(uniforms, {\r\n u_numActiveLightSources: { value: lights.length}, //value: lights.length },\r\n u_lightData: { value: lightData },\r\n u_envMatrix: { value: (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getLightRotation)() },\r\n u_envRadiance: { value: radianceTexture },\r\n u_envRadianceMips: { value: Math.trunc(Math.log2(Math.max(radianceTexture.image.width, radianceTexture.image.height))) + 1 },\r\n u_envRadianceSamples: { value: 2 },\r\n u_envIrradiance: { value: irradianceTexture },\r\n u_refractionEnv: { value: false }\r\n });\r\n\r\n // Create Three JS Material\r\n let newMaterial = new three__WEBPACK_IMPORTED_MODULE_1__.RawShaderMaterial({\r\n uniforms: uniforms,\r\n vertexShader: vShader,\r\n fragmentShader: fShader,\r\n transparent: isTransparent,\r\n blendEquation: three__WEBPACK_IMPORTED_MODULE_1__.AddEquation,\r\n blendSrc: three__WEBPACK_IMPORTED_MODULE_1__.OneMinusSrcAlphaFactor,\r\n blendDst: three__WEBPACK_IMPORTED_MODULE_1__.SrcAlphaFactor,\r\n side: three__WEBPACK_IMPORTED_MODULE_1__.DoubleSide\r\n });\r\n\r\n if (logDetailedTime)\r\n console.log(\" - Three material update time: \", performance.now() - startUniformUpdate, \"ms\");\r\n\r\n // Update property editor\r\n const gui = viewer.getEditor().getGUI();\r\n this.updateEditor(matassign, shader, newMaterial, gui, closeUI, viewer);\r\n\r\n if (logDetailedTime)\r\n console.log(\"- Per material generate time: \", performance.now() - startGenerateMat, \"ms\");\r\n\r\n return newMaterial;\r\n }\r\n\r\n clearSoloMaterialUI()\r\n {\r\n for (let i = 0; i < this._materials.length; ++i)\r\n {\r\n let matassign = this._materials[i];\r\n let matUI = matassign.getMaterialUI();\r\n if (matUI)\r\n {\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n matTitle.classList.remove('peditor_material_assigned');\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n img.src = 'public/shader_ball.svg';\r\n //matTitle.classList.remove('peditor_material_unassigned');\r\n }\r\n }\r\n }\r\n\r\n static updateSoloMaterial(viewer, elemPath, materials, event)\r\n {\r\n // Prevent the event from being passed to parent folder\r\n event.stopPropagation();\r\n\r\n for (let i = 0; i < materials.length; ++i)\r\n {\r\n let matassign = materials[i];\r\n // Need to use path vs name to get a unique key.\r\n let materialName = matassign.getMaterial().getNamePath();\r\n var matUI = matassign.getMaterialUI();\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n if (materialName == elemPath)\r\n {\r\n if (this._soloMaterial == elemPath)\r\n {\r\n img.src = 'public/shader_ball.svg';\r\n matTitle.classList.remove('peditor_material_assigned');\r\n this._soloMaterial = \"\";\r\n }\r\n else\r\n {\r\n img.src = 'public/shader_ball2.svg';\r\n matTitle.classList.add('peditor_material_assigned');\r\n this._soloMaterial = elemPath;\r\n }\r\n }\r\n else\r\n {\r\n img.src = 'public/shader_ball.svg';\r\n matTitle.classList.remove('peditor_material_assigned');\r\n }\r\n }\r\n viewer.getMaterial().updateMaterialAssignments(viewer, \"\");\r\n viewer.getScene().setUpdateTransforms();\r\n }\r\n\r\n //\r\n // Update property editor for a given MaterialX element, it's shader, and\r\n // Three material\r\n //\r\n updateEditor(matassign, shader, material, gui, closeUI, viewer)\r\n {\r\n var elem = matassign.getMaterial();\r\n var materials = this._materials;\r\n\r\n const DEFAULT_MIN = 0;\r\n const DEFAULT_MAX = 100;\r\n\r\n var startTime = performance.now();\r\n\r\n const elemPath = elem.getNamePath();\r\n\r\n // Create and cache associated UI\r\n var matUI = gui.addFolder(elemPath);\r\n matassign.setMaterialUI(matUI);\r\n\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n // Add a icon to the title to allow for assigning the material to geometry\r\n // Clicking on the icon will \"solo\" the material to the geometry.\r\n // Clicking on the title will open/close the material folder.\r\n matTitle.innerHTML = \" \" + elem.getNamePath();\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n if (img)\r\n {\r\n // Add event listener to icon to call updateSoloMaterial function\r\n img.addEventListener('click', function (event)\r\n {\r\n Material.updateSoloMaterial(viewer, elemPath, materials, event);\r\n });\r\n }\r\n\r\n if (closeUI)\r\n {\r\n matUI.close();\r\n }\r\n const uniformBlocks = Object.values(shader.getStage('pixel').getUniformBlocks());\r\n var uniformToUpdate;\r\n const ignoreList = ['u_envRadianceMips', 'u_envRadianceSamples', 'u_alphaThreshold'];\r\n\r\n var folderList = new Map();\r\n folderList[elemPath] = matUI;\r\n\r\n uniformBlocks.forEach(uniforms =>\r\n {\r\n if (!uniforms.empty())\r\n {\r\n for (let i = 0; i < uniforms.size(); ++i)\r\n {\r\n const variable = uniforms.get(i);\r\n const value = variable.getValue()?.getData();\r\n let name = variable.getVariable();\r\n\r\n if (ignoreList.includes(name))\r\n {\r\n continue;\r\n }\r\n\r\n let currentFolder = matUI;\r\n let currentElemPath = variable.getPath();\r\n if (!currentElemPath || currentElemPath.length == 0)\r\n {\r\n continue;\r\n }\r\n let currentElem = elem.getDocument().getDescendant(currentElemPath);\r\n if (!currentElem)\r\n {\r\n continue;\r\n }\r\n\r\n let currentNode = null;\r\n if (currentElem.getParent() && currentElem.getParent().getNamePath() != \"\")\r\n {\r\n currentNode = currentElem.getParent();\r\n }\r\n let uiname = \"\";\r\n let nodeDefInput = null;\r\n if (currentNode)\r\n {\r\n\r\n let currentNodePath = currentNode.getNamePath();\r\n var pathSplit = currentNodePath.split('/');\r\n if (pathSplit.length)\r\n {\r\n currentNodePath = pathSplit[0];\r\n }\r\n currentFolder = folderList[currentNodePath];\r\n if (!currentFolder)\r\n {\r\n currentFolder = matUI.addFolder(currentNodePath);\r\n folderList[currentNodePath] = currentFolder;\r\n }\r\n\r\n // Check for ui attributes\r\n var nodeDef = currentNode.getNodeDef();\r\n if (nodeDef)\r\n {\r\n // Remove node name from shader uniform name for non root nodes\r\n let lookup_name = name.replace(currentNode.getName() + '_', '');\r\n nodeDefInput = nodeDef.getActiveInput(lookup_name);\r\n if (nodeDefInput)\r\n {\r\n uiname = nodeDefInput.getAttribute('uiname');\r\n let uifolderName = nodeDefInput.getAttribute('uifolder');\r\n if (uifolderName && uifolderName.length)\r\n {\r\n let newFolderName = currentNodePath + '/' + uifolderName;\r\n currentFolder = folderList[newFolderName];\r\n if (!currentFolder)\r\n {\r\n currentFolder = matUI.addFolder(uifolderName);\r\n currentFolder.domElement.classList.add('peditorfolder');\r\n folderList[newFolderName] = currentFolder;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Determine UI name to use\r\n let path = name;\r\n let interfaceName = currentElem.getAttribute(\"interfacename\");\r\n if (interfaceName && interfaceName.length)\r\n {\r\n const graph = currentNode.getParent();\r\n if (graph)\r\n {\r\n const graphInput = graph.getInput(interfaceName);\r\n if (graphInput)\r\n {\r\n let uiname = graphInput.getAttribute('uiname');\r\n if (uiname.length)\r\n {\r\n path = uiname;\r\n }\r\n else\r\n {\r\n path = graphInput.getName();\r\n }\r\n }\r\n }\r\n else\r\n {\r\n path = interfaceName;\r\n }\r\n }\r\n else\r\n {\r\n if (!uiname)\r\n {\r\n uiname = currentElem.getAttribute('uiname');\r\n }\r\n if (uiname && uiname.length)\r\n {\r\n path = uiname;\r\n }\r\n }\r\n\r\n switch (variable.getType().getName())\r\n {\r\n case 'float':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = DEFAULT_MIN;\r\n if (value < minValue)\r\n {\r\n minValue = value;\r\n }\r\n var maxValue = DEFAULT_MAX;\r\n if (value > maxValue)\r\n {\r\n maxValue = value;\r\n }\r\n var step = 0;\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = parseFloat(nodeDefInput.getAttribute('uisoftmin'));\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = parseFloat(nodeDefInput.getAttribute('uimin'));\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = parseFloat(nodeDefInput.getAttribute('uisoftmax'));\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = parseFloat(nodeDefInput.getAttribute('uimax'));\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = parseFloat(nodeDefInput.getAttribute('uistep'));\r\n }\r\n if (step == 0)\r\n {\r\n step = (maxValue - minValue) / 1000.0;\r\n }\r\n const w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'integer':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = DEFAULT_MIN;\r\n if (value < minValue)\r\n {\r\n minValue = value;\r\n }\r\n var maxValue = DEFAULT_MAX;\r\n if (value > maxValue)\r\n {\r\n maxValue = value;\r\n }\r\n var step = 0;\r\n var enumList = []\r\n var enumValues = []\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('enum'))\r\n {\r\n // Get enum and enum values attributes (if present)\r\n enumList = nodeDefInput.getAttribute('enum').split(',');\r\n if (nodeDefInput.hasAttribute('enumvalues'))\r\n {\r\n enumValues = nodeDefInput.getAttribute('enumvalues').split(',').map(Number);\r\n }\r\n }\r\n else\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = parseInt(nodeDefInput.getAttribute('uisoftmin'));\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = parseInt(nodeDefInput.getAttribute('uimin'));\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = parseInt(nodeDefInput.getAttribute('uisoftmax'));\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = parseInt(nodeDefInput.getAttribute('uimax'));\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = parseInt(nodeDefInput.getAttribute('uistep'));\r\n }\r\n }\r\n if (enumList.length == 0)\r\n {\r\n if (step == 0)\r\n {\r\n step = 1 / (maxValue - minValue);\r\n step = Math.ceil(step);\r\n if (step == 0)\r\n {\r\n step = 1;\r\n }\r\n }\r\n }\r\n if (enumList.length == 0)\r\n {\r\n let w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n else\r\n {\r\n // Map enumList strings to values\r\n // Map to 0..N if no values are specified via enumvalues attribute\r\n if (enumValues.length == 0)\r\n {\r\n for (let i = 0; i < enumList.length; ++i)\r\n {\r\n enumValues.push(i);\r\n }\r\n }\r\n const enumeration = {};\r\n enumList.forEach((str, index) =>\r\n {\r\n enumeration[str] = enumValues[index];\r\n });\r\n\r\n // Function to handle enum drop-down\r\n function handleDropdownChange(value)\r\n {\r\n if (material.uniforms[name])\r\n {\r\n material.uniforms[name].value = value;\r\n }\r\n }\r\n const defaultOption = enumList[value]; // Set the default selected option\r\n const dropdownController = currentFolder.add(enumeration, defaultOption, enumeration).name(path);\r\n dropdownController.onChange(handleDropdownChange);\r\n dropdownController.domElement.classList.add('peditoritem');\r\n }\r\n }\r\n break;\r\n\r\n case 'boolean':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n let w = currentFolder.add(material.uniforms[name], 'value').name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'vector2':\r\n case 'vector3':\r\n case 'vector4':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = [DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN];\r\n var maxValue = [DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX];\r\n var step = [0, 0, 0, 0];\r\n\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = nodeDefInput.getAttribute('uisoftmin').split(',').map(Number);\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = nodeDefInput.getAttribute('uimin').split(',').map(Number);\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = nodeDefInput.getAttribute('uisoftmax').split(',').map(Number);\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = nodeDefInput.getAttribute('uimax').split(',').map(Number);\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = nodeDefInput.getAttribute('uistep').split(',').map(Number);\r\n }\r\n for (let i = 0; i < 4; ++i)\r\n {\r\n if (step[i] == 0)\r\n {\r\n step[i] = 1 / (maxValue[i] - minValue[i]);\r\n }\r\n }\r\n\r\n const keyString = [\"x\", \"y\", \"z\", \"w\"];\r\n let vecFolder = currentFolder.addFolder(path);\r\n Object.keys(material.uniforms[name].value).forEach((key) =>\r\n {\r\n let w = vecFolder.add(material.uniforms[name].value,\r\n key, minValue[key], maxValue[key], step[key]).name(keyString[key]);\r\n w.domElement.classList.add('peditoritem');\r\n })\r\n }\r\n break;\r\n\r\n case 'color3':\r\n // Irksome way to map arrays to colors and back\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var dummy =\r\n {\r\n color: 0xFF0000\r\n };\r\n const color3 = new three__WEBPACK_IMPORTED_MODULE_1__.Color(dummy.color);\r\n color3.fromArray(material.uniforms[name].value);\r\n dummy.color = color3.getHex();\r\n let w = currentFolder.addColor(dummy, 'color').name(path)\r\n .onChange(function (value)\r\n {\r\n const color3 = new three__WEBPACK_IMPORTED_MODULE_1__.Color(value);\r\n material.uniforms[name].value.set(color3.toArray());\r\n });\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'color4':\r\n break;\r\n\r\n case 'matrix33':\r\n case 'matrix44':\r\n case 'samplerCube':\r\n case 'filename':\r\n break;\r\n case 'string':\r\n console.log('String: ', name);\r\n if (value != null)\r\n {\r\n var dummy =\r\n {\r\n thevalue: value\r\n }\r\n let item = currentFolder.add(dummy, 'thevalue');\r\n item.name(path);\r\n item.disable(true);\r\n item.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n }\r\n });\r\n\r\n if (logDetailedTime)\r\n {\r\n console.log(\" - Editor update time: \", performance.now() - startTime, \"ms\");\r\n }\r\n }\r\n\r\n // List of material assignments: { MaterialX node, geometry assignment string, and hardware shader }\r\n _materials;\r\n\r\n // Fallback material if nothing was assigned explicitly\r\n _defaultMaterial;\r\n}\r\n\r\n/*\r\n Viewer class\r\n\r\n Keeps track of local scene, and property editor as well as current MaterialX document \r\n and assocaited material, shader and lighting information.\r\n*/\r\nclass Viewer\r\n{\r\n static create()\r\n {\r\n return new Viewer();\r\n }\r\n\r\n constructor()\r\n {\r\n this.scene = new Scene();\r\n this.editor = new Editor();\r\n this.materials.push(new Material());\r\n\r\n this.fileLoader = new three__WEBPACK_IMPORTED_MODULE_1__.FileLoader();\r\n this.hdrLoader = new three_examples_jsm_loaders_RGBELoader_js__WEBPACK_IMPORTED_MODULE_5__.RGBELoader();\r\n }\r\n\r\n //\r\n // Create shader generator, generation context and \"base\" document which\r\n // contains the standard definition libraries and lighting elements.\r\n //\r\n async initialize(mtlxIn, renderer, radianceTexture, irradianceTexture, lightRigXml)\r\n {\r\n this.mx = mtlxIn;\r\n\r\n // Initialize base document\r\n this.generator = new this.mx.EsslShaderGenerator();\r\n this.genContext = new this.mx.GenContext(this.generator);\r\n\r\n this.document = this.mx.createDocument();\r\n this.stdlib = this.mx.loadStandardLibraries(this.genContext);\r\n this.document.importLibrary(this.stdlib);\r\n\r\n this.initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml);\r\n\r\n radianceTexture.mapping = three__WEBPACK_IMPORTED_MODULE_1__.EquirectangularReflectionMapping;\r\n this.getScene().setBackgroundTexture(radianceTexture);\r\n }\r\n\r\n //\r\n // Load in lighting rig document and register lights with generation context\r\n // Initialize environment lighting (IBLs).\r\n //\r\n async initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml)\r\n {\r\n // Load lighting setup into document\r\n const mx = this.getMx();\r\n this.lightRigDoc = mx.createDocument();\r\n await mx.readFromXmlString(this.lightRigDoc, lightRigXml);\r\n this.document.importLibrary(this.lightRigDoc);\r\n\r\n // Register lights with generation context\r\n this.lights = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.findLights)(this.document);\r\n this.lightData = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.registerLights)(mx, this.lights, this.genContext);\r\n\r\n this.radianceTexture = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.prepareEnvTexture)(radianceTexture, renderer.capabilities);\r\n this.irradianceTexture = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.prepareEnvTexture)(irradianceTexture, renderer.capabilities);\r\n }\r\n\r\n getEditor()\r\n {\r\n return this.editor;\r\n }\r\n\r\n getScene()\r\n {\r\n return this.scene;\r\n }\r\n\r\n getMaterial()\r\n {\r\n return this.materials[0];\r\n }\r\n\r\n getFileLoader()\r\n {\r\n return this.fileLoader;\r\n }\r\n\r\n getHdrLoader()\r\n {\r\n return this.hdrLoader;\r\n }\r\n\r\n setDocument(doc)\r\n {\r\n this.doc = doc;\r\n }\r\n getDocument()\r\n {\r\n return this.doc;\r\n }\r\n\r\n getLibrary()\r\n {\r\n return this.stdlib;\r\n }\r\n\r\n getLightRig()\r\n {\r\n return this.lightRigDoc;\r\n }\r\n\r\n getMx()\r\n {\r\n return this.mx;\r\n }\r\n\r\n getGenerator()\r\n {\r\n return this.generator;\r\n }\r\n\r\n getGenContext()\r\n {\r\n return this.genContext;\r\n }\r\n\r\n getLights()\r\n {\r\n return this.lights;\r\n }\r\n\r\n getLightData()\r\n {\r\n return this.lightData;\r\n }\r\n\r\n getRadianceTexture()\r\n {\r\n return this.radianceTexture;\r\n }\r\n\r\n getIrradianceTexture()\r\n {\r\n return this.irradianceTexture;\r\n }\r\n\r\n // Three scene and materials. \r\n scene = null;\r\n materials = [];\r\n\r\n // Property editor\r\n editor = null;\r\n\r\n // Utility loaders\r\n fileloader = null;\r\n hdrLoader = null;\r\n\r\n // MaterialX module, current document and support documents.\r\n mx = null;\r\n doc = null;\r\n stdlib = null;\r\n lightRigDoc = null;\r\n\r\n // MaterialX code generator and context\r\n generator = null;\r\n genContext = null;\r\n\r\n // Lighting information\r\n lights = null;\r\n lightData = null;\r\n radianceTexture = null;\r\n irradianceTexture = null;\r\n}\r\n\n\n//# sourceURL=webpack://MaterialX-Swatch-Viewer/./source/viewer.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Editor: () => (/* binding */ Editor),\n/* harmony export */ Material: () => (/* binding */ Material),\n/* harmony export */ Scene: () => (/* binding */ Scene),\n/* harmony export */ Viewer: () => (/* binding */ Viewer)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n/* harmony import */ var three_examples_jsm_loaders_GLTFLoader__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! three/examples/jsm/loaders/GLTFLoader */ \"./node_modules/three/examples/jsm/loaders/GLTFLoader.js\");\n/* harmony import */ var three_examples_jsm_loaders_ObjLoader__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! three/examples/jsm/loaders/ObjLoader */ \"./node_modules/three/examples/jsm/loaders/ObjLoader.js\");\n/* harmony import */ var three_examples_jsm_loaders_RGBELoader_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! three/examples/jsm/loaders/RGBELoader.js */ \"./node_modules/three/examples/jsm/loaders/RGBELoader.js\");\n/* harmony import */ var _helper_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helper.js */ \"./source/helper.js\");\n/* harmony import */ var lil_gui__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! lil-gui */ \"./node_modules/lil-gui/dist/lil-gui.esm.js\");\n//\r\n// Copyright Contributors to the MaterialX Project\r\n// SPDX-License-Identifier: Apache-2.0\r\n//\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nconst ALL_GEOMETRY_SPECIFIER = \"*\";\r\nconst NO_GEOMETRY_SPECIFIER = \"\";\r\nconst DAG_PATH_SEPERATOR = \"/\";\r\n\r\n// Logging toggle\r\nvar logDetailedTime = false;\r\n\r\n/*\r\n Scene management\r\n*/\r\nclass Scene\r\n{\r\n constructor()\r\n {\r\n this._geometryURL = new URLSearchParams(document.location.search).get(\"geom\");\r\n if (!this._geometryURL)\r\n {\r\n this._geometryURL = 'Geometry/teapot.glb';\r\n }\r\n }\r\n\r\n initialize()\r\n {\r\n this._scene = new three__WEBPACK_IMPORTED_MODULE_1__.Scene();\r\n this._scene.background = new three__WEBPACK_IMPORTED_MODULE_1__.Color(this.#_backgroundColor);\r\n this._scene.background.convertSRGBToLinear();\r\n\r\n let cc = document.getElementById('webglcanvas');\r\n console.log('cc: ', cc)\r\n const aspectRatio = cc.width / cc.height;\r\n const cameraNearDist = 0.01;\r\n const cameraFarDist = 1000.0;\r\n const cameraFOV = 60.0;\r\n this._camera = new three__WEBPACK_IMPORTED_MODULE_1__.PerspectiveCamera(cameraFOV, aspectRatio, cameraNearDist, cameraFarDist);\r\n\r\n this.#_gltfLoader = new three_examples_jsm_loaders_GLTFLoader__WEBPACK_IMPORTED_MODULE_2__.GLTFLoader();\r\n this.#_objLoader = new three_examples_jsm_loaders_ObjLoader__WEBPACK_IMPORTED_MODULE_3__.OBJLoader();\r\n\r\n this.#_normalMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix3();\r\n this.#_viewProjMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4();\r\n this.#_worldViewPos = new three__WEBPACK_IMPORTED_MODULE_1__.Vector3();\r\n }\r\n\r\n // Set whether to flip UVs in V for loaded geometry\r\n setFlipGeometryV(val)\r\n {\r\n this.#_flipV = val;\r\n }\r\n\r\n // Get whether to flip UVs in V for loaded geometry\r\n getFlipGeometryV()\r\n {\r\n return this.#_flipV;\r\n }\r\n\r\n // Utility to perform geometry file load\r\n loadGeometryFile(geometryFilename, loader)\r\n {\r\n return new Promise((resolve, reject) =>\r\n {\r\n if (loader) \r\n {\r\n console.log(\"Load geometry: \", geometryFilename); \r\n loader.load(geometryFilename, data => resolve(data), null, reject);\r\n }\r\n });\r\n }\r\n\r\n //\r\n // Load in geometry specified by a given file name,\r\n // then update the scene geometry and camera.\r\n //\r\n async loadGeometry(viewer, orbitControls)\r\n {\r\n var startTime = performance.now();\r\n var geomLoadTime = startTime;\r\n\r\n var gltfData = null;\r\n if (this.getGeometryURL().endsWith('glb'))\r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_gltfLoader);\r\n else if (this.getGeometryURL().endsWith('obj'))\r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_objLoader);\r\n else \r\n gltfData = await this.loadGeometryFile(this.getGeometryURL(), this.#_gltfLoader);\r\n\r\n if (gltfData == null)\r\n {\r\n console.log(\"Failed to load geometry: \", this.getGeometryURL());\r\n return;\r\n }\r\n\r\n const scene = this.getScene();\r\n while (scene.children.length > 0)\r\n {\r\n scene.remove(scene.children[0]);\r\n }\r\n\r\n this.#_rootNode = null;\r\n const model = gltfData.scene;\r\n if (!model)\r\n {\r\n const geometry = new three__WEBPACK_IMPORTED_MODULE_1__.BoxGeometry(1, 1, 1);\r\n const material = new three__WEBPACK_IMPORTED_MODULE_1__.MeshBasicMaterial({ color: 0xdddddd });\r\n const cube = new three__WEBPACK_IMPORTED_MODULE_1__.Mesh(geometry, material);\r\n obj = new three__WEBPACK_IMPORTED_MODULE_1__.Group();\r\n obj.add(geometry);\r\n }\r\n else\r\n {\r\n this.#_rootNode = model;\r\n }\r\n scene.add(model);\r\n\r\n // Always reset controls based on camera for each load. \r\n orbitControls.reset();\r\n console.log(\"- Scene load time: \", performance.now() - geomLoadTime, \"ms\");\r\n\r\n console.log(\"Total geometry load time: \", performance.now() - startTime, \" ms.\");\r\n\r\n viewer.getMaterial().clearSoloMaterialUI();\r\n viewer.getMaterial().updateMaterialAssignments(viewer, viewer.getMaterial().getSoloMaterial());\r\n this.setUpdateTransforms();\r\n\r\n this.updateScene(viewer, orbitControls);\r\n }\r\n\r\n //\r\n // Update the geometry buffer, assigned materials, and camera controls.\r\n //\r\n updateScene(viewer, orbitControls)\r\n {\r\n var startUpdateSceneTime = performance.now();\r\n var uvTime = 0;\r\n var normalTime = 0;\r\n var tangentTime = 0;\r\n var streamTime = 0;\r\n var bboxTime = 0;\r\n\r\n var startBboxTime = performance.now();\r\n const bbox = new three__WEBPACK_IMPORTED_MODULE_1__.Box3().setFromObject(this._scene);\r\n const bsphere = new three__WEBPACK_IMPORTED_MODULE_1__.Sphere();\r\n bbox.getBoundingSphere(bsphere);\r\n bboxTime = performance.now() - startBboxTime;\r\n\r\n let theScene = viewer.getScene();\r\n let flipV = theScene.getFlipGeometryV();\r\n\r\n\r\n this._scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n var startUVTime = performance.now();\r\n if (!child.geometry.attributes.uv)\r\n {\r\n const posCount = child.geometry.attributes.position.count;\r\n const uvs = [];\r\n const pos = child.geometry.attributes.position.array;\r\n\r\n for (let i = 0; i < posCount; i++)\r\n {\r\n uvs.push((pos[i * 3] - bsphere.center.x) / bsphere.radius);\r\n uvs.push((pos[i * 3 + 1] - bsphere.center.y) / bsphere.radius);\r\n }\r\n\r\n child.geometry.setAttribute('uv', new three__WEBPACK_IMPORTED_MODULE_1__.BufferAttribute(new Float32Array(uvs), 2));\r\n }\r\n else if (flipV)\r\n {\r\n const uvCount = child.geometry.attributes.position.count;\r\n const uvs = child.geometry.attributes.uv.array;\r\n for (let i = 0; i < uvCount; i++)\r\n {\r\n let v = 1.0 - (uvs[i * 2 + 1]);\r\n uvs[i * 2 + 1] = v;\r\n }\r\n }\r\n uvTime += performance.now() - startUVTime;\r\n\r\n if (!child.geometry.attributes.normal)\r\n {\r\n var startNormalTime = performance.new();\r\n child.geometry.computeVertexNormals();\r\n normalTime += performance.now() - startNormalTime;\r\n }\r\n\r\n if (child.geometry.getIndex())\r\n {\r\n if (!child.geometry.attributes.tangent)\r\n {\r\n var startTangentTime = performance.now();\r\n child.geometry.computeTangents();\r\n tangentTime += performance.now() - startTangentTime;\r\n }\r\n }\r\n\r\n // Use default MaterialX naming convention.\r\n var startStreamTime = performance.now();\r\n child.geometry.attributes.i_position = child.geometry.attributes.position;\r\n child.geometry.attributes.i_normal = child.geometry.attributes.normal;\r\n child.geometry.attributes.i_tangent = child.geometry.attributes.tangent;\r\n child.geometry.attributes.i_texcoord_0 = child.geometry.attributes.uv;\r\n streamTime += performance.now() - startStreamTime;\r\n }\r\n });\r\n\r\n console.log(\"- Stream update time: \", performance.now() - startUpdateSceneTime, \"ms\");\r\n if (logDetailedTime)\r\n {\r\n console.log(' - UV time: ', uvTime);\r\n console.log(' - Normal time: ', normalTime);\r\n console.log(' - Tangent time: ', tangentTime);\r\n console.log(' - Stream Update time: ', streamTime);\r\n console.log(' - Bounds compute time: ', bboxTime);\r\n }\r\n\r\n // Update the background\r\n this._scene.background = this.getBackground();\r\n\r\n //console.log('bounding sphere:', bsphere.center, bsphere.radius);\r\n\r\n // Fit camera to model\r\n const camera = this.getCamera();\r\n camera.position.y = bsphere.center.y;\r\n camera.position.z = bsphere.radius * 2.0;\r\n camera.updateProjectionMatrix();\r\n\r\n orbitControls.target = bsphere.center;\r\n orbitControls.update();\r\n }\r\n\r\n setUpdateTransforms()\r\n {\r\n this.#_updateTransforms = true;\r\n }\r\n\r\n updateTransforms()\r\n {\r\n // Only update on demand versus continuously.\r\n // Call setUpdateTransforms() to trigger an update here.\r\n // Required for: scene geometry, camera change and viewport resize. \r\n if (!this.#_updateTransforms)\r\n {\r\n return;\r\n }\r\n this.#_updateTransforms = false;\r\n\r\n const scene = this.getScene();\r\n const camera = this.getCamera();\r\n scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n const uniforms = child.material.uniforms;\r\n if (uniforms)\r\n {\r\n uniforms.u_worldMatrix.value = child.matrixWorld;\r\n uniforms.u_viewProjectionMatrix.value = this.#_viewProjMat.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);\r\n\r\n if (uniforms.u_viewPosition)\r\n uniforms.u_viewPosition.value = camera.getWorldPosition(this.#_worldViewPos);\r\n\r\n if (uniforms.u_worldInverseTransposeMatrix)\r\n uniforms.u_worldInverseTransposeMatrix.value =\r\n new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4().setFromMatrix3(this.#_normalMat.getNormalMatrix(child.matrixWorld));\r\n }\r\n }\r\n });\r\n }\r\n\r\n // Determine string DAG path based on individual node names.\r\n getDagPath(node)\r\n {\r\n const rootNode = this.#_rootNode;\r\n\r\n let path = [node.name];\r\n while (node.parent)\r\n {\r\n node = node.parent;\r\n if (node)\r\n {\r\n // Stop at the root of the scene read in.\r\n if (node == rootNode)\r\n {\r\n break;\r\n }\r\n path.unshift(node.name);\r\n }\r\n }\r\n return path;\r\n }\r\n\r\n // Assign material shader to associated geometry\r\n updateMaterial(matassign)\r\n {\r\n let assigned = 0;\r\n\r\n const shader = matassign.getShader();\r\n const material = matassign.getMaterial().getName();\r\n const geometry = matassign.getGeometry();\r\n const collection = matassign.getCollection();\r\n\r\n const scene = this.getScene();\r\n const camera = this.getCamera();\r\n scene.traverse((child) =>\r\n {\r\n if (child.isMesh)\r\n {\r\n const dagPath = this.getDagPath(child).join('/');\r\n\r\n // Note that this is a very simplistic\r\n // assignment resolve and assumes basic\r\n // regular expression name match.\r\n let matches = (geometry == ALL_GEOMETRY_SPECIFIER);\r\n if (!matches)\r\n {\r\n if (collection)\r\n {\r\n if (collection.matchesGeomString(dagPath))\r\n {\r\n matches = true;\r\n }\r\n }\r\n else\r\n {\r\n if (geometry != NO_GEOMETRY_SPECIFIER)\r\n {\r\n const paths = geometry.split(',');\r\n for (let path of paths)\r\n {\r\n if (dagPath.match(path))\r\n {\r\n matches = true;\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n if (matches)\r\n {\r\n child.material = shader;\r\n assigned++;\r\n }\r\n }\r\n });\r\n\r\n return assigned;\r\n }\r\n\r\n updateCamera()\r\n {\r\n const camera = this.getCamera();\r\n let container = document.getElementById('canvasContainer');\r\n var maxWidth = 4086;\r\n var maxHeight = 1024;\r\n var width = Math.min(container.clientWidth, maxWidth);\r\n var height = Math.min(container.clientHeight, maxHeight); \r\n\r\n camera.aspect = width / height;\r\n camera.updateProjectionMatrix();\r\n }\r\n\r\n getScene()\r\n {\r\n return this._scene;\r\n }\r\n\r\n getCamera()\r\n {\r\n return this._camera;\r\n }\r\n\r\n getGeometryURL()\r\n {\r\n return this._geometryURL;\r\n }\r\n\r\n setGeometryURL(url)\r\n {\r\n this._geometryURL = url;\r\n }\r\n\r\n setBackgroundTexture(texture)\r\n {\r\n this.#_backgroundTexture = texture;\r\n }\r\n\r\n getShowBackgroundTexture()\r\n {\r\n return this.#_showBackgroundTexture;\r\n }\r\n\r\n setShowBackgroundTexture(enable)\r\n {\r\n this.#_showBackgroundTexture = enable;\r\n }\r\n\r\n getBackground()\r\n {\r\n if (this.#_backgroundTexture && this.#_showBackgroundTexture)\r\n {\r\n return this.#_backgroundTexture;\r\n }\r\n var color = new three__WEBPACK_IMPORTED_MODULE_1__.Color(this.#_backgroundColor);\r\n color.convertSRGBToLinear();\r\n return color;\r\n }\r\n\r\n toggleBackgroundTexture()\r\n {\r\n this.#_showBackgroundTexture = !this.#_showBackgroundTexture;\r\n this._scene.background = this.getBackground();\r\n }\r\n\r\n // Geometry file\r\n #_geometryURL = '';\r\n // Geometry loaders\r\n #_gltfLoader = null;\r\n #_objLoader = null;\r\n // Flip V coordinate of texture coordinates.\r\n // Set to true to be consistent with desktop viewer.\r\n #_flipV = true;\r\n\r\n // Scene\r\n #_scene = null;\r\n\r\n // Camera\r\n #_camera = null;\r\n\r\n // Background color\r\n #_backgroundColor = 0xAcAdBB;\r\n\r\n // Background texture\r\n #_backgroundTexture = null;\r\n #_showBackgroundTexture = false;\r\n\r\n // Transform matrices\r\n #_normalMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix3();\r\n #_viewProjMat = new three__WEBPACK_IMPORTED_MODULE_1__.Matrix4();\r\n #_worldViewPos = new three__WEBPACK_IMPORTED_MODULE_1__.Vector3();\r\n #_updateTransforms = true;\r\n\r\n // Root node of imported scene\r\n #_rootNode = null;\r\n}\r\n\r\n/* \r\n Property editor\r\n*/\r\nclass Editor\r\n{\r\n // Initialize the editor, clearing any elements from previous materials.\r\n initialize()\r\n {\r\n Array.from(document.getElementsByClassName('lil-gui')).forEach(\r\n function (element, index, array)\r\n {\r\n if (element.className)\r\n {\r\n element.remove();\r\n }\r\n }\r\n );\r\n\r\n let parent = document.getElementById( 'webglcanvas' );\r\n //console.log('parent:', parent);\r\n this._gui = new lil_gui__WEBPACK_IMPORTED_MODULE_4__[\"default\"]( { title: \"Properties\" }, { container: parent } );\r\n //parent = this._gui.domElement;\r\n //console.log('gui parent:', parent);\r\n // Parent parent under webglcanvas\r\n //document.getElementById( 'webglcanvas' ).appendChild( parent );\r\n\r\n //this._gui = new GUI({ title: \"Property Editor\" });\r\n this._gui.close();\r\n this._gui.hide();\r\n }\r\n\r\n // Update ui properties\r\n // - Hide close button\r\n // - Update transparency so scene shows through if overlapping\r\n updateProperties(targetOpacity = 1)\r\n {\r\n // Set opacity\r\n Array.from(document.getElementsByClassName('dg')).forEach(\r\n function (element, index, array)\r\n {\r\n element.style.opacity = targetOpacity;\r\n }\r\n );\r\n }\r\n\r\n getGUI()\r\n {\r\n return this._gui;\r\n }\r\n\r\n _gui = null;\r\n}\r\n\r\nclass MaterialAssign\r\n{\r\n constructor(material, geometry, collection)\r\n {\r\n this._material = material;\r\n this._geometry = geometry;\r\n this._collection = collection;\r\n this._shader = null;\r\n this._materialUI = null;\r\n }\r\n\r\n setMaterialUI(value)\r\n {\r\n this._materialUI = value;\r\n }\r\n\r\n getMaterialUI()\r\n {\r\n return this._materialUI;\r\n }\r\n\r\n setShader(shader)\r\n {\r\n this._shader = shader;\r\n }\r\n\r\n getShader()\r\n {\r\n return this._shader;\r\n }\r\n\r\n getMaterial()\r\n {\r\n return this._material;\r\n }\r\n\r\n getGeometry()\r\n {\r\n return this._geometry;\r\n }\r\n\r\n setGeometry(value)\r\n {\r\n this._geometry = value;\r\n }\r\n\r\n getCollection()\r\n {\r\n return this._collection;\r\n }\r\n\r\n // MaterialX material node name\r\n _material;\r\n\r\n // MaterialX assignment geometry string\r\n _geometry;\r\n\r\n // MaterialX assignment collection\r\n _collection;\r\n\r\n // THREE.JS shader\r\n _shader;\r\n}\r\n\r\nclass Material\r\n{\r\n constructor()\r\n {\r\n this._materials = [];\r\n this._defaultMaterial = null;\r\n this._soloMaterial = \"\";\r\n this._shaderInterfaceType = 0;\r\n }\r\n\r\n clearMaterials()\r\n {\r\n this._materials.length = 0;\r\n this._defaultMaterial = null;\r\n this._soloMaterial = \"\";\r\n }\r\n\r\n setSoloMaterial(value)\r\n {\r\n this._soloMaterial = value;\r\n }\r\n\r\n getSoloMaterial()\r\n {\r\n return this._soloMaterial;\r\n }\r\n\r\n // If no material file is selected, we programmatically create a default material as a fallback\r\n static createFallbackMaterial(doc)\r\n {\r\n let ssNode = doc.getChild('Generated_Default_Shader');\r\n if (ssNode)\r\n {\r\n return ssNode;\r\n }\r\n const ssName = 'Generated_Default_Shader';\r\n ssNode = doc.addChildOfCategory('standard_surface', ssName);\r\n ssNode.setType('surfaceshader');\r\n const smNode = doc.addChildOfCategory('surfacematerial', 'Default');\r\n smNode.setType('material');\r\n const shaderElement = smNode.addInput('surfaceshader');\r\n shaderElement.setType('surfaceshader');\r\n shaderElement.setNodeName(ssName);\r\n\r\n return ssNode;\r\n }\r\n\r\n async loadMaterialFile(loader, materialFilename)\r\n {\r\n return new Promise((resolve, reject) =>\r\n {\r\n loader.load(materialFilename, data => resolve(data), null, reject);\r\n });\r\n }\r\n\r\n async loadMaterials(viewer, materialFilename)\r\n {\r\n const fileloader = viewer.getFileLoader();\r\n\r\n let mtlxMaterial = await viewer.getMaterial().loadMaterialFile(fileloader, materialFilename);\r\n\r\n this.loadMaterialFromString(viewer, mtlxMaterial, materialFilename);\r\n }\r\n\r\n async loadMaterialFromString(viewer, mtlxMaterial, materialFilename, searchPath)\r\n {\r\n var startTime = performance.now();\r\n\r\n const mx = viewer.getMx();\r\n\r\n // Re-initialize document\r\n var startDocTime = performance.now();\r\n var doc = mx.createDocument();\r\n doc.importLibrary(viewer.getLibrary());\r\n if (!doc.validate())\r\n {\r\n console.log(\"MaterialX document validation failed.\");\r\n return;\r\n }\r\n\r\n viewer.setDocument(doc);\r\n\r\n // Load lighting setup into document\r\n doc.importLibrary(viewer.getLightRig());\r\n\r\n console.log(\"- Material document load time: \", performance.now() - startDocTime, \"ms.\");\r\n\r\n // Set search path. Assumes images are relative to current file\r\n // location.\r\n if (!materialFilename) materialFilename = \"/\";\r\n const paths = materialFilename.split('/');\r\n paths.pop();\r\n searchPath = '/javascript/shader_utilities/dist';\r\n console.log('Global search path: ', searchPath);\r\n\r\n // Load material\r\n if (mtlxMaterial)\r\n try { \r\n await mx.readFromXmlString(doc, mtlxMaterial, searchPath);\r\n }\r\n catch (error) {\r\n console.error('Error loading material file: ', error);\r\n }\r\n else\r\n Material.createFallbackMaterial(doc);\r\n\r\n // Check if there are any looks defined in the document\r\n // If so then traverse the looks for all material assignments.\r\n // Generate code and compile for any associated surface shader\r\n // and assign to the associated geometry. If there are no looks\r\n // then the first material is found and assignment to all the\r\n // geometry.\r\n this.clearMaterials();\r\n var looks = doc.getLooks();\r\n if (looks.length)\r\n {\r\n for (let look of looks)\r\n {\r\n const materialAssigns = look.getMaterialAssigns();\r\n for (let materialAssign of materialAssigns)\r\n {\r\n let matName = materialAssign.getMaterial();\r\n if (matName)\r\n {\r\n let mat = doc.getChild(matName);\r\n var shader;\r\n if (mat)\r\n {\r\n var shaders = mx.getShaderNodes(mat);\r\n if (shaders.length)\r\n {\r\n shader = shaders[0];\r\n }\r\n }\r\n let collection = materialAssign.getCollection();\r\n let geom = materialAssign.getGeom();\r\n let newAssignment;\r\n if (collection || geom)\r\n {\r\n // Remove leading \"/\" from collection and geom for \r\n // later assignment comparison checking\r\n if (collection && collection.charAt(0) == \"/\")\r\n {\r\n collection = collection.slice(1);\r\n }\r\n if (geom && geom.charAt(0) == \"/\")\r\n {\r\n geom = geom.slice(1);\r\n }\r\n newAssignment = new MaterialAssign(shader, geom, collection);\r\n }\r\n else\r\n {\r\n newAssignment = new MaterialAssign(shader, NO_GEOMETRY_SPECIFIER, null);\r\n }\r\n\r\n if (newAssignment)\r\n {\r\n this._materials.push(newAssignment);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n else\r\n {\r\n // Search for any surface shaders. The first found\r\n // is assumed to be assigned to the entire scene\r\n // The identifier used is \"*\" to mean the entire scene. \r\n const materialNodes = doc.getMaterialNodes();\r\n let shaderList = [];\r\n let foundRenderable = false;\r\n for (let i = 0; i < materialNodes.length; ++i)\r\n {\r\n let materialNode = materialNodes[i];\r\n if (materialNode)\r\n {\r\n //console.log('Scan material: ', materialNode.getNamePath());\r\n let shaderNodes = mx.getShaderNodes(materialNode)\r\n if (shaderNodes.length > 0)\r\n {\r\n let shaderNodePath = shaderNodes[0].getNamePath()\r\n if (!shaderList.includes(shaderNodePath))\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n //console.log('-- add shader: ', shaderNodePath);\r\n shaderList.push(shaderNodePath);\r\n this._materials.push(new MaterialAssign(shaderNodes[0], assignment));\r\n }\r\n }\r\n }\r\n }\r\n const nodeGraphs = doc.getNodeGraphs();\r\n for (let i = 0; i < nodeGraphs.length; ++i)\r\n {\r\n let nodeGraph = nodeGraphs[i];\r\n if (nodeGraph)\r\n {\r\n if (nodeGraph.hasAttribute('nodedef') || nodeGraph.hasSourceUri())\r\n {\r\n continue;\r\n }\r\n // Skip any nodegraph that is connected to something downstream\r\n if (nodeGraph.getDownstreamPorts().length > 0)\r\n {\r\n continue\r\n }\r\n let outputs = nodeGraph.getOutputs();\r\n for (let j = 0; j < outputs.length; ++j)\r\n {\r\n let output = outputs[j];\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n let newMat = new MaterialAssign(output, assignment, null);\r\n this._materials.push(newMat);\r\n }\r\n }\r\n }\r\n }\r\n const outputs = doc.getOutputs();\r\n for (let i = 0; i < outputs.length; ++i)\r\n {\r\n let output = outputs[i];\r\n if (output)\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n this._materials.push(new MaterialAssign(output, assignment));\r\n }\r\n }\r\n\r\n const shaderNodes = [];\r\n for (let i = 0; i < shaderNodes.length; ++i)\r\n {\r\n let shaderNode = shaderNodes[i];\r\n let shaderNodePath = shaderNode.getNamePath()\r\n if (!shaderList.includes(shaderNodePath))\r\n {\r\n let assignment = NO_GEOMETRY_SPECIFIER;\r\n if (foundRenderable == false)\r\n {\r\n assignment = ALL_GEOMETRY_SPECIFIER;\r\n foundRenderable = true;\r\n }\r\n shaderList.push(shaderNodePath);\r\n this._materials.push(new MaterialAssign(shaderNode, assignment));\r\n }\r\n }\r\n }\r\n\r\n // Assign to default material if none found\r\n if (this._materials.length == 0)\r\n {\r\n const defaultNode = Material.createFallbackMaterial(doc);\r\n this._materials.push(new MaterialAssign(defaultNode, ALL_GEOMETRY_SPECIFIER));\r\n }\r\n\r\n // Create a new shader for each material node.\r\n // Only create the shader once even if assigned more than once.\r\n var startGenTime = performance.now();\r\n let shaderMap = new Map();\r\n let closeUI = false;\r\n for (let matassign of this._materials)\r\n {\r\n // Need to use path vs name to get a unique key.\r\n let materialName = matassign.getMaterial().getNamePath();\r\n let shader = shaderMap[materialName];\r\n if (!shader)\r\n {\r\n shader = viewer.getMaterial().generateMaterial(matassign, viewer, searchPath, closeUI);\r\n shaderMap[materialName] = shader;\r\n }\r\n matassign.setShader(shader);\r\n closeUI = true;\r\n }\r\n console.log(\"- Generate (\", this._materials.length, \") shader(s) time: \", performance.now() - startGenTime, \" ms.\",);\r\n\r\n // Update scene shader assignments\r\n this.updateMaterialAssignments(viewer, this._soloMaterial);\r\n\r\n // Mark transform update\r\n viewer.getScene().setUpdateTransforms();\r\n\r\n console.log(\"Total material time: \", (performance.now() - startTime), \"ms\");\r\n }\r\n\r\n //\r\n // Update the assignments for scene objects based on the\r\n // material assignment information stored in the viewer.\r\n // Note: If none of the MaterialX assignments match the geometry\r\n // in the scene, then the first material assignment shader is assigned\r\n // to the entire scene.\r\n //\r\n async updateMaterialAssignments(viewer, soloMaterial)\r\n {\r\n console.log(\"Update material assignments. Solo=\", soloMaterial);\r\n var startTime = performance.now();\r\n\r\n let assigned = 0;\r\n let assignedSolo = false;\r\n for (let matassign of this._materials)\r\n {\r\n if (matassign.getShader())\r\n {\r\n if (soloMaterial.length)\r\n {\r\n if (matassign.getMaterial().getNamePath() == soloMaterial)\r\n {\r\n let temp = matassign.getGeometry();\r\n matassign.setGeometry(ALL_GEOMETRY_SPECIFIER);\r\n assigned += viewer.getScene().updateMaterial(matassign);\r\n matassign.setGeometry(temp);\r\n assignedSolo = true;\r\n break\r\n }\r\n }\r\n else\r\n {\r\n assigned += viewer.getScene().updateMaterial(matassign);\r\n }\r\n }\r\n }\r\n if (assigned == 0 && this._materials.length)\r\n {\r\n this._defaultMaterial = new MaterialAssign(this._materials[0].getMaterial(), ALL_GEOMETRY_SPECIFIER);\r\n this._defaultMaterial.setShader(this._materials[0].getShader());\r\n viewer.getScene().updateMaterial(this._defaultMaterial);\r\n }\r\n\r\n if (assigned > 0)\r\n {\r\n console.log('Material assignment time: ', performance.now() - startTime, \" ms.\");\r\n }\r\n }\r\n\r\n // \r\n // Generate a new material for a given element\r\n //\r\n generateMaterial(matassign, viewer, searchPath, closeUI)\r\n {\r\n var elem = matassign.getMaterial();\r\n\r\n var startGenerateMat = performance.now();\r\n\r\n const mx = viewer.getMx();\r\n const textureLoader = new three__WEBPACK_IMPORTED_MODULE_1__.TextureLoader();\r\n\r\n const lights = viewer.getLights();\r\n const lightData = viewer.getLightData();\r\n const radianceTexture = viewer.getRadianceTexture();\r\n const irradianceTexture = viewer.getIrradianceTexture();\r\n const gen = viewer.getGenerator();\r\n const genContext = viewer.getGenContext();\r\n\r\n // Perform transparency check on renderable item\r\n var startTranspCheckTime = performance.now();\r\n const isTransparent = mx.isTransparentSurface(elem, gen.getTarget());\r\n genContext.getOptions().hwTransparency = isTransparent;\r\n // Always set to complete. \r\n // Can consider option to set to reduced as the parsing of large numbers of uniforms (e.g. on shading models)\r\n // can be quite expensive.\r\n if (this._shaderInterfaceType == 0)\r\n genContext.getOptions().shaderInterfaceType = mx.ShaderInterfaceType.SHADER_INTERFACE_REDUCED;\r\n else\r\n genContext.getOptions().shaderInterfaceType = mx.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE;\r\n\r\n if (logDetailedTime)\r\n console.log(\" - Transparency check time: \", performance.now() - startTranspCheckTime, \"ms\");\r\n\r\n // Generate GLES code\r\n var startMTLXGenTime = performance.now();\r\n let shader = gen.generate(elem.getNamePath(), elem, genContext);\r\n if (logDetailedTime)\r\n console.log(\" - MaterialX gen time: \", performance.now() - startMTLXGenTime, \"ms\");\r\n\r\n var startUniformUpdate = performance.now();\r\n\r\n // Get shaders and uniform values\r\n let vShader = shader.getSourceCode(\"vertex\");\r\n let fShader = shader.getSourceCode(\"pixel\");\r\n\r\n let theScene = viewer.getScene();\r\n let flipV = theScene.getFlipGeometryV();\r\n let uniforms = {\r\n ...(0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getUniformValues)(shader.getStage('vertex'), textureLoader, searchPath, flipV),\r\n ...(0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getUniformValues)(shader.getStage('pixel'), textureLoader, searchPath, flipV),\r\n }\r\n\r\n Object.assign(uniforms, {\r\n u_numActiveLightSources: { value: lights.length}, //value: lights.length },\r\n u_lightData: { value: lightData },\r\n u_envMatrix: { value: (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.getLightRotation)() },\r\n u_envRadiance: { value: radianceTexture },\r\n u_envRadianceMips: { value: Math.trunc(Math.log2(Math.max(radianceTexture.image.width, radianceTexture.image.height))) + 1 },\r\n u_envRadianceSamples: { value: 2 },\r\n u_envIrradiance: { value: irradianceTexture },\r\n u_refractionEnv: { value: false }\r\n });\r\n\r\n // Create Three JS Material\r\n let newMaterial = new three__WEBPACK_IMPORTED_MODULE_1__.RawShaderMaterial({\r\n uniforms: uniforms,\r\n vertexShader: vShader,\r\n fragmentShader: fShader,\r\n transparent: isTransparent,\r\n blendEquation: three__WEBPACK_IMPORTED_MODULE_1__.AddEquation,\r\n blendSrc: three__WEBPACK_IMPORTED_MODULE_1__.OneMinusSrcAlphaFactor,\r\n blendDst: three__WEBPACK_IMPORTED_MODULE_1__.SrcAlphaFactor,\r\n side: three__WEBPACK_IMPORTED_MODULE_1__.DoubleSide\r\n });\r\n\r\n if (logDetailedTime)\r\n console.log(\" - Three material update time: \", performance.now() - startUniformUpdate, \"ms\");\r\n\r\n // Update property editor\r\n const gui = viewer.getEditor().getGUI();\r\n this.updateEditor(matassign, shader, newMaterial, gui, closeUI, viewer);\r\n\r\n if (logDetailedTime)\r\n console.log(\"- Per material generate time: \", performance.now() - startGenerateMat, \"ms\");\r\n\r\n return newMaterial;\r\n }\r\n\r\n clearSoloMaterialUI()\r\n {\r\n for (let i = 0; i < this._materials.length; ++i)\r\n {\r\n let matassign = this._materials[i];\r\n let matUI = matassign.getMaterialUI();\r\n if (matUI)\r\n {\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n matTitle.classList.remove('peditor_material_assigned');\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n img.src = 'public/shader_ball.svg';\r\n //matTitle.classList.remove('peditor_material_unassigned');\r\n }\r\n }\r\n }\r\n\r\n static updateSoloMaterial(viewer, elemPath, materials, event)\r\n {\r\n // Prevent the event from being passed to parent folder\r\n event.stopPropagation();\r\n\r\n for (let i = 0; i < materials.length; ++i)\r\n {\r\n let matassign = materials[i];\r\n // Need to use path vs name to get a unique key.\r\n let materialName = matassign.getMaterial().getNamePath();\r\n var matUI = matassign.getMaterialUI();\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n if (materialName == elemPath)\r\n {\r\n if (this._soloMaterial == elemPath)\r\n {\r\n img.src = 'public/shader_ball.svg';\r\n matTitle.classList.remove('peditor_material_assigned');\r\n this._soloMaterial = \"\";\r\n }\r\n else\r\n {\r\n img.src = 'public/shader_ball2.svg';\r\n matTitle.classList.add('peditor_material_assigned');\r\n this._soloMaterial = elemPath;\r\n }\r\n }\r\n else\r\n {\r\n img.src = 'public/shader_ball.svg';\r\n matTitle.classList.remove('peditor_material_assigned');\r\n }\r\n }\r\n viewer.getMaterial().updateMaterialAssignments(viewer, \"\");\r\n viewer.getScene().setUpdateTransforms();\r\n }\r\n\r\n //\r\n // Update property editor for a given MaterialX element, it's shader, and\r\n // Three material\r\n //\r\n updateEditor(matassign, shader, material, gui, closeUI, viewer)\r\n {\r\n return;\r\n\r\n var elem = matassign.getMaterial();\r\n var materials = this._materials;\r\n\r\n const DEFAULT_MIN = 0;\r\n const DEFAULT_MAX = 100;\r\n\r\n var startTime = performance.now();\r\n\r\n const elemPath = elem.getNamePath();\r\n\r\n // Create and cache associated UI\r\n var matUI = gui.addFolder(elemPath);\r\n matassign.setMaterialUI(matUI);\r\n\r\n let matTitle = matUI.domElement.getElementsByClassName('title')[0];\r\n // Add a icon to the title to allow for assigning the material to geometry\r\n // Clicking on the icon will \"solo\" the material to the geometry.\r\n // Clicking on the title will open/close the material folder.\r\n matTitle.innerHTML = \" \" + elem.getNamePath();\r\n let img = matTitle.getElementsByTagName('img')[0];\r\n if (img)\r\n {\r\n // Add event listener to icon to call updateSoloMaterial function\r\n img.addEventListener('click', function (event)\r\n {\r\n Material.updateSoloMaterial(viewer, elemPath, materials, event);\r\n });\r\n }\r\n\r\n if (closeUI)\r\n {\r\n matUI.close();\r\n }\r\n const uniformBlocks = Object.values(shader.getStage('pixel').getUniformBlocks());\r\n var uniformToUpdate;\r\n const ignoreList = ['u_envRadianceMips', 'u_envRadianceSamples', 'u_alphaThreshold'];\r\n\r\n var folderList = new Map();\r\n folderList[elemPath] = matUI;\r\n\r\n uniformBlocks.forEach(uniforms =>\r\n {\r\n if (!uniforms.empty())\r\n {\r\n for (let i = 0; i < uniforms.size(); ++i)\r\n {\r\n const variable = uniforms.get(i);\r\n const value = variable.getValue()?.getData();\r\n let name = variable.getVariable();\r\n\r\n if (ignoreList.includes(name))\r\n {\r\n continue;\r\n }\r\n\r\n let currentFolder = matUI;\r\n let currentElemPath = variable.getPath();\r\n if (!currentElemPath || currentElemPath.length == 0)\r\n {\r\n continue;\r\n }\r\n let currentElem = elem.getDocument().getDescendant(currentElemPath);\r\n if (!currentElem)\r\n {\r\n continue;\r\n }\r\n\r\n let currentNode = null;\r\n if (currentElem.getParent() && currentElem.getParent().getNamePath() != \"\")\r\n {\r\n currentNode = currentElem.getParent();\r\n }\r\n let uiname = \"\";\r\n let nodeDefInput = null;\r\n if (currentNode)\r\n {\r\n\r\n let currentNodePath = currentNode.getNamePath();\r\n var pathSplit = currentNodePath.split('/');\r\n if (pathSplit.length)\r\n {\r\n currentNodePath = pathSplit[0];\r\n }\r\n currentFolder = folderList[currentNodePath];\r\n if (!currentFolder)\r\n {\r\n currentFolder = matUI.addFolder(currentNodePath);\r\n folderList[currentNodePath] = currentFolder;\r\n }\r\n\r\n // Check for ui attributes\r\n var nodeDef = currentNode.getNodeDef();\r\n if (nodeDef)\r\n {\r\n // Remove node name from shader uniform name for non root nodes\r\n let lookup_name = name.replace(currentNode.getName() + '_', '');\r\n nodeDefInput = nodeDef.getActiveInput(lookup_name);\r\n if (nodeDefInput)\r\n {\r\n uiname = nodeDefInput.getAttribute('uiname');\r\n let uifolderName = nodeDefInput.getAttribute('uifolder');\r\n if (uifolderName && uifolderName.length)\r\n {\r\n let newFolderName = currentNodePath + '/' + uifolderName;\r\n currentFolder = folderList[newFolderName];\r\n if (!currentFolder)\r\n {\r\n currentFolder = matUI.addFolder(uifolderName);\r\n currentFolder.domElement.classList.add('peditorfolder');\r\n folderList[newFolderName] = currentFolder;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Determine UI name to use\r\n let path = name;\r\n let interfaceName = currentElem.getAttribute(\"interfacename\");\r\n if (interfaceName && interfaceName.length)\r\n {\r\n const graph = currentNode.getParent();\r\n if (graph)\r\n {\r\n const graphInput = graph.getInput(interfaceName);\r\n if (graphInput)\r\n {\r\n let uiname = graphInput.getAttribute('uiname');\r\n if (uiname.length)\r\n {\r\n path = uiname;\r\n }\r\n else\r\n {\r\n path = graphInput.getName();\r\n }\r\n }\r\n }\r\n else\r\n {\r\n path = interfaceName;\r\n }\r\n }\r\n else\r\n {\r\n if (!uiname)\r\n {\r\n uiname = currentElem.getAttribute('uiname');\r\n }\r\n if (uiname && uiname.length)\r\n {\r\n path = uiname;\r\n }\r\n }\r\n\r\n switch (variable.getType().getName())\r\n {\r\n case 'float':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = DEFAULT_MIN;\r\n if (value < minValue)\r\n {\r\n minValue = value;\r\n }\r\n var maxValue = DEFAULT_MAX;\r\n if (value > maxValue)\r\n {\r\n maxValue = value;\r\n }\r\n var step = 0;\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = parseFloat(nodeDefInput.getAttribute('uisoftmin'));\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = parseFloat(nodeDefInput.getAttribute('uimin'));\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = parseFloat(nodeDefInput.getAttribute('uisoftmax'));\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = parseFloat(nodeDefInput.getAttribute('uimax'));\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = parseFloat(nodeDefInput.getAttribute('uistep'));\r\n }\r\n if (step == 0)\r\n {\r\n step = (maxValue - minValue) / 1000.0;\r\n }\r\n const w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'integer':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = DEFAULT_MIN;\r\n if (value < minValue)\r\n {\r\n minValue = value;\r\n }\r\n var maxValue = DEFAULT_MAX;\r\n if (value > maxValue)\r\n {\r\n maxValue = value;\r\n }\r\n var step = 0;\r\n var enumList = []\r\n var enumValues = []\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('enum'))\r\n {\r\n // Get enum and enum values attributes (if present)\r\n enumList = nodeDefInput.getAttribute('enum').split(',');\r\n if (nodeDefInput.hasAttribute('enumvalues'))\r\n {\r\n enumValues = nodeDefInput.getAttribute('enumvalues').split(',').map(Number);\r\n }\r\n }\r\n else\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = parseInt(nodeDefInput.getAttribute('uisoftmin'));\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = parseInt(nodeDefInput.getAttribute('uimin'));\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = parseInt(nodeDefInput.getAttribute('uisoftmax'));\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = parseInt(nodeDefInput.getAttribute('uimax'));\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = parseInt(nodeDefInput.getAttribute('uistep'));\r\n }\r\n }\r\n if (enumList.length == 0)\r\n {\r\n if (step == 0)\r\n {\r\n step = 1 / (maxValue - minValue);\r\n step = Math.ceil(step);\r\n if (step == 0)\r\n {\r\n step = 1;\r\n }\r\n }\r\n }\r\n if (enumList.length == 0)\r\n {\r\n let w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n else\r\n {\r\n // Map enumList strings to values\r\n // Map to 0..N if no values are specified via enumvalues attribute\r\n if (enumValues.length == 0)\r\n {\r\n for (let i = 0; i < enumList.length; ++i)\r\n {\r\n enumValues.push(i);\r\n }\r\n }\r\n const enumeration = {};\r\n enumList.forEach((str, index) =>\r\n {\r\n enumeration[str] = enumValues[index];\r\n });\r\n\r\n // Function to handle enum drop-down\r\n function handleDropdownChange(value)\r\n {\r\n if (material.uniforms[name])\r\n {\r\n material.uniforms[name].value = value;\r\n }\r\n }\r\n const defaultOption = enumList[value]; // Set the default selected option\r\n const dropdownController = currentFolder.add(enumeration, defaultOption, enumeration).name(path);\r\n dropdownController.onChange(handleDropdownChange);\r\n dropdownController.domElement.classList.add('peditoritem');\r\n }\r\n }\r\n break;\r\n\r\n case 'boolean':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n let w = currentFolder.add(material.uniforms[name], 'value').name(path);\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'vector2':\r\n case 'vector3':\r\n case 'vector4':\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var minValue = [DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN, DEFAULT_MIN];\r\n var maxValue = [DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX, DEFAULT_MAX];\r\n var step = [0, 0, 0, 0];\r\n\r\n if (nodeDefInput)\r\n {\r\n if (nodeDefInput.hasAttribute('uisoftmin'))\r\n minValue = nodeDefInput.getAttribute('uisoftmin').split(',').map(Number);\r\n else if (nodeDefInput.hasAttribute('uimin'))\r\n minValue = nodeDefInput.getAttribute('uimin').split(',').map(Number);\r\n\r\n if (nodeDefInput.hasAttribute('uisoftmax'))\r\n maxValue = nodeDefInput.getAttribute('uisoftmax').split(',').map(Number);\r\n else if (nodeDefInput.hasAttribute('uimax'))\r\n maxValue = nodeDefInput.getAttribute('uimax').split(',').map(Number);\r\n\r\n if (nodeDefInput.hasAttribute('uistep'))\r\n step = nodeDefInput.getAttribute('uistep').split(',').map(Number);\r\n }\r\n for (let i = 0; i < 4; ++i)\r\n {\r\n if (step[i] == 0)\r\n {\r\n step[i] = 1 / (maxValue[i] - minValue[i]);\r\n }\r\n }\r\n\r\n const keyString = [\"x\", \"y\", \"z\", \"w\"];\r\n let vecFolder = currentFolder.addFolder(path);\r\n Object.keys(material.uniforms[name].value).forEach((key) =>\r\n {\r\n let w = vecFolder.add(material.uniforms[name].value,\r\n key, minValue[key], maxValue[key], step[key]).name(keyString[key]);\r\n w.domElement.classList.add('peditoritem');\r\n })\r\n }\r\n break;\r\n\r\n case 'color3':\r\n // Irksome way to map arrays to colors and back\r\n uniformToUpdate = material.uniforms[name];\r\n if (uniformToUpdate && value != null)\r\n {\r\n var dummy =\r\n {\r\n color: 0xFF0000\r\n };\r\n const color3 = new three__WEBPACK_IMPORTED_MODULE_1__.Color(dummy.color);\r\n color3.fromArray(material.uniforms[name].value);\r\n dummy.color = color3.getHex();\r\n let w = currentFolder.addColor(dummy, 'color').name(path)\r\n .onChange(function (value)\r\n {\r\n const color3 = new three__WEBPACK_IMPORTED_MODULE_1__.Color(value);\r\n material.uniforms[name].value.set(color3.toArray());\r\n });\r\n w.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n\r\n case 'color4':\r\n break;\r\n\r\n case 'matrix33':\r\n case 'matrix44':\r\n case 'samplerCube':\r\n case 'filename':\r\n break;\r\n case 'string':\r\n console.log('String: ', name);\r\n if (value != null)\r\n {\r\n var dummy =\r\n {\r\n thevalue: value\r\n }\r\n let item = currentFolder.add(dummy, 'thevalue');\r\n item.name(path);\r\n item.disable(true);\r\n item.domElement.classList.add('peditoritem');\r\n }\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n }\r\n });\r\n\r\n if (logDetailedTime)\r\n {\r\n console.log(\" - Editor update time: \", performance.now() - startTime, \"ms\");\r\n }\r\n }\r\n\r\n // List of material assignments: { MaterialX node, geometry assignment string, and hardware shader }\r\n _materials;\r\n\r\n // Fallback material if nothing was assigned explicitly\r\n _defaultMaterial;\r\n}\r\n\r\n/*\r\n Viewer class\r\n\r\n Keeps track of local scene, and property editor as well as current MaterialX document \r\n and assocaited material, shader and lighting information.\r\n*/\r\nclass Viewer\r\n{\r\n static create()\r\n {\r\n return new Viewer();\r\n }\r\n\r\n constructor()\r\n {\r\n this.scene = new Scene();\r\n this.editor = new Editor();\r\n this.materials.push(new Material());\r\n\r\n this.fileLoader = new three__WEBPACK_IMPORTED_MODULE_1__.FileLoader();\r\n this.hdrLoader = new three_examples_jsm_loaders_RGBELoader_js__WEBPACK_IMPORTED_MODULE_5__.RGBELoader();\r\n }\r\n\r\n setStopRendering(value)\r\n {\r\n this.stopRendering = value;\r\n }\r\n\r\n getStopRendering(value)\r\n {\r\n return this.stopRendering;\r\n }\r\n\r\n //\r\n // Create shader generator, generation context and \"base\" document which\r\n // contains the standard definition libraries and lighting elements.\r\n //\r\n async initialize(mtlxIn, renderer, radianceTexture, irradianceTexture, lightRigXml)\r\n {\r\n this.mx = mtlxIn;\r\n\r\n // Initialize base document\r\n this.generator = new this.mx.EsslShaderGenerator();\r\n this.genContext = new this.mx.GenContext(this.generator);\r\n\r\n this.document = this.mx.createDocument();\r\n this.stdlib = this.mx.loadStandardLibraries(this.genContext);\r\n this.document.importLibrary(this.stdlib);\r\n\r\n this.initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml);\r\n\r\n radianceTexture.mapping = three__WEBPACK_IMPORTED_MODULE_1__.EquirectangularReflectionMapping;\r\n this.getScene().setBackgroundTexture(radianceTexture);\r\n\r\n this.stopRendering = false;\r\n }\r\n\r\n //\r\n // Load in lighting rig document and register lights with generation context\r\n // Initialize environment lighting (IBLs).\r\n //\r\n async initializeLighting(renderer, radianceTexture, irradianceTexture, lightRigXml)\r\n {\r\n // Load lighting setup into document\r\n const mx = this.getMx();\r\n this.lightRigDoc = mx.createDocument();\r\n await mx.readFromXmlString(this.lightRigDoc, lightRigXml);\r\n this.document.importLibrary(this.lightRigDoc);\r\n\r\n // Register lights with generation context\r\n this.lights = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.findLights)(this.document);\r\n this.lightData = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.registerLights)(mx, this.lights, this.genContext);\r\n\r\n this.radianceTexture = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.prepareEnvTexture)(radianceTexture, renderer.capabilities);\r\n this.irradianceTexture = (0,_helper_js__WEBPACK_IMPORTED_MODULE_0__.prepareEnvTexture)(irradianceTexture, renderer.capabilities);\r\n }\r\n\r\n getEditor()\r\n {\r\n return this.editor;\r\n }\r\n\r\n getScene()\r\n {\r\n return this.scene;\r\n }\r\n\r\n getMaterial()\r\n {\r\n return this.materials[0];\r\n }\r\n\r\n getFileLoader()\r\n {\r\n return this.fileLoader;\r\n }\r\n\r\n getHdrLoader()\r\n {\r\n return this.hdrLoader;\r\n }\r\n\r\n setDocument(doc)\r\n {\r\n this.doc = doc;\r\n }\r\n getDocument()\r\n {\r\n return this.doc;\r\n }\r\n\r\n getLibrary()\r\n {\r\n return this.stdlib;\r\n }\r\n\r\n getLightRig()\r\n {\r\n return this.lightRigDoc;\r\n }\r\n\r\n getMx()\r\n {\r\n return this.mx;\r\n }\r\n\r\n getGenerator()\r\n {\r\n return this.generator;\r\n }\r\n\r\n getGenContext()\r\n {\r\n return this.genContext;\r\n }\r\n\r\n getLights()\r\n {\r\n return this.lights;\r\n }\r\n\r\n getLightData()\r\n {\r\n return this.lightData;\r\n }\r\n\r\n getRadianceTexture()\r\n {\r\n return this.radianceTexture;\r\n }\r\n\r\n getIrradianceTexture()\r\n {\r\n return this.irradianceTexture;\r\n }\r\n\r\n // Three scene and materials. \r\n scene = null;\r\n materials = [];\r\n\r\n // Property editor\r\n editor = null;\r\n\r\n // Utility loaders\r\n fileloader = null;\r\n hdrLoader = null;\r\n\r\n // MaterialX module, current document and support documents.\r\n mx = null;\r\n doc = null;\r\n stdlib = null;\r\n lightRigDoc = null;\r\n\r\n // MaterialX code generator and context\r\n generator = null;\r\n genContext = null;\r\n\r\n // Lighting information\r\n lights = null;\r\n lightData = null;\r\n radianceTexture = null;\r\n irradianceTexture = null;\r\n}\r\n\n\n//# sourceURL=webpack://MaterialX-Swatch-Viewer/./source/viewer.js?");
/***/ }),
diff --git a/javascript/viewer/dist/public/favicon.ico b/javascript/shader_utilities/dist/public/favicon.ico
similarity index 100%
rename from javascript/viewer/dist/public/favicon.ico
rename to javascript/shader_utilities/dist/public/favicon.ico
diff --git a/javascript/viewer/dist/public/shader_ball.svg b/javascript/shader_utilities/dist/public/shader_ball.svg
similarity index 100%
rename from javascript/viewer/dist/public/shader_ball.svg
rename to javascript/shader_utilities/dist/public/shader_ball.svg
diff --git a/javascript/viewer/dist/public/shader_ball2.svg b/javascript/shader_utilities/dist/public/shader_ball2.svg
similarity index 100%
rename from javascript/viewer/dist/public/shader_ball2.svg
rename to javascript/shader_utilities/dist/public/shader_ball2.svg
diff --git a/javascript/viewer/dist/Images/brass_color.jpg b/javascript/viewer/dist/Images/brass_color.jpg
deleted file mode 100644
index 047f1619..00000000
Binary files a/javascript/viewer/dist/Images/brass_color.jpg and /dev/null differ
diff --git a/javascript/viewer/dist/Images/brass_roughness.jpg b/javascript/viewer/dist/Images/brass_roughness.jpg
deleted file mode 100644
index 2f005401..00000000
Binary files a/javascript/viewer/dist/Images/brass_roughness.jpg and /dev/null differ
diff --git a/javascript/viewer/dist/Images/brick_base_gray.jpg b/javascript/viewer/dist/Images/brick_base_gray.jpg
deleted file mode 100644
index 0b77aff1..00000000
Binary files a/javascript/viewer/dist/Images/brick_base_gray.jpg and /dev/null differ
diff --git a/javascript/viewer/dist/Images/brick_dirt_mask.jpg b/javascript/viewer/dist/Images/brick_dirt_mask.jpg
deleted file mode 100644
index b3745644..00000000
Binary files a/javascript/viewer/dist/Images/brick_dirt_mask.jpg and /dev/null differ
diff --git a/javascript/viewer/dist/Images/brick_mask.jpg b/javascript/viewer/dist/Images/brick_mask.jpg
deleted file mode 100644
index 66d5439c..00000000
Binary files a/javascript/viewer/dist/Images/brick_mask.jpg and /dev/null differ
diff --git a/javascript/viewer/dist/Images/brick_normal.jpg b/javascript/viewer/dist/Images/brick_normal.jpg
deleted file mode 100644
index 0f672d82..00000000
Binary files a/javascript/viewer/dist/Images/brick_normal.jpg and /dev/null differ
diff --git a/javascript/viewer/dist/Images/brick_roughness.jpg b/javascript/viewer/dist/Images/brick_roughness.jpg
deleted file mode 100644
index bcf49203..00000000
Binary files a/javascript/viewer/dist/Images/brick_roughness.jpg and /dev/null differ
diff --git a/javascript/viewer/dist/Images/brick_variation_mask.jpg b/javascript/viewer/dist/Images/brick_variation_mask.jpg
deleted file mode 100644
index 3ad359b9..00000000
Binary files a/javascript/viewer/dist/Images/brick_variation_mask.jpg and /dev/null differ
diff --git a/javascript/viewer/dist/Images/cloth.bmp b/javascript/viewer/dist/Images/cloth.bmp
deleted file mode 100644
index b6191de9..00000000
Binary files a/javascript/viewer/dist/Images/cloth.bmp and /dev/null differ
diff --git a/javascript/viewer/dist/Images/cloth.gif b/javascript/viewer/dist/Images/cloth.gif
deleted file mode 100644
index d9cd2b48..00000000
Binary files a/javascript/viewer/dist/Images/cloth.gif and /dev/null differ
diff --git a/javascript/viewer/dist/Images/cloth.jpg b/javascript/viewer/dist/Images/cloth.jpg
deleted file mode 100644
index 53f55c39..00000000
Binary files a/javascript/viewer/dist/Images/cloth.jpg and /dev/null differ
diff --git a/javascript/viewer/dist/Images/cloth.png b/javascript/viewer/dist/Images/cloth.png
deleted file mode 100644
index c4e3459b..00000000
Binary files a/javascript/viewer/dist/Images/cloth.png and /dev/null differ
diff --git a/javascript/viewer/dist/Images/cloth.tga b/javascript/viewer/dist/Images/cloth.tga
deleted file mode 100644
index bd38dd95..00000000
Binary files a/javascript/viewer/dist/Images/cloth.tga and /dev/null differ
diff --git a/javascript/viewer/dist/Images/greysphere_calibration.png b/javascript/viewer/dist/Images/greysphere_calibration.png
deleted file mode 100644
index 76bff27d..00000000
Binary files a/javascript/viewer/dist/Images/greysphere_calibration.png and /dev/null differ
diff --git a/javascript/viewer/dist/Images/grid.png b/javascript/viewer/dist/Images/grid.png
deleted file mode 100644
index 9af2fba9..00000000
Binary files a/javascript/viewer/dist/Images/grid.png and /dev/null differ
diff --git a/javascript/viewer/dist/Images/mesh_wire_norm.png b/javascript/viewer/dist/Images/mesh_wire_norm.png
deleted file mode 100644
index 75dc2ccf..00000000
Binary files a/javascript/viewer/dist/Images/mesh_wire_norm.png and /dev/null differ
diff --git a/javascript/viewer/dist/Images/plain_heightmap.png b/javascript/viewer/dist/Images/plain_heightmap.png
deleted file mode 100644
index 763685fb..00000000
Binary files a/javascript/viewer/dist/Images/plain_heightmap.png and /dev/null differ
diff --git a/javascript/viewer/dist/Images/wood_color.jpg b/javascript/viewer/dist/Images/wood_color.jpg
deleted file mode 100644
index c61b13a0..00000000
Binary files a/javascript/viewer/dist/Images/wood_color.jpg and /dev/null differ
diff --git a/javascript/viewer/dist/Images/wood_roughness.jpg b/javascript/viewer/dist/Images/wood_roughness.jpg
deleted file mode 100644
index af292bdd..00000000
Binary files a/javascript/viewer/dist/Images/wood_roughness.jpg and /dev/null differ
diff --git a/pymaterialx/mtlx_connectivity_notebook.html b/pymaterialx/mtlx_connectivity_notebook.html
index 806070c7..db953cff 100644
--- a/pymaterialx/mtlx_connectivity_notebook.html
+++ b/pymaterialx/mtlx_connectivity_notebook.html
@@ -15129,7 +15129,7 @@ The Javascript module JsMaterialGraph
is used for interactive graph generation on the Graph Editing page.
diff --git a/pymaterialx/mtlx_connectivity_notebook.ipynb b/pymaterialx/mtlx_connectivity_notebook.ipynb
index a8fbaa7f..aedea418 100644
--- a/pymaterialx/mtlx_connectivity_notebook.ipynb
+++ b/pymaterialx/mtlx_connectivity_notebook.ipynb
@@ -23,7 +23,7 @@
"- The utilities (including Mermaid generation) in this tutorial are collected in the `mtlxutils` file: `mxtraversal.py`.\n",
"- The command `mxgraphio.py` found in the `pymaterialx` folder wraps up these utilities. \n",
"- All Mermaid diagrams on this site are generated using the `mxgraphio.py` command line utility or the `mtlxutils` library.\n",
- "- The Javascript module `JsMaterialGraph` is used for interactive graph generation on the