31        this.monitoring = 
true;
 
 
   44            console.log(text + path);
 
 
   57        if (parentGraph.length > 0)
 
   58            path = path + parentGraph + 
'/'             
 
   78            this.
debugMessage(
'Monitor> Document attribute "' + attribute + 
'" changed from: ' + prevValue + 
' to: ' + value, 
'');
 
 
  112        if (!this.monitoring)
 
  119            let targetOutput = node.outputs[slot].name;
 
  121            let sourceInput = input.name;
 
  123            this.
debugMessage(
'Monitor> Output connection change: ' +
 
  124                targetPath + 
"[" + slot + 
"]." + targetOutput + 
' to: ' +
 
  125                sourcePath + 
"[" + target_slot + 
"]." + sourceInput + 
" (" + input_type + 
")", 
"");
 
 
  142        if (!this.monitoring)
 
  150            let sourceOutput = output.name;
 
  152            let targetInput = node.inputs[target_slot].name;
 
  154            this.
debugMessage(
'Monitor> Input connection change: ' +
 
  155                sourcePath + 
"[" + slot + 
"]." + sourceOutput + 
' to: ' +
 
  156                targetPath + 
"[" + target_slot + 
"]." + targetInput + 
" (" + output_type + 
")", 
"");
 
 
  169        if (!this.monitoring)
 
 
  199        if (!this.monitoring)
 
 
  220            path = 
graphcanvas.graph._subgraph_node.title + 
'/';
 
  226                is_subgraph = node.graph._is_subgraph;
 
  228                    path = node.graph._subgraph_node.title + 
'/';
 
 
  244        if (!this.monitoring)
 
  250        let path = parentPath + node.title;
 
  251        let newpath = parentPath + newName;
 
  253            this.
debugMessage(
'Monitor> Node renamed: ', path + 
' to: ' + newpath);
 
 
  266        if (!this.monitoring)
 
 
  285        if (!this.monitoring)
 
 
  307        if (!this.monitoring)
 
  314            console.log(
'Monitor> Property changed:', path, 
'. Property: ' + propertyName + 
 
  315            '. Value: ' + newValue + 
'. Previous Value: ' + previousValue, 
'. Category:', node.nodedef_node);
 
 
  332        if (!this.monitoring)
 
  339            console.log(
'Monitor> Property Info changed:', path, 
'. Property: ' + propertyName + 
 
  340                '. Property Info: ' + propertyInfoName +
 
  341            '. Value: ' + newValue + 
'. Previous Value: ' + previousValue, 
'. Category:', node.nodedef_node);
 
 
  363        this.renderer = theRenderer
 
 
  372        return this.renderer;
 
 
  383        this.monitoring = monitor;
 
 
  393        return this.monitoring;
 
 
  503        this.monitoring = monitor;
 
  508        theGraph.onConnectionChange = 
null;
 
  509        theGraph.onNodeAdded = 
null;
 
  510        theGraph.onNodeRemoved = 
null;
 
  514            console.log(
'> Monitor graph: ', 
graph.title? 
graph.title : 
'ROOT')
 
  518            theGraph.onConnectionChange = 
function (node) {
 
  519                let parentGraph = 
'';
 
  520                var is_subgraph = node.graph._is_subgraph;
 
  522                    parentGraph = 
graphcanvas.graph._subgraph_node.title;
 
  523                that.onConnectionChange(node, parentGraph);
 
  526                for (var s in selected) {
 
  533            theGraph.onNodeAdded = 
function (node) {
 
  534                let parentGraph = 
'';
 
  536                if (node.type == 
'graph/subgraph') {
 
  540                    var node_subgraph = node.subgraph;
 
  541                    var node_graph = node.graph;
 
  544                        for (var i in node_subgraph._nodes) {
 
  545                            let theNode = node_subgraph._nodes[i];
 
  546                            if (!node_graph.findNodeByTitle(theNode.title)) {
 
  547                                if (theNode.nodedef_node == 
'input') {
 
  548                                    node.addInput(theNode.title, theNode.nodedef_type);
 
  551                                else if (theNode.nodedef_node == 
'output') {
 
  553                                    node.addOutput(theNode.title, theNode.nodedef_type);
 
  561                node.setSize(node.computeSize());
 
  565                var is_subgraph = node.graph._is_subgraph;
 
  567                    parentGraph = 
graphcanvas.graph._subgraph_node.title;
 
  569                    if (node.nodedef_node == 
'input') {
 
  571                        node.graph.addInput(node.title, node.nodedef_type);
 
  573                    else if (node.nodedef_node == 
'output') {
 
  575                        node.graph.addOutput(node.title, node.nodedef_type);
 
  579                if (node.type == 
'graph/subgraph') {
 
  580                    that.monitorGraph(node.subgraph, monitor);
 
  583                that.onNodeAdded(node, parentGraph);
 
  587            theGraph.onNodeRemoved = 
function (node) {
 
  589                let parentGraph = 
'';
 
  593                    parentGraph = 
graphcanvas.graph._subgraph_node.title;
 
  594                    if (node.nodedef_node == 
'input') {
 
  598                    else if (node.nodedef_node == 
'output') {
 
  604                that.onNodeRemoved(node, parentGraph);
 
  607            for (var i in theGraph._nodes) {
 
  608                var node = theGraph._nodes[i];
 
  609                if (node.type == 
'graph/subgraph') {
 
  610                    console.log(
'> Monitor subgraph:', node.title);
 
  611                    that.monitorGraph(node.subgraph, monitor);
 
 
 
  632        this.extension = extension;
 
  637        this.DEFAULT_COLOR_SPACE = 
'lin_rec709';
 
  638        this.DEFAULT_DISTANCE_UNIT = 
'meter';
 
  639        this.sourceColorSpace = this.DEFAULT_COLOR_SPACE;
 
  640        this.targetDistanceUnit = this.DEFAULT_DISTANCE_UNIT;
 
  641        this.colorSpaces = [];
 
  646        this.converters = [];
 
 
  660        this.converters.unshift(converter);
 
 
  672        this.monitor = monitor;
 
 
  684        if (extension == 
'mtlx')
 
 
  702        for (let converter of this.converters) {
 
  703            if (converter.exportType() == extension) {
 
 
  718        if (extension == 
'mtlx' || extension == 
'zip')
 
 
  736        for (let converter of this.converters) {
 
  737            if (converter.importType() == extension) {
 
 
  751        this.colorSpaces = colorSpaces;
 
 
  760        return this.colorSpaces;
 
 
  789        let newSpace = this.DEFAULT_COLOR_SPACE;
 
  790        if (colorSpace && colorSpace.length > 0)        
 
  791            newSpace = colorSpace;
 
  795            this.monitor.onDocumentChange(
'colorspace', colorSpace, this.sourceColorSpace);
 
  797        this.sourceColorSpace = newSpace;
 
 
  807        let newUnit = this.DEFAULT_DISTANCE_UNIT;
 
  808        if (unit && unit.length > 0)
 
  813            this.monitor.onDocumentChange(
'distanceunit', newUnit, this.targetDistanceUnit);
 
  815        this.targetDistanceUnit = newUnit;
 
 
  826        return this.sourceColorSpace;
 
 
  836        return this.targetDistanceUnit;
 
 
  845        return this.extension;
 
 
  855        this.editor = editor;
 
 
  877        if (_type === 
'string' || _type === 
'filename') {
 
  878            value = 
"'" + value + 
"'";
 
  880        else if (this.isArray(_type)) {
 
  881            if (value.length == 0) {
 
  882                if (_type === 
'color3')
 
  883                    value = 
"[0.0, 0.0, 0.0]";
 
  884                else if (_type === 
'color4')
 
  885                    value = 
"[0.0, 0.0, 0.0, 0.0]";
 
  886                else if (_type === 
'vector2')
 
  887                    value = 
"[0.0, 0.0]";
 
  888                else if (_type === 
'vector3')
 
  889                    value = 
"[0.0, 0.0, 0.0]";
 
  890                else if (_type === 
'vector4')
 
  891                    value = 
"[0.0, 0.0, 0.0, 0.0]";
 
  892                else if (_type === 
'matrix33')
 
  893                    value = 
"[1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]";
 
  894                else if (_type === 
'matrix44')
 
  895                    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]";
 
  898                value = 
"[" + value + 
"]";
 
  901        else if (_type === 
'integer') {
 
  902            if (value.length == 0) {
 
  906        else if (_type === 
'float') {
 
  907            if (value.length == 0) {
 
  911        else if (_type === 
'boolean') {
 
  918        if (value.length == 0) {
 
 
 
  941        super(
id, extension);
 
 
  951        return new Promise((resolve, reject) => {
 
  952            MaterialX().then((ne_mtlx) => {
 
  956            }).
catch((error) => {
 
 
  970        function loadInitialText(filePath, handler) {
 
  973                    .then(response => response.blob())
 
  975                        const reader = 
new FileReader();
 
  976                        reader.onload = 
function (e) {
 
  977                            console.log(
'Loaded document:', filePath);
 
  978                            editor.loadGraphFromString(
'mtlx', e.target.result, filePath, 80, 
true);
 
  980                        reader.readAsText(blob);
 
  983                console.error(
'Error loading file %s:' % filePath, error);
 
  987        loadInitialText(materialFilename, 
this);
 
 
 1001        super.initialize(editor);
 
 1008                editor.debugOutput(
"Loaded MaterialX version:" + 
ne_mx.getVersionString(), 0, 
true);
 
 1011                var generator = 
new ne_mx.EsslShaderGenerator.create();
 
 1012                var genContext = 
new ne_mx.GenContext(generator);
 
 1014                editor.debugOutput(
'Loaded standard libraries definitions:' + 
stdlib.getNodeDefs().length, 0, 
false);
 
 1017                let units = 
new Map();
 
 1018                for (let ud of 
stdlib.getUnitDefs()) {
 
 1019                    let unittype = ud.getAttribute(
'unittype')
 
 1020                    for (let unit of ud.getChildren()) {
 
 1021                        units.set(unit.getName(), unittype);
 
 1025                this.
setUnits(Array.from(units).sort());
 
 1026                console.log(
'> Setup real-world units: ', this.
getUnits());
 
 1030                let colorSpaces = 
new Set();
 
 1031                let docNodeDefs = 
stdlib.getNodeDefs();
 
 1032                for (let i = 0; i < docNodeDefs.length; i++) {
 
 1033                    let cmnode = docNodeDefs[i];
 
 1034                    if (cmnode.getNodeGroup() === 
'colortransform') {
 
 1035                        let name = cmnode.getName();
 
 1036                        name = name.replace(
'ND_', 
'');
 
 1037                        let namesplit = name.split(
'_to_');
 
 1038                        let type = 
'color3';
 
 1039                        if (namesplit[1].includes(
'color4')) {
 
 1040                            namesplit[1] = namesplit[1].replace(
'_color4', 
'');
 
 1043                            namesplit[1] = namesplit[1].replace(
'_color3', 
'');
 
 1045                        colorSpaces.add(namesplit[0]);
 
 1046                        colorSpaces.add(namesplit[1]);
 
 1053                var definitionsList = [];
 
 1055                var definitionsDisplayUpdater = editor.ui.definitionsDisplayUpdater;
 
 1056                if (definitionsDisplayUpdater) {
 
 1057                    definitionsDisplayUpdater(result);
 
 1060                editor.clearNodeTypes();
 
 1064                    editor.debugOutput(
'Error evaluating source: ' + e, 2, 
false);
 
 1067                var nodeTypes = LiteGraph.registered_node_types;
 
 1069                for (var typeName in nodeTypes) {
 
 1072                editor.debugOutput(
"Registered node types:" + definitionsList.length, 0, 
false);
 
 1074                editor.displayNodeTypes();
 
 1076                if (materialFilename.length > 0) {
 
 1080                editor.updatePropertyPanel(
null);
 
 1082            }).
catch((error) => {
 
 1083                editor.debugOutput(
"Error on initialization:" + error, 2);
 
 
 1096        let graphWriteOptions = { writeCustomLibs : 
false, saveNodePositions: 
false, writeOutputs : 
true };
 
 1099            console.log(
'Failed to save graph to document');
 
 
 1113        const materialNodes = mdoc.getMaterialNodes();
 
 1114        let shaderList = [];
 
 1115        let renderableItems = [];
 
 1117        for (let i = 0; i < materialNodes.length; ++i) {
 
 1118            let materialNode = materialNodes[i];
 
 1121                let shaderNodes = 
ne_mx.getShaderNodes(materialNode)
 
 1122                if (shaderNodes.length > 0) {
 
 1123                    let shaderNodePath = shaderNodes[0].getNamePath()
 
 1124                    if (!shaderList.includes(shaderNodePath)) {
 
 1126                        shaderList.push(shaderNodePath);
 
 1127                        renderableItems.push(shaderNodePath);
 
 1132        const nodeGraphs = mdoc.getNodeGraphs();
 
 1133        for (let i = 0; i < nodeGraphs.length; ++i) {
 
 1134            let nodeGraph = nodeGraphs[i];
 
 1136                if (nodeGraph.hasAttribute(
'nodedef') || nodeGraph.hasSourceUri()) {
 
 1140                if (nodeGraph.getDownstreamPorts().length > 0) {
 
 1143                let outputs = nodeGraph.getOutputs();
 
 1144                for (let j = 0; j < outputs.length; ++j) {
 
 1145                    let output = outputs[j];
 
 1147                        renderableItems.push(output.getNamePath());
 
 1152        const outputs = mdoc.getOutputs();
 
 1153        for (let i = 0; i < outputs.length; ++i) {
 
 1154            let output = outputs[i];
 
 1156                renderableItems.push(output.getNamePath());
 
 1160        return renderableItems;
 
 
 1178    buildMetaData(colorSpace, unit, unitType, uiname, uimin, uimax, uifolder, _type) {
 
 1181        metaData[
'colorspace'] = colorSpace;
 
 1182        metaData[
'unit'] = unit;
 
 1183        metaData[
'unittype'] = unitType;
 
 1184        metaData[
'uiname'] = uiname;
 
 1185        if (_type == 
'vector2' || _type == 
'vector3' || _type == 
'vector4' || _type == 
'matrix33' || _type == 
'matrix44') {
 
 1187                uimin = uimin.split(
',').map(Number);
 
 1190                uimax = uimax.split(
',').map(Number);
 
 1193        metaData[
'uimin'] = uimin;
 
 1194        metaData[
'uimax'] = uimax;
 
 1195        metaData[
'uifolder'] = uifolder;
 
 
 1218        var definition_code = 
"" 
 1220        console.log(
'Creating LiteGraph definitions from MaterialX document:', 
doc);
 
 1223        var nodeDefs = 
doc.getNodeDefs();
 
 1226            definition_code += 
"console.log('Loading MaterialX Definitions...');\n";
 
 1228        definition_code += 
"// MaterialX LiteGraph Functional Definitions\n" 
 1229        definition_code += 
"//\n";
 
 1230        definition_code += 
"// MaterialX Version: " + 
ne_mx.getVersionString() + 
"\n";
 
 1231        const date = 
new Date();
 
 1232        definition_code += 
"// Generated on: " + date.toString() + 
"\n"; 
 
 1233        definition_code += 
"//\n";
 
 1236        TMAP[
'float'] = 
'float';
 
 1237        TMAP[
'color3'] = 
'color3';
 
 1238        TMAP[
'color4'] = 
'color4';
 
 1239        TMAP[
'vector2'] = 
'vector2';
 
 1240        TMAP[
'vector3'] = 
'vector3';
 
 1241        TMAP[
'vector4'] = 
'vector4';
 
 1242        TMAP[
'matrix33'] = 
'matrix33';
 
 1243        TMAP[
'matrix44'] = 
'matrix44';
 
 1244        TMAP[
'integer'] = 
'integer';
 
 1245        TMAP[
'string'] = 
'string';
 
 1246        TMAP[
'boolean'] = 
'boolean';
 
 1247        TMAP[
'filename'] = 
'filename';
 
 1248        TMAP[
'BSDF'] = 
'BSDF';
 
 1249        TMAP[
'EDF'] = 
'EDF';
 
 1250        TMAP[
'VDF'] = 
'VDF';
 
 1251        TMAP[
'surfaceshader'] = 
'surfaceshader';
 
 1252        TMAP[
'volumeshader'] = 
'volumeshader';
 
 1253        TMAP[
'displacementshader'] = 
'displacementshader';
 
 1254        TMAP[
'lightshader'] = 
'lightshader';
 
 1255        TMAP[
'material'] = 
'material';
 
 1256        TMAP[
'vector2array'] = 
'vector2array';
 
 1259        CMAP[
'integer'] = 
"#A32";
 
 1260        CMAP[
'float'] = 
"#161";
 
 1261        CMAP[
'vector2'] = 
"#265";
 
 1262        CMAP[
'vector3'] = 
"#465";
 
 1263        CMAP[
'vector4'] = 
"#275";
 
 1264        CMAP[
'color3'] = 
"#37A";
 
 1265        CMAP[
'color4'] = 
"#69A";
 
 1266        CMAP[
'matrix33'] = 
"#333";
 
 1267        CMAP[
'matrix44'] = 
"#444";
 
 1268        CMAP[
'string'] = 
"#395";
 
 1269        CMAP[
'filename'] = 
"#888";
 
 1270        CMAP[
'boolean'] = 
"#060";
 
 1272        var inputTypes = [
'float', 
'color3', 
'color4', 
'vector2', 
'vector3', 
'vector4', 
'matrix33', 
'matrix44', 
'integer', 
'string', 
'boolean', 
'filename', 
'BSDF', 
'EDF', 
'VDF', 
'surfaceshader', 
'volumeshader', 
'displacementshader', 
'lightshader', 
'material', 
'vector2array'];
 
 1273        var outputTypes = [
'float', 
'color3', 
'color4', 
'vector2', 
'vector3', 
'vector4', 
'matrix33', 
'matrix44', 
'integer', 
'string', 
'boolean', 
'filename', 
'BSDF', 
'EDF', 
'VDF', 
'surfaceshader', 
'volumeshader', 
'displacementshader', 
'lightshader', 
'material', 
'vector2array'];
 
 1276        var supporTokens = 
false;
 
 1278            inputTypes.push(
'token');
 
 1279            TMAP[
'token'] = 
'string';
 
 1282        const INPUT_ND = 
'ND_input_';
 
 1283        const OUTPUT_ND = 
'ND_output_';
 
 1284        const INPUT_NODE_STRING = 
'input';
 
 1285        const OUTPUT_NODE_STRING = 
'output';
 
 1286        const LIBRARY_ICON = 
'';
 
 1289        if (addInputOutputs) {
 
 1290            for (var _type of inputTypes) {
 
 1291                var 
id = libraryPrefix + 
'/input/input_' + _type;
 
 1292                var functionName = 
ne_mx.createValidName(
id);
 
 1293                var titleName = 
'input_' + _type;
 
 1294                definition_code += 
"\n/**\n"; 
 
 1295                definition_code += 
"  * @function "+ functionName + 
"\n";
 
 1296                definition_code += 
"  * @description Library: " + libraryPrefix + 
". Category: input. Type: " + _type + 
"\n";
 
 1297                definition_code += 
"  *   LiteGraph id: " + 
id + 
"\n"; 
 
 1298                definition_code += 
"  */\n";
 
 1299                definition_code += 
"function " + functionName + 
"() {\n";
 
 1301                    definition_code += 
"  this.nodedef_icon = '" + LIBRARY_ICON + 
"';\n";
 
 1302                    definition_code += 
"  this.nodedef_name = '" + INPUT_ND + _type + 
"';\n";
 
 1303                    definition_code += 
"  this.nodedef_node = '" + INPUT_NODE_STRING + 
"';\n";
 
 1304                    definition_code += 
"  this.nodedef_type = '" + _type + 
"';\n";
 
 1305                    definition_code += 
"  this.nodedef_group = '" + INPUT_NODE_STRING + 
"';\n";
 
 1306                    if (_type == 
'token')
 
 1308                    definition_code += 
"  this.addInput('in', '" + TMAP[_type] + 
"');\n";
 
 1310                    var metaData = this.
buildMetaData(
'', 
'', 
'', 
'', 
null, 
null, 
'', 
null);
 
 1311                    metaData = JSON.stringify(metaData);
 
 1316                    if (_type == 
'filename')
 
 1321                    definition_code += 
"  this.addProperty('in', " + value + 
", '" + _type + 
"'," + metaData + 
");\n";
 
 1322                    definition_code += 
"  this.addOutput('out', '" + TMAP[_type] + 
"');\n";
 
 1324                    definition_code += 
"  this.title = '" + titleName + 
"';\n" 
 1325                    var desc = 
'"MaterialX:' + 
id + 
'"';
 
 1326                    definition_code += 
"  this.desc = " + desc + 
";\n";
 
 1328                    var onNodeCreated = 
"function() {\n";
 
 1329                    onNodeCreated += 
"    //console.log('Node created:', this);\n";
 
 1330                    onNodeCreated += 
"  }";
 
 1331                    definition_code += 
"  this.onNodeCreated = " + onNodeCreated + 
"\n";
 
 1332                    var onRemoved = 
"function() {\n";
 
 1333                    onRemoved += 
"    //console.log('Node removed:', this);\n";
 
 1335                    definition_code += 
"  this.onRemoved = " + onRemoved + 
"\n";
 
 1338                    let monitor = editor.monitor;
 
 1339                    var onPropertyChanged = 
"function(name, value, prev_value) {\n";
 
 1342                        onPropertyChanged += 
" MxShadingGraphEditor.theEditor.monitor.onPropertyChanged(this.title, name, value, prev_value, this);\n";
 
 1346                        onPropertyChanged += 
"    console.log('+ Internal property changed:', this.title, name, value, prev_value, this);\n";
 
 1348                    onPropertyChanged += 
"  }";
 
 1349                    definition_code += 
"  this.onPropertyChanged = " + onPropertyChanged + 
"\n";
 
 1352                    var onPropertyInfoChanged = 
"function(name, info, value, prev_value) {\n";
 
 1355                        onPropertyInfoChanged += 
" MxShadingGraphEditor.theEditor.monitor.onPropertyInfoChanged(this.title, name, info, value, prev_value, this);\n";
 
 1359                        onPropertyInfoChanged += 
"    console.log('+ Internal property info changed:', this.title, name, info, value, prev_value, this);\n";
 
 1361                    onPropertyInfoChanged += 
"  }"                     
 1362                    definition_code += 
"  this.onPropertyInfoChanged = " + onPropertyInfoChanged + 
"\n";
 
 1365                    var onConnectOutput = 
"function(slot, input_type, input, target_node, target_slot) {\n";
 
 1368                        onConnectOutput += 
" MxShadingGraphEditor.theEditor.monitor.onConnectOutput(slot, input_type, input, target_node, target_slot, this);\n";
 
 1372                        onConnectOutput += 
"    console.log('+ Output connection changed:', this.title, slot, input_type, input, target_node, target_slot);\n";
 
 1374                    onConnectOutput += 
"  }"                     
 1375                    definition_code += 
"  this.onConnectOutput = " + onConnectOutput + 
"\n";    
 
 1378                    var onConnectInput = 
"function(target_slot, output_type, output, source, slot) {\n";
 
 1381                        onConnectInput += 
" MxShadingGraphEditor.theEditor.monitor.onConnectInput(target_slot, output_type, output, source, slot, this);\n";
 
 1385                        onConnectInput += 
"    console.log('+ Input connection changed:', this.title, target_slot, output_type, output, source, slot);\n";
 
 1387                    onConnectInput += 
"  }"                     
 1388                    definition_code += 
"  this.onConnectInput = " + onConnectInput + 
"\n";
 
 1390                    definition_code += 
"  this.color = '#004C94';\n";
 
 1391                    definition_code += 
"  this.bgcolor = '#000';\n";
 
 1392                    if (_type in CMAP) {
 
 1393                        definition_code += 
"  this.boxcolor = '" + CMAP[_type] + 
"';\n";
 
 1395                    definition_code += 
"  this.shape = LiteGraph.ROUND_SHAPE;\n";
 
 1397                    definition_code += 
"  this.onExecute = function() {\n";
 
 1398                    definition_code += 
"    console.log('Executing node: ', this);\n";
 
 1399                    definition_code += 
"  }\n";
 
 1401                definition_code += 
"}\n" 
 1402                definition_code += 
"LiteGraph.registerNodeType('" + 
id + 
"', " + functionName + 
");\n";
 
 1406            for (var _type of outputTypes) {
 
 1407                var 
id = libraryPrefix + 
'/output/output_' + _type;
 
 1408                var functionName = 
ne_mx.createValidName(
id);
 
 1409                var titleName = 
'output_' + _type;
 
 1411                definition_code += 
"\n/**\n"; 
 
 1412                definition_code += 
"  * @function "+ functionName + 
"\n";
 
 1413                definition_code += 
"  * @description Library: " + libraryPrefix + 
". Category: output. Type: " + _type + 
"\n";
 
 1414                definition_code += 
"  *   LiteGraph id: " + 
id + 
"\n"; 
 
 1415                definition_code += 
"  */\n";
 
 1417                definition_code += 
"function " + functionName + 
"() {\n";
 
 1419                    definition_code += 
"  this.title = '" + titleName + 
"';\n" 
 1420                    var desc = 
'"MaterialX Node :' + 
id + 
'"';
 
 1421                    definition_code += 
"  this.desc = " + desc + 
";\n";
 
 1423                    definition_code += 
"  this.nodedef_icon = '" + LIBRARY_ICON + 
"';\n";
 
 1424                    definition_code += 
"  this.nodedef_name = '" + OUTPUT_ND + + _type + 
"';\n";
 
 1425                    definition_code += 
"  this.nodedef_node = '" + OUTPUT_NODE_STRING + 
"';\n";
 
 1426                    definition_code += 
"  this.nodedef_type = '" + _type + 
"';\n";
 
 1427                    definition_code += 
"  this.nodedef_group = '" + OUTPUT_NODE_STRING + 
"';\n";
 
 1428                    definition_code += 
"  this.addInput('in', '" + TMAP[_type] + 
"');\n";
 
 1430                    definition_code += 
"  this.addProperty('in', " + value + 
", '" + _type + 
"');\n";
 
 1431                    definition_code += 
"  this.addOutput('out', '" + TMAP[_type] + 
"');\n";
 
 1433                    var onNodeCreated = 
"function() {\n";
 
 1434                    onNodeCreated += 
"  //console.log('Node created:', this);\n";
 
 1435                    onNodeCreated += 
"  }";
 
 1436                    definition_code += 
"  this.onNodeCreated = " + onNodeCreated + 
"\n";
 
 1437                    var onRemoved = 
"function() {\n";
 
 1438                    onRemoved += 
"  //console.log('Node removed:', this);\n";
 
 1440                    definition_code += 
"  this.onRemoved = " + onRemoved + 
"\n";
 
 1442                    let monitor = editor.monitor;
 
 1443                    var onPropertyChanged = 
"function(name, value, prev_value) {\n";
 
 1446                        onPropertyChanged += 
" MxShadingGraphEditor.theEditor.monitor.onPropertyChanged(this.title, name, value, prev_value, this);\n";
 
 1450                        onPropertyChanged += 
"    console.log('+ Internal property changed:', this.title, name, value, prev_value, this);\n";
 
 1452                    onPropertyChanged += 
"  }";
 
 1453                    definition_code += 
"  this.onPropertyChanged = " + onPropertyChanged + 
"\n";    
 
 1455                    var onPropertyInfoChanged = 
"function(name, info, value, prev_value) {\n";
 
 1458                        onPropertyInfoChanged += 
" MxShadingGraphEditor.theEditor.monitor.onPropertyInfoChanged(this.title, name, info, value, prev_value, this);\n";
 
 1462                        onPropertyInfoChanged += 
"    console.log('+ Internal property info changed:', this.title, name, info, value, prev_value, this);\n";
 
 1464                    onPropertyInfoChanged += 
"  }"                     
 1465                    definition_code += 
"  this.onPropertyInfoChanged = " + onPropertyInfoChanged + 
"\n";
 
 1469                    var onConnectOutput = 
"function(slot, input_type, input, target_node, target_slot) {\n";
 
 1472                        onConnectOutput += 
" MxShadingGraphEditor.theEditor.monitor.onConnectOutput(slot, input_type, input, target_node, target_slot, this);\n";
 
 1476                        onConnectOutput += 
"    console.log('+ Output connection changed:', this.title, slot, input_type, input, target_node, target_slot);\n";
 
 1478                    onConnectOutput += 
"  }"                     
 1479                    definition_code += 
"  this.onConnectOutput = " + onConnectOutput + 
"\n";    
 
 1482                    var onConnectInput = 
"function(target_slot, output_type, output, source, slot) {\n";
 
 1485                        onConnectInput += 
" MxShadingGraphEditor.theEditor.monitor.onConnectInput(target_slot, output_type, output, source, slot, this);\n";
 
 1489                        onConnectInput += 
"    console.log('+ Input connection changed:', this.title, target_slot, output_type, output, source, slot);\n";
 
 1491                    onConnectInput += 
"  }"                     
 1492                    definition_code += 
"  this.onConnectInput = " + onConnectInput + 
"\n";
 
 1494                    definition_code += 
"  this.color = '#013514';\n";
 
 1495                    definition_code += 
"  this.bgcolor = '#000';\n";
 
 1496                    if (_type in CMAP) {
 
 1497                        definition_code += 
"  this.boxcolor = '" + CMAP[_type] + 
"';\n";
 
 1499                    definition_code += 
"  this.shape = LiteGraph.ROUND_SHAPE;\n";
 
 1501                    definition_code += 
"  this.onExecute = function() {\n";
 
 1502                    definition_code += 
"  console.log('Executing node:', this);\n";
 
 1503                    definition_code += 
"  }\n";
 
 1505                definition_code += 
"}\n" 
 1506                definition_code += 
"LiteGraph.registerNodeType('" + 
id + 
"', " + functionName + 
");\n";
 
 1507                definitionsList.push(
id);
 
 1512        for (var nodeDef of nodeDefs) {
 
 1514            var nodeDefName = nodeDef.getName();
 
 1515            var 
id = libraryPrefix + 
'/' + nodeDef.getNodeGroup() + 
'/' + nodeDefName;
 
 1516            id = 
id.replace(
'ND_', 
'');
 
 1517            var functionName = 
ne_mx.createValidName(
id);
 
 1518            var nodeType = nodeDef.getType();
 
 1519            var titleName = nodeDef.getNodeString() + 
"_" + nodeType;
 
 1520            var swatchLocation = 
'https://kwokcb.github.io/MaterialX_Learn/resources/mtlx/nodedef_materials/';
 
 1521            var outputs = nodeDef.getActiveOutputs();
 
 1522            var outputName = outputs[0].getName(); 
 
 1523            var swatchId = swatchLocation + 
'material_' + nodeDefName + 
'_' + outputName + 
'_genglsl.png';
 
 1524            swatchId = swatchId.replace(
'ND_', 
'');
 
 1526                console.log(
'\n--- Registering node type:', 
id, 
'----');
 
 1529            definition_code += 
"\n/**\n"; 
 
 1530            definition_code += 
"  * @function "+ functionName + 
"\n";
 
 1531            definition_code += 
"  * @description Library: " + libraryPrefix + 
". Category: " + nodeString + 
". Type: " + nodeType + 
"\n";
 
 1532            definition_code += 
"  *   LiteGraph id: " + 
id + 
"\n"; 
 
 1533            definition_code += 
"  */\n";
 
 1535            definition_code += 
"function " + functionName + 
"() {\n";
 
 1537                var nodeGroup = nodeDef.getNodeGroup();
 
 1538                var nodeString = nodeDef.getNodeString();
 
 1540                if (theIcon.length == 0) {
 
 1541                    for (var key in editor.ui.icon_map) {
 
 1542                        if (nodeString.toLowerCase().startsWith(key.toLowerCase())) {
 
 1543                            if (key in editor.ui.icon_map)
 
 1544                                theIcon = editor.ui.icon_map[key];
 
 1548                        else if (nodeGroup.toLowerCase().startsWith(key.toLowerCase())) {
 
 1549                            if (key in editor.ui.icon_map)
 
 1550                                theIcon = editor.ui.icon_map[key];
 
 1557                definition_code += 
"  this.nodedef_icon = '" + theIcon + 
"';\n";
 
 1558                definition_code += 
"  this.nodedef_name = '" + nodeDefName + 
"';\n";
 
 1559                definition_code += 
"  this.nodedef_type = '" + nodeType + 
"';\n";
 
 1560                definition_code += 
"  this.nodedef_node = '" + nodeString + 
"';\n";
 
 1561                definition_code += 
"  this.nodedef_href = 'https://kwokcb.github.io/MaterialX_Learn/documents/definitions/" + nodeString + 
".html';\n";
 
 1562                definition_code += 
"  this.nodedef_swatch = '" + swatchId + 
"';\n";
 
 1563                definition_code += 
"  this.nodedef_group = '" + nodeGroup + 
"';\n";
 
 1565                for (var input of nodeDef.getActiveInputs()) {
 
 1566                    var _name = input.getName();
 
 1567                    var _type = input.getType();
 
 1569                        _type = TMAP[_type];
 
 1571                        console.log(
'Unmappable type:', _type)
 
 1572                    definition_code += 
"  this.addInput('" + _name + 
"','" + _type + 
"');\n";
 
 1574                    let value = input.getValueString();
 
 1576                    let uiname = input.getAttribute(
'uiname');
 
 1578                    let uimin = input.getAttribute(
'uimin');
 
 1579                    if (uimin.length == 0) {
 
 1582                    let uimax = input.getAttribute(
'uimax');
 
 1583                    if (uimax.length == 0) {
 
 1586                    let uisoftmin = input.getAttribute(
'uisoftmin');
 
 1587                    if (uisoftmin.length > 0) {
 
 1590                    let uisoftmax = input.getAttribute(
'uisoftmax');
 
 1591                    if (uisoftmax.length > 0) {
 
 1594                    var uifolder = input.getAttribute(
'uifolder');
 
 1595                    var metaData = this.
buildMetaData(
'', 
'', 
'', uiname, uimin, uimax, uifolder, _type);
 
 1598                    let colorspace = input.getAttribute(
'colorspace');     
 
 1599                    let nodeDefType = nodeDef.getType();               
 
 1600                    if (_type == 
'filename' && (nodeDefType == 
'color3' || nodeDefType == 
'color4'))
 
 1602                        if (colorspace.length == 0)
 
 1604                            colorspace = 
'none';
 
 1607                    if (colorspace.length > 0)
 
 1608                        metaData[
'colorspace'] = colorspace;
 
 1612                    let unitAttributes = [
'unit', 
'unittype'];
 
 1613                    for (let unitAttribute of unitAttributes)
 
 1615                        let value = input.getAttribute(unitAttribute);
 
 1616                        if (value.length > 0)
 
 1618                            metaData[unitAttribute] = value;
 
 1623                    let defaultgeomprop = input.getAttribute(
'defaultgeomprop')
 
 1624                    metaData[
'defaultgeomprop'] = defaultgeomprop;
 
 1627                    let enums = input.getAttribute(
'enum');
 
 1628                    if (enums.length > 0)
 
 1630                        metaData[
'enum'] = enums.split(
',');
 
 1631                        metaData[
'enum'].map(
function(x) { 
return x.trim(); });                
 
 1633                    let enumvalues = input.getAttribute(
'enumvalues');
 
 1634                    if (enumvalues.length > 0)
 
 1636                        metaData[
'enumvalues'] = enumvalues.split(
',');
 
 1637                        metaData[
'enumvalues'].map(
function(x) { 
return x.trim(); });                
 
 1640                    metaData = JSON.stringify(metaData);
 
 1641                    definition_code += 
"  this.addProperty('" + _name + 
"', " + value + 
", '" + _type + 
"'," + metaData + 
");\n";
 
 1643                for (var output of nodeDef.getActiveOutputs()) {
 
 1644                    var _name = output.getName();
 
 1645                    var _type = output.getType();
 
 1647                        _type = TMAP[_type];
 
 1649                        console.log(
'Unmappable type:', _type)
 
 1652                    definition_code += 
"  this.addOutput('" + _name + 
"','" + _type + 
"');\n";
 
 1655                definition_code += 
"  this.title = '" + titleName + 
"';\n" 
 1656                var desc = 
'"MaterialX:' + 
id + 
'"';
 
 1657                definition_code += 
"  this.desc = " + desc + 
";\n";
 
 1663                var onNodeCreated = 
"function() {\n";
 
 1664                onNodeCreated += 
"  //console.log('Node created:', this);\n";
 
 1665                onNodeCreated += 
"}";
 
 1666                definition_code += 
"  this.onNodeCreated = " + onNodeCreated + 
"\n";
 
 1667                var onRemoved = 
"function() {\n";
 
 1668                onRemoved += 
"  //console.log('Node removed:', this);\n";
 
 1670                definition_code += 
"  this.onRemoved = " + onRemoved + 
"\n";
 
 1672                let monitor = editor.monitor;
 
 1673                var onPropertyChanged = 
"function(name, value, prev_value) {\n";
 
 1676                    onPropertyChanged += 
" MxShadingGraphEditor.theEditor.monitor.onPropertyChanged(this.title, name, value, prev_value, this);\n";
 
 1680                    onPropertyChanged += 
"    console.log('+ Internal property changed:', this.title, name, value, prev_value, this);\n";
 
 1682                onPropertyChanged += 
"  }";
 
 1683                definition_code += 
"  this.onPropertyChanged = " + onPropertyChanged + 
"\n";
 
 1685                var onPropertyInfoChanged = 
"function(name, info, value, prev_value) {\n";
 
 1688                    onPropertyInfoChanged += 
" MxShadingGraphEditor.theEditor.monitor.onPropertyInfoChanged(this.title, name, info, value, prev_value, this);\n";
 
 1692                    onPropertyInfoChanged += 
"    console.log('+ Internal property info changed:', this.title, name, info, value, prev_value, this);\n";
 
 1694                onPropertyInfoChanged += 
"  }"                     
 1695                definition_code += 
"  this.onPropertyInfoChanged = " + onPropertyInfoChanged + 
"\n";
 
 1698                var onConnectOutput = 
"function(slot, input_type, input, target_node, target_slot) {\n";
 
 1701                    onConnectOutput += 
" MxShadingGraphEditor.theEditor.monitor.onConnectOutput(slot, input_type, input, target_node, target_slot, this);\n";
 
 1705                    onConnectOutput += 
"    console.log('+ Output connection changed:', this.title, slot, input_type, input, target_node, target_slot);\n";
 
 1707                onConnectOutput += 
"  }"                     
 1708                definition_code += 
"  this.onConnectOutput = " + onConnectOutput + 
"\n";    
 
 1711                var onConnectInput = 
"function(target_slot, output_type, output, source, slot) {\n";
 
 1714                    onConnectInput += 
" MxShadingGraphEditor.theEditor.monitor.onConnectInput(target_slot, output_type, output, source, slot, this);\n";
 
 1718                    onConnectInput += 
"    console.log('+ Input connection changed:', this.title, target_slot, output_type, output, source, slot);\n";
 
 1720                onConnectInput += 
"  }"                     
 1721                definition_code += 
"  this.onConnectInput = " + onConnectInput + 
"\n";
 
 1724                definition_code += 
"  this.bgcolor = '#111';\n";
 
 1726                if (nodeGroup == 
'conditional') {
 
 1728                    definition_code += 
"  this.color = '#532200';\n";
 
 1729                    definition_code += 
"  this.title_text_color = '#000';\n";
 
 1730                    definition_code += 
"  this.shape = LiteGraph.CARD_SHAPE;\n";
 
 1733                else if (nodeString != 
'convert' &&
 
 1734                    (nodeGroup == 
'shader' || nodeType == 
'surfaceshader' || nodeType == 
'volumshader' || nodeType == 
'displacementshader')) {
 
 1735                    definition_code += 
"  this.color = '#232';\n";
 
 1736                    definition_code += 
"  this.shape = LiteGraph.ROUND_SHAPE;\n";
 
 1738                else if (nodeGroup == 
'material') {
 
 1739                    definition_code += 
"  this.color = '#151';\n";
 
 1740                    definition_code += 
"  this.shape = LiteGraph.BOX_SHAPE;\n";
 
 1743                    definition_code += 
"  this.color = '#222';\n";
 
 1744                    definition_code += 
"  this.shape = LiteGraph.ROUND_SHAPE;\n";
 
 1746                if (nodeType in CMAP) {
 
 1747                    definition_code += 
"  this.boxcolor = '" + CMAP[nodeType] + 
"';\n";
 
 1750            definition_code += 
"}\n" 
 1753            definition_code += functionName + 
".nodedef_name = '" + nodeDefName + 
"';\n";
 
 1754            definition_code += functionName + 
".nodedef_node = '" + nodeString + 
"';\n";
 
 1755            definition_code += functionName + 
".nodedef_href = 'https://kwokcb.github.io/MaterialX_Learn/documents/definitions/" + nodeString + 
".html';\n";
 
 1757            definition_code += 
"LiteGraph.registerNodeType(" + 
"'" + 
id + 
"'," + functionName + 
");\n";
 
 1758            definitionsList.push(
id);
 
 1760                definition_code += 
"console.log('Registered node type:', '" + 
id + 
"');\n";
 
 1764        return definition_code;
 
 
 1781        let validationDocument = 
ne_mx.createDocument();
 
 1782        validationDocument.copyContentFrom(
doc);
 
 1783        validationDocument.importLibrary(
stdlib);
 
 1786        var valid = validationDocument.validate(errors);
 
 1788            this.editor.debugOutput(
'Failed to validate document:\n' + errors.message, 2);
 
 
 1802            this.editor.debugOutput(
"MaterialX is not initialized", 2);
 
 1806        let writeCustomLibs = graphWriteOptions.writeCustomLibs;
 
 1807        if (writeCustomLibs == undefined)
 
 1809            console.error(
'Graph output option: writeCustomLibs is undefined.')
 
 1810            writeCustomLibs = 
true;
 
 1813        var outputDoc = 
ne_mx.createDocument();
 
 1816            var generator = 
new ne_mx.EsslShaderGenerator.create();
 
 1817            var genContext = 
new ne_mx.GenContext(generator);
 
 1824        let doc_string = 
ne_mx.writeToXmlString(outputDoc);
 
 1828        if (writeCustomLibs) {
 
 1829            console.log(
'Write custom libraries:', 
customlibs.length);
 
 1831                outputDoc.copyContentFrom(customlib[1]);
 
 1833            console.log(
'Write document custom definitions:', 
customDocLibs.length);
 
 1835                outputDoc.copyContentFrom(customDocLib[1]);
 
 1841        outputDoc.removeAttribute(
'fileprefix');
 
 
 1859            this.editor.debugOutput(
"MaterialX is not initialized", 2);
 
 1860            return [
'', 
'MaterialX is not initialized'];
 
 1865            this.editor.debugOutput(
"Failed to save graph to document", 2);
 
 1866            return [
'', 
'Failed to save graph to document'];
 
 1869        if (extension == 
'mtlx')
 
 1871            const writeOptions = 
new ne_mx.XmlWriteOptions();
 
 1872            writeOptions.writeXIncludeEnable = 
false;
 
 1875                data = 
ne_mx.writeToXmlString(outputDoc, writeOptions);
 
 1877                this.editor.debugOutput(
"Failed to write graph:" + e, 2);
 
 1887                this.editor.debugOutput(
'Failed to find ' + extension + 
' exporter', 2);
 
 1890                let exportDoc = 
ne_mx.createDocument();
 
 1891                exportDoc.copyContentFrom(outputDoc);
 
 1892                exportDoc.importLibrary(
stdlib);
 
 1894                let result = exporter.export(
ne_mx, exportDoc);
 
 1898        return [
'', 
'Failed to export graph to ' + extension];
 
 
 1916        var blob = 
new Blob([data[0]], { type: 
"text/plain" });
 
 1917        var url = URL.createObjectURL(blob);
 
 1918        var a = document.createElement(
"a");
 
 1920        a.download = 
"output_graph.mtlx";
 
 
 1937            console.log(
'***** START Scan Graph:', 
graph.title);
 
 1938        for (var node of 
graph._nodes) {
 
 1939            if (node.type == 
'graph/subgraph') {
 
 1940                var subgraph = node.subgraph;
 
 1942                var subgraphNode = mltxgraph.addChildOfCategory(
'nodegraph', node.title);
 
 1944                    console.log(
'---->>> Scan NodeGraph:', node.title);
 
 1950                console.log(
'---->>> Scan Node:', node.title);
 
 1952            var nodeDefName = node.nodedef_name;
 
 1961            var nodedefName = node.nodedef_name;
 
 1963            var nodeElement = 
null;
 
 1976                    nodeElement = mltxgraph.addChildOfCategory(node.nodedef_node, node.nodedef_type);
 
 1977                    nodeElement.setType(node.nodedef_type);                               
 
 1979                    if (graphWriteOptions.saveNodePositions) {
 
 1981                        nodeElement.setAttribute(
'xpos', JSON.stringify(node.pos[0]));
 
 1982                        nodeElement.setAttribute(
'ypos', JSON.stringify(node.pos[1]));
 
 1985                        console.log(
'** Create node:', nodeElement.getNamePath(), nodeElement.getType());
 
 1986                    nodeElement.setName(node.title);
 
 1992                    console.log(
'-> Write Node:', 
graph.title + 
'/' + node.title, 
' --> ', nodeElement.getNamePath());
 
 1995                console.log(
'Skip writing :', node.title);
 
 2000            var properties = node.properties;
 
 2002            var node_inputs = node.inputs;
 
 2003            var isInputNode = 
false;
 
 2004            var isOutputNode = 
false;
 
 2005            if (nodeElement.getCategory() == 
'input') {
 
 2007                node_inputs = [node];
 
 2009            else if (nodeElement.getCategory() == 
'output') {
 
 2010                isOutputNode = 
true;
 
 2011                node_inputs = [node];
 
 2015            if (!isInputNode && !isOutputNode)
 
 2017                if (node.nodedef_type == 
"multioutput")
 
 2019                    console.log(
'Write outputs for:', node, 
'. type: ', node.nodedef_type);
 
 2020                    for (var output of node.outputs) {
 
 2021                        var outputName = output.name;
 
 2022                        var outputType = output.type;
 
 2023                        var outputElement = nodeElement.addOutput(outputName, outputType);
 
 2025                            console.log(
'> Read: node.nodedef_type: ', node.nodedef_type);
 
 2026                            console.log(
'> Write: output:', outputElement.getNamePath(), outputElement.getType());
 
 2035                var inputs = node_inputs;
 
 2036                for (var i in inputs) {
 
 2037                    let input = inputs[i];
 
 2039                        console.log(
'---- Write port:', input);
 
 2041                    let inputName = input.name;
 
 2042                    let inputType = input.type;
 
 2043                    if (nodeElement.getCategory() == 
'input' ||
 
 2044                        nodeElement.getCategory() == 
'output') {
 
 2046                        inputType = node.nodedef_type;
 
 2050                    var inputElement = 
null;
 
 2051                    var nodeToCheck = node;
 
 2052                    var inputNode = 
null;
 
 2053                    var inputLink = 
null;
 
 2054                    if (isInputNode && node.graph._subgraph_node) {
 
 2055                        nodeToCheck = node.graph._subgraph_node;
 
 2056                        for (var i = 0; i < nodeToCheck.inputs.length; i++) {
 
 2057                            var nci = nodeToCheck.inputs[i];
 
 2058                            if (nci.name == node.title) {
 
 2059                                inputNode = nodeToCheck.getInputNode(i);
 
 2060                                inputLink = nodeToCheck.getInputLink(i);
 
 2067                        inputNode = node.getInputNode(i);
 
 2068                        inputLink = node.getInputLink(i);
 
 2070                    var inputLinkOutput = 
'';
 
 2071                    var numInputOutputs = 0;
 
 2073                        numInputOutputs = inputNode.outputs.length;
 
 2074                        inputLinkOutput = inputNode.outputs[inputLink.origin_slot];
 
 2078                        if (nodeElement.getCategory() != 
'input' &&
 
 2079                            nodeElement.getCategory() != 
'output') {
 
 2080                            inputElement = nodeElement.getInput(inputName);
 
 2082                            inputElement = nodeElement.addInput(inputName, inputType);
 
 2085                            inputElement = nodeElement;
 
 2089                            console.log(
'Write connection');
 
 2090                            console.log(
'  - TO:', inputElement.getName() + 
"." + inputName);
 
 2091                            console.log(
'  - FROM link:', inputNode.id + 
"." + inputLinkOutput.name);
 
 2093                        if (inputNode.type == 
'graph/subgraph') {
 
 2094                            inputElement.setNodeGraphString(inputNode.title);
 
 2096                            if (numInputOutputs > 1 && inputLinkOutput) {
 
 2097                                inputElement.setOutputString(inputLinkOutput.name);
 
 2105                                if (inputNode.nodedef_node == 
'input') {
 
 2108                                    inputElement.setInterfaceName(inputNode.title);
 
 2112                                    inputElement.setNodeName(inputNode.title);
 
 2115                                    if (numInputOutputs > 1 && inputNode.nodedef_node != 
'output') {
 
 2117                                        if (inputLinkOutput) {
 
 2118                                            inputElement.setOutputString(inputLinkOutput.name);
 
 2127                        var inputValue = node.properties[inputName];
 
 2128                        if (inputValue == 
null) {
 
 2129                            console.log(
'Cannot find property value for input:', inputName);
 
 2132                            var origValue = inputValue;
 
 2134                            if ([
'float', 
'integer'].includes(inputType)) {
 
 2135                                inputValue = inputValue.toString();
 
 2137                            else if ([
'vector2', 
'vector3', 
'vector4', 
'matrix33', 
'matrix44', 
'color3', 
'color4'].includes(inputType)) {
 
 2138                                inputValue = inputValue.toString();
 
 2139                                inputValue = inputValue.split(
',').map(Number).join(
', ');
 
 2141                            else if (inputType === 
'boolean') {
 
 2142                                if (inputValue === 
'true')
 
 2143                                    inputValue = 
'true';
 
 2145                                    inputValue = 
'false';
 
 2148                                inputValue = inputValue.toString();
 
 2152                            if (nodeElement.getCategory() != 
'input' &&
 
 2153                                nodeElement.getCategory() != 
'output') {
 
 2154                                inputElement = nodeElement.getInput(inputName);
 
 2156                                    inputElement = nodeElement.addInput(inputName, inputType);
 
 2159                                    console.log(
'Error> Trying add input more than once:', inputName, 
' to node: ', nodeElement.getNamePath());
 
 2163                                inputElement = nodeElement;
 
 2167                                inputElement.setValueString(inputValue, inputType);
 
 2170                                console.warn(
"Set value error: ", e);
 
 2177                        var propInfo = 
null;
 
 2178                        var skip_attributes = [];
 
 2179                        if (isInputNode || isOutputNode) {
 
 2180                            if (input.properties_info) {
 
 2182                                skip_attributes = [
'interfacename', 
'nodegraph', 
'nodename', 
'name', 
'type', 
'value', 
'default_value'];
 
 2183                                propInfo = input.properties_info[0];
 
 2187                            if (node.properties_info) {
 
 2189                                skip_attributes = [
'interfacename', 
'nodegraph', 
'nodename', 
'name', 
'type', 
'value', 
'default_value', 
'uimin', 
'uimax', 
'uiname', 
'uifolder'];
 
 2190                                propInfo = node.properties_info[i];
 
 2197                            skip_attributes = skip_attributes.concat([
'defaultgeomprop', 
'enum', 
'enumvalues']);
 
 2199                            for (var propAttribute in propInfo) {
 
 2200                                if (skip_attributes.includes(propAttribute))
 
 2204                                var propAttributeValue = propInfo[propAttribute];
 
 2205                                if (propAttributeValue && propAttributeValue.length > 0) {
 
 2206                                    inputElement.setAttribute(propAttribute, propAttributeValue);
 
 2214                    console.log(
'---- END Write inputs:', node.inputs);
 
 2218                console.log(
'---> End write node', node.title);
 
 2222            console.log(
'***** END Scan Graph:', 
graph.title);
 
 
 2232        var ARRAY_TYPES = [
'color3', 
'color4', 
'vector2', 
'vector3', 
'vector4', 
'matrix33', 
'matrix44'];
 
 2233        if (ARRAY_TYPES.includes(_type)) {
 
 
 2245        const uriSchemes = [
'http://', 
'https://', 
'ftp://', 
'blob:', 
'file://', 
'data:'];
 
 2246        return uriSchemes.some(scheme => s.startsWith(scheme));
 
 
 2261        var nodeInputs = [];
 
 2262        var isOutput = (node.getCategory() == 
'output');
 
 2263        var isInput = (node.getCategory() == 
'input');
 
 2264        if (isOutput || isInput) {
 
 2265            nodeInputs = [node];
 
 2268            nodeInputs = node.getInputs();
 
 2270        for (var input of nodeInputs) {
 
 2274            if (!isOutput && !isInput) {
 
 2275                _name = input.getName();
 
 2276                explicitInputs.push(_name);
 
 2279            var nodeName = input.getNodeName();
 
 2280            var nodeGraphName = input.getNodeGraphString();
 
 2281            var inputInterfaceName = input.getInterfaceName();
 
 2282            var outputName = input.getOutputString();
 
 2284            if (nodeName.length ||
 
 2285                nodeGraphName.length ||
 
 2286                inputInterfaceName.length ||
 
 2287                outputName.length) {
 
 2294                var target_node = lg_node;
 
 2295                var target_slot = 
null;
 
 2296                if (!isOutput && !isInput)
 
 2297                    target_slot = target_node.findInputSlot(_name);
 
 2300                var source_node = 
null;
 
 2301                var source_slot = 0;
 
 2302                var source_name = nodeName;
 
 2303                if (nodeGraphName.length) {
 
 2304                    source_name = nodeGraphName;
 
 2306                if (inputInterfaceName.length) {
 
 2307                    source_name = inputInterfaceName;
 
 2310                var graphToCheck = 
graph;
 
 2311                if (isInput && 
graph._subgraph_node) {
 
 2312                    target_node = 
graph._subgraph_node;
 
 2313                    target_slot = target_node.findInputSlot(lg_node.title);
 
 2315                    graphToCheck = parentGraph;
 
 2320                source_node = graphToCheck.findNodeByTitle(source_name);
 
 2323                        var outputSlot = source_node.findOutputSlot(outputName);
 
 2324                        if (outputSlot >= 0) {
 
 2325                            source_slot = outputSlot;
 
 2328                            editor.debugOutput(
'Failed to find output slot:' + outputName, 1);
 
 2330                        var linkInfo = source_node.connect(source_slot, target_node, target_slot);
 
 2332                            editor.debugOutput(
'Failed to connect:' + source_node.title + 
'.' + outputName, 
'->', target_node.title + 
'.' + _name), 1, 
false;
 
 2337                    var linkInfo = 
null;
 
 2338                    if (source_slot == 
null || target_slot == 
null || target_node == 
null) {
 
 2339                        console.warning(
'Cannot connect!')
 
 2342                        linkInfo = source_node.connect(source_slot, target_node, target_slot);
 
 2345                        editor.debugOutput(
'Failed to connect:' + source_node.title + 
'.' + outputName, 
'->', target_node.title + 
'.' + _name, 1);
 
 2351                    console.log(
'Failed to find node ', source_name, 
'in graph:', graphToCheck);
 
 2352                    this.editor.debugOutput(
'Failed to find source node: ' + source_node + 
"." +
 
 2353                        source_name, 
'->', lg_node.title + 
"." + _name, 2);
 
 2357                const inputType = input.getAttribute(
ne_mx.TypedElement.TYPE_ATTRIBUTE);
 
 2358                let valueString = input.getValueString();
 
 2359                if (valueString.length > 0) {
 
 2362                    if (inputType === 
ne_mx.FILENAME_TYPE_STRING) {
 
 2365                        if (this.
isURI(valueString)) {
 
 2366                            this.editor.debugOutput(
'Filename is a url:' + valueString + 
'. Cannot use resolved path value.');
 
 2367                            _value = input.getValueString();
 
 2370                            _value = input.getResolvedValueString();
 
 2375                        _value = input.getResolvedValueString(); 
 
 2377                        if (this.
isArray(input.getType())) {
 
 2378                            let valueArray = 
"[" + _value + 
"]" 
 2379                            valueArray = JSON.parse(valueArray);                        
 
 2382                            _value = valueArray;
 
 2388                    lg_node.setProperty(_name, _value);
 
 2392            var property_info = lg_node.getPropertyInfo(_name);
 
 
 2406        if (input && property_info) {
 
 2409            var colorspace = input.getColorSpace();
 
 2410            if (colorspace.length > 0)
 
 2411                property_info[
'colorspace'] = colorspace;
 
 2413            var unit = input.getUnit();
 
 2414            if (unit.length > 0)
 
 2415                property_info[
'unit'] = unit;
 
 2417            var uiname = input.getAttribute(
'uiname');
 
 2418            if (uiname.length > 0)
 
 2419                property_info[
'uiname'] = uiname;
 
 2421            var uimin = input.getAttribute(
'uimin');
 
 2422            if (uimin.length > 0)
 
 2423                property_info[
'uimin'] = uimin;
 
 2425            var uimax = input.getAttribute(
'uimax');
 
 2426            if (uimax.length > 0)
 
 2427                property_info[
'uimax'] = uimax;
 
 2428            var uisoftmin = input.getAttribute(
'uisoftmin');
 
 2429            if (uisoftmin.length > 0)
 
 2430                property_info[
'uimin'] = uisoftmin;
 
 2432            var uisoftmax = input.getAttribute(
'uisoftmax');
 
 2433            if (uisoftmax.length > 0)
 
 2434                property_info[
'uimax'] = uisoftmax;
 
 2436            var uifolder = input.getAttribute(
'uifolder');
 
 2437            if (uifolder.length > 0)
 
 2438                property_info[
'uifolder'] = uifolder;
 
 2440            var basicMetaData = [
'colorspace', 
'unit', 
'uiname', 
'uimin', 
'uimax', 
'uifolder', 
'name', 
'type', 
'output', 
'nodename', 
'nodegraph'];
 
 2441            for (var attrName of input.getAttributeNames()) {
 
 2442                if (!basicMetaData.includes(attrName)) {
 
 2443                    property_info[attrName] = input.getAttribute(attrName);
 
 2447            if (node && input.getType() == 
'filename') 
 
 2449                let nodeType = node.getType();
 
 2450                let colorTypes = [
'color3', 
'color4'];
 
 2452                if (colorTypes.includes(nodeType))
 
 2454                    if (!property_info[
'colorspace']) {
 
 2455                        console.log(
'Auto create "none" colorspace for input:', input.getName());
 
 2456                        let 
doc = node.getDocument();
 
 2457                        let defaultColorSpace = 
'none';
 
 2462                        property_info[
'colorspace'] = defaultColorSpace;
 
 
 2481        let loadNodePositions = 
false; 
 
 2485            editor.debugOutput(
"MaterialX is not initialized", 2);
 
 2489        editor.clearGraph();
 
 2492        editor.monitor.monitorGraph(
graph, 
false);
 
 2496        var mtlxNodeDefs = [];
 
 2498        for (var interfaceInput of 
doc.getInputs()) {
 
 2499            var _type = interfaceInput.getType();
 
 2500            var 
id = 
'mtlx/input/input_' + _type;
 
 2502            var lg_node = LiteGraph.createNode(
id);
 
 2504                lg_node.title = interfaceInput.getName();
 
 2506                    console.log(
'Add top level input:', lg_node.title, 
'to graph', 
graph);
 
 2508                var _value = interfaceInput.getValueString();
 
 2509                if (_value && _value.length > 0) {
 
 2510                    if (this.
isArray(interfaceInput.getType())) {
 
 2511                        _value = 
"[" + _value + 
"]" 
 2512                        _value = JSON.parse(_value);
 
 2514                    lg_node.setProperty(
'in', _value);
 
 2517                if (loadNodePositions) {
 
 2518                    var xpos = interfaceInput.getAttribute(
'xpos');
 
 2519                    var ypos = interfaceInput.getAttribute(
'ypos');
 
 2520                    if (xpos.length > 0 && ypos.length > 0) {
 
 2521                        lg_node.pos[0] = xpos;
 
 2522                        lg_node.pos[1] = ypos;
 
 2528                lg_node.setSize(lg_node.computeSize());
 
 2536        for (var interfaceOutput of 
doc.getOutputs()) {
 
 2537            var _type = interfaceOutput.getType()
 
 2538            var 
id = 
'mtlx/output/output_' + _type;
 
 2540            var lg_node = LiteGraph.createNode(
id);
 
 2542                lg_node.title = interfaceOutput.getName();
 
 2545                    console.log(
'Add graph output:', lg_node.title);
 
 2549                lg_node.setSize(lg_node.computeSize());
 
 2551                if (loadNodePositions) {
 
 2552                    var xpos = interfaceOutput.getAttribute(
'xpos');
 
 2553                    var ypos = interfaceOutput.getAttribute(
'ypos');
 
 2554                    if (xpos.length > 0 && ypos.length > 0)
 
 2555                        lg_node.pos = [xpos, ypos];
 
 2558                mtlxNodes.push([interfaceOutput, lg_node, 
graph]);
 
 2562        for (var node of 
doc.getNodes()) {
 
 2563            var nodeDef = node.getNodeDef();
 
 2565                editor.debugOutput(
'Skip node w/o nodedef:' + node.getName(), 1)
 
 2570            var 
id = 
'mtlx/' + nodeDef.getNodeGroup() + 
'/' + nodeDef.getName();
 
 2571            id = 
id.replace(
'ND_', 
'');
 
 2573                console.log(
'Load node:', node.getName(), 
' -> ', 
id);
 
 2575            var lg_node = LiteGraph.createNode(
id);
 
 2578                lg_node.title = node.getName();
 
 2583                lg_node.setSize(lg_node.computeSize());
 
 2585                if (loadNodePositions) {
 
 2586                    var xpos = node.getAttribute(
'xpos');
 
 2587                    var ypos = node.getAttribute(
'ypos');
 
 2588                    if (xpos.length > 0 && ypos.length > 0)
 
 2589                        lg_node.pos = [xpos, ypos];
 
 2592                mtlxNodes.push([node, lg_node, 
graph]);
 
 2593                mtlxNodeDefs.push(nodeDef);
 
 2596                editor.debugOutput(
'Failed to create node:' + node.getName(), 2);
 
 2600        for (var nodegraph of 
doc.getNodeGraphs()) {
 
 2601            if (nodegraph.hasSourceUri()) {
 
 2604            var nodedefAttrib = nodegraph.getAttribute(
'nodedef');
 
 2605            if (nodedefAttrib && nodedefAttrib.length > 0) {
 
 2606                console.log(
'Skip loading in functional graph:', nodegraph.getName(), 
'nodedef:', nodedefAttrib);
 
 2610                console.log(
'Create nodegraph:', nodegraph.getName());
 
 2612            var title = nodegraph.getName();
 
 2613            var subgraphNode = LiteGraph.createNode(
"graph/subgraph", title);
 
 2617            subgraphNode.bgImageUrl = 
"./Icons/nodegraph.png";
 
 2619            var mtlxSubGraphNodes = [];
 
 2620            for (var interfaceInput of nodegraph.getInputs()) {
 
 2621                var _type = interfaceInput.getType();
 
 2622                var 
id = 
'mtlx/input/input_' + _type;
 
 2624                var lg_node = LiteGraph.createNode(
id);
 
 2626                    lg_node.title = interfaceInput.getName();
 
 2628                    subgraphNode.subgraph.add(lg_node);
 
 2631                        console.log(
'-------- Add subgraph input:', lg_node.title, lg_node);
 
 2633                    subgraphNode.addInput(interfaceInput.getName(), _type);
 
 2634                    subgraphNode.subgraph.addInput(interfaceInput.getName(), _type);
 
 2636                    var _value = interfaceInput.getValueString();
 
 2637                    if (_value && _value.length > 0) {
 
 2638                        if (this.
isArray(interfaceInput.getType())) {
 
 2639                            _value = 
"[" + _value + 
"]" 
 2640                            _value = JSON.parse(_value);
 
 2642                        lg_node.setProperty(
'in', _value);
 
 2646                    lg_node.setSize(lg_node.computeSize());
 
 2648                    if (loadNodePositions) {
 
 2649                        var xpos = nodegraph.getAttribute(
'xpos');
 
 2650                        var ypos = nodegraph.getAttribute(
'ypos');
 
 2651                        if (xpos.length > 0 && ypos.length > 0)
 
 2652                            lg_node.pos = [xpos, ypos];
 
 2655                    mtlxSubGraphNodes.push([interfaceInput, lg_node, 
graph]);
 
 2659            for (var interfaceOutput of nodegraph.getOutputs()) {
 
 2660                var _type = interfaceOutput.getType()
 
 2661                var 
id = 
'mtlx/output/output_' + _type;
 
 2663                var lg_node = LiteGraph.createNode(
id);
 
 2665                    lg_node.title = interfaceOutput.getName();
 
 2666                    subgraphNode.subgraph.add(lg_node);
 
 2668                        console.log(
'Add subgraph output:', lg_node.title);
 
 2670                    subgraphNode.addOutput(interfaceOutput.getName(), _type);
 
 2671                    subgraphNode.subgraph.addOutput(interfaceOutput.getName(), _type);
 
 2674                    lg_node.setSize(lg_node.computeSize());
 
 2676                    if (loadNodePositions) {
 
 2677                        var xpos = interfaceOutput.getAttribute(
'xpos');
 
 2678                        var ypos = interfaceOutput.getAttribute(
'ypos');
 
 2679                        if (xpos.length > 0 && ypos.length > 0)
 
 2680                            lg_node.pos = [xpos, ypos];
 
 2683                    mtlxSubGraphNodes.push([interfaceOutput, lg_node, 
graph]);
 
 2688            for (var node of nodegraph.getNodes()) {
 
 2689                var nodeDef = node.getNodeDef();
 
 2691                    editor.debugOutput(
'Skip node w/o nodedef:' + node.getName(), 1)
 
 2696                var 
id = 
'mtlx/' + nodeDef.getNodeGroup() + 
'/' + nodeDef.getName();
 
 2697                id = 
id.replace(
'ND_', 
'');
 
 2699                var lg_node = LiteGraph.createNode(
id);
 
 2700                lg_node.title = node.getName();
 
 2701                subgraphNode.subgraph.add(lg_node);
 
 2703                    console.log(
'Add subgraph node:', lg_node.title);
 
 2706                lg_node.setSize(lg_node.computeSize());
 
 2708                if (loadNodePositions) {
 
 2709                    var xpos = node.getAttribute(
'xpos');
 
 2710                    var ypos = node.getAttribute(
'ypos');
 
 2711                    if (xpos.length > 0 && ypos.length > 0)
 
 2712                        lg_node.pos = [xpos, ypos];
 
 2715                mtlxSubGraphNodes.push([node, lg_node, 
graph]);
 
 2718            for (var item of mtlxSubGraphNodes) {
 
 2720                var lg_node = item[1];
 
 2721                var parentGraph = item[2];
 
 2722                var explicitInputs = [];
 
 2725                lg_node.setSize(lg_node.computeSize());
 
 2728                this.
buildConnections(editor, node, lg_node, explicitInputs, subgraphNode.subgraph, parentGraph);
 
 2732                console.log(
'Add subgraph:', subgraphNode.title);
 
 2734            if (auto_arrange > 0) {
 
 2735                subgraphNode.subgraph.arrange(auto_arrange);
 
 2738            graph.add(subgraphNode);
 
 2745        for (var item of mtlxNodes) {
 
 2747            var lg_node = item[1];
 
 2750            var explicitInputs = [];
 
 2754            if (lg_node.nodedef_node == 
'input' || lg_node.nodedef_node == 
'output') {
 
 2782        editor.monitor.monitorGraph(
graph, 
true);
 
 2784        if (auto_arrange > 0) {
 
 2785            graph.arrange(auto_arrange);
 
 2788        graph.setDirtyCanvas(
true, 
true);
 
 
 2801        var input = document.createElement(
"input");
 
 2802        input.style = this.fontSizeStyle;
 
 2803        input.type = 
"file";
 
 2804        input.accept = 
".mtlx";
 
 2805        input.onchange = 
function (e) {
 
 2806            var file = e.target.files[0];
 
 2807            console.log(
'Loading definitions from file: ' + file.name);
 
 2812                const reader = 
new FileReader();
 
 2813                reader.readAsText(file, 
'UTF-8');
 
 2815                reader.onload = 
function (e) {
 
 2817                    let fileContents = e.target.result;
 
 2822                            const readOptions = 
new ne_mx.XmlReadOptions();
 
 2823                            readOptions.readXIncludes = 
false;
 
 2824                            var customLib = 
ne_mx.createDocument();
 
 2826                            await 
ne_mx.readFromXmlString(customLib, fileContents, 
'', readOptions);
 
 2830                                console.log(
'Create custom library definitions', 
ne_mx.prettyPrint(customLib));
 
 2832                                var scanForIcon = 
false;
 
 2835                                    var iconName = file.name.replace(/\.[^/.]+$/, 
".webp");
 
 2837                                    var iconExists = await that.editor.uriExists(iconName);
 
 2842                                var definitionsList = [];
 
 2843                                var result = that.createLiteGraphDefinitions(customLib, 
false, 
false, definitionsList, 
'mtlx', that.editor, iconName);
 
 2846                                    var definitionsListString = definitionsList.join(
', ');
 
 2847                                    that.editor.debugOutput(
"Registered custom node types: [" + definitionsListString + 
"]", 0, 
false);
 
 2848                                    that.editor.displayNodeTypes();
 
 2851                                console.log(
'Error evaluating source:', e);
 
 2859                            that.editor.debugOutput(
'Error reading definitions:' + error, 2, 
false);
 
 2866                that.editor.debugOutput(
"MaterialX is not initialized", 2);
 
 
 2886            console.log(
'MaterialX is not initialized');
 
 2891        if (extension != 
'mtlx')
 
 2895                let result = converter.import(
ne_mx, fileContents, 
stdlib);
 
 2897                    fileContents = result[0];
 
 2900                    console.log(
'Failed to convert from:', extension, 
'to mtlx. Errors:', result[1]);
 
 2906                console.log(
'Failed to find converter from:', extension, 
'to mtlx.');
 
 2913                const readOptions = 
new ne_mx.XmlReadOptions();
 
 2914                readOptions.readXIncludes = 
false;
 
 2920                    console.log(
'Import custom library:', item[0]);
 
 2921                    doc.importLibrary(item[1]);
 
 2923                var loadDoc = 
ne_mx.createDocument();
 
 2924                await 
ne_mx.readFromXmlString(loadDoc, fileContents, 
'', readOptions);
 
 2928                var customLib = 
ne_mx.createDocument();
 
 2929                customLib.copyContentFrom(loadDoc);
 
 2930                var keepChildren = [];
 
 2931                var existingDefs = []
 
 2932                var saveCustomLib = 
false;
 
 2933                doc.getNodeDefs().forEach(def => { existingDefs.push(def.getName()); });
 
 2934                for (var nodedef of loadDoc.getNodeDefs()) {
 
 2935                    var nodedefName = nodedef.getName();
 
 2936                    if (!existingDefs.includes(nodedefName)) {
 
 2937                        keepChildren.push(nodedef.getName());
 
 2938                        saveCustomLib = 
true;
 
 2941                for (var ng of loadDoc.getNodeGraphs()) {
 
 2942                    if (ng.getAttribute(
'nodedef') && ng.getAttribute(
'nodedef').length > 0) {
 
 2943                        saveCustomLib = 
true;
 
 2944                        keepChildren.push(ng.getName());
 
 2948                if (saveCustomLib) {
 
 2950                    for (var child of customLib.getChildren()) {
 
 2951                        if (!keepChildren.includes(child.getName())) {
 
 2953                            customLib.removeChild(child.getName());
 
 2957                    var additionDefs = [];
 
 2958                    console.log(
'Create custom library definitions from addtionDefs:', 
 
 2959                        ne_mx.prettyPrint(customLib));
 
 2964                        console.log(
'Loaded local definitions: ', additionDefs);
 
 2966                        console.log(
'Error evaluating source:', e);
 
 2970                doc.copyContentFrom(loadDoc);
 
 2977                if (saveCustomLib) {
 
 2982                var documentColorSpace = 
doc.getColorSpace();
 
 2988                loadDoc.removeAttribute(
'fileprefix');
 
 2989                fileContents = 
ne_mx.writeToXmlString(loadDoc);
 
 2997                if (documentDisplayUpdater) {
 
 2998                    documentDisplayUpdater(fileContents);
 
 3001                    console.log(
'No docDisplayUpdater!!!');
 
 3006                if (renderableItemUpdater) {
 
 3008                    if (!renderableItems || renderableItems.length == 0) {
 
 3009                        MxShadingGraphEditor.theEditor.debugOutput(
'No renderable items found in graph: ' + fileName, 1, 
false);
 
 3011                    renderableItemUpdater(renderableItems);
 
 3018                    console.log(
'> Update rendering from document');
 
 3019                    let theRenderer = this.editor.monitor.renderer; 
 
 3022                        theRenderer.updateMaterialFromText(fileContents);
 
 3026                MxShadingGraphEditor.theEditor.debugOutput(
'Error reading document: ' + fileName + 
'. Error: ' + error, 2, 
false);
 
 
 3050            const reader = 
new FileReader();
 
 3051            reader.readAsText(file, 
'UTF-8');
 
 3052            reader.accept = 
'.mtlx';
 
 3055            console.log(
'loadFromFile:', file, fileName);
 
 3057                reader.onload = 
function (e) {
 
 3059                    let fileContents = e.target.result;
 
 3060                    console.log(
"read file: ", file.name, 
" with extension: ", extension, 
" and length: ", fileContents.length);
 
 3062                    that.loadFromString(
'mtlx', fileContents, fileName, auto_arrange, 
true);
 
 3065                MxShadingGraphEditor.theEditor.debugOutput(
'Error reading document: ' + fileName + 
'. Error: ' + error, 2, 
false);
 
 3069            editor.debugOutput(
"MaterialX is not initialized", 2, 
false);
 
 
 3073    loadFromZip(extension, file, fileName, editor, auto_arrange, rerender=
false) 
 
 3077            console.log(
"Loading content from zip:", file.name);
 
 3079            const reader = 
new FileReader();
 
 3082            reader.onload = async 
function (e) {
 
 3084                    const zipData = 
new Uint8Array(e.target.result); 
 
 3086                    let documents = result[0];
 
 3087                    let docText = documents[0].content;
 
 3088                    let docFile = documents[0].name;
 
 3089                    console.log(
'Documents:', docText);
 
 3091                    let textures = result[1];
 
 3092                    for (let i = 0; i < textures.length; i++) {
 
 3093                        const url = textures[i].url;
 
 3094                        const textureName = textures[i].name;
 
 3098                        docText = docText.replace(
new RegExp(textureName, 
'i'), url);
 
 3099                        console.log(
'Replace reference:' + textureName + 
' with blob: ' + url);
 
 3102                    that.loadFromString(
'mtlx', docText, docFile, auto_arrange, rerender);
 
 3106                    console.error(
'Error loading ZIP file:', error);
 
 3110            reader.readAsArrayBuffer(file);
 
 3113            console.error(
"MaterialX is not initialized");
 
 
 3132        var generator = 
new ne_mx.EsslShaderGenerator.create();
 
 3133        var genContext = 
new ne_mx.GenContext(generator);
 
 3136            console.log(
'Loaded standard libraries:', 
stdlib.getNodeDefs().length);
 
 
 3150        if (name.length == 0) {
 
 3152                msg = 
'Setting empty name as "blank"';
 
 3159        var nodes = 
graph._nodes;
 
 3161        for (var node of nodes) {
 
 3162            nodenames.push(node.title);
 
 3166        name = 
ne_mx.createValidName(name);
 
 3168        if (!nodenames.includes(name)) {
 
 3173        var rootName = name;
 
 3175        var number = name.match(/\d+$/);
 
 3177            i = (parseInt(number) + 1)
 
 3178            rootName = name.slice(0, -number[0].length);
 
 3181        var valid_name = rootName + i.toString();
 
 3182        while (nodenames.includes(valid_name)) {
 
 3184            valid_name = rootName + i.toString();
 
 
 
 3206            this.fontSizeStyle = 
'font-size: 11px;';
 
 3209            let gltfConverter = 
new glTFMaterialX();
 
 3210            this.handler.addConverter(gltfConverter);
 
 3212            console.log(
'Create new editor with exporter for:', gltfConverter.exportType());            
 
 3231    setDirty(w = 
null, h = 
null) {
 
 3233            graph.setDirtyCanvas(
true, 
true);
 
 3247    debugOutput(text, severity, clear = 
null) {
 
 3250            consoleLog(text, severity, clear);
 
 3253            console.log(
'> ', text, 
' severity:', severity);
 
 3263    setSourceColorSpace(colorSpace) {
 
 3265            this.handler.setSourceColorSpace(colorSpace);
 
 3275    setTargetDistanceUnit(unit) {
 
 3277            this.handler.setTargetDistanceUnit(unit);
 
 3286    getSourceColorSpace() {
 
 3288            return this.handler.getSourceColorSpace();
 
 3290        return 'lin_rec709';
 
 3298    getTargetDistanceUnit() {
 
 3300            return this.handler.getTargetDistanceUnit();
 
 3312        if (title.length == 0) {
 
 3317            let nodesFound = [];
 
 3321            const pattern = 
new RegExp(title);
 
 3322            for (var i = 0, l = theGraph._nodes.length; i < l; ++i) {
 
 3323                if (pattern.test(theGraph._nodes[i].title)) {
 
 3324                    console.log(
'-- add found node:', theGraph._nodes[i].title);
 
 3325                    nodesFound.push(theGraph._nodes[i]);
 
 3328                    if (theGraph._nodes[i].title == title)
 
 3330                        nodesFound.length = 0;
 
 3331                        nodesFound.push(theGraph._nodes[i]);
 
 3337            if (nodesFound.length > 0)
 
 3345                this.debugOutput(
'Node not found: ' + title, 0, 
false);
 
 3356    arrangeGraph(spacing = 80) {
 
 3368        for (var s in selected) {
 
 3369            var node = selected[s];
 
 3370            if (node.type == 
'graph/subgraph') {
 
 3413        this.handler.sourceColorSpace = this.handler.DEFAULT_COLOR_SPACE;
 
 3414        this.handler.targetDistanceUnits = this.handler.DEFAULT_DISTANCE_UNITS;
 
 3416        this.updatePropertyPanel(
null);
 
 3430    saveSerialization() {
 
 3431        var data = JSON.stringify(
graph.serialize(), 
null, 2);
 
 3432        var blob = 
new Blob([data], { type: 
"text/plain" });
 
 3433        var url = URL.createObjectURL(blob);
 
 3434        var a = document.createElement(
"a");
 
 3436        a.download = 
"serialized_graph.json";
 
 3443    loadSerialization() {
 
 3446        var input = document.createElement(
"input");
 
 3447        input.style = this.fontSizeStyle;
 
 3448        input.type = 
"file";
 
 3449        input.accept = 
".json";
 
 3450        input.onchange = 
function (e) {
 
 3451            var file = e.target.files[0];
 
 3452            var reader = 
new FileReader();
 
 3453            reader.onload = 
function (event) {
 
 3454                var data = JSON.parse(event.target.result);
 
 3455                graph.configure(data);
 
 3457            reader.readAsText(file);
 
 3469    saveGraphToFile(extension, graphWriteOptions) {
 
 3470        if (this.handler.canExport(extension)) {
 
 3471            this.handler.saveGraphToFile(extension, 
graph, graphWriteOptions);
 
 3475            this.debugOutput(
'Unsupported extension for saving graph:' + extension, 2, 
false);
 
 3485    saveGraphToString(extension, graphWriteOptions) {
 
 3486        if (this.handler.canExport(extension)) {
 
 3487            return this.handler.saveGraphToString(extension, 
graph, graphWriteOptions);
 
 3491            this.debugOutput(
'Unsupported extension for saving graph: ' + extension, 2, 
false);
 
 3502    loadDefinitionsFromFile(extension) {
 
 3503        if (extension == 
'mtlx') {
 
 3504            this.handler.loadDefinitionsFromFile();
 
 3508            this.debugOutput(
'Unsupported extension for loading definitions: ' + extension, 2, 
false);
 
 3520    loadGraphFromFile(extension, auto_arrange, rerender=
false) {
 
 3522        if (!this.handler.canImport(extension)) {
 
 3523            this.debugOutput(
'Unsupported extension for loading graph: ' + extension, 2, 
false);
 
 3528        if (extension == 
'mtlx')
 
 3530        var input = document.createElement(
"input");
 
 3531        input.style = this.fontSizeStyle;
 
 3532        input.type = 
"file";
 
 3533        input.accept = 
"." + this.handler.getExtension();
 
 3534        input.onchange = 
function (e) {
 
 3535            var file = e.target.files[0];
 
 3536            console.log(
'Loading file: ' + file.name);
 
 3541        else if (extension == 
'zip')
 
 3543            var input = document.createElement(
"input");
 
 3544            input.style = this.fontSizeStyle;
 
 3545            input.type = 
"file";
 
 3546            input.accept = 
".zip";
 
 3547            input.onchange = 
function (e) {
 
 3548                var file = e.target.files[0];
 
 3550                    console.log(
'Loading zip file: ' + file.name);          
 
 3563    findRenderableItems() {
 
 3564        return this.handler.findRenderableItems(
graph);
 
 3577    loadGraphFromString(extension, content, fileName, auto_arrange, rerender=
false) {
 
 3578        if (!this.handler.canImport(extension)) {
 
 3579            this.debugOutput(
'Unsupported extension for loading graph: ' + extension, 2, 
false);
 
 3583        if (content.length > 0)
 
 3584            this.handler.loadFromString(extension, content, fileName, auto_arrange, rerender);
 
 3597            console.log(
'rgbToHex empty !', rgb);
 
 3600        return '#' + rgb.map(x => {
 
 3601            var hex = Math.round(x * 255).toString(16);
 
 3602            return hex.length === 1 ? 
'0' + hex : hex;
 
 3614    createButtonWithImageAndText(imageSrc, text, 
id) {
 
 3616        var img = document.createElement(
"img");
 
 3617        img.id = 
id + 
"_img";
 
 3619        img.classList.add(
"img-fluid");
 
 3622        var span = document.createElement(
"span");
 
 3623        span.id = 
id + 
"_text";
 
 3624        span.textContent = 
" " + text;
 
 3627        var button = document.createElement(
"button");
 
 3629        button.classList.add(
"btn", 
"btn-sm", 
"btn-outline-secondary", 
"form-control", 
"form-control-sm");
 
 3630        button.style = this.fontSizeStyle;
 
 3631        button.appendChild(img);
 
 3632        button.appendChild(span);
 
 3644    openImageDialog(theNode, updateProp, wantURI) {
 
 3647        var fileInput = document.createElement(
'input');
 
 3648        fileInput.type = 
'file';
 
 3649        fileInput.accept = 
'image/*'; 
 
 3650        fileInput.style.display = 
'none';
 
 3651        document.body.appendChild(fileInput);
 
 3656        fileInput.addEventListener(
'change', 
function () {
 
 3657            var fileURI = fileInput.value.split(
'\\').pop(); 
 
 3658            var file = fileInput.files[0];
 
 3660            fileURI = URL.createObjectURL(file);
 
 3662            var updateElementId = 
'__pp:' + updateProp;
 
 3663            var textInput = document.getElementById(updateElementId);
 
 3665            textInput.value = fileURI;
 
 3666            theNode.setProperty(updateProp, fileURI);
 
 3668            var propertypanel_preview = document.getElementById(
'propertypanel_preview');
 
 3669            if (propertypanel_preview) {
 
 3670                propertypanel_preview.src = URL.createObjectURL(file);
 
 3671                propertypanel_preview.style.display = 
"block";
 
 3674            var previewImage = 
false;
 
 3676                if (propertypanel_preview) {
 
 3677                    var reader = 
new FileReader();
 
 3678                    reader.onload = 
function (event) {
 
 3679                        propertypanel_preview.src = 
event.target.result;
 
 3683                    reader.readAsDataURL(file);
 
 3684                    propertypanel_preview.style.display = 
"block";
 
 3688            document.body.removeChild(fileInput);
 
 3702                    return Promise.resolve(
true);
 
 3704                    return Promise.resolve(
false);
 
 3708                console.log(
'Error checking URI:', error);
 
 3709                return Promise.resolve(
false);
 
 3720    createColorSpaceInput(colorSpaces, activeItem) {
 
 3721        var select = document.createElement(
"select");
 
 3722        select.className = 
"form-control form-control-sm";
 
 3723        select.style = this.fontSizeStyle;
 
 3724        select.id = 
"propertypanel_colorspace";
 
 3725        for (var i = 0; i < colorSpaces.length; i++) {
 
 3726            var option = document.createElement(
"option");
 
 3727            option.value = colorSpaces[i];
 
 3728            option.text = colorSpaces[i];
 
 3732        var option = document.createElement(
"option");
 
 3733        option.value = 
"none";
 
 3734        option.text = 
"none";
 
 3737        select.value = activeItem;
 
 3749    createUnitsInput(units, unittype, activeItem) {
 
 3750        var select = document.createElement(
"select");
 
 3751        select.className = 
"form-control form-control-sm";
 
 3752        select.style = this.fontSizeStyle;
 
 3753        select.id = 
"propertypanel_units";
 
 3754        for (var i = 0; i < units.length; i++) {
 
 3755            var option = document.createElement(
"option");
 
 3756            var unit_pair = units[i];
 
 3757            if (unit_pair[1] == unittype) {
 
 3758                option.value = unit_pair[0];
 
 3759                option.text = unit_pair[0];
 
 3763        select.value = activeItem;
 
 3773    updateImagePreview(curImage) {
 
 3774        var propertypanel_preview = document.getElementById(
'propertypanel_preview');
 
 3775        if (curImage && propertypanel_preview) {
 
 3776            this.uriExists(curImage)
 
 3779                        propertypanel_preview.src = curImage;
 
 3780                        propertypanel_preview.style.display = 
"block";
 
 3783                        propertypanel_preview.src = 
"./Icons/no_image.png";
 
 3784                        propertypanel_preview.style.display = 
"block";
 
 3801    updatePropertyPanel(node) {
 
 3802        const TRUNC_TEXT = 20;
 
 3806        if (!propertypanelcontent) {
 
 3807            console.error(
'No property panel content widget found!');
 
 3811        while (propertypanelcontent.firstChild) {
 
 3812            propertypanelcontent.removeChild(propertypanelcontent.firstChild);
 
 3817        if (node && node.nodedef_icon) {
 
 3818            panelIcon.src = node.nodedef_icon;
 
 3820        else if (this.ui.icon_map) {
 
 3821            if (!node || node.type == 
'graph/subgraph') {
 
 3822                panelIcon.src = this.ui.icon_map[
'_default_graph_'];
 
 3824                panelIcon.src = this.ui.icon_map[
'_default_'];
 
 3828        propertypanelcontent.innerHTML = 
"";
 
 3830        let colorSpaces = this.handler.getColorSpaces();
 
 3831        let targetUnits = this.handler.getUnits();
 
 3833        let inUnselectedNodeGraph = 
false 
 3836            inUnselectedNodeGraph = 
true 
 3842        else if (!node && !
graphcanvas.graph._is_subgraph) {
 
 3843            var docInfo = [[
'Colorspace', this.getSourceColorSpace()],
 
 3844            [
'Distance', this.getTargetDistanceUnit()]];
 
 3846            for (let item of docInfo) {
 
 3848                let elem = document.createElement(
"div");
 
 3849                elem.className = 
"row px-1 py-0";
 
 3850                let label = document.createElement(
"div");
 
 3851                label.className = 
"col py-0 col-form-label-sm text-left";
 
 3852                label.style = this.fontSizeStyle;
 
 3853                label.innerHTML = 
"<b>" + item[0] + 
"</b>";
 
 3854                elem.appendChild(label);
 
 3856                if (item[0] == 
'Colorspace' && colorSpaces.length > 0) {
 
 3858                    var inputCol = document.createElement(
"div");
 
 3859                    inputCol.className = 
"col text-left";
 
 3860                    var select = this.createColorSpaceInput(colorSpaces, item[1]);
 
 3861                    select.onchange = 
function (e) {
 
 3864                    inputCol.appendChild(select);
 
 3865                    elem.appendChild(inputCol);
 
 3867                else if (item[0] == 
'Distance' && targetUnits.length > 0) {
 
 3869                    var inputCol = document.createElement(
"div");
 
 3870                    inputCol.className = 
"col text-left";
 
 3871                    var select = this.createUnitsInput(targetUnits, 
'distance', item[1]);
 
 3872                    select.onchange = 
function (e) {
 
 3875                    inputCol.appendChild(select);
 
 3876                    elem.appendChild(inputCol);
 
 3889                propertypanelcontent.appendChild(elem);
 
 3894        var _category = node.nodedef_node;
 
 3895        var _type = node.nodedef_type;
 
 3897        var isNodeGraph = node.type == 
'graph/subgraph';
 
 3900            _category = 
'nodegraph';
 
 3902                if (node.outputs.length > 1) {
 
 3905                else if (node.outputs.length > 0) {
 
 3906                    _type = node.outputs[0].type;
 
 3914            if (_category == 
'surfacematerial') {
 
 3920        var elem = document.createElement(
"div");
 
 3921        elem.className = 
"row px-1 py-1";
 
 3924        var label = document.createElement(
"div");
 
 3925        label.className = 
"col-4 px-1 py-0 col-form-label-sm text-end";
 
 3926        label.style = this.fontSizeStyle;
 
 3927        label.innerHTML = 
"<b>" + _category;
 
 3928        if (_type.length > 0) {
 
 3929            label.innerHTML += 
'<br>' + _type;
 
 3931        label.innerHTML += 
"</b>";
 
 3932        elem.appendChild(label);
 
 3935        var inputCol = document.createElement(
"div");
 
 3936        inputCol.className = 
"col py-0";
 
 3937        var nameInput = document.createElement(
"input");
 
 3938        nameInput.style = this.fontSizeStyle;
 
 3939        nameInput.type = 
"text";
 
 3940        nameInput.value = node.title;
 
 3941        nameInput.className = 
"form-control form-control-sm";
 
 3943        nameInput.onchange = 
function (e) {
 
 3944            var oldTitle = node.title;
 
 3946            if (newTitle != oldTitle)
 
 3948                that.monitor.onNodeRenamed(node, newTitle);
 
 3949                node.title = newTitle;
 
 3951            e.target.value = node.title;
 
 3953            if (node.graph._is_subgraph) {
 
 3954                if (node.nodedef_node == 
'input') {
 
 3956                    node.graph.renameInput(oldTitle, node.title);
 
 3958                else if (node.nodedef_node == 
'output') {
 
 3960                    node.graph.renameOutput(oldTitle, node.title);
 
 3965            node.setSize(node.computeSize());
 
 3966            node.setDirtyCanvas(
true, 
true);
 
 3968        inputCol.appendChild(nameInput);
 
 3971        if (node.nodedef_node != 
'input' && node.nodedef_node != 
'output' 
 3972            && node.type != 
'graph/subgraph') {
 
 3973            var imagePreview = document.createElement(
"img");
 
 3974            imagePreview.src = 
"./Icons/no_image.png";
 
 3975            var previewSet = 
false;
 
 3977            imagePreview.style.display = 
"none";
 
 3978            imagePreview.src = 
"./Icons/no_image.png";
 
 3991            imagePreview.id = 
"propertypanel_preview";
 
 3992            imagePreview.className = 
"img-fluid form-control form-control-sm";
 
 3993            inputCol.appendChild(imagePreview);
 
 3996        elem.appendChild(label);
 
 3997        elem.appendChild(inputCol);
 
 4002            var filterCol = document.createElement(
"div");
 
 4003            filterCol.className = 
"col-2 py-0";
 
 4004            filterCol.width = 16;
 
 4005            var filterIcon = document.createElement(
"button");
 
 4008            if (node.showDefaultValueInputs == 
null)
 
 4010                node.showDefaultValueInputs = 
true;
 
 4012            var img = document.createElement(
"img");
 
 4013            if (node.showDefaultValueInputs)
 
 4015                img.src = 
"./Icons/funnel_white.svg";
 
 4016                filterIcon.className = 
"btn btn-sm btn-outline-secondary";
 
 4020                img.src = 
"./Icons/funnel-fill_white.svg";
 
 4021                filterIcon.className = 
"btn btn-sm btn-outline-warning";
 
 4023            filterIcon.appendChild(img);
 
 4024            filterIcon.onclick = 
function (e) {
 
 4025                node.showDefaultValueInputs = !node.showDefaultValueInputs;
 
 4028            filterCol.appendChild(filterIcon);
 
 4029            elem.appendChild(filterCol); 
 
 4032        propertypanelcontent.appendChild(elem);
 
 4034        let hr = document.createElement(
"hr");
 
 4035        hr.classList.add(
"my-1");
 
 4036        propertypanelcontent.appendChild(hr);
 
 4038        let current_details = 
null;
 
 4039        let first_details = 
true;
 
 4040        let nodeInputs = node.inputs;
 
 4043        let targetNodes = [];
 
 4044        for (var i in nodeInputs) {
 
 4045            let nodeInput = nodeInputs[i];
 
 4047            let inputName = nodeInput.name;
 
 4048            let nodeInputLink = nodeInput.link;
 
 4049            let uiName = inputName;
 
 4051            uiName = uiName.replace(/_/g, 
' ');
 
 4054            let colorspace = 
'';
 
 4056            let defaultgeomprop = 
'';
 
 4060            let property_info = node.getPropertyInfo(inputName);
 
 4061            let ng_property_info = 
null;
 
 4065                let sg = node.subgraph;
 
 4068                    let sg_nodes = sg._nodes;
 
 4069                    for (var sg_node of sg_nodes)
 
 4071                        if (sg_node.title == inputName)
 
 4074                            ng_property_info = sg_node.getPropertyInfo(
"in");
 
 4075                            if (ng_property_info)
 
 4086            var skipInterorConnectedInput = 
false;
 
 4087            if (node.graph._is_subgraph) {
 
 4090                var sg_node = node.graph._subgraph_node;
 
 4093                    var slot = sg_node.findInputSlot(node.title);
 
 4095                        if (sg_node.inputs) {
 
 4097                            var slotInput = sg_node.inputs[slot];
 
 4099                            if (slotInput != 
null && slotInput.link != 
null) {
 
 4100                                skipInterorConnectedInput = 
true;
 
 4110            if (skipInterorConnectedInput) {
 
 4111                console.log(
'Skip interior connected input: ', nodeInput);
 
 4116            if (ng_property_info) {
 
 4118                property_info = ng_property_info;
 
 4120            if (property_info) {
 
 4122                if (property_info.defaultgeomprop)
 
 4124                    defaultgeomprop = property_info.defaultgeomprop;
 
 4126                if (property_info.colorspace) {
 
 4127                    colorspace = property_info.colorspace;
 
 4129                if (property_info.unit) {
 
 4130                    units = property_info.unit;
 
 4132                if (property_info.uiname) {
 
 4133                    uiName = property_info.uiname;
 
 4135                if (property_info.uimin) {
 
 4136                    uimin = property_info.uimin;
 
 4138                if (property_info.uimax) {
 
 4139                    uimax = property_info.uimax;
 
 4141                if (property_info.uifolder && property_info.uifolder.length > 0) {
 
 4143                    if (current_details == 
null || current_details.id != property_info.uifolder) {
 
 4145                        current_details = document.createElement(
"details");
 
 4146                        current_details.id = property_info.uifolder;
 
 4147                        current_details.open = first_details;
 
 4148                        current_details.classList.add(
'w-100', 
'p-1', 
'border', 
'border-secondary', 
'rounded', 
'my-1');
 
 4149                        first_details = 
false;
 
 4150                        var summary = document.createElement(
'summary')
 
 4151                        summary.style = this.fontSizeStyle;
 
 4152                        summary.innerHTML = 
"<b>" + property_info.uifolder + 
"</b>" 
 4154                        current_details.appendChild(summary);
 
 4162                    current_details = 
null;
 
 4167                current_details = 
null;
 
 4173            if (nodeInputLink) {
 
 4174                let upstreamLink = 
null;
 
 4176                let nodegraph = node.graph;
 
 4177                let link = nodegraph.links[nodeInputLink];
 
 4179                let linkId = link && link.origin_id;
 
 4180                let linkNode = linkId && nodegraph.getNodeById(linkId);
 
 4185                    let linkSlot = link.origin_slot;
 
 4187                    let linkOutput = linkNode.outputs[linkSlot];
 
 4189                    upstreamLink = linkNode.title + 
'.' + linkOutput.name;
 
 4192                    let 
id = 
"__pp:" + inputName;
 
 4193                    let buttonText = upstreamLink;
 
 4195                    if (buttonText.length > TRUNC_TEXT) {
 
 4196                        buttonText = buttonText.substring(0, TRUNC_TEXT) + 
"...";
 
 4198                    let input = this.createButtonWithImageAndText(
"./Icons/arrow_up_white.svg", buttonText, 
id);
 
 4200                    input.onclick = 
function (e) {
 
 4202                        var inputName = e.target.id;
 
 4203                        inputName = inputName.replace(
'__pp:', 
'');
 
 4204                        inputName = inputName.replace(
'_text', 
'');
 
 4205                        inputName = inputName.replace(
'_img', 
'');
 
 4206                        console.log(
'Clicked traversal button:', inputName);
 
 4208                        console.log(
'Jump to node:', linkNode.title);
 
 4212                        node.setDirtyCanvas(
true, 
true);
 
 4216                    elem = document.createElement(
"div");
 
 4217                    elem.className = 
"row px-1 py-0";
 
 4219                    input.id = 
"__pp:" + inputName;
 
 4221                    var label = document.createElement(
"div");
 
 4223                    label.className = 
"col-4 px-1 py-0 col-form-label-sm text-end";
 
 4224                    label.style = this.fontSizeStyle;
 
 4225                    label.innerHTML = uiName;
 
 4226                    label.for = input.id;
 
 4227                    elem.appendChild(label);
 
 4230                    if (useFormControl) {
 
 4231                        input.classList.add(
"form-control");
 
 4233                    input.classList.add(
"form-control-sm");
 
 4236                        input.disabled = 
true;
 
 4238                    var propvalue = document.createElement(
"div");
 
 4239                    propvalue.className = 
"col p-1";
 
 4240                    propvalue.appendChild(input);
 
 4242                    elem.appendChild(propvalue);
 
 4248                targetNodes[i] = node;
 
 4249                let targetNode = targetNodes[i];
 
 4250                let propertyKey = inputName;
 
 4252                var 
property = targetNode.properties[inputName];
 
 4253                if (property == 
null) {
 
 4255                        var subgraph = targetNode.subgraph;
 
 4258                            var subNode = subgraph.findNodeByTitle(inputName);
 
 4260                                targetNodes[i] = subNode;
 
 4262                                property = targetNodes[i].properties[
'in'];
 
 4267                    if (property == 
null) {
 
 4268                        console.log(
'Update: Cannot find property value for input:', inputName);
 
 4274                if (defaultgeomprop)
 
 4281                if (!node.showDefaultValueInputs && !isNodeGraph)
 
 4283                    let isDefault = node.isDefaultValue(inputName);
 
 4291                elem = document.createElement(
"div");
 
 4292                elem.className = 
"row px-1 py-0";
 
 4295                var input_btn = 
null;
 
 4296                let input_slider = 
null;
 
 4297                var colorspace_unit_btn = 
null;
 
 4298                var useFormControl = 
true;
 
 4301                if (colorspace.length > 0) {
 
 4305                    colorspace_unit_btn = this.createColorSpaceInput(colorSpaces, colorspace);
 
 4306                    let theNode = targetNodes[i];
 
 4307                    colorspace_unit_btn.onchange = 
function (e) {
 
 4309                        theNode.setPropertyInfo(inputName, 
'colorspace', e.target.value);
 
 4312                else if (units.length > 0 && property_info.unittype) {
 
 4314                    colorspace_unit_btn = this.createUnitsInput(targetUnits, property_info.unittype, units);
 
 4315                    let theNode = targetNodes[i];
 
 4316                    colorspace_unit_btn.onchange = 
function (e) {
 
 4317                        theNode.setPropertyInfo(inputName, 
'unit', e.target.value);
 
 4321                let proptype = nodeInput.type;
 
 4322                if (proptype == 
'float' || proptype == 
'integer') {
 
 4323                    var isFloat = proptype == 
'float';
 
 4325                    input = document.createElement(
"input");
 
 4326                    input.id = propertyKey + 
'_box';
 
 4327                    input.style = this.fontSizeStyle;
 
 4328                    input.type = 
'number';
 
 4329                    input.classList.add(
"form-control", 
"form-control-sm", 
"ps-0");
 
 4330                    input.setAttribute(
'propertyKey', propertyKey);
 
 4332                    input_slider = document.createElement(
"input");
 
 4333                    input_slider.id = propertyKey + 
'_slider';
 
 4335                    input_slider.type = 
'range';
 
 4336                    input_slider.classList.add(
'form-range', 
'custom-slider', 
'pe-0');
 
 4337                    input_slider.setAttribute(
'propertyKey', propertyKey);
 
 4343                        input.min = Math.min(property, 0);
 
 4351                            input.max = Math.max(property*3, 10.0);
 
 4354                            input.max = Math.max(property*3, 100);
 
 4359                    input_slider.min = input.min;
 
 4360                    input_slider.max = input.max;
 
 4362                        input.step = (input.max - input.min) / 100.0;
 
 4363                        input_slider.step = input.step;
 
 4366                        input_slider.step = 1;
 
 4370                    input.value = input_slider.value = property;
 
 4380                    let theSlider = input_slider;
 
 4381                    let theNode = targetNodes[i];
 
 4382                    input_slider.onchange = 
function (e) {
 
 4383                        var pi = e.target.getAttribute(
'propertyKey');
 
 4384                        var val = parseFloat(e.target.value);
 
 4385                        theNode.setProperty(pi, val);
 
 4388                    input_slider.oninput = 
function(e) {
 
 4389                        var pi = e.target.getAttribute(
'propertyKey');
 
 4390                        var val = parseFloat(e.target.value);
 
 4391                        theNode.setProperty(pi, val);
 
 4392                        theBox.value = e.target.value;
 
 4395                    input.onchange = 
function (e) {
 
 4396                        var pi = e.target.getAttribute(
'propertyKey');
 
 4397                        var val = parseFloat(e.target.value);
 
 4398                        theNode.setProperty(pi, val);
 
 4401                    input.oninput = 
function(e) {
 
 4402                        var pi = e.target.getAttribute(
'propertyKey');
 
 4403                        var val = parseFloat(e.target.value);
 
 4404                        theNode.setProperty(pi, val);
 
 4405                        theSlider.value = e.target.value;
 
 4408                else if (proptype == 
'string' || proptype == 
'filename') {
 
 4409                    input = document.createElement(
"input");
 
 4410                    input.style = this.fontSizeStyle;
 
 4411                    input.type = 
"text";
 
 4412                    if (proptype == 
'filename') {
 
 4413                        var curImage = property;
 
 4414                        this.updateImagePreview(curImage);
 
 4416                        input_btn = document.createElement(
"button");
 
 4417                        input_btn.classList.add(
"btn", 
"btn-sm", 
"btn-outline-secondary");
 
 4418                        input_btn.innerHTML = 
"+";
 
 4419                        input_btn.setAttribute(
'propertyKey', propertyKey);
 
 4420                        var fileId = 
"__pp:" + inputName;
 
 4421                        let theNode = targetNodes[i];
 
 4422                        input_btn.onclick = 
function (e) {
 
 4423                            var pi = e.target.getAttribute(
'propertyKey');
 
 4432                        if (property_info && property_info.enum) {
 
 4437                            input = document.createElement(
"select");
 
 4438                            input.style = this.fontSizeStyle;
 
 4439                            input.classList.add(
"form-control", 
"form-control-sm");
 
 4441                            input.setAttribute(
'propertyKey', propertyKey);
 
 4442                            let theNode = targetNodes[i];
 
 4443                            let enums = property_info.enum;
 
 4444                            for (let j = 0; j < enums.length; j++) {
 
 4445                                let option = document.createElement(
"option");
 
 4446                                option.value = enums[j];
 
 4447                                option.text = enums[j];
 
 4450                            input.value = property;
 
 4451                            input.setAttribute(
'propertyKey', propertyKey);
 
 4452                            input.onchange = 
function (e) {
 
 4453                                var pi = e.target.getAttribute(
'propertyKey');
 
 4454                                theNode.setProperty(pi, e.target.value);
 
 4460                    if (property_info && !property_info.enm) {
 
 4461                        input.value = property;
 
 4462                        input.setAttribute(
'propertyKey', propertyKey);
 
 4463                        let theNode = targetNodes[i];
 
 4464                        let isFilename = proptype == 
'filename';
 
 4466                        input.onchange = 
function (e) {
 
 4467                            var pi = e.target.getAttribute(
'propertyKey');
 
 4469                            theNode.setProperty(pi, e.target.value);
 
 4472                                that.updateImagePreview(e.target.value);
 
 4480                else if (proptype == 
'boolean') {
 
 4482                    input = document.createElement(
"input");
 
 4483                    input.style = this.fontSizeStyle;
 
 4484                    input.type = 
"checkbox";
 
 4485                    input.classList = 
"form-check-input";
 
 4486                    useFormControl = 
false;
 
 4487                    input.checked = property;
 
 4488                    input.setAttribute(
'propertyKey', propertyKey);
 
 4489                    let theNode = targetNodes[i];
 
 4490                    input.onchange = 
function (e) {
 
 4491                        var pi = e.target.getAttribute(
'propertyKey');
 
 4493                        theNode.setProperty(pi, e.target.checked);
 
 4498                else if (proptype == 
'vector2' || proptype == 
'vector3' || proptype == 
'vector4') 
 
 4501                    var vector_size = [
'vector2', 
'vector3', 
'vector4'].indexOf(proptype) + 2;
 
 4502                    input = document.createElement(
"div");
 
 4503                    useFormControl = 
false;
 
 4505                    input.className = 
"row py-1 ps-4 pe-0";
 
 4507                    for (let v=0; v<vector_size; v++) 
 
 4510                        let subinput = document.createElement(
"input");
 
 4511                        subinput.style = this.fontSizeStyle;
 
 4512                        subinput.type = 
'number';
 
 4513                        subinput.classList.add(
"form-control");
 
 4514                        subinput.classList.add(
"form-control-sm");
 
 4515                        subinput.setAttribute(
'propertyKey', propertyKey);
 
 4517                        let subinput_slider = document.createElement(
"input");
 
 4518                        subinput_slider.id = propertyKey + 
'_slider';
 
 4519                        subinput_slider.type = 
'range';
 
 4520                        subinput_slider.classList.add(
'form-range', 
'custom-slider', 
'pe-0');
 
 4521                        subinput_slider.setAttribute(
'propertyKey', propertyKey);
 
 4524                            subinput.min = uimin[v];
 
 4527                            subinput.min = Math.min(property[v]*3, 0);
 
 4530                            subinput.max = uimax[v];
 
 4533                            subinput.max = Math.max(property[v]*3, 10.0);
 
 4536                        subinput_slider.min = subinput.min;
 
 4537                        subinput_slider.max = subinput.max;
 
 4538                        subinput.step = (subinput.max - subinput.min) / 100.0;
 
 4539                        subinput_slider.step = subinput.step;
 
 4541                        subinput.value = subinput_slider.value = 
property[v];
 
 4543                        let theNode = targetNodes[i];
 
 4544                        let vector_index = v;
 
 4545                        let theBox = subinput;
 
 4546                        let theSlider = subinput_slider;
 
 4547                        theBox.onchange = 
function (e) {
 
 4548                            let pi = e.target.getAttribute(
'propertyKey');
 
 4549                            let value = parseFloat(e.target.value);
 
 4550                            let newValue = theNode.properties[pi].map(item => item);
 
 4551                            newValue[vector_index] = value; 
 
 4552                            theNode.setProperty(pi, newValue);
 
 4556                        theBox.oninput = 
function(e) {
 
 4557                            let pi = e.target.getAttribute(
'propertyKey');
 
 4558                            let value = parseFloat(e.target.value);
 
 4559                            let newValue = theNode.properties[pi].map(item => item);
 
 4560                            newValue[vector_index] = value; 
 
 4561                            theNode.setProperty(pi, newValue);
 
 4562                            theSlider.value = e.target.value;
 
 4565                        theSlider.onchange = 
function (e) {
 
 4566                            let pi = e.target.getAttribute(
'propertyKey');
 
 4567                            let value = parseFloat(e.target.value);
 
 4568                            let newValue = theNode.properties[pi].map(item => item);
 
 4569                            newValue[vector_index] = value; 
 
 4570                            theNode.setProperty(pi, newValue);
 
 4573                        theSlider.oninput = 
function(e) {
 
 4574                            let pi = e.target.getAttribute(
'propertyKey');
 
 4575                            let value = parseFloat(e.target.value);
 
 4576                            let newValue = theNode.properties[pi].map(item => item);
 
 4577                            newValue[vector_index] = value; 
 
 4578                            theNode.setProperty(pi, newValue);
 
 4579                            theBox.value = e.target.value;
 
 4583                        let propvalue_slider = document.createElement(
"div");
 
 4584                        propvalue_slider.className = 
"col p-0";
 
 4585                        propvalue_slider.appendChild(subinput_slider);
 
 4587                        let propvalue_box = document.createElement(
"div");
 
 4588                        propvalue_box.className = 
"col p-0";
 
 4589                        propvalue_box.appendChild(subinput);                                                
 
 4591                        let input_row = document.createElement(
"div");
 
 4592                        input_row.className = 
"row p-0";
 
 4593                        input_row.appendChild(propvalue_slider);                        
 
 4594                        input_row.appendChild(propvalue_box);
 
 4596                        input.appendChild(input_row);
 
 4599                else if (proptype == 
'color3' || proptype == 
'color4') {
 
 4600                    input = document.createElement(
"input");
 
 4601                    input.type = 
"color";
 
 4603                    if (property.length == 4) {
 
 4604                        input.value = this.rgbToHex([ property[0], property[1], property[2] ]);
 
 4607                        input.value = this.rgbToHex(property);
 
 4609                    input.setAttribute(
'propertyKey', propertyKey);
 
 4610                    let theNode = targetNodes[i];
 
 4611                    input.onchange = 
function (e) {
 
 4613                        var hex = e.target.value;
 
 4616                        rgb[0] = parseInt(hex.substring(1, 3), 16) / 255.0;
 
 4617                        rgb[0] = parseFloat(rgb[0].toFixed(fprecision));
 
 4618                        rgb[1] = parseInt(hex.substring(3, 5), 16) / 255.0;
 
 4619                        rgb[1] = parseFloat(rgb[1].toFixed(fprecision));
 
 4620                        rgb[2] = parseInt(hex.substring(5, 7), 16) / 255.0;
 
 4621                        rgb[2] = parseFloat(rgb[2].toFixed(fprecision));
 
 4622                        if (proptype == 
'color4')
 
 4625                        var pi = e.target.getAttribute(
'propertyKey');
 
 4626                        theNode.setProperty(pi, rgb);
 
 4628                    let func = 
function (e) {
 
 4630                        var hex = e.target.value;
 
 4631                        let rgb = [0, 0, 0];
 
 4633                        rgb[0] = parseInt(hex.substring(1, 3), 16) / 255.0;
 
 4634                        rgb[0] = parseFloat(rgb[0].toFixed(fprecision));
 
 4635                        rgb[1] = parseInt(hex.substring(3, 5), 16) / 255.0;
 
 4636                        rgb[1] = parseFloat(rgb[1].toFixed(fprecision));
 
 4637                        rgb[2] = parseInt(hex.substring(5, 7), 16) / 255.0;
 
 4638                        rgb[2] = parseFloat(rgb[2].toFixed(fprecision));
 
 4639                        if (proptype == 
'color4')
 
 4642                        var pi = e.target.getAttribute(
'propertyKey');
 
 4643                        theNode.setProperty(pi, rgb);
 
 4645                    input.onchange = func;
 
 4646                    input.oninput = func;
 
 4649                    input = document.createElement(
"input");
 
 4650                    input.style = this.fontSizeStyle;
 
 4651                    input.type = 
"text";
 
 4652                    input.value = property;
 
 4653                    let propertyKey = inputName;
 
 4654                    let theNode = targetNodes[i];
 
 4655                    input.onchange = 
function (e) {
 
 4656                        theNode.setProperty(propertyKey, e.target.value);
 
 4662                    input.id = 
"__pp:" + inputName;
 
 4665                    var label = document.createElement(
"div");
 
 4666                    label.className = 
"col-4 p-0 col-form-label-sm text-end";
 
 4667                    label.style = this.fontSizeStyle;
 
 4668                    label.innerHTML = uiName;
 
 4669                    label.for = input.id;
 
 4670                    elem.appendChild(label);
 
 4673                    if (useFormControl) {
 
 4674                        input.classList.add(
"form-control");
 
 4676                    input.classList.add(
"form-control-sm");
 
 4679                        input.disabled = 
true;
 
 4681                    var propvalue = document.createElement(
"div");
 
 4682                    propvalue.className = 
"col py-0";
 
 4685                        propvalue.classList.add(
'ps-1');
 
 4687                    propvalue.appendChild(input);
 
 4690                        var propbutton = document.createElement(
"div");
 
 4691                        propbutton.className = 
"col-2 py-0";
 
 4693                        propbutton.appendChild(input_btn);
 
 4694                        elem.appendChild(propbutton);
 
 4696                    if (colorspace_unit_btn) {
 
 4698                        var propbutton = document.createElement(
"div");
 
 4699                        propbutton.className = 
"col col-form-label-sm";
 
 4700                        var details = document.createElement(
"details");
 
 4701                        var summary = document.createElement(
'summary')
 
 4702                        summary.style = this.fontSizeStyle;
 
 4703                        if (colorspace.length > 0)
 
 4704                            summary.innerHTML = 
"Colorspace";
 
 4705                        else if (targetUnits.length > 0)
 
 4706                            summary.innerHTML = 
"Units";
 
 4707                        details.appendChild(summary);
 
 4708                        details.appendChild(colorspace_unit_btn);
 
 4709                        propbutton.appendChild(details);
 
 4710                        propvalue.appendChild(propbutton);
 
 4715                        var propvalue_slider = document.createElement(
"div");
 
 4716                        propvalue_slider.className = 
"col py-0 pe-0";
 
 4717                        propvalue_slider.appendChild(input_slider);
 
 4718                        elem.appendChild(propvalue_slider);
 
 4721                    elem.appendChild(propvalue);
 
 4726                if (current_details) {
 
 4728                    current_details.appendChild(elem);
 
 4730                    if (current_details.parentElement == 
null) {
 
 4731                        propertypanelcontent.appendChild(current_details);
 
 4735                    propertypanelcontent.appendChild(elem);
 
 4743        let output_details = 
null;
 
 4744        let nodeOutputs = 
null;
 
 4748        if (!inUnselectedNodeGraph)
 
 4749            nodeOutputs = node.outputs;
 
 4750        for (let k in nodeOutputs) {
 
 4751            let nodeOutput = nodeOutputs[k];
 
 4753            let nodeOutputLinks = nodeOutput.links;
 
 4754            for (let j in nodeOutputLinks) {
 
 4755                let link_id = nodeOutputLinks[j];
 
 4762                    if (!output_details) {
 
 4763                        output_details = document.createElement(
"details");
 
 4764                        output_details.id = 
"pp::outputs";
 
 4765                        output_details.open = 
true;
 
 4766                        output_details.classList.add(
'w-100', 
'p-1', 
'border', 
'border-secondary', 
'rounded', 
'my-1');
 
 4767                        first_details = 
false;
 
 4768                        var summary = document.createElement(
'summary');
 
 4770                            summary.style = this.fontSizeStyle;
 
 4771                            summary.innerHTML = 
"<b>Outputs</b>" 
 4774                        output_details.appendChild(summary);
 
 4779                    const targetNode = 
graphcanvas.graph.getNodeById(link.target_id);
 
 4783                        let targetSlot = link.target_slot;
 
 4784                        let targetInput = targetNode.inputs[targetSlot];
 
 4787                        let downstreamLink = targetNode.title + 
'.' + targetInput.name;
 
 4789                        let 
id = 
"__pp:" + nodeOutput.name;
 
 4790                        let buttonText = downstreamLink;
 
 4792                        if (buttonText.length > TRUNC_TEXT) {
 
 4793                            buttonText = buttonText.substring(0, TRUNC_TEXT) + 
"...";
 
 4795                        let output = this.createButtonWithImageAndText(
"./Icons/arrow_down_white.svg", buttonText, 
id);
 
 4797                        output.onclick = 
function (e) {
 
 4799                            var inputName = e.target.id;
 
 4800                            inputName = inputName.replace(
'__pp:', 
'');
 
 4801                            inputName = inputName.replace(
'_text', 
'');
 
 4802                            inputName = inputName.replace(
'_img', 
'');
 
 4803                            console.log(
'Clicked traversal button:', inputName);
 
 4805                            console.log(
'Jump to node:', targetNode.title);
 
 4809                            node.setDirtyCanvas(
true, 
true);
 
 4813                        elem = document.createElement(
"div");
 
 4814                        elem.className = 
"row px-1 py-0";
 
 4816                        let outputName = nodeOutput.name;
 
 4817                        output.id = 
"__pp:" + outputName;
 
 4819                        var label = document.createElement(
"div");
 
 4821                        label.className = 
"col-4 px-1 py-0 col-form-label-sm text-end";
 
 4822                        label.style = this.fontSizeStyle;
 
 4823                        label.innerHTML = outputName;
 
 4824                        label.for = nodeOutput.id;
 
 4825                        elem.appendChild(label);
 
 4828                        if (useFormControl) {
 
 4829                            output.classList.add(
"form-control");
 
 4831                        output.classList.add(
"form-control-sm");
 
 4834                            output.disabled = 
true;
 
 4836                        var propvalue = document.createElement(
"div");
 
 4837                        propvalue.className = 
"col p-1";
 
 4838                        propvalue.appendChild(output);
 
 4840                        elem.appendChild(propvalue); 
 
 4842                        output_details.appendChild(elem);
 
 4845                        console.log(`- Node with ID ${link.target_id} not found.`);
 
 4846                        console.log(
'--- Available nodes:', 
graphcanvas.graph._nodes_by_id);
 
 4849                    console.log(`- Link with ID ${link_id} not found.`);
 
 4854        if (output_details) {
 
 4855            propertypanelcontent.appendChild(output_details);
 
 4867    initializeLiteGraph(canvas, readOnly = 
false) {
 
 4869        graph = 
new LiteGraph.LGraph();
 
 4884        graphcanvas.default_connection_color_byTypeOff = {
 
 4923                let parentGraph = 
'';
 
 4926                    parentGraph = 
graphcanvas.graph._subgraph_node.title;
 
 4936                let parentGraph = 
'';
 
 4939                    parentGraph = 
graphcanvas.graph._subgraph_node.title;
 
 4947        LGraphNode.prototype.setPropertyInfo = 
function(property, propertyInfo, value)
 
 4951            if (this.properties_info) {
 
 4952                for (var i = 0; i < this.properties_info.length; ++i) {
 
 4953                    if (this.properties_info[i].name == property) {
 
 4954                        info = this.properties_info[i];
 
 4960            if (info && info[propertyInfo])
 
 4962                if (this.onPropertyInfoChanged)
 
 4964                    this.onPropertyInfoChanged(property, propertyInfo, value, info[propertyInfo]);
 
 4966                info[propertyInfo] = value;
 
 4970                console.warning(
'Failed to set property: ', property, 
'. info: ', propertyInfo, 
'. Value: ', value, 
'. Infos: ', this.properties_info);
 
 4975        LGraphNode.prototype.isDefaultValue = 
function(property)
 
 4980            if (this.properties[property] == 
null)
 
 4982                console.warn(
'> Property value does not exist:', property);
 
 4986            if (this.getInputLink(property))
 
 4991            if (this.properties_info != 
null) 
 
 4993                for (let i = 0; i < this.properties_info.length; ++i) {
 
 4994                    if (this.properties_info[i].name == property) {
 
 4995                        info = this.properties_info[i];
 
 5001            if (info != 
null && info.default_value != 
null)
 
 5003                let property_string = this.properties[property];
 
 5004                let default_value_string = info.default_value;
 
 5005                let isDefault = 
false;
 
 5006                if (Array.isArray(default_value_string)) {
 
 5007                    default_value_string = default_value_string.map(String); 
 
 5008                    property_string = property_string.map(String); 
 
 5009                    isDefault = (JSON.stringify(default_value_string) == JSON.stringify(property_string));                                 
 
 5013                    isDefault = (default_value_string == property_string);
 
 5019                console.warn(
'> Default value does not exist for:', property);
 
 5028        this.monitor.monitorGraph(
graph, 
true);
 
 5036        console.log(
'> Read only mode: ', readOnly);
 
 5052        graph.ctrl_shift_v_paste_connect_unselected_outputs = 
true;
 
 5058        canvas.addEventListener(
"keydown", 
function (e) {
 
 5059            if (e.key === 
"f") {                
 
 5065        canvas.addEventListener(
"keydown", 
function (e) {
 
 5066            if (e.key === 
"l") {
 
 5073        var context = canvas.getContext(
'2d');
 
 5075        function drawstart(event) {
 
 5078            console.log(
'>>>>>>>>>>> draw start');
 
 5082        function drawmove(event) {
 
 5086            console.log(
'>>>>>>>>>>> draw move');
 
 5089        function drawend(event) {
 
 5092            console.log(
'>>>>>>>>>>> draw move');
 
 5096        function touchstart(event) {
 
 5097            drawstart(event.touches[0]);
 
 5100        function touchmove(event) {
 
 5101            drawmove(event.touches[0]);
 
 5105        function touchend(event) {
 
 5106            drawend(event.changedTouches[0]);
 
 5124        var haveSelected = 
false;
 
 5125        for (var s in selected) {
 
 5126            haveSelected = 
true; 
 
 5129        console.log(
'Center nodes:', selected, 
'. Have selected:', haveSelected);
 
 5137        LiteGraph.searchbox_extras = [];
 
 5138        var nodeTypes = LiteGraph.registered_node_types;
 
 5139        for (var typeName in nodeTypes) {
 
 5140            if (typeName !== 
"graph/subgraph") {
 
 5141                console.log(
'Removing node type:', LiteGraph.getNodeType(typeName));
 
 5142                LiteGraph.unregisterNodeType(typeName);
 
 5150    collapseNode(node, collapse) {
 
 5151        if (node.constructor.collapsable === 
false) {
 
 5154        if (node.flags.collapsed != collapse) {
 
 5155            node.flags.collapsed = collapse;
 
 5164    collapseExpandNodes(collapse) {
 
 5169        var modified = 
false;
 
 5170        if (selected_nodes) {
 
 5171            for (var i in selected_nodes) {
 
 5172                var node = selected_nodes[i];
 
 5174                if (this.collapseNode(node, collapse))
 
 5179            var nodes = curGraph._nodes;
 
 5180            for (var i in nodes) {
 
 5181                var node = nodes[i];
 
 5182                if (this.collapseNode(node, collapse))
 
 5189            graph.setDirtyCanvas(
true, 
true);
 
 5203    pasteFromClipboard() {
 
 5210    extractNodeGraph() {
 
 5212        if (selected.length == 0) {
 
 5213            console.log(
'No nodes selected.');
 
 5217        var subgraphsSelected = []
 
 5218        for (var i in selected) {
 
 5219            var node = selected[i];
 
 5220            if (node.type == 
'graph/subgraph') {
 
 5221                subgraphsSelected.push(node);
 
 5224        if (subgraphsSelected.length == 0) {
 
 5225            console.log(
'No subgraphs selected.');
 
 5230        var subGraph = subgraphsSelected[0];
 
 5231        var subGraphNodes = subGraph.subgraph._nodes;
 
 5232        for (var i in subGraphNodes) {
 
 5233            var node = subGraphNodes[i];
 
 5254            this.debugOutput(
'Cannot create nest subgraphs.', 1);
 
 5260        if (selected.length == 0) {
 
 5261            console.log(
'No nodes selected.');
 
 5269        var node = LiteGraph.createNode(
'graph/subgraph');
 
 5277        node.subgraph.arrange(80);
 
 5285    displayNodeTypes() {
 
 5287        var nodeTypesListUpdater = this.ui.nodeTypesListUpdater;
 
 5288        if (!nodeTypesListUpdater) {
 
 5293        var nodeTypes = LiteGraph.registered_node_types;
 
 5294        nodeTypesListUpdater(nodeTypes);
 
 5306    initialize(canvas, ui, monitor, materialFilename, readOnly = 
false) {
 
 5310            console.log(
'Set custom monitor:', monitor.getName());
 
 5312        this.monitor = monitor;         
 
 5313        this.initializeLiteGraph(canvas, readOnly);
 
 5315        this.handler.setMonitor(this.monitor);
 
Base class for graph handlers.
getColorSpaces()
Get the color spaces used by the handler.
setMonitor(monitor)
Set the monitor for the handler.
getDefaultValue(value, _type)
Get default value as a string for the given value and type.
setSourceColorSpace(colorSpace)
Set the source color space for the handler.
canImport(extension)
Return if the handler can import the given extension / format.
createValidName(name)
Create a valid name for the given name.
getImporter(extension='')
Find the first importer that can import the given extension / format.
getUnits()
Get the units used by the handler.
setTargetDistanceUnit(unit)
Set the target distance unit for the handler.
initialize(editor)
Initialize the handler for the given editor.
getSourceColorSpace()
Get the source color space for the handler.
getTargetDistanceUnit()
Get the target distance unit for the handler.
getExporter(extension='')
Find the first exporter that can export to the given extension / format.
getExtension()
Get the extension /format for the handler.
canExport(extension)
Return if the handler can export to the given extension / format.
constructor(id, extension)
setColorSpaces(colorSpaces)
Set the color spaces used by the handler.
setUnits(units)
Set the units used by the handler.
addConverter(converter)
Add a converter to the handler.
This class provides a monitoring interface for the graph editor.
getRenderer()
Get the renderer for the monitor.
debugMessage(text, path)
Output a debug message to the console.
onConnectOutput(slot, input_type, input, target_node, target_slot, node)
Callback for connection to output.
onNodeDeselected(node, parentGraph)
Callback for when a node is deselected in the graph.
getPath(node, parentGraph)
Get a '/' separated path.
setOnNodeRemoved(callback)
Set node removed callback.
setMonitoring(monitor)
Set the monitoring state of the monitor.
onNodeRemoved(node, parentGraph)
Callback for when a node is removed from the graph.
onNodeSelected(node, parentGraph)
Callback for when a node is selected in the graph.
setOnNodeDeselected(callback)
Set node deselected callback.
onConnectInput(target_slot, output_type, output, source, slot, node)
Callback for connection to output.
getMonitoring()
Get the monitoring state of the monitor.
onPropertyInfoChanged(nodeName, propertyName, propertyInfoName, newValue, previousValue, node)
Callback for when a property info changes on a node in the graph.
onNodeAdded(node, parentGraph)
Callback for when a node is added to the graph.
monitorGraph(theGraph, monitor)
Core monitoring of graph changes.
setOnNodeAdded(callback)
Set node added callback.
setRenderer(theRenderer)
Set the renderer for the monitor.
setOnNodeSelected(callback)
Set node selected callback.
setOnPropertyChanged(callback)
Set property changed callback.
onNodeRenamed(node, newName)
Callback for when a node is renamed in the graph.
setOnConnectionChange(callback)
Set connection change callback.
onPropertyChanged(nodeName, propertyName, newValue, previousValue, node)
Callback for when a property changes on a node in the graph.
getName()
Get the name of the monitor.
onDocumentChange(attribute, value, prevValue)
Callback for when a scene / document level change is made.
setOnNodeRenamed(callback)
Set node renamed callback.
getParentPath(node)
Get the parent path of a node.
onConnectionChange(node, parentGraph)
Callback for when a connection changes in the graph.
This class extends the MxGraphHandler class to provide MaterialX-specific functionality for handling ...
loadFromString(extension, fileContents, fileName, auto_arrange, rerender=false)
Load graph editor from a string.
saveGraphToDocument(graph, graphWriteOptions)
Saves the graph to a MaterialX document.
validateDocument(doc)
Validates the provided MaterialX document.
constructor(id, extension)
Constructor for the MxMaterialXHandler class.
buildConnections(editor, node, lg_node, explicitInputs, graph, parentGraph)
Builds the connections between MaterialX nodes.
loadLibraryDocument(editor, materialFilename)
Load the MaterialX document from library into the editor.
loadFromFile(extension, file, fileName, editor, auto_arrange)
Load graph editor from a file.
findRenderableItemsInDoc(mdoc)
Find all renderable items in the MaterialX document.
loadFromZip(extension, file, fileName, editor, auto_arrange, rerender=false)
loadDefinitionsFromFile()
Load MaterialX document containing node definitions from a file.
isArray(_type)
Determines if the specified type is an array type.
initialize(editor, materialFilename)
Initialize the MaterialX handler for the given editor.
createLiteGraphDefinitions(doc, debug, addInputOutputs, definitionsList, libraryPrefix='mtlx', editor, icon='')
Creates LiteGraph node definitions based on the MaterialX document.
buildMetaData(colorSpace, unit, unitType, uiname, uimin, uimax, uifolder, _type)
Builds and returns metadata for a node based on the provided parameters.
loadMaterialXLibraries(stdlib)
Load MaterialX definition libraries.
writeGraphToDocument(mltxgraph, graph, graphWriteOptions)
Writes the graph to the specified MaterialX document.
buildGraphFromDoc(doc, editor, auto_arrange)
Builds the LiteGraph graph from the specified MaterialX document.
saveGraphToFile(extension, graph, graphWriteOptions)
Saves the graph to a file with the specified extension.
loadMaterialX()
Load in the MaterialX library.
saveGraphToString(extension, graph, graphWriteOptions)
Saves the graph to a string in the specified format.
createValidName(name, msg=null)
Create a valid MaterialX name within the context of the current graph.
findRenderableItems(graph)
Find all MaterialX renderable items in a graph.
loadInputMetaData(node, input, property_info)
Set the meta-data for the specified input based on LiteGraph node property info.
This class is a wrapper around the LiteGraph library to provide a MaterialX node editor.
Utility class for unzipping ZIP which contain MaterialX files and dependent images .
static async unzipMaterialXData(zipData)
Unzips the given ZIP data and returns the MaterialX documents and textures.