From 1a16d6bc24aac189da4df7042a09d58c98302fbd Mon Sep 17 00:00:00 2001 From: tamat Date: Thu, 29 Mar 2018 19:44:03 +0200 Subject: [PATCH] lots of fixes, added support for selection rectangle, rearrange nodes, highlight links, copypaste with links and fixed several bugs --- build/litegraph.js | 553 +++++++++++++------- build/litegraph.min.js | 805 +++++++++++++++-------------- demo/demo.js | 18 +- doc/classes/ContextMenu.html | 4 +- doc/classes/LGraph.html | 85 ++- doc/classes/LGraphCanvas.html | 20 +- doc/classes/LGraphNode.html | 75 +-- doc/classes/LiteGraph.html | 13 +- doc/data.json | 162 +++--- doc/files/.._src_litegraph.js.html | 553 +++++++++++++------- src/litegraph-editor.js | 1 + src/litegraph.js | 553 +++++++++++++------- 12 files changed, 1753 insertions(+), 1089 deletions(-) diff --git a/build/litegraph.js b/build/litegraph.js index d71d6e203..2c2d00fef 100644 --- a/build/litegraph.js +++ b/build/litegraph.js @@ -135,7 +135,8 @@ var LiteGraph = global.LiteGraph = { }, /** - * create a new node type by passing a function, it wraps it with a propper class + * Create a new node type by passing a function, it wraps it with a propper class and generates inputs according to the parameters of the function. + * Useful to wrap simple methods that do not require properties, and that only process some input to generate an output. * @method wrapFunctionAsNode * @param {String} name node name with namespace (p.e.: 'math/sum') * @param {Function} func @@ -632,7 +633,7 @@ LGraph.prototype.updateExecutionOrder = function() } //This is more internal, it computes the order and returns it -LGraph.prototype.computeExecutionOrder = function( only_onExecute ) +LGraph.prototype.computeExecutionOrder = function( only_onExecute, set_level ) { var L = []; var S = []; @@ -643,22 +644,30 @@ LGraph.prototype.computeExecutionOrder = function( only_onExecute ) //search for the nodes without inputs (starting nodes) for (var i = 0, l = this._nodes.length; i < l; ++i) { - var n = this._nodes[i]; - if( only_onExecute && !n.onExecute ) + var node = this._nodes[i]; + if( only_onExecute && !node.onExecute ) continue; - M[n.id] = n; //add to pending nodes + M[node.id] = node; //add to pending nodes var num = 0; //num of input connections - if(n.inputs) - for(var j = 0, l2 = n.inputs.length; j < l2; j++) - if(n.inputs[j] && n.inputs[j].link != null) + if(node.inputs) + for(var j = 0, l2 = node.inputs.length; j < l2; j++) + if(node.inputs[j] && node.inputs[j].link != null) num += 1; if(num == 0) //is a starting node - S.push(n); + { + S.push(node); + if(set_level) + node._level = 1; + } else //num of input links - remaining_links[n.id] = num; + { + if(set_level) + node._level = 0; + remaining_links[node.id] = num; + } } while(true) @@ -667,43 +676,49 @@ LGraph.prototype.computeExecutionOrder = function( only_onExecute ) break; //get an starting node - var n = S.shift(); - L.push(n); //add to ordered list - delete M[n.id]; //remove from the pending nodes + var node = S.shift(); + L.push(node); //add to ordered list + delete M[node.id]; //remove from the pending nodes + + if(!node.outputs) + continue; //for every output - if(n.outputs) - for(var i = 0; i < n.outputs.length; i++) + for(var i = 0; i < node.outputs.length; i++) + { + var output = node.outputs[i]; + //not connected + if(output == null || output.links == null || output.links.length == 0) + continue; + + //for every connection + for(var j = 0; j < output.links.length; j++) { - var output = n.outputs[i]; - //not connected - if(output == null || output.links == null || output.links.length == 0) + var link_id = output.links[j]; + var link = this.links[link_id]; + if(!link) continue; - //for every connection - for(var j = 0; j < output.links.length; j++) + //already visited link (ignore it) + if(visited_links[ link.id ]) + continue; + + var target_node = this.getNodeById( link.target_id ); + if(target_node == null) { - var link_id = output.links[j]; - var link = this.links[link_id]; - if(!link) continue; - - //already visited link (ignore it) - if(visited_links[ link.id ]) - continue; - - var target_node = this.getNodeById( link.target_id ); - if(target_node == null) - { - visited_links[ link.id ] = true; - continue; - } - - visited_links[link.id] = true; //mark as visited - remaining_links[target_node.id] -= 1; //reduce the number of links remaining - if (remaining_links[target_node.id] == 0) - S.push(target_node); //if no more links, then add to Starters array + visited_links[ link.id ] = true; + continue; } + + if(set_level && (!target_node._level || target_node._level <= node._level)) + target_node._level = node._level + 1; + + visited_links[link.id] = true; //mark as visited + remaining_links[target_node.id] -= 1; //reduce the number of links remaining + if (remaining_links[ target_node.id ] == 0) + S.push(target_node); //if no more links, then add to starters array } + } } //the remaining ones (loops) @@ -720,13 +735,55 @@ LGraph.prototype.computeExecutionOrder = function( only_onExecute ) return L; } +/** +* Positions every node in a more readable manner +* @method arrange +*/ +LGraph.prototype.arrange = function( margin ) +{ + margin = margin || 40; + + var nodes = this.computeExecutionOrder( false, true ); + var columns = []; + for(var i = 0; i < nodes.length; ++i) + { + var node = nodes[i]; + var col = node._level || 1; + if(!columns[col]) + columns[col] = []; + columns[col].push( node ); + } + + var x = margin; + + for(var i = 0; i < columns.length; ++i) + { + var column = columns[i]; + if(!column) + continue; + var max_size = 100; + var y = margin; + for(var j = 0; j < column.length; ++j) + { + var node = column[j]; + node.pos[0] = x; + node.pos[1] = y; + if(node.size[0] > max_size) + max_size = node.size[0]; + y += node.size[1] + margin; + } + x += max_size + margin; + } + + this.setDirtyCanvas(true,true); +} + /** * Returns the amount of time the graph has been running in milliseconds * @method getTime * @return {number} number of milliseconds the graph has been running */ - LGraph.prototype.getTime = function() { return this.globaltime; @@ -2177,6 +2234,7 @@ LGraphNode.prototype.computeSize = function( minHeight, out ) /** * returns the bounding of the object, used for rendering purposes +* bounding is: [topleft_cornerx, topleft_cornery, width, height] * @method getBounding * @return {Float32Array[4]} the total size */ @@ -2185,8 +2243,8 @@ LGraphNode.prototype.getBounding = function( out ) out = out || new Float32Array(4); out[0] = this.pos[0] - 4; out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT; - out[2] = this.pos[0] + this.size[0] + 4; - out[3] = this.pos[1] + this.size[1] + LGraph.NODE_TITLE_HEIGHT; + out[2] = this.size[0] + 4; + out[3] = this.size[1] + LiteGraph.NODE_TITLE_HEIGHT; return out; } @@ -2532,8 +2590,7 @@ LGraphNode.prototype.disconnectInput = function( slot ) //search in the inputs list for this link for(var i = 0, l = output.links.length; i < l; i++) { - var link_id = output.links[i]; - if( link_info.target_id == this.id ) + if( output.links[i] == link_id ) { output.links.splice(i,1); break; @@ -2741,7 +2798,7 @@ function LGraphCanvas( canvas, graph, options ) //if(graph === undefined) // throw ("No graph assigned"); - this.background_image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII=' + this.background_image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII=' if(canvas && canvas.constructor === String ) canvas = document.querySelector( canvas ); @@ -2765,6 +2822,8 @@ function LGraphCanvas( canvas, graph, options ) this.allow_dragcanvas = true; this.allow_dragnodes = true; this.allow_interaction = true; //allow to control widgets, buttons, collapse, etc + this.drag_mode = false; + this.dragging_rectangle = null; this.always_render_background = false; this.render_connections_shadows = false; //too much cpu @@ -2807,11 +2866,15 @@ LGraphCanvas.prototype.clear = function() this.scale = 1; this.offset = [0,0]; + this.dragging_rectangle = null; + this.selected_nodes = {}; + this.visible_nodes = []; this.node_dragged = null; this.node_over = null; this.node_capturing_input = null; this.connecting_node = null; + this.highlighted_links = {}; this.dirty_canvas = true; this.dirty_bgcanvas = true; @@ -2897,6 +2960,7 @@ LGraphCanvas.prototype.closeSubgraph = function() return; var graph = this._graph_stack.pop(); this.selected_nodes = {}; + this.highlighted_links = {}; graph.attachCanvas(this); this.setDirty(true,true); } @@ -2984,6 +3048,8 @@ LGraphCanvas.prototype.bindEvents = function() } var canvas = this.canvas; + var ref_window = this.getCanvasWindow(); + var document = ref_window.document; //hack used when moving canvas between windows this._mousedown_callback = this.processMouseDown.bind(this); this._mousewheel_callback = this.processMouseWheel.bind(this); @@ -3007,8 +3073,8 @@ LGraphCanvas.prototype.bindEvents = function() //Keyboard ****************** this._key_callback = this.processKey.bind(this); - canvas.addEventListener("keydown", this._key_callback ); - canvas.addEventListener("keyup", this._key_callback ); + canvas.addEventListener("keydown", this._key_callback, true ); + document.addEventListener("keyup", this._key_callback, true ); //in document, otherwise it doesnt fire keyup //Droping Stuff over nodes ************************************ this._ondrop_callback = this.processDrop.bind(this); @@ -3029,11 +3095,14 @@ LGraphCanvas.prototype.unbindEvents = function() return; } + var ref_window = this.getCanvasWindow(); + var document = ref_window.document; + this.canvas.removeEventListener( "mousedown", this._mousedown_callback ); this.canvas.removeEventListener( "mousewheel", this._mousewheel_callback ); this.canvas.removeEventListener( "DOMMouseScroll", this._mousewheel_callback ); this.canvas.removeEventListener( "keydown", this._key_callback ); - this.canvas.removeEventListener( "keyup", this._key_callback ); + document.removeEventListener( "keyup", this._key_callback ); this.canvas.removeEventListener( "contextmenu", this._doNothing ); this.canvas.removeEventListener( "drop", this._ondrop_callback ); this.canvas.removeEventListener( "dragenter", this._doReturnTrue ); @@ -3224,34 +3293,30 @@ LGraphCanvas.prototype.processMouseDown = function(e) var n = this.graph.getNodeOnPos( e.canvasX, e.canvasY, this.visible_nodes ); var skip_dragging = false; + var skip_action = false; LiteGraph.closeAllContextMenus( ref_window ); if(e.which == 1) //left button mouse { - if(!e.shiftKey) //REFACTOR: integrate with function + if( e.ctrlKey ) { - //no node or another node selected - if (!n || !this.selected_nodes[n.id]) { - - var todeselect = []; - for (var i in this.selected_nodes) - if (this.selected_nodes[i] != n) - todeselect.push(this.selected_nodes[i]); - //two passes to avoid problems modifying the container - for (var i in todeselect) - this.processNodeDeselected(todeselect[i]); - } + this.dragging_rectangle = new Float32Array(4); + this.dragging_rectangle[0] = e.canvasX; + this.dragging_rectangle[1] = e.canvasY; + this.dragging_rectangle[2] = 1; + this.dragging_rectangle[3] = 1; + skip_action = true; } + var clicking_canvas_bg = false; //when clicked on top of a node //and it is not interactive - if(n && this.allow_interaction ) + if( n && this.allow_interaction && !skip_action ) { if(!this.live_mode && !n.flags.pinned) this.bringToFront(n); //if it wasnt selected? - var skip_action = false; //not dragging mouse to connect two slots if(!this.connecting_node && !n.flags.collapsed && !this.live_mode) @@ -3348,7 +3413,7 @@ LGraphCanvas.prototype.processMouseDown = function(e) else clicking_canvas_bg = true; - if(clicking_canvas_bg && this.allow_dragcanvas) + if(!skip_action && clicking_canvas_bg && this.allow_dragcanvas) { this.dragging_canvas = true; } @@ -3404,7 +3469,13 @@ LGraphCanvas.prototype.processMouseMove = function(e) this.last_mouse = mouse; this.canvas_mouse = [e.canvasX, e.canvasY]; - if(this.dragging_canvas) + if( this.dragging_rectangle ) + { + this.dragging_rectangle[2] = e.canvasX - this.dragging_rectangle[0]; + this.dragging_rectangle[3] = e.canvasY - this.dragging_rectangle[1]; + this.dirty_canvas = true; + } + else if(this.dragging_canvas) { this.offset[0] += delta[0] / this.scale; this.offset[1] += delta[1] / this.scale; @@ -3417,7 +3488,7 @@ LGraphCanvas.prototype.processMouseMove = function(e) this.dirty_canvas = true; //get node over - var n = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes); + var n = this.graph.getNodeOnPos( e.canvasX, e.canvasY, this.visible_nodes ); //remove mouseover flag for(var i = 0, l = this.graph._nodes.length; i < l; ++i) @@ -3556,8 +3627,32 @@ LGraphCanvas.prototype.processMouseUp = function(e) if (e.which == 1) //left button { - //dragging a connection - if(this.connecting_node) + if( this.dragging_rectangle ) + { + if(this.graph) + { + var nodes = this.graph._nodes; + var node_bounding = new Float32Array(4); + this.deselectAllNodes(); + if( this.dragging_rectangle[2] < 0 ) //flip if negative width + this.dragging_rectangle[0] += this.dragging_rectangle[2]; + if( this.dragging_rectangle[3] < 0 ) //flip if negative height + this.dragging_rectangle[1] += this.dragging_rectangle[3]; + this.dragging_rectangle[2] = Math.abs( this.dragging_rectangle[2] * this.scale ); //abs to convert negative width + this.dragging_rectangle[3] = Math.abs( this.dragging_rectangle[3] * this.scale ); //abs to convert negative height + + for(var i = 0; i < nodes.length; ++i) + { + var node = nodes[i]; + node.getBounding( node_bounding ); + if(!overlapBounding( this.dragging_rectangle, node_bounding )) + continue; //out of the visible area + this.selectNode( node, true ); + } + } + this.dragging_rectangle = null; + } + else if(this.connecting_node) //dragging a connection { this.dirty_canvas = true; this.dirty_bgcanvas = true; @@ -3616,6 +3711,13 @@ LGraphCanvas.prototype.processMouseUp = function(e) } else //no node being dragged { + //get node over + var node = this.graph.getNodeOnPos( e.canvasX, e.canvasY, this.visible_nodes ); + + var now = LiteGraph.getTime(); + if ( !node && (now - this.last_mouseclick) < 300 ) + this.deselectAllNodes(); + this.dirty_canvas = true; this.dragging_canvas = false; @@ -3714,18 +3816,23 @@ LGraphCanvas.prototype.processKey = function(e) return; var block_default = false; + //console.log(e); //debug if(e.target.localName == "input") return; if(e.type == "keydown") { - //console.log(e); //debug + if(e.keyCode == 32) + { + this.dragging_canvas = true; + block_default = true; + } //select all Control A if(e.keyCode == 65 && e.ctrlKey) { - this.selectAllNodes(); + this.selectNodes(); block_default = true; } @@ -3733,36 +3840,16 @@ LGraphCanvas.prototype.processKey = function(e) { if(this.selected_nodes) { - var nodes_data = []; - for(var i in this.selected_nodes) - nodes_data.push( this.selected_nodes[i].serialize() ); - localStorage.setItem( "litegrapheditor_clipboard", JSON.stringify(nodes_data) ); + this.copyToClipboard(); block_default = true; } } if(e.code == "KeyV" && (e.metaKey || e.ctrlKey) && !e.shiftKey ) //paste { - var data = localStorage.getItem( "litegrapheditor_clipboard" ); - if(data) - { - var nodes_data = JSON.parse(data); - for(var i = 0; i < nodes_data.length; ++i) - { - var node_data = nodes_data[i]; - var node = LiteGraph.createNode( node_data.type ); - if(node) - { - node.configure(node_data); - node.pos[0] += 5; - node.pos[1] += 5; - this.graph.add( node ); - } - } - } + this.pasteFromClipboard(); } - //delete or backspace if(e.keyCode == 46 || e.keyCode == 8) { @@ -3781,6 +3868,9 @@ LGraphCanvas.prototype.processKey = function(e) } else if( e.type == "keyup" ) { + if(e.keyCode == 32) + this.dragging_canvas = false; + if(this.selected_nodes) for (var i in this.selected_nodes) if(this.selected_nodes[i].onKeyUp) @@ -3796,6 +3886,79 @@ LGraphCanvas.prototype.processKey = function(e) } } +LGraphCanvas.prototype.copyToClipboard = function() +{ + var clipboard_info = { + nodes: [], + links: [] + }; + var index = 0; + var selected_nodes_array = []; + for(var i in this.selected_nodes) + { + var node = this.selected_nodes[i]; + node._relative_id = index; + selected_nodes_array.push( node ); + index += 1; + } + + for(var i = 0; i < selected_nodes_array.length; ++i) + { + var node = selected_nodes_array[i]; + clipboard_info.nodes.push( node.clone().serialize() ); + if(node.inputs && node.inputs.length) + for(var j = 0; j < node.inputs.length; ++j) + { + var input = node.inputs[j]; + if(!input || input.link == null) + continue; + var link_info = this.graph.links[ input.link ]; + if(!link_info) + continue; + var target_node = this.graph.getNodeById( link_info.origin_id ); + if(!target_node || !this.selected_nodes[ target_node.id ] ) //improve this by allowing connections to non-selected nodes + continue; //not selected + clipboard_info.links.push([ target_node._relative_id, j, node._relative_id, link_info.target_slot ]); + } + } + localStorage.setItem( "litegrapheditor_clipboard", JSON.stringify( clipboard_info ) ); +} + +LGraphCanvas.prototype.pasteFromClipboard = function() +{ + var data = localStorage.getItem( "litegrapheditor_clipboard" ); + if(!data) + return; + + //create nodes + var clipboard_info = JSON.parse(data); + var nodes = []; + for(var i = 0; i < clipboard_info.nodes.length; ++i) + { + var node_data = clipboard_info.nodes[i]; + var node = LiteGraph.createNode( node_data.type ); + if(node) + { + node.configure(node_data); + node.pos[0] += 5; + node.pos[1] += 5; + this.graph.add( node ); + nodes.push( node ); + } + } + + //create links + for(var i = 0; i < clipboard_info.links.length; ++i) + { + var link_info = clipboard_info.links[i]; + var origin_node = nodes[ link_info[0] ]; + var target_node = nodes[ link_info[2] ]; + origin_node.connect( link_info[1], target_node, link_info[3] ); + } + + this.selectNodes( nodes ); +} + LGraphCanvas.prototype.processDrop = function(e) { e.preventDefault(); @@ -3885,42 +4048,6 @@ LGraphCanvas.prototype.checkDropItem = function(e) } -LGraphCanvas.prototype.processNodeSelected = function(n,e) -{ - n.selected = true; - if (n.onSelected) - n.onSelected(); - - if(e && e.shiftKey) //add to selection - this.selected_nodes[n.id] = n; - else - { - this.selected_nodes = {}; - this.selected_nodes[ n.id ] = n; - } - - this.dirty_canvas = true; - - if(this.onNodeSelected) - this.onNodeSelected(n); - - //if(this.node_in_panel) this.showNodePanel(n); -} - -LGraphCanvas.prototype.processNodeDeselected = function(n) -{ - n.selected = false; - if(n.onDeselected) - n.onDeselected(); - - delete this.selected_nodes[n.id]; - - if(this.onNodeDeselected) - this.onNodeDeselected(n); - - this.dirty_canvas = true; -} - LGraphCanvas.prototype.processNodeDblClicked = function(n) { if(this.onShowNodePanel) @@ -3932,44 +4059,100 @@ LGraphCanvas.prototype.processNodeDblClicked = function(n) this.setDirty(true); } -LGraphCanvas.prototype.selectNode = function(node) +LGraphCanvas.prototype.processNodeSelected = function(node,e) { - this.deselectAllNodes(); - - if(!node) - return; - - if(!node.selected && node.onSelected) - node.onSelected(); - node.selected = true; - this.selected_nodes[ node.id ] = node; - this.setDirty(true); + this.selectNode( node, e && e.shiftKey ); + if(this.onNodeSelected) + this.onNodeSelected(node); } -LGraphCanvas.prototype.selectAllNodes = function() +LGraphCanvas.prototype.processNodeDeselected = function(node) { - for(var i = 0; i < this.graph._nodes.length; ++i) + this.deselectNode(node); + if(this.onNodeDeselected) + this.onNodeDeselected(node); +} + +LGraphCanvas.prototype.selectNode = function( node, add_to_current_selection ) +{ + if(node == null) + this.deselectAllNodes(); + else + this.selectNodes([node], add_to_current_selection ); +} + +LGraphCanvas.prototype.selectNodes = function( nodes, add_to_current_selection ) +{ + if(!add_to_current_selection) + this.deselectAllNodes(); + + nodes = nodes || this.graph._nodes; + for(var i = 0; i < nodes.length; ++i) { - var n = this.graph._nodes[i]; - if(!n.selected && n.onSelected) - n.onSelected(); - n.selected = true; - this.selected_nodes[this.graph._nodes[i].id] = n; + var node = nodes[i]; + if(node.selected) + continue; + + if( !node.selected && node.onSelected ) + node.onSelected(); + node.selected = true; + this.selected_nodes[ node.id ] = node; + + if(node.inputs) + for(var i = 0; i < node.inputs.length; ++i) + this.highlighted_links[ node.inputs[i].link ] = true; + if(node.outputs) + for(var i = 0; i < node.outputs.length; ++i) + { + var out = node.outputs[i]; + if( out.links ) + for(var j = 0; j < out.links.length; ++j) + this.highlighted_links[ out.links[j] ] = true; + } + } this.setDirty(true); } +LGraphCanvas.prototype.deselectNode = function( node ) +{ + if(!node.selected) + return; + if(node.onDeselected) + node.onDeselected(); + node.selected = false; + + //remove highlighted + if(node.inputs) + for(var i = 0; i < node.inputs.length; ++i) + delete this.highlighted_links[ node.inputs[i].link ]; + if(node.outputs) + for(var i = 0; i < node.outputs.length; ++i) + { + var out = node.outputs[i]; + if( out.links ) + for(var j = 0; j < out.links.length; ++j) + delete this.highlighted_links[ out.links[j] ]; + } +} + LGraphCanvas.prototype.deselectAllNodes = function() { - for(var i in this.selected_nodes) + if(!this.graph) + return; + var nodes = this.graph._nodes; + for(var i = 0, l = nodes.length; i < l; ++i) { - var n = this.selected_nodes; - if(n.onDeselected) - n.onDeselected(); - n.selected = false; + var node = nodes[i]; + if(!node.selected) + continue; + if(node.onDeselected) + node.onDeselected(); + node.selected = false; } this.selected_nodes = {}; + this.highlighted_links = {}; this.setDirty(true); } @@ -3982,6 +4165,7 @@ LGraphCanvas.prototype.deleteSelectedNodes = function() this.graph.remove(m); } this.selected_nodes = {}; + this.highlighted_links = {}; this.setDirty(true); } @@ -4026,20 +4210,25 @@ LGraphCanvas.prototype.setZoom = function(value, zooming_center) this.dirty_bgcanvas = true; } -LGraphCanvas.prototype.convertOffsetToCanvas = function(pos) +LGraphCanvas.prototype.convertOffsetToCanvas = function( pos, out ) { - return [pos[0] / this.scale - this.offset[0], pos[1] / this.scale - this.offset[1]]; + out = out || []; + out[0] = pos[0] / this.scale - this.offset[0]; + out[1] = pos[1] / this.scale - this.offset[1]; + return out; } -LGraphCanvas.prototype.convertCanvasToOffset = function(pos) +LGraphCanvas.prototype.convertCanvasToOffset = function( pos, out ) { - return [(pos[0] + this.offset[0]) * this.scale, - (pos[1] + this.offset[1]) * this.scale ]; + out = out || []; + out[0] = (pos[0] + this.offset[0]) * this.scale; + out[1] = (pos[1] + this.offset[1]) * this.scale; + return out; } LGraphCanvas.prototype.convertEventToCanvas = function(e) { - var rect = this.canvas.getClientRects()[0]; + var rect = this.canvas.getBoundingClientRect(); return this.convertOffsetToCanvas([e.pageX - rect.left,e.pageY - rect.top]); } @@ -4066,14 +4255,16 @@ LGraphCanvas.prototype.sendToBack = function(n) /* LGraphCanvas render */ +var temp = new Float32Array(4); -LGraphCanvas.prototype.computeVisibleNodes = function() +LGraphCanvas.prototype.computeVisibleNodes = function( nodes, out ) { - var temp = new Float32Array(4); - var visible_nodes = []; - for(var i = 0, l = this.graph._nodes.length; i < l; ++i) + var visible_nodes = out || []; + visible_nodes.length = 0; + nodes = nodes || this.graph._nodes; + for(var i = 0, l = nodes.length; i < l; ++i) { - var n = this.graph._nodes[i]; + var n = nodes[i]; //skip rendering nodes in live mode if(this.live_mode && !n.onDrawBackground && !n.onDrawForeground) @@ -4101,7 +4292,7 @@ LGraphCanvas.prototype.draw = function(force_canvas, force_bgcanvas) { var start = [-this.offset[0], -this.offset[1] ]; var end = [start[0] + this.canvas.width / this.scale, start[1] + this.canvas.height / this.scale]; - this.visible_area = new Float32Array([start[0],start[1],end[0],end[1]]); + this.visible_area = new Float32Array([ start[0], start[1], end[0] - start[0], end[1] - start[1] ]); } if(this.dirty_bgcanvas || force_bgcanvas || this.always_render_background || (this.graph && this.graph._last_trigger_time && (now - this.graph._last_trigger_time) < 1000) ) @@ -4168,8 +4359,7 @@ LGraphCanvas.prototype.drawFrontCanvas = function() //draw nodes var drawn_nodes = 0; - var visible_nodes = this.computeVisibleNodes(); - this.visible_nodes = visible_nodes; + var visible_nodes = this.computeVisibleNodes( null, this.visible_nodes ); for (var i = 0; i < visible_nodes.length; ++i) { @@ -4221,6 +4411,14 @@ LGraphCanvas.prototype.drawFrontCanvas = function() ctx.fill(); } } + + if( this.dragging_rectangle ) + { + ctx.strokeStyle = "#FFF"; + ctx.strokeRect( this.dragging_rectangle[0], this.dragging_rectangle[1], this.dragging_rectangle[2], this.dragging_rectangle[3] ); + } + + ctx.restore(); } @@ -4325,7 +4523,7 @@ LGraphCanvas.prototype.drawBackCanvas = function() if(pattern) { ctx.fillStyle = pattern; - ctx.fillRect(this.visible_area[0],this.visible_area[1],this.visible_area[2]-this.visible_area[0],this.visible_area[3]-this.visible_area[1]); + ctx.fillRect(this.visible_area[0],this.visible_area[1],this.visible_area[2],this.visible_area[3]); ctx.fillStyle = "transparent"; } @@ -4338,7 +4536,7 @@ LGraphCanvas.prototype.drawBackCanvas = function() //DEBUG: show clipping area //ctx.fillStyle = "red"; - //ctx.fillRect( this.visible_area[0] + 10, this.visible_area[1] + 10, this.visible_area[2] - this.visible_area[0] - 20, this.visible_area[3] - this.visible_area[1] - 20); + //ctx.fillRect( this.visible_area[0] + 10, this.visible_area[1] + 10, this.visible_area[2] - 20, this.visible_area[3] - 20); //bg ctx.strokeStyle = "#235"; @@ -4816,6 +5014,9 @@ LGraphCanvas.prototype.renderLink = function( ctx, a, b, link, skip_border, flow if(!color) color = this.default_link_color; + if( link != null && this.highlighted_links[ link.id ] ) + color = "#FFF"; + //begin line shape ctx.beginPath(); @@ -5425,7 +5626,7 @@ LGraphCanvas.prototype.createDialog = function( html, options ) dialog.className = "graphdialog"; dialog.innerHTML = html; - var rect = this.canvas.getClientRects()[0]; + var rect = this.canvas.getBoundingClientRect(); var offsetx = -20; var offsety = -20; if(rect) @@ -5561,7 +5762,8 @@ LGraphCanvas.onMenuNodeClone = function( value, options, e, menu, node ) { if(node.clonable == false) return; var newnode = node.clone(); - if(!newnode) return; + if(!newnode) + return; newnode.pos = [node.pos[0]+5,node.pos[1]+5]; node.graph.add(newnode); node.setDirtyCanvas(true,true); @@ -5823,13 +6025,18 @@ function isInsideBounding(p,bb) } LiteGraph.isInsideBounding = isInsideBounding; -//boundings overlap, format: [start,end] +//boundings overlap, format: [ startx, starty, width, height ] function overlapBounding(a,b) { - if ( a[0] > b[2] || - a[1] > b[3] || - a[2] < b[0] || - a[3] < b[1]) + var A_end_x = a[0] + a[2]; + var A_end_y = a[1] + a[3]; + var B_end_x = b[0] + b[2]; + var B_end_y = b[1] + b[3]; + + if ( a[0] > B_end_x || + a[1] > B_end_y || + A_end_x < b[0] || + A_end_y < b[1]) return false; return true; } diff --git a/build/litegraph.min.js b/build/litegraph.min.js index 28d70ba2b..5109b7b17 100755 --- a/build/litegraph.min.js +++ b/build/litegraph.min.js @@ -1,406 +1,411 @@ -(function(r){function e(){f.debug&&console.log("Graph created");this.list_of_graphcanvas=null;this.clear()}function g(a){this._ctor()}function d(a,b,c){c=c||{};this.background_image="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII="; -a&&a.constructor===String&&(a=document.querySelector(a));this.max_zoom=10;this.min_zoom=0.1;this.title_text_font="bold 14px Arial";this.inner_text_font="normal 12px Arial";this.default_link_color="#AAC";this.highquality_render=!0;this.editor_alpha=1;this.pause_rendering=!1;this.render_only_selected=this.clear_background=this.render_shadows=!0;this.live_mode=!1;this.allow_interaction=this.allow_dragnodes=this.allow_dragcanvas=this.show_info=!0;this.render_connections_shadows=this.always_render_background= -!1;this.render_connection_arrows=this.render_curved_connections=this.render_connections_border=!0;this.connections_width=3;b&&b.attachCanvas(this);this.setCanvas(a);this.clear();c.skip_render||this.startRendering();this.autoresize=c.autoresize}function q(a,b){return Math.sqrt((b[0]-a[0])*(b[0]-a[0])+(b[1]-a[1])*(b[1]-a[1]))}function l(a,b,c,h,k,f){return ca&&hb?!0:!1}function t(a,b){return a[0]>b[2]||a[1]>b[3]||a[2]d.width-n.width-10&&(k=d.width-n.width-10);f>d.height-n.height-10&&(f=d.height-n.height-10)}h.style.left=k+"px";h.style.top=f+"px"}var f=r.LiteGraph={NODE_TITLE_HEIGHT:16,NODE_SLOT_HEIGHT:15,NODE_WIDTH:140,NODE_MIN_WIDTH:50,NODE_COLLAPSED_RADIUS:10,NODE_COLLAPSED_WIDTH:80,CANVAS_GRID_SIZE:10,NODE_TITLE_COLOR:"#222",NODE_DEFAULT_COLOR:"#999",NODE_DEFAULT_BGCOLOR:"#444",NODE_DEFAULT_BOXCOLOR:"#AEF",NODE_DEFAULT_SHAPE:"box",MAX_NUMBER_OF_NODES:1E3, -DEFAULT_POSITION:[100,100],node_images_path:"",VALID_SHAPES:["box","round"],BOX_SHAPE:1,ROUND_SHAPE:2,CIRCLE_SHAPE:3,INPUT:1,OUTPUT:2,EVENT:-1,ACTION:-1,ALWAYS:0,ON_EVENT:1,NEVER:2,ON_TRIGGER:3,proxy:null,debug:!1,throw_errors:!0,allow_scripts:!0,registered_node_types:{},node_types_by_file_extension:{},Nodes:{},registerNodeType:function(a,b){if(!b.prototype)throw"Cannot register a simple object, it must be a class with a prototype";b.type=a;f.debug&&console.log("Node registered: "+a);a.split("/"); -var c=b.constructor.name,h=a.lastIndexOf("/");b.category=a.substr(0,h);b.title||(b.title=c);if(b.prototype)for(var k in g.prototype)b.prototype[k]||(b.prototype[k]=g.prototype[k]);Object.defineProperty(b.prototype,"shape",{set:function(a){switch(a){case "box":this._shape=f.BOX_SHAPE;break;case "round":this._shape=f.ROUND_SHAPE;break;case "circle":this._shape=f.CIRCLE_SHAPE;break;default:this._shape=a}},get:function(a){return this._shape},enumerable:!0});this.registered_node_types[a]=b;b.constructor.name&& -(this.Nodes[c]=b);b.prototype.onPropertyChange&&console.warn("LiteGraph node class "+a+" has onPropertyChange method, it must be called onPropertyChanged with d at the end");if(b.supported_extensions)for(k in b.supported_extensions)this.node_types_by_file_extension[b.supported_extensions[k].toLowerCase()]=b},wrapFunctionAsNode:function(a,b,c,h){for(var k=Array(b.length),d="",s=f.getParameterNames(b),n=0;n=f.MAX_NUMBER_OF_NODES)throw"LiteGraph: max number of nodes in a graph reached"; -null==a.id||-1==a.id?a.id=++this.last_node_id:this.last_node_ida&&hb?!0:!1}function u(a,b){var c=a[0]+a[2],h=a[1]+a[3],k=b[1]+b[3];return a[0]>b[0]+b[2]||a[1]>k|| +cn.width-e.width-10&&(k=n.width-e.width-10);d>n.height-e.height-10&&(d=n.height-e.height-10)}h.style.left=k+"px";h.style.top=d+"px"}var d=q.LiteGraph={NODE_TITLE_HEIGHT:16,NODE_SLOT_HEIGHT:15,NODE_WIDTH:140,NODE_MIN_WIDTH:50,NODE_COLLAPSED_RADIUS:10,NODE_COLLAPSED_WIDTH:80,CANVAS_GRID_SIZE:10,NODE_TITLE_COLOR:"#222",NODE_DEFAULT_COLOR:"#999", +NODE_DEFAULT_BGCOLOR:"#444",NODE_DEFAULT_BOXCOLOR:"#AEF",NODE_DEFAULT_SHAPE:"box",MAX_NUMBER_OF_NODES:1E3,DEFAULT_POSITION:[100,100],node_images_path:"",VALID_SHAPES:["box","round"],BOX_SHAPE:1,ROUND_SHAPE:2,CIRCLE_SHAPE:3,INPUT:1,OUTPUT:2,EVENT:-1,ACTION:-1,ALWAYS:0,ON_EVENT:1,NEVER:2,ON_TRIGGER:3,proxy:null,debug:!1,throw_errors:!0,allow_scripts:!0,registered_node_types:{},node_types_by_file_extension:{},Nodes:{},registerNodeType:function(a,b){if(!b.prototype)throw"Cannot register a simple object, it must be a class with a prototype"; +b.type=a;d.debug&&console.log("Node registered: "+a);a.split("/");var c=b.constructor.name,h=a.lastIndexOf("/");b.category=a.substr(0,h);b.title||(b.title=c);if(b.prototype)for(var k in f.prototype)b.prototype[k]||(b.prototype[k]=f.prototype[k]);Object.defineProperty(b.prototype,"shape",{set:function(a){switch(a){case "box":this._shape=d.BOX_SHAPE;break;case "round":this._shape=d.ROUND_SHAPE;break;case "circle":this._shape=d.CIRCLE_SHAPE;break;default:this._shape=a}},get:function(a){return this._shape}, +enumerable:!0});this.registered_node_types[a]=b;b.constructor.name&&(this.Nodes[c]=b);b.prototype.onPropertyChange&&console.warn("LiteGraph node class "+a+" has onPropertyChange method, it must be called onPropertyChanged with d at the end");if(b.supported_extensions)for(k in b.supported_extensions)this.node_types_by_file_extension[b.supported_extensions[k].toLowerCase()]=b},wrapFunctionAsNode:function(a,b,c,h){for(var k=Array(b.length),r="",n=d.getParameterNames(b),e=0;en&&(n=k.size[0]),e+=k.size[1]+a;b+=n+a}this.setDirtyCanvas(!0,!0)};g.prototype.getTime=function(){return this.globaltime};g.prototype.getFixedTime=function(){return this.fixedtime};g.prototype.getElapsedTime=function(){return this.elapsed_time};g.prototype.sendEventToAllNodes=function(a,b,c){c=c||d.ALWAYS;var h=this._nodes_in_order?this._nodes_in_order:this._nodes;if(h)for(var k=0,e=h.length;k=d.MAX_NUMBER_OF_NODES)throw"LiteGraph: max number of nodes in a graph reached"; +null==a.id||-1==a.id?a.id=++this.last_node_id:this.last_node_id!a.length||(this._pos[0]=a[0],this._pos[1]=a[1])},get:function(){return this._pos},enumerable:!0});this.id=-1;this.type=null;this.inputs=[];this.outputs=[];this.connections=[];this.properties={};this.properties_info=[];this.data=null;this.flags={}};g.prototype.configure=function(a){for(var b in a)if("console"!=b)if("properties"==b)for(var c in a.properties){if(this.properties[c]=a.properties[c], -this.onPropertyChanged)this.onPropertyChanged(c,a.properties[c])}else null!=a[b]&&("object"==typeof a[b]?this[b]&&this[b].configure?this[b].configure(a[b]):this[b]=f.cloneObject(a[b],this[b]):this[b]=a[b]);if(this.onConnectionsChange){if(this.inputs)for(var h=0;h=this.outputs.length)){var c= -this.outputs[a];if(c&&(c._data=b,this.outputs[a].links))for(c=0;c=this.inputs.length||null==this.inputs[a].link)){var c=this.graph.links[this.inputs[a].link];if(!c)return null;if(!b)return c.data;var h=this.graph.getNodeById(c.origin_id);if(!h)return c.data;if(h.updateOutputData)h.updateOutputData(c.origin_slot);else if(h.onExecute)h.onExecute();return c.data}}; -g.prototype.isInputConnected=function(a){return this.inputs?a=this.inputs.length)return null;a=this.inputs[a];return a&&a.link?(a=this.graph.links[a.link])?this.graph.getNodeById(a.origin_id):null:null};g.prototype.getOutputData=function(a){return!this.outputs||a>=this.outputs.length?null:this.outputs[a]._data}; -g.prototype.getOutputInfo=function(a){return this.outputs?a=this.outputs.length)return null;a=this.outputs[a];if(!a.links||0==a.links.length)return null;for(var b=[],c=0;ca&&this.pos[1]-h-cb)return!0;return!1};g.prototype.getSlotInPosition= -function(a,b){if(this.inputs)for(var c=0,h=this.inputs.length;c=this.outputs.length)return f.debug&&console.log("Connect: Error, slot number not found"),!1;b&&b.constructor=== -Number&&(b=this.graph.getNodeById(b));if(!b)throw"Node not found";if(b==this)return!1;if(c.constructor===String){if(c=b.findInputSlot(c),-1==c)return f.debug&&console.log("Connect: Error, no slot of name "+c),!1}else{if(c===f.EVENT)return!1;if(!b.inputs||c>=b.inputs.length)return f.debug&&console.log("Connect: Error, slot number not found"),!1}null!=b.inputs[c].link&&b.disconnectInput(c);this.setDirtyCanvas(!1,!0);this.graph.connectionChange(this);var h=this.outputs[a];if(b.onConnectInput&&!1===b.onConnectInput(c, -h.type,h))return!1;var k=b.inputs[c];if(f.isValidConnection(h.type,k.type)){var d={id:this.graph.last_link_id++,type:k.type,origin_id:this.id,origin_slot:a,target_id:b.id,target_slot:c};this.graph.links[d.id]=d;null==h.links&&(h.links=[]);h.links.push(d.id);b.inputs[c].link=d.id;if(this.onConnectionsChange)this.onConnectionsChange(f.OUTPUT,a,!0,d,h);if(b.onConnectionsChange)b.onConnectionsChange(f.INPUT,c,!0,d,k)}this.setDirtyCanvas(!1,!0);this.graph.connectionChange(this);return!0};g.prototype.disconnectOutput= -function(a,b){if(a.constructor===String){if(a=this.findOutputSlot(a),-1==a)return f.debug&&console.log("Connect: Error, no slot of name "+a),!1}else if(!this.outputs||a>=this.outputs.length)return f.debug&&console.log("Connect: Error, slot number not found"),!1;var c=this.outputs[a];if(!c.links||0==c.links.length)return!1;if(b){b.constructor===Number&&(b=this.graph.getNodeById(b));if(!b)throw"Target Node not found";for(var h=0,k=c.links.length;h=this.inputs.length)return f.debug&&console.log("Connect: Error, slot number not found"),!1;var b=this.inputs[a];if(!b)return!1;var c=this.inputs[a].link; -this.inputs[a].link=null;var h=this.graph.links[c];if(h){var k=this.graph.getNodeById(h.origin_id);if(!k)return!1;var d=k.outputs[h.origin_slot];if(!d||!d.links||0==d.links.length)return!1;for(var e=0,n=d.links.length;eb&&this.inputs[b].pos?[this.pos[0]+this.inputs[b].pos[0],this.pos[1]+this.inputs[b].pos[1]]:!a&&this.outputs.length>b&&this.outputs[b].pos?[this.pos[0]+this.outputs[b].pos[0],this.pos[1]+this.outputs[b].pos[1]]:a?[this.pos[0],this.pos[1]+ -10+b*f.NODE_SLOT_HEIGHT]:[this.pos[0]+this.size[0]+1,this.pos[1]+10+b*f.NODE_SLOT_HEIGHT]};g.prototype.alignToGrid=function(){this.pos[0]=f.CANVAS_GRID_SIZE*Math.round(this.pos[0]/f.CANVAS_GRID_SIZE);this.pos[1]=f.CANVAS_GRID_SIZE*Math.round(this.pos[1]/f.CANVAS_GRID_SIZE)};g.prototype.trace=function(a){this.console||(this.console=[]);this.console.push(a);this.console.length>g.MAX_CONSOLE&&this.console.shift();this.graph.onNodeTrace(this,a)};g.prototype.setDirtyCanvas=function(a,b){this.graph&&this.graph.sendActionToCanvas("setDirty", -[a,b])};g.prototype.loadImage=function(a){var b=new Image;b.src=f.node_images_path+a;b.ready=!1;var c=this;b.onload=function(){this.ready=!0;c.setDirtyCanvas(!0)};return b};g.prototype.captureInput=function(a){if(this.graph&&this.graph.list_of_graphcanvas)for(var b=this.graph.list_of_graphcanvas,c=0;c element, you passed a "+a.localName;throw"This browser doesnt support Canvas";}null==(this.ctx=a.getContext("2d"))&&(console.warn("This canvas seems to be WebGL, enabling WebGL renderer"), -this.enableWebGL());this._mousemove_callback=this.processMouseMove.bind(this);this._mouseup_callback=this.processMouseUp.bind(this);b||this.bindEvents()}};d.prototype._doNothing=function(a){a.preventDefault();return!1};d.prototype._doReturnTrue=function(a){a.preventDefault();return!0};d.prototype.bindEvents=function(){if(this._events_binded)console.warn("LGraphCanvas: events already binded");else{var a=this.canvas;this._mousedown_callback=this.processMouseDown.bind(this);this._mousewheel_callback= -this.processMouseWheel.bind(this);a.addEventListener("mousedown",this._mousedown_callback,!0);a.addEventListener("mousemove",this._mousemove_callback);a.addEventListener("mousewheel",this._mousewheel_callback,!1);a.addEventListener("contextmenu",this._doNothing);a.addEventListener("DOMMouseScroll",this._mousewheel_callback,!1);a.addEventListener("touchstart",this.touchHandler,!0);a.addEventListener("touchmove",this.touchHandler,!0);a.addEventListener("touchend",this.touchHandler,!0);a.addEventListener("touchcancel", -this.touchHandler,!0);this._key_callback=this.processKey.bind(this);a.addEventListener("keydown",this._key_callback);a.addEventListener("keyup",this._key_callback);this._ondrop_callback=this.processDrop.bind(this);a.addEventListener("dragover",this._doNothing,!1);a.addEventListener("dragend",this._doNothing,!1);a.addEventListener("drop",this._ondrop_callback,!1);a.addEventListener("dragenter",this._doReturnTrue,!1);this._events_binded=!0}};d.prototype.unbindEvents=function(){this._events_binded?(this.canvas.removeEventListener("mousedown", -this._mousedown_callback),this.canvas.removeEventListener("mousewheel",this._mousewheel_callback),this.canvas.removeEventListener("DOMMouseScroll",this._mousewheel_callback),this.canvas.removeEventListener("keydown",this._key_callback),this.canvas.removeEventListener("keyup",this._key_callback),this.canvas.removeEventListener("contextmenu",this._doNothing),this.canvas.removeEventListener("drop",this._ondrop_callback),this.canvas.removeEventListener("dragenter",this._doReturnTrue),this.canvas.removeEventListener("touchstart", -this.touchHandler),this.canvas.removeEventListener("touchmove",this.touchHandler),this.canvas.removeEventListener("touchend",this.touchHandler),this.canvas.removeEventListener("touchcancel",this.touchHandler),this._ondrop_callback=this._key_callback=this._mousewheel_callback=this._mousedown_callback=null,this._events_binded=!1):console.warn("LGraphCanvas: no events binded")};d.getFileExtension=function(a){var b=a.indexOf("?");-1!=b&&(a=a.substr(0,b));b=a.lastIndexOf(".");return-1==b?"":a.substr(b+ -1).toLowerCase()};d.prototype.enableWebGL=function(){if(void 0===typeof GL)throw"litegl.js must be included to use a WebGL canvas";if(void 0===typeof enableWebGLCanvas)throw"webglCanvas.js must be included to use this feature";this.gl=this.ctx=enableWebGLCanvas(this.canvas);this.ctx.webgl=!0;this.bgcanvas=this.canvas;this.bgctx=this.gl};d.prototype.setDirty=function(a,b){a&&(this.dirty_canvas=!0);b&&(this.dirty_bgcanvas=!0)};d.prototype.getCanvasWindow=function(){if(!this.canvas)return window;var a= -this.canvas.ownerDocument;return a.defaultView||a.parentWindow};d.prototype.startRendering=function(){function a(){this.pause_rendering||this.draw();var b=this.getCanvasWindow();this.is_rendering&&b.requestAnimationFrame(a.bind(this))}this.is_rendering||(this.is_rendering=!0,a.call(this))};d.prototype.stopRendering=function(){this.is_rendering=!1};d.prototype.processMouseDown=function(a){if(this.graph){this.adjustMouseEvent(a);var b=this.getCanvasWindow();d.active_canvas=this;this.canvas.removeEventListener("mousemove", -this._mousemove_callback);b.document.addEventListener("mousemove",this._mousemove_callback,!0);b.document.addEventListener("mouseup",this._mouseup_callback,!0);var c=this.graph.getNodeOnPos(a.canvasX,a.canvasY,this.visible_nodes);f.closeAllContextMenus(b);if(1==a.which){if(!(a.shiftKey||c&&this.selected_nodes[c.id])){var h=[],k;for(k in this.selected_nodes)this.selected_nodes[k]!=c&&h.push(this.selected_nodes[k]);for(k in h)this.processNodeDeselected(h[k])}h=!1;if(c&&this.allow_interaction){this.live_mode|| -c.flags.pinned||this.bringToFront(c);var e=!1;if(!this.connecting_node&&!c.flags.collapsed&&!this.live_mode){if(c.outputs){k=0;for(var g=c.outputs.length;kf.getTime()-this.last_mouseclick&&this.selected_nodes[c.id]){if(c.onDblClick)c.onDblClick(a);this.processNodeDblClicked(c);k=!0}c.onMouseDown&& -c.onMouseDown(a,[a.canvasX-c.pos[0],a.canvasY-c.pos[1]])?k=!0:this.live_mode&&(k=h=!0);k||(this.allow_dragnodes&&(this.node_dragged=c),this.selected_nodes[c.id]||this.processNodeSelected(c,a));this.dirty_canvas=!0}}else h=!0;h&&this.allow_dragcanvas&&(this.dragging_canvas=!0)}else 2!=a.which&&3==a.which&&this.processContextMenu(c,a);this.last_mouse[0]=a.localX;this.last_mouse[1]=a.localY;this.last_mouseclick=f.getTime();this.canvas_mouse=[a.canvasX,a.canvasY];this.graph.change();(!b.document.activeElement|| -"input"!=b.document.activeElement.nodeName.toLowerCase()&&"textarea"!=b.document.activeElement.nodeName.toLowerCase())&&a.preventDefault();a.stopPropagation();if(this.onMouseDown)this.onMouseDown(a);return!1}};d.prototype.processMouseMove=function(a){this.autoresize&&this.resize();if(this.graph){d.active_canvas=this;this.adjustMouseEvent(a);var b=[a.localX,a.localY],c=[b[0]-this.last_mouse[0],b[1]-this.last_mouse[1]];this.last_mouse=b;this.canvas_mouse=[a.canvasX,a.canvasY];if(this.dragging_canvas)this.offset[0]+= -c[0]/this.scale,this.offset[1]+=c[1]/this.scale,this.dirty_bgcanvas=this.dirty_canvas=!0;else if(this.allow_interaction){this.connecting_node&&(this.dirty_canvas=!0);for(var b=this.graph.getNodeOnPos(a.canvasX,a.canvasY,this.visible_nodes),h=0,k=this.graph._nodes.length;hb&&(c*=1/1.1);this.setZoom(c,[a.localX,a.localY]);this.graph.change();a.preventDefault();return!1}};d.prototype.isOverNodeBox=function(a,b,c){var h=f.NODE_TITLE_HEIGHT;return l(b,c,a.pos[0]+2,a.pos[1]+2-h,h-4,h-4)?!0:!1};d.prototype.isOverNodeInput=function(a,b,c,h){if(a.inputs)for(var f=0,d=a.inputs.length;fthis.max_zoom?this.scale=this.max_zoom:this.scalec-this.graph._last_trigger_time)&&this.drawBackCanvas();(this.dirty_canvas||a)&&this.drawFrontCanvas();this.fps=this.render_time?1/ -this.render_time:0;this.frame+=1}};d.prototype.drawFrontCanvas=function(){this.ctx||(this.ctx=this.bgcanvas.getContext("2d"));var a=this.ctx;if(a){a.start2D&&a.start2D();var b=this.canvas;a.restore();a.setTransform(1,0,0,1,0,0);this.dirty_area&&(a.save(),a.beginPath(),a.rect(this.dirty_area[0],this.dirty_area[1],this.dirty_area[2],this.dirty_area[3]),a.clip());this.clear_background&&a.clearRect(0,0,b.width,b.height);this.bgcanvas==this.canvas?this.drawBackCanvas():a.drawImage(this.bgcanvas,0,0);if(this.onRender)this.onRender(b, -a);this.show_info&&this.renderInfo(a);if(this.graph){a.save();a.scale(this.scale,this.scale);a.translate(this.offset[0],this.offset[1]);this.visible_nodes=b=this.computeVisibleNodes();for(var c=0;cb-g._last_time&&(n=2-0.002*(b-g._last_time),p="rgba(255,255,255, "+ -n.toFixed(2)+")",this.renderLink(a,l,d.getConnectionPos(!0,e),g,!0,n,p))}}}}a.globalAlpha=1};d.prototype.renderLink=function(a,b,c,h,e,g,p){if(this.highquality_render){var n=q(b,c);this.render_connections_border&&0.6b[1]?0:Math.PI,a.save(),a.translate(h[0],h[1]),a.rotate(p),a.beginPath(),a.moveTo(-5,-5),a.lineTo(0,5),a.lineTo(5,-5),a.fill(),a.restore());if(g)for(g=0;5>g;++g)h=(0.001*f.getTime()+0.2*g)%1,h=this.computeConnectionPoint(b,c,h),a.beginPath(),a.arc(h[0],h[1],5,0,2*Math.PI),a.fill()}else a.beginPath(),a.moveTo(b[0],b[1]),a.lineTo(c[0],c[1]),a.stroke()};d.prototype.computeConnectionPoint=function(a,b,c){var h=q(a,b),f=[a[0]+0.25*h,a[1]],h=[b[0]-0.25*h,b[1]],d=(1-c)*(1-c)*(1-c),e=3*(1-c)*(1-c)*c, -n=3*(1-c)*c*c;c*=c*c;return[d*a[0]+e*f[0]+n*h[0]+c*b[0],d*a[1]+e*f[1]+n*h[1]+c*b[1]]};d.prototype.resize=function(a,b){if(!a&&!b){var c=this.canvas.parentNode;a=c.offsetWidth;b=c.offsetHeight}if(this.canvas.width!=a||this.canvas.height!=b)this.canvas.width=a,this.canvas.height=b,this.bgcanvas.width=this.canvas.width,this.bgcanvas.height=this.canvas.height,this.setDirty(!0,!0)};d.prototype.switchLiveMode=function(a){if(a){var b=this,c=this.live_mode?1.1:0.9;this.live_mode&&(this.live_mode=!1,this.editor_alpha= -0.1);var h=setInterval(function(){b.editor_alpha*=c;b.dirty_canvas=!0;b.dirty_bgcanvas=!0;1>c&&0.01>b.editor_alpha&&(clearInterval(h),1>c&&(b.live_mode=!0));1"+l+""+a+"",value:l});if(n.length)return new f.ContextMenu(n,{event:c,callback:g,parentMenu:h,allow_html:!0,node:e},b),!1}};d.decodeHTML=function(a){var b=document.createElement("div");b.innerText=a;return b.innerHTML};d.onResizeNode=function(a, -b,c,h,f){f&&(f.size=f.computeSize(),f.setDirtyCanvas(!0,!0))};d.onShowTitleEditor=function(a,b,c,h,f){function e(){f.title=n.value;g.parentNode.removeChild(g);f.setDirtyCanvas(!0,!0)}var g=document.createElement("div");g.className="graphdialog";g.innerHTML="Title";var n=g.querySelector("input");n&&(n.value=f.title,n.addEventListener("keydown",function(a){13==a.keyCode&&(e(),a.preventDefault(),a.stopPropagation())})); -a=d.active_canvas.canvas;b=a.getBoundingClientRect();h=c=-20;b&&(c-=b.left,h-=b.top);event?(g.style.left=event.pageX+c+"px",g.style.top=event.pageY+h+"px"):(g.style.left=0.5*a.width+c+"px",g.style.top=0.5*a.height+h+"px");g.querySelector("button").addEventListener("click",e);a.parentNode.appendChild(g)};d.prototype.showEditPropertyValue=function(a,b,c){function h(){f(A.value)}function f(c){"number"==typeof a.properties[b]&&(c=Number(c));a.properties[b]=c;if(a.onPropertyChanged)a.onPropertyChanged(b, -c);l.close();a.setDirtyCanvas(!0,!0)}if(a&&void 0!==a.properties[b]){c=c||{};var d="string";null!==a.properties[b]&&(d=typeof a.properties[b]);var e=null;a.getPropertyInfo&&(e=a.getPropertyInfo(b));if(a.properties_info)for(var n=0;n";else if("enum"==d&&e.values){g=""}else"boolean"==d&&(g="");var l=this.createDialog(""+b+""+g+"",c);if("enum"==d&&e.values){var A=l.querySelector("select");A.addEventListener("change",function(a){f(a.target.value)})}else if("boolean"== -d)(A=l.querySelector("input"))&&A.addEventListener("click",function(a){f(!!A.checked)});else if(A=l.querySelector("input"))A.value=void 0!==a.properties[b]?a.properties[b]:"",A.addEventListener("keydown",function(a){13==a.keyCode&&(h(),a.preventDefault(),a.stopPropagation())});l.querySelector("button").addEventListener("click",h)}};d.prototype.createDialog=function(a,b){b=b||{};var c=document.createElement("div");c.className="graphdialog";c.innerHTML=a;var h=this.canvas.getClientRects()[0],f=-20, -d=-20;h&&(f-=h.left,d-=h.top);b.position?(f+=b.position[0],d+=b.position[1]):b.event?(f+=b.event.pageX,d+=b.event.pageY):(f+=0.5*this.canvas.width,d+=0.5*this.canvas.height);c.style.left=f+"px";c.style.top=d+"px";this.canvas.parentNode.appendChild(c);c.close=function(){this.parentNode&&this.parentNode.removeChild(this)};return c};d.onMenuNodeCollapse=function(a,b,c,h,f){f.flags.collapsed=!f.flags.collapsed;f.setDirtyCanvas(!0,!0)};d.onMenuNodePin=function(a,b,c,f,d){d.pin()};d.onMenuNodeMode=function(a, -b,c,h,d){new f.ContextMenu(["Always","On Event","On Trigger","Never"],{event:c,callback:function(a){if(d)switch(a){case "On Event":d.mode=f.ON_EVENT;break;case "On Trigger":d.mode=f.ON_TRIGGER;break;case "Never":d.mode=f.NEVER;break;default:d.mode=f.ALWAYS}},parentMenu:h,node:d});return!1};d.onMenuNodeColors=function(a,b,c,h,e){if(!e)throw"no node for color";b=[];for(var g in d.node_colors)a=d.node_colors[g],a={value:g,content:""+g+""},b.push(a);new f.ContextMenu(b,{event:c,callback:function(a){e&&(a=d.node_colors[a.value])&&(e.color=a.color,e.bgcolor=a.bgcolor,e.setDirtyCanvas(!0))},parentMenu:h,node:e});return!1};d.onMenuNodeShapes=function(a,b,c,h,d){if(!d)throw"no node passed";new f.ContextMenu(f.VALID_SHAPES,{event:c,callback:function(a){d&&(d.shape=a,d.setDirtyCanvas(!0))},parentMenu:h,node:d});return!1};d.onMenuNodeRemove=function(a,b,c,f,d){if(!d)throw"no node passed";!1!=d.removable&&(d.graph.remove(d), -d.setDirtyCanvas(!0,!0))};d.onMenuNodeClone=function(a,b,c,f,d){!1!=d.clonable&&(a=d.clone())&&(a.pos=[d.pos[0]+5,d.pos[1]+5],d.graph.add(a),d.setDirtyCanvas(!0,!0))};d.node_colors={red:{color:"#FAA",bgcolor:"#944"},green:{color:"#AFA",bgcolor:"#494"},blue:{color:"#AAF",bgcolor:"#449"},cyan:{color:"#AFF",bgcolor:"#499"},purple:{color:"#FAF",bgcolor:"#949"},yellow:{color:"#FFA",bgcolor:"#994"},black:{color:"#777",bgcolor:"#000"},white:{color:"#FFF",bgcolor:"#AAA"}};d.prototype.getCanvasMenuOptions= -function(){var a=null;this.getMenuOptions?a=this.getMenuOptions():(a=[{content:"Add Node",has_submenu:!0,callback:d.onMenuAdd}],this._graph_stack&&0Name",f),g=e.querySelector("input");e.querySelector("button").addEventListener("click",function(b){if(g.value){if(b= -d.input?a.getInputInfo(d.slot):a.getOutputInfo(d.slot))b.label=g.value;c.setDirty(!0)}e.close()})}},node:a},p=null;a&&(p=a.getSlotInPosition(b.canvasX,b.canvasY),d.active_node=a);p?(e=[],e.push(p.locked?"Cannot remove":{content:"Remove Slot",slot:p}),e.push({content:"Rename Slot",slot:p}),g.title=(p.input?p.input.type:p.output.type)||"*",p.input&&p.input.type==f.ACTION&&(g.title="Action"),p.output&&p.output.type==f.EVENT&&(g.title="Event")):e=a?this.getNodeMenuOptions(a):this.getCanvasMenuOptions(); -e&&new f.ContextMenu(e,g,h)};this.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.roundRect=function(a,b,c,f,d,e){void 0===d&&(d=5);void 0===e&&(e=d);this.beginPath();this.moveTo(a+d,b);this.lineTo(a+c-d,b);this.quadraticCurveTo(a+c,b,a+c,b+d);this.lineTo(a+c,b+f-e);this.quadraticCurveTo(a+c,b+f,a+c-e,b+f);this.lineTo(a+e,b+f);this.quadraticCurveTo(a,b+f,a,b+f-e);this.lineTo(a,b+d);this.quadraticCurveTo(a,b,a+d,b)});f.compareObjects=function(a,b){for(var c in a)if(a[c]!=b[c])return!1; -return!0};f.distance=q;f.colorToString=function(a){return"rgba("+Math.round(255*a[0]).toFixed()+","+Math.round(255*a[1]).toFixed()+","+Math.round(255*a[2]).toFixed()+","+(4==a.length?a[3].toFixed(2):"1.0")+")"};f.isInsideRectangle=l;f.growBounding=function(a,b,c){ba[2]&&(a[2]=b);ca[3]&&(a[3]=c)};f.isInsideBounding=function(a,b){return a[0]b[1][0]||a[1]>b[1][1]?!1:!0};f.overlapBounding=t;f.hex2num=function(a){"#"==a.charAt(0)&&(a=a.slice(1)); -a=a.toUpperCase();for(var b=Array(3),c=0,f,d,e=0;6>e;e+=2)f="0123456789ABCDEF".indexOf(a.charAt(e)),d="0123456789ABCDEF".indexOf(a.charAt(e+1)),b[c]=16*f+d,c++;return b};f.num2hex=function(a){for(var b="#",c,f,d=0;3>d;d++)c=a[d]/16,f=a[d]%16,b+="0123456789ABCDEF".charAt(c)+"0123456789ABCDEF".charAt(f);return b};u.prototype.addItem=function(a,b,c){function f(a){var b=this.value;b&&b.has_submenu&&d.call(this,a)}function d(a){var b=this.value,f=!0;e.current_submenu&&e.current_submenu.close(a);if(c.callback){var h= -c.callback.call(this,b,c,a,e,c.node);!0===h&&(f=!1)}if(b&&(b.callback&&!c.ignore_item_callbacks&&!0!==b.disabled&&(h=b.callback.call(this,b,c,a,e,c.node),!0===h&&(f=!1)),b.submenu)){if(!b.submenu.options)throw"ContextMenu submenu needs options";new e.constructor(b.submenu.options,{callback:b.submenu.callback,event:a,parentMenu:e,ignore_item_callbacks:b.submenu.ignore_item_callbacks,title:b.submenu.title,autoopen:c.autoopen});f=!1}f&&!e.lock&&e.close()}var e=this;c=c||{};var g=document.createElement("div"); -g.className="litemenu-entry submenu";var n=!1;if(null===b)g.classList.add("separator");else{g.innerHTML=b&&b.title?b.title:a;if(g.value=b)b.disabled&&(n=!0,g.classList.add("disabled")),(b.submenu||b.has_submenu)&&g.classList.add("has_submenu");"function"==typeof b?(g.dataset.value=a,g.onclick_callback=b):g.dataset.value=b;b.className&&(g.className+=" "+b.className)}this.root.appendChild(g);n||g.addEventListener("click",d);c.autoopen&&g.addEventListener("mouseenter",f);return g};u.prototype.close= -function(a,b){this.root.parentNode&&this.root.parentNode.removeChild(this.root);this.parentMenu&&!b&&(this.parentMenu.lock=!1,this.parentMenu.current_submenu=null,void 0===a?this.parentMenu.close():a&&!u.isCursorOverElement(a,this.parentMenu.root)&&u.trigger(this.parentMenu.root,"mouseleave",a));this.current_submenu&&this.current_submenu.close(a,!0)};u.trigger=function(a,b,c,f){var d=document.createEvent("CustomEvent");d.initCustomEvent(b,!0,!0,c);d.srcElement=f;a.dispatchEvent?a.dispatchEvent(d): -a.__events&&a.__events.dispatchEvent(d);return d};u.prototype.getTopMenu=function(){return this.options.parentMenu?this.options.parentMenu.getTopMenu():this};u.prototype.getFirstEvent=function(){return this.options.parentMenu?this.options.parentMenu.getFirstEvent():this.options.event};u.isCursorOverElement=function(a,b){var c=a.pageX,f=a.pageY,d=b.getBoundingClientRect();return d?f>d.top&&fd.left&&cf.canvasY-this.pos[1]||u.distance([f.canvasX,f.canvasY],[this.pos[0]+this.center[0],this.pos[1]+this.center[1]])>this.radius)return!1;this.oldmouse=[f.canvasX-this.pos[0],f.canvasY-this.pos[1]];this.captureInput(!0);return!0}};g.prototype.onMouseMove=function(f){if(this.oldmouse){f=[f.canvasX-this.pos[0],f.canvasY-this.pos[1]];var d=this.value,d=d-0.01*(f[1]-this.oldmouse[1]);1d&&(d=0);this.value=d;this.properties.value= -this.properties.min+(this.properties.max-this.properties.min)*this.value;this.oldmouse=f;this.setDirtyCanvas(!0)}};g.prototype.onMouseUp=function(f){this.oldmouse&&(this.oldmouse=null,this.captureInput(!1))};g.prototype.onMouseLeave=function(f){};g.prototype.onWidget=function(f,d){if("increase"==d.name)this.onPropertyChanged("size",this.properties.size+10);else if("decrease"==d.name)this.onPropertyChanged("size",this.properties.size-10)};g.prototype.onPropertyChanged=function(f,d){if("wcolor"==f)this.properties[f]= -d;else if("size"==f)d=parseInt(d),this.properties[f]=d,this.size=[d+4,d+24],this.setDirtyCanvas(!0,!0);else if("min"==f||"max"==f||"value"==f)this.properties[f]=parseFloat(d);else return!1;return!0};u.registerNodeType("widget/knob",g);d.title="H.Slider";d.desc="Linear slider controller";d.prototype.onAdded=function(){this.value=0.5;this.imgfg=this.loadImage("imgs/slider_fg.png")};d.prototype.onDrawVectorial=function(d){this.imgfg&&this.imgfg.width&&(d.lineWidth=1,d.strokeStyle=this.mouseOver?"#FFF": -"#AAA",d.fillStyle="#000",d.beginPath(),d.rect(2,0,this.size[0]-4,20),d.stroke(),d.fillStyle=this.properties.wcolor,d.beginPath(),d.rect(2+(this.size[0]-4-20)*this.value,0,20,20),d.fill())};d.prototype.onDrawImage=function(d){this.imgfg&&this.imgfg.width&&(d.lineWidth=1,d.fillStyle="#000",d.fillRect(2,9,this.size[0]-4,2),d.strokeStyle="#333",d.beginPath(),d.moveTo(2,9),d.lineTo(this.size[0]-4,9),d.stroke(),d.strokeStyle="#AAA",d.beginPath(),d.moveTo(2,11),d.lineTo(this.size[0]-4,11),d.stroke(),d.drawImage(this.imgfg, -2+(this.size[0]-4)*this.value-0.5*this.imgfg.width,0.5*-this.imgfg.height+10))};d.prototype.onDrawForeground=function(d){this.onDrawImage(d)};d.prototype.onExecute=function(){this.properties.value=this.properties.min+(this.properties.max-this.properties.min)*this.value;this.setOutputData(0,this.properties.value);this.boxcolor=u.colorToString([this.value,this.value,this.value])};d.prototype.onMouseDown=function(d){if(0>d.canvasY-this.pos[1])return!1;this.oldmouse=[d.canvasX-this.pos[0],d.canvasY-this.pos[1]]; -this.captureInput(!0);return!0};d.prototype.onMouseMove=function(d){if(this.oldmouse){d=[d.canvasX-this.pos[0],d.canvasY-this.pos[1]];var e=this.value,e=e+(d[0]-this.oldmouse[0])/this.size[0];1e&&(e=0);this.value=e;this.oldmouse=d;this.setDirtyCanvas(!0)}};d.prototype.onMouseUp=function(d){this.oldmouse=null;this.captureInput(!1)};d.prototype.onMouseLeave=function(d){};d.prototype.onPropertyChanged=function(d,e){if("wcolor"==d)this.properties[d]=e;else return!1;return!0};u.registerNodeType("widget/hslider", -d);q.title="Progress";q.desc="Shows data in linear progress";q.prototype.onExecute=function(){var d=this.getInputData(0);void 0!=d&&(this.properties.value=d)};q.prototype.onDrawForeground=function(d){d.lineWidth=1;d.fillStyle=this.properties.wcolor;var e=(this.properties.value-this.properties.min)/(this.properties.max-this.properties.min),e=Math.min(1,e),e=Math.max(0,e);d.fillRect(2,2,(this.size[0]-4)*e,this.size[1]-4)};u.registerNodeType("widget/progress",q);l.title="Text";l.desc="Shows the input value"; -l.widgets=[{name:"resize",text:"Resize box",type:"button"},{name:"led_text",text:"LED",type:"minibutton"},{name:"normal_text",text:"Normal",type:"minibutton"}];l.prototype.onDrawForeground=function(d){d.fillStyle=this.properties.color;var e=this.properties.value;this.properties.glowSize?(d.shadowColor=this.properties.color,d.shadowOffsetX=0,d.shadowOffsetY=0,d.shadowBlur=this.properties.glowSize):d.shadowColor="transparent";var a=this.properties.fontsize;d.textAlign=this.properties.align;d.font=a.toString()+ -"px "+this.properties.font;this.str="number"==typeof e?e.toFixed(this.properties.decimals):e;if("string"==typeof this.str){var e=this.str.split("\\n"),b;for(b in e)d.fillText(e[b],"left"==this.properties.align?15:this.size[0]-15,-0.15*a+a*(parseInt(b)+1))}d.shadowColor="transparent";this.last_ctx=d;d.textAlign="left"};l.prototype.onExecute=function(){var d=this.getInputData(0);null!=d&&(this.properties.value=d)};l.prototype.resize=function(){if(this.last_ctx){var d=this.str.split("\\n");this.last_ctx.font= -this.properties.fontsize+"px "+this.properties.font;var e=0,a;for(a in d){var b=this.last_ctx.measureText(d[a]).width;eg?d.xbox.axes.lx:0,this._left_axis[1]=Math.abs(d.xbox.axes.ly)>g?d.xbox.axes.ly:0,this._right_axis[0]=Math.abs(d.xbox.axes.rx)>g?d.xbox.axes.rx:0,this._right_axis[1]=Math.abs(d.xbox.axes.ry)>g?d.xbox.axes.ry:0,this._triggers[0]=Math.abs(d.xbox.axes.ltrigger)>g?d.xbox.axes.ltrigger:0,this._triggers[1]=Math.abs(d.xbox.axes.rtrigger)>g?d.xbox.axes.rtrigger:0);if(this.outputs)for(g= -0;gd;d++)if(e[d]){d=e[d];e=this.xbox_mapping;e||(e=this.xbox_mapping= -{axes:[],buttons:{},hat:""});e.axes.lx=d.axes[0];e.axes.ly=d.axes[1];e.axes.rx=d.axes[2];e.axes.ry=d.axes[3];e.axes.ltrigger=d.buttons[6].value;e.axes.rtrigger=d.buttons[7].value;for(var g=0;g","string",{values:v.values}); -this.size=[60,40]}function s(){this.addInput("inc","number");this.addOutput("total","number");this.addProperty("increment",1);this.addProperty("value",0)}function n(){this.addInput("v","number");this.addOutput("sin","number");this.addProperty("amplitude",1);this.addProperty("offset",0);this.bgImageUrl="nodes/imgs/icon-sin.png"}function y(){this.addInput("vec2","vec2");this.addOutput("x","number");this.addOutput("y","number")}function x(){this.addInputs([["x","number"],["y","number"]]);this.addOutput("vec2", -"vec2");this.properties={x:0,y:0};this._data=new Float32Array(2)}function z(){this.addInput("vec3","vec3");this.addOutput("x","number");this.addOutput("y","number");this.addOutput("z","number")}function A(){this.addInputs([["x","number"],["y","number"],["z","number"]]);this.addOutput("vec3","vec3");this.properties={x:0,y:0,z:0};this._data=new Float32Array(3)}function C(){this.addInput("vec4","vec4");this.addOutput("x","number");this.addOutput("y","number");this.addOutput("z","number");this.addOutput("w", -"number")}function D(){this.addInputs([["x","number"],["y","number"],["z","number"],["w","number"]]);this.addOutput("vec4","vec4");this.properties={x:0,y:0,z:0,w:0};this._data=new Float32Array(4)}var w=r.LiteGraph;e.title="Converter";e.desc="type A to type B";e.prototype.onExecute=function(){var a=this.getInputData(0);if(null!=a&&this.outputs)for(var b=0;bb&&(this._current=0);for(var c=a=0;cb&&(b=1);this.properties.samples=Math.round(b);var c=this._values;this._values=new Float32Array(this.properties.samples); -c.length<=this._values.length?this._values.set(c):this._values.set(c.subarray(0,this._values.length))};w.registerNodeType("math/average",c);h.values="+-*/%^".split("");h.title="Operation";h.desc="Easy math operators";h["@OP"]={type:"enum",title:"operation",values:h.values};h.prototype.setValue=function(a){"string"==typeof a&&(a=parseFloat(a));this.properties.value=a};h.prototype.onExecute=function(){var a=this.getInputData(0),b=this.getInputData(1);null!=a?this.properties.A=a:a=this.properties.A; -null!=b?this.properties.B=b:b=this.properties.B;var c=0;switch(this.properties.OP){case "+":c=a+b;break;case "-":c=a-b;break;case "x":case "X":case "*":c=a*b;break;case "/":c=a/b;break;case "%":c=a%b;break;case "^":c=Math.pow(a,b);break;default:console.warn("Unknown operation: "+this.properties.OP)}this.setOutputData(0,c)};h.prototype.onDrawBackground=function(a){this.flags.collapsed||(a.font="40px Arial",a.fillStyle="black",a.textAlign="center",a.fillText(this.properties.OP,0.5*this.size[0],0.5* -this.size[1]+w.NODE_TITLE_HEIGHT),a.textAlign="left")};w.registerNodeType("math/operation",h);k.title="Compare";k.desc="compares between two values";k.prototype.onExecute=function(){var a=this.getInputData(0),b=this.getInputData(1);void 0!==a?this.properties.A=a:a=this.properties.A;void 0!==b?this.properties.B=b:b=this.properties.B;for(var c=0,d=this.outputs.length;cB":value= -a>b;break;case "A=B":value=a>=b}this.setOutputData(c,value)}}};k.prototype.onGetOutputs=function(){return[["A==B","boolean"],["A!=B","boolean"],["A>B","boolean"],["A=B","boolean"],["A<=B","boolean"]]};w.registerNodeType("math/compare",k);v.values="> < == != <= >=".split(" ");v["@OP"]={type:"enum",title:"operation",values:v.values};v.title="Condition";v.desc="evaluates condition between A and B";v.prototype.onExecute=function(){var a= -this.getInputData(0);void 0===a?a=this.properties.A:this.properties.A=a;var b=this.getInputData(1);void 0===b?b=this.properties.B:this.properties.B=b;var c=!0;switch(this.properties.OP){case ">":c=a>b;break;case "<":c=a=":c=a>=b}this.setOutputData(0,c)};w.registerNodeType("math/condition",v);s.title="Accumulate";s.desc="Increments a value every time";s.prototype.onExecute=function(){null===this.properties.value&& -(this.properties.value=0);var a=this.getInputData(0);this.properties.value=null!==a?this.properties.value+a:this.properties.value+this.properties.increment;this.setOutputData(0,this.properties.value)};w.registerNodeType("math/accumulate",s);n.title="Trigonometry";n.desc="Sin Cos Tan";n.filter="shader";n.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=0);var b=this.properties.amplitude,c=this.findInputSlot("amplitude");-1!=c&&(b=this.getInputData(c));var d=this.properties.offset, +this.setDirtyCanvas(!0,!0);this.change();this.updateExecutionOrder()}};g.prototype.getNodeById=function(a){return null==a?null:this._nodes_by_id[a]};g.prototype.findNodesByClass=function(a){for(var b=[],c=0,h=this._nodes.length;c!a.length||(this._pos[0]=a[0],this._pos[1]=a[1])},get:function(){return this._pos},enumerable:!0});this.id=-1;this.type=null;this.inputs=[];this.outputs=[];this.connections=[];this.properties={};this.properties_info=[];this.data=null;this.flags={}};f.prototype.configure=function(a){for(var b in a)if("console"!=b)if("properties"==b)for(var c in a.properties){if(this.properties[c]=a.properties[c], +this.onPropertyChanged)this.onPropertyChanged(c,a.properties[c])}else null!=a[b]&&("object"==typeof a[b]?this[b]&&this[b].configure?this[b].configure(a[b]):this[b]=d.cloneObject(a[b],this[b]):this[b]=a[b]);if(this.onConnectionsChange){if(this.inputs)for(var h=0;h=this.outputs.length)){var c= +this.outputs[a];if(c&&(c._data=b,this.outputs[a].links))for(c=0;c=this.inputs.length||null==this.inputs[a].link)){var c=this.graph.links[this.inputs[a].link];if(!c)return null;if(!b)return c.data;var h=this.graph.getNodeById(c.origin_id);if(!h)return c.data;if(h.updateOutputData)h.updateOutputData(c.origin_slot);else if(h.onExecute)h.onExecute();return c.data}}; +f.prototype.isInputConnected=function(a){return this.inputs?a=this.inputs.length)return null;a=this.inputs[a];return a&&a.link?(a=this.graph.links[a.link])?this.graph.getNodeById(a.origin_id):null:null};f.prototype.getOutputData=function(a){return!this.outputs||a>=this.outputs.length?null:this.outputs[a]._data}; +f.prototype.getOutputInfo=function(a){return this.outputs?a=this.outputs.length)return null;a=this.outputs[a];if(!a.links||0==a.links.length)return null;for(var b=[],c=0;ca&&this.pos[1]-h-cb)return!0;return!1};f.prototype.getSlotInPosition= +function(a,b){if(this.inputs)for(var c=0,h=this.inputs.length;c=this.outputs.length)return d.debug&&console.log("Connect: Error, slot number not found"),!1;b&&b.constructor=== +Number&&(b=this.graph.getNodeById(b));if(!b)throw"Node not found";if(b==this)return!1;if(c.constructor===String){if(c=b.findInputSlot(c),-1==c)return d.debug&&console.log("Connect: Error, no slot of name "+c),!1}else{if(c===d.EVENT)return!1;if(!b.inputs||c>=b.inputs.length)return d.debug&&console.log("Connect: Error, slot number not found"),!1}null!=b.inputs[c].link&&b.disconnectInput(c);this.setDirtyCanvas(!1,!0);this.graph.connectionChange(this);var h=this.outputs[a];if(b.onConnectInput&&!1===b.onConnectInput(c, +h.type,h))return!1;var k=b.inputs[c];if(d.isValidConnection(h.type,k.type)){var e={id:this.graph.last_link_id++,type:k.type,origin_id:this.id,origin_slot:a,target_id:b.id,target_slot:c};this.graph.links[e.id]=e;null==h.links&&(h.links=[]);h.links.push(e.id);b.inputs[c].link=e.id;if(this.onConnectionsChange)this.onConnectionsChange(d.OUTPUT,a,!0,e,h);if(b.onConnectionsChange)b.onConnectionsChange(d.INPUT,c,!0,e,k)}this.setDirtyCanvas(!1,!0);this.graph.connectionChange(this);return!0};f.prototype.disconnectOutput= +function(a,b){if(a.constructor===String){if(a=this.findOutputSlot(a),-1==a)return d.debug&&console.log("Connect: Error, no slot of name "+a),!1}else if(!this.outputs||a>=this.outputs.length)return d.debug&&console.log("Connect: Error, slot number not found"),!1;var c=this.outputs[a];if(!c.links||0==c.links.length)return!1;if(b){b.constructor===Number&&(b=this.graph.getNodeById(b));if(!b)throw"Target Node not found";for(var h=0,k=c.links.length;h=this.inputs.length)return d.debug&&console.log("Connect: Error, slot number not found"),!1;var b=this.inputs[a];if(!b)return!1;var c=this.inputs[a].link; +this.inputs[a].link=null;var h=this.graph.links[c];if(h){var k=this.graph.getNodeById(h.origin_id);if(!k)return!1;var e=k.outputs[h.origin_slot];if(!e||!e.links||0==e.links.length)return!1;for(var n=0,l=e.links.length;nb&&this.inputs[b].pos?[this.pos[0]+this.inputs[b].pos[0],this.pos[1]+this.inputs[b].pos[1]]:!a&&this.outputs.length>b&&this.outputs[b].pos?[this.pos[0]+this.outputs[b].pos[0],this.pos[1]+this.outputs[b].pos[1]]:a?[this.pos[0],this.pos[1]+10+b* +d.NODE_SLOT_HEIGHT]:[this.pos[0]+this.size[0]+1,this.pos[1]+10+b*d.NODE_SLOT_HEIGHT]};f.prototype.alignToGrid=function(){this.pos[0]=d.CANVAS_GRID_SIZE*Math.round(this.pos[0]/d.CANVAS_GRID_SIZE);this.pos[1]=d.CANVAS_GRID_SIZE*Math.round(this.pos[1]/d.CANVAS_GRID_SIZE)};f.prototype.trace=function(a){this.console||(this.console=[]);this.console.push(a);this.console.length>f.MAX_CONSOLE&&this.console.shift();this.graph.onNodeTrace(this,a)};f.prototype.setDirtyCanvas=function(a,b){this.graph&&this.graph.sendActionToCanvas("setDirty", +[a,b])};f.prototype.loadImage=function(a){var b=new Image;b.src=d.node_images_path+a;b.ready=!1;var c=this;b.onload=function(){this.ready=!0;c.setDirtyCanvas(!0)};return b};f.prototype.captureInput=function(a){if(this.graph&&this.graph.list_of_graphcanvas)for(var b=this.graph.list_of_graphcanvas,c=0;c element, you passed a "+a.localName;throw"This browser doesnt support Canvas";}null==(this.ctx=a.getContext("2d"))&& +(console.warn("This canvas seems to be WebGL, enabling WebGL renderer"),this.enableWebGL());this._mousemove_callback=this.processMouseMove.bind(this);this._mouseup_callback=this.processMouseUp.bind(this);b||this.bindEvents()}};e.prototype._doNothing=function(a){a.preventDefault();return!1};e.prototype._doReturnTrue=function(a){a.preventDefault();return!0};e.prototype.bindEvents=function(){if(this._events_binded)console.warn("LGraphCanvas: events already binded");else{var a=this.canvas,b=this.getCanvasWindow().document; +this._mousedown_callback=this.processMouseDown.bind(this);this._mousewheel_callback=this.processMouseWheel.bind(this);a.addEventListener("mousedown",this._mousedown_callback,!0);a.addEventListener("mousemove",this._mousemove_callback);a.addEventListener("mousewheel",this._mousewheel_callback,!1);a.addEventListener("contextmenu",this._doNothing);a.addEventListener("DOMMouseScroll",this._mousewheel_callback,!1);a.addEventListener("touchstart",this.touchHandler,!0);a.addEventListener("touchmove",this.touchHandler, +!0);a.addEventListener("touchend",this.touchHandler,!0);a.addEventListener("touchcancel",this.touchHandler,!0);this._key_callback=this.processKey.bind(this);a.addEventListener("keydown",this._key_callback,!0);b.addEventListener("keyup",this._key_callback,!0);this._ondrop_callback=this.processDrop.bind(this);a.addEventListener("dragover",this._doNothing,!1);a.addEventListener("dragend",this._doNothing,!1);a.addEventListener("drop",this._ondrop_callback,!1);a.addEventListener("dragenter",this._doReturnTrue, +!1);this._events_binded=!0}};e.prototype.unbindEvents=function(){if(this._events_binded){var a=this.getCanvasWindow().document;this.canvas.removeEventListener("mousedown",this._mousedown_callback);this.canvas.removeEventListener("mousewheel",this._mousewheel_callback);this.canvas.removeEventListener("DOMMouseScroll",this._mousewheel_callback);this.canvas.removeEventListener("keydown",this._key_callback);a.removeEventListener("keyup",this._key_callback);this.canvas.removeEventListener("contextmenu", +this._doNothing);this.canvas.removeEventListener("drop",this._ondrop_callback);this.canvas.removeEventListener("dragenter",this._doReturnTrue);this.canvas.removeEventListener("touchstart",this.touchHandler);this.canvas.removeEventListener("touchmove",this.touchHandler);this.canvas.removeEventListener("touchend",this.touchHandler);this.canvas.removeEventListener("touchcancel",this.touchHandler);this._ondrop_callback=this._key_callback=this._mousewheel_callback=this._mousedown_callback=null;this._events_binded= +!1}else console.warn("LGraphCanvas: no events binded")};e.getFileExtension=function(a){var b=a.indexOf("?");-1!=b&&(a=a.substr(0,b));b=a.lastIndexOf(".");return-1==b?"":a.substr(b+1).toLowerCase()};e.prototype.enableWebGL=function(){if(void 0===typeof GL)throw"litegl.js must be included to use a WebGL canvas";if(void 0===typeof enableWebGLCanvas)throw"webglCanvas.js must be included to use this feature";this.gl=this.ctx=enableWebGLCanvas(this.canvas);this.ctx.webgl=!0;this.bgcanvas=this.canvas;this.bgctx= +this.gl};e.prototype.setDirty=function(a,b){a&&(this.dirty_canvas=!0);b&&(this.dirty_bgcanvas=!0)};e.prototype.getCanvasWindow=function(){if(!this.canvas)return window;var a=this.canvas.ownerDocument;return a.defaultView||a.parentWindow};e.prototype.startRendering=function(){function a(){this.pause_rendering||this.draw();var b=this.getCanvasWindow();this.is_rendering&&b.requestAnimationFrame(a.bind(this))}this.is_rendering||(this.is_rendering=!0,a.call(this))};e.prototype.stopRendering=function(){this.is_rendering= +!1};e.prototype.processMouseDown=function(a){if(this.graph){this.adjustMouseEvent(a);var b=this.getCanvasWindow();e.active_canvas=this;this.canvas.removeEventListener("mousemove",this._mousemove_callback);b.document.addEventListener("mousemove",this._mousemove_callback,!0);b.document.addEventListener("mouseup",this._mouseup_callback,!0);var c=this.graph.getNodeOnPos(a.canvasX,a.canvasY,this.visible_nodes),h=!1;d.closeAllContextMenus(b);if(1==a.which){a.ctrlKey&&(this.dragging_rectangle=new Float32Array(4), +this.dragging_rectangle[0]=a.canvasX,this.dragging_rectangle[1]=a.canvasY,this.dragging_rectangle[2]=1,this.dragging_rectangle[3]=1,h=!0);var k=!1;if(c&&this.allow_interaction&&!h){this.live_mode||c.flags.pinned||this.bringToFront(c);if(!this.connecting_node&&!c.flags.collapsed&&!this.live_mode){if(c.outputs)for(var l=0,n=c.outputs.length;ld.getTime()-this.last_mouseclick&&this.selected_nodes[c.id]){if(c.onDblClick)c.onDblClick(a);this.processNodeDblClicked(c);l=!0}c.onMouseDown&&c.onMouseDown(a,[a.canvasX-c.pos[0],a.canvasY-c.pos[1]])?l=!0:this.live_mode&&(l=k=!0);l||(this.allow_dragnodes&&(this.node_dragged=c),this.selected_nodes[c.id]||this.processNodeSelected(c,a));this.dirty_canvas=!0}}else k=!0;!h&&k&&this.allow_dragcanvas&&(this.dragging_canvas=!0)}else 2!=a.which&&3==a.which&&this.processContextMenu(c, +a);this.last_mouse[0]=a.localX;this.last_mouse[1]=a.localY;this.last_mouseclick=d.getTime();this.canvas_mouse=[a.canvasX,a.canvasY];this.graph.change();(!b.document.activeElement||"input"!=b.document.activeElement.nodeName.toLowerCase()&&"textarea"!=b.document.activeElement.nodeName.toLowerCase())&&a.preventDefault();a.stopPropagation();if(this.onMouseDown)this.onMouseDown(a);return!1}};e.prototype.processMouseMove=function(a){this.autoresize&&this.resize();if(this.graph){e.active_canvas=this;this.adjustMouseEvent(a); +var b=[a.localX,a.localY],c=[b[0]-this.last_mouse[0],b[1]-this.last_mouse[1]];this.last_mouse=b;this.canvas_mouse=[a.canvasX,a.canvasY];if(this.dragging_rectangle)this.dragging_rectangle[2]=a.canvasX-this.dragging_rectangle[0],this.dragging_rectangle[3]=a.canvasY-this.dragging_rectangle[1],this.dirty_canvas=!0;else if(this.dragging_canvas)this.offset[0]+=c[0]/this.scale,this.offset[1]+=c[1]/this.scale,this.dirty_bgcanvas=this.dirty_canvas=!0;else if(this.allow_interaction){this.connecting_node&&(this.dirty_canvas= +!0);for(var b=this.graph.getNodeOnPos(a.canvasX,a.canvasY,this.visible_nodes),h=0,k=this.graph._nodes.length;hthis.dragging_rectangle[2]&&(this.dragging_rectangle[0]+=this.dragging_rectangle[2]);0>this.dragging_rectangle[3]&&(this.dragging_rectangle[1]+=this.dragging_rectangle[3]);this.dragging_rectangle[2]=Math.abs(this.dragging_rectangle[2]*this.scale);this.dragging_rectangle[3]=Math.abs(this.dragging_rectangle[3]*this.scale); +for(var k=0;kc-this.last_mouseclick&&this.deselectAllNodes();this.dirty_canvas=!0;this.dragging_canvas=!1;if(this.node_over&&this.node_over.onMouseUp)this.node_over.onMouseUp(a,[a.canvasX-this.node_over.pos[0], +a.canvasY-this.node_over.pos[1]]);if(this.node_capturing_input&&this.node_capturing_input.onMouseUp)this.node_capturing_input.onMouseUp(a,[a.canvasX-this.node_capturing_input.pos[0],a.canvasY-this.node_capturing_input.pos[1]])}else 2==a.which?(this.dirty_canvas=!0,this.dragging_canvas=!1):3==a.which&&(this.dirty_canvas=!0,this.dragging_canvas=!1);this.graph.change();a.stopPropagation();a.preventDefault();return!1}};e.prototype.processMouseWheel=function(a){if(this.graph&&this.allow_dragcanvas){var b= +null!=a.wheelDeltaY?a.wheelDeltaY:-60*a.detail;this.adjustMouseEvent(a);var c=this.scale;0b&&(c*=1/1.1);this.setZoom(c,[a.localX,a.localY]);this.graph.change();a.preventDefault();return!1}};e.prototype.isOverNodeBox=function(a,b,c){var h=d.NODE_TITLE_HEIGHT;return p(b,c,a.pos[0]+2,a.pos[1]+2-h,h-4,h-4)?!0:!1};e.prototype.isOverNodeInput=function(a,b,c,h){if(a.inputs)for(var d=0,e=a.inputs.length;dthis.max_zoom?this.scale=this.max_zoom:this.scalec-this.graph._last_trigger_time)&& +this.drawBackCanvas();(this.dirty_canvas||a)&&this.drawFrontCanvas();this.fps=this.render_time?1/this.render_time:0;this.frame+=1}};e.prototype.drawFrontCanvas=function(){this.ctx||(this.ctx=this.bgcanvas.getContext("2d"));var a=this.ctx;if(a){a.start2D&&a.start2D();var b=this.canvas;a.restore();a.setTransform(1,0,0,1,0,0);this.dirty_area&&(a.save(),a.beginPath(),a.rect(this.dirty_area[0],this.dirty_area[1],this.dirty_area[2],this.dirty_area[3]),a.clip());this.clear_background&&a.clearRect(0,0,b.width, +b.height);this.bgcanvas==this.canvas?this.drawBackCanvas():a.drawImage(this.bgcanvas,0,0);if(this.onRender)this.onRender(b,a);this.show_info&&this.renderInfo(a);if(this.graph){a.save();a.scale(this.scale,this.scale);a.translate(this.offset[0],this.offset[1]);for(var b=this.computeVisibleNodes(null,this.visible_nodes),c=0;cb-n._last_time&&(l=2-0.002*(b-n._last_time),f="rgba(255,255,255, "+l.toFixed(2)+")",this.renderLink(a,g,k.getConnectionPos(!0,e),n,!0,l,f))}}}}a.globalAlpha=1};e.prototype.renderLink=function(a,b,c,h,k,l,n){if(this.highquality_render){var f=t(b,c);this.render_connections_border&&0.6b[1]?0:Math.PI,a.save(),a.translate(h[0],h[1]),a.rotate(n),a.beginPath(),a.moveTo(-5,-5),a.lineTo(0,5),a.lineTo(5,-5),a.fill(),a.restore());if(l)for(l=0;5>l;++l)h=(0.001*d.getTime()+0.2*l)% +1,h=this.computeConnectionPoint(b,c,h),a.beginPath(),a.arc(h[0],h[1],5,0,2*Math.PI),a.fill()}else a.beginPath(),a.moveTo(b[0],b[1]),a.lineTo(c[0],c[1]),a.stroke()};e.prototype.computeConnectionPoint=function(a,b,c){var d=t(a,b),e=[a[0]+0.25*d,a[1]],d=[b[0]-0.25*d,b[1]],l=(1-c)*(1-c)*(1-c),n=3*(1-c)*(1-c)*c,f=3*(1-c)*c*c;c*=c*c;return[l*a[0]+n*e[0]+f*d[0]+c*b[0],l*a[1]+n*e[1]+f*d[1]+c*b[1]]};e.prototype.resize=function(a,b){if(!a&&!b){var c=this.canvas.parentNode;a=c.offsetWidth;b=c.offsetHeight}if(this.canvas.width!= +a||this.canvas.height!=b)this.canvas.width=a,this.canvas.height=b,this.bgcanvas.width=this.canvas.width,this.bgcanvas.height=this.canvas.height,this.setDirty(!0,!0)};e.prototype.switchLiveMode=function(a){if(a){var b=this,c=this.live_mode?1.1:0.9;this.live_mode&&(this.live_mode=!1,this.editor_alpha=0.1);var d=setInterval(function(){b.editor_alpha*=c;b.dirty_canvas=!0;b.dirty_bgcanvas=!0;1>c&&0.01>b.editor_alpha&&(clearInterval(d),1>c&&(b.live_mode=!0));1"+ +g+""+a+"",value:g});if(f.length)return new d.ContextMenu(f,{event:c,callback:l,parentMenu:h,allow_html:!0,node:k},b),!1}};e.decodeHTML=function(a){var b=document.createElement("div");b.innerText=a;return b.innerHTML};e.onResizeNode=function(a,b,c,d,e){e&&(e.size=e.computeSize(),e.setDirtyCanvas(!0,!0))};e.onShowTitleEditor=function(a,b,c,d,k){function l(){k.title=f.value;n.parentNode.removeChild(n);k.setDirtyCanvas(!0,!0)}var n=document.createElement("div"); +n.className="graphdialog";n.innerHTML="Title";var f=n.querySelector("input");f&&(f.value=k.title,f.addEventListener("keydown",function(a){13==a.keyCode&&(l(),a.preventDefault(),a.stopPropagation())}));a=e.active_canvas.canvas;b=a.getBoundingClientRect();d=c=-20;b&&(c-=b.left,d-=b.top);event?(n.style.left=event.pageX+c+"px",n.style.top=event.pageY+d+"px"):(n.style.left=0.5*a.width+c+"px",n.style.top=0.5*a.height+ +d+"px");n.querySelector("button").addEventListener("click",l);a.parentNode.appendChild(n)};e.prototype.showEditPropertyValue=function(a,b,c){function d(){e(y.value)}function e(c){"number"==typeof a.properties[b]&&(c=Number(c));a.properties[b]=c;if(a.onPropertyChanged)a.onPropertyChanged(b,c);w.close();a.setDirtyCanvas(!0,!0)}if(a&&void 0!==a.properties[b]){c=c||{};var l="string";null!==a.properties[b]&&(l=typeof a.properties[b]);var n=null;a.getPropertyInfo&&(n=a.getPropertyInfo(b));if(a.properties_info)for(var f= +0;f";else if("enum"==l&&n.values){g=""}else"boolean"==l&&(g="");var w=this.createDialog(""+b+""+g+"",c);if("enum"==l&&n.values){var y=w.querySelector("select");y.addEventListener("change",function(a){e(a.target.value)})}else if("boolean"==l)(y=w.querySelector("input"))&&y.addEventListener("click",function(a){e(!!y.checked)});else if(y=w.querySelector("input"))y.value=void 0!==a.properties[b]?a.properties[b]:"",y.addEventListener("keydown",function(a){13==a.keyCode&&(d(),a.preventDefault(), +a.stopPropagation())});w.querySelector("button").addEventListener("click",d)}};e.prototype.createDialog=function(a,b){b=b||{};var c=document.createElement("div");c.className="graphdialog";c.innerHTML=a;var d=this.canvas.getBoundingClientRect(),e=-20,l=-20;d&&(e-=d.left,l-=d.top);b.position?(e+=b.position[0],l+=b.position[1]):b.event?(e+=b.event.pageX,l+=b.event.pageY):(e+=0.5*this.canvas.width,l+=0.5*this.canvas.height);c.style.left=e+"px";c.style.top=l+"px";this.canvas.parentNode.appendChild(c); +c.close=function(){this.parentNode&&this.parentNode.removeChild(this)};return c};e.onMenuNodeCollapse=function(a,b,c,d,e){e.flags.collapsed=!e.flags.collapsed;e.setDirtyCanvas(!0,!0)};e.onMenuNodePin=function(a,b,c,d,e){e.pin()};e.onMenuNodeMode=function(a,b,c,e,l){new d.ContextMenu(["Always","On Event","On Trigger","Never"],{event:c,callback:function(a){if(l)switch(a){case "On Event":l.mode=d.ON_EVENT;break;case "On Trigger":l.mode=d.ON_TRIGGER;break;case "Never":l.mode=d.NEVER;break;default:l.mode= +d.ALWAYS}},parentMenu:e,node:l});return!1};e.onMenuNodeColors=function(a,b,c,l,k){if(!k)throw"no node for color";b=[];for(var f in e.node_colors)a=e.node_colors[f],a={value:f,content:""+f+""},b.push(a);new d.ContextMenu(b,{event:c,callback:function(a){k&&(a=e.node_colors[a.value])&&(k.color=a.color,k.bgcolor=a.bgcolor,k.setDirtyCanvas(!0))},parentMenu:l,node:k});return!1};e.onMenuNodeShapes=function(a,b,c,e,l){if(!l)throw"no node passed"; +new d.ContextMenu(d.VALID_SHAPES,{event:c,callback:function(a){l&&(l.shape=a,l.setDirtyCanvas(!0))},parentMenu:e,node:l});return!1};e.onMenuNodeRemove=function(a,b,c,d,e){if(!e)throw"no node passed";!1!=e.removable&&(e.graph.remove(e),e.setDirtyCanvas(!0,!0))};e.onMenuNodeClone=function(a,b,c,d,e){!1!=e.clonable&&(a=e.clone())&&(a.pos=[e.pos[0]+5,e.pos[1]+5],e.graph.add(a),e.setDirtyCanvas(!0,!0))};e.node_colors={red:{color:"#FAA",bgcolor:"#944"},green:{color:"#AFA",bgcolor:"#494"},blue:{color:"#AAF", +bgcolor:"#449"},cyan:{color:"#AFF",bgcolor:"#499"},purple:{color:"#FAF",bgcolor:"#949"},yellow:{color:"#FFA",bgcolor:"#994"},black:{color:"#777",bgcolor:"#000"},white:{color:"#FFF",bgcolor:"#AAA"}};e.prototype.getCanvasMenuOptions=function(){var a=null;this.getMenuOptions?a=this.getMenuOptions():(a=[{content:"Add Node",has_submenu:!0,callback:e.onMenuAdd}],this._graph_stack&&0Name",d),h=n.querySelector("input");n.querySelector("button").addEventListener("click",function(b){if(h.value){if(b=l.input?a.getInputInfo(l.slot):a.getOutputInfo(l.slot))b.label=h.value;c.setDirty(!0)}n.close()})}},node:a},n=null;a&&(n=a.getSlotInPosition(b.canvasX,b.canvasY),e.active_node=a);n?(f=[],f.push(n.locked?"Cannot remove":{content:"Remove Slot",slot:n}),f.push({content:"Rename Slot",slot:n}),g.title= +(n.input?n.input.type:n.output.type)||"*",n.input&&n.input.type==d.ACTION&&(g.title="Action"),n.output&&n.output.type==d.EVENT&&(g.title="Event")):f=a?this.getNodeMenuOptions(a):this.getCanvasMenuOptions();f&&new d.ContextMenu(f,g,l)};this.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.roundRect=function(a,b,c,d,e,l){void 0===e&&(e=5);void 0===l&&(l=e);this.beginPath();this.moveTo(a+e,b);this.lineTo(a+c-e,b);this.quadraticCurveTo(a+c,b,a+c,b+e);this.lineTo(a+c,b+d-l);this.quadraticCurveTo(a+ +c,b+d,a+c-l,b+d);this.lineTo(a+l,b+d);this.quadraticCurveTo(a,b+d,a,b+d-l);this.lineTo(a,b+e);this.quadraticCurveTo(a,b,a+e,b)});d.compareObjects=function(a,b){for(var c in a)if(a[c]!=b[c])return!1;return!0};d.distance=t;d.colorToString=function(a){return"rgba("+Math.round(255*a[0]).toFixed()+","+Math.round(255*a[1]).toFixed()+","+Math.round(255*a[2]).toFixed()+","+(4==a.length?a[3].toFixed(2):"1.0")+")"};d.isInsideRectangle=p;d.growBounding=function(a,b,c){ba[2]&&(a[2]=b);ca[3]&&(a[3]=c)};d.isInsideBounding=function(a,b){return a[0]b[1][0]||a[1]>b[1][1]?!1:!0};d.overlapBounding=u;d.hex2num=function(a){"#"==a.charAt(0)&&(a=a.slice(1));a=a.toUpperCase();for(var b=Array(3),c=0,d,e,l=0;6>l;l+=2)d="0123456789ABCDEF".indexOf(a.charAt(l)),e="0123456789ABCDEF".indexOf(a.charAt(l+1)),b[c]=16*d+e,c++;return b};d.num2hex=function(a){for(var b="#",c,d,e=0;3>e;e++)c=a[e]/16,d=a[e]%16,b+="0123456789ABCDEF".charAt(c)+"0123456789ABCDEF".charAt(d);return b}; +v.prototype.addItem=function(a,b,c){function d(a){var b=this.value;b&&b.has_submenu&&e.call(this,a)}function e(a){var b=this.value,d=!0;l.current_submenu&&l.current_submenu.close(a);if(c.callback){var n=c.callback.call(this,b,c,a,l,c.node);!0===n&&(d=!1)}if(b&&(b.callback&&!c.ignore_item_callbacks&&!0!==b.disabled&&(n=b.callback.call(this,b,c,a,l,c.node),!0===n&&(d=!1)),b.submenu)){if(!b.submenu.options)throw"ContextMenu submenu needs options";new l.constructor(b.submenu.options,{callback:b.submenu.callback, +event:a,parentMenu:l,ignore_item_callbacks:b.submenu.ignore_item_callbacks,title:b.submenu.title,autoopen:c.autoopen});d=!1}d&&!l.lock&&l.close()}var l=this;c=c||{};var n=document.createElement("div");n.className="litemenu-entry submenu";var f=!1;if(null===b)n.classList.add("separator");else{n.innerHTML=b&&b.title?b.title:a;if(n.value=b)b.disabled&&(f=!0,n.classList.add("disabled")),(b.submenu||b.has_submenu)&&n.classList.add("has_submenu");"function"==typeof b?(n.dataset.value=a,n.onclick_callback= +b):n.dataset.value=b;b.className&&(n.className+=" "+b.className)}this.root.appendChild(n);f||n.addEventListener("click",e);c.autoopen&&n.addEventListener("mouseenter",d);return n};v.prototype.close=function(a,b){this.root.parentNode&&this.root.parentNode.removeChild(this.root);this.parentMenu&&!b&&(this.parentMenu.lock=!1,this.parentMenu.current_submenu=null,void 0===a?this.parentMenu.close():a&&!v.isCursorOverElement(a,this.parentMenu.root)&&v.trigger(this.parentMenu.root,"mouseleave",a));this.current_submenu&& +this.current_submenu.close(a,!0)};v.trigger=function(a,b,c,d){var e=document.createEvent("CustomEvent");e.initCustomEvent(b,!0,!0,c);e.srcElement=d;a.dispatchEvent?a.dispatchEvent(e):a.__events&&a.__events.dispatchEvent(e);return e};v.prototype.getTopMenu=function(){return this.options.parentMenu?this.options.parentMenu.getTopMenu():this};v.prototype.getFirstEvent=function(){return this.options.parentMenu?this.options.parentMenu.getFirstEvent():this.options.event};v.isCursorOverElement=function(a, +b){var c=a.pageX,d=a.pageY,e=b.getBoundingClientRect();return e?d>e.top&&de.left&&cd.canvasY-this.pos[1]||v.distance([d.canvasX,d.canvasY],[this.pos[0]+this.center[0],this.pos[1]+this.center[1]])>this.radius)return!1;this.oldmouse=[d.canvasX-this.pos[0],d.canvasY-this.pos[1]];this.captureInput(!0);return!0}};f.prototype.onMouseMove=function(d){if(this.oldmouse){d=[d.canvasX-this.pos[0],d.canvasY-this.pos[1]];var e=this.value,e=e-0.01*(d[1]-this.oldmouse[1]);1e&&(e=0);this.value=e;this.properties.value= +this.properties.min+(this.properties.max-this.properties.min)*this.value;this.oldmouse=d;this.setDirtyCanvas(!0)}};f.prototype.onMouseUp=function(d){this.oldmouse&&(this.oldmouse=null,this.captureInput(!1))};f.prototype.onMouseLeave=function(d){};f.prototype.onWidget=function(d,e){if("increase"==e.name)this.onPropertyChanged("size",this.properties.size+10);else if("decrease"==e.name)this.onPropertyChanged("size",this.properties.size-10)};f.prototype.onPropertyChanged=function(d,e){if("wcolor"==d)this.properties[d]= +e;else if("size"==d)e=parseInt(e),this.properties[d]=e,this.size=[e+4,e+24],this.setDirtyCanvas(!0,!0);else if("min"==d||"max"==d||"value"==d)this.properties[d]=parseFloat(e);else return!1;return!0};v.registerNodeType("widget/knob",f);e.title="H.Slider";e.desc="Linear slider controller";e.prototype.onAdded=function(){this.value=0.5;this.imgfg=this.loadImage("imgs/slider_fg.png")};e.prototype.onDrawVectorial=function(d){this.imgfg&&this.imgfg.width&&(d.lineWidth=1,d.strokeStyle=this.mouseOver?"#FFF": +"#AAA",d.fillStyle="#000",d.beginPath(),d.rect(2,0,this.size[0]-4,20),d.stroke(),d.fillStyle=this.properties.wcolor,d.beginPath(),d.rect(2+(this.size[0]-4-20)*this.value,0,20,20),d.fill())};e.prototype.onDrawImage=function(d){this.imgfg&&this.imgfg.width&&(d.lineWidth=1,d.fillStyle="#000",d.fillRect(2,9,this.size[0]-4,2),d.strokeStyle="#333",d.beginPath(),d.moveTo(2,9),d.lineTo(this.size[0]-4,9),d.stroke(),d.strokeStyle="#AAA",d.beginPath(),d.moveTo(2,11),d.lineTo(this.size[0]-4,11),d.stroke(),d.drawImage(this.imgfg, +2+(this.size[0]-4)*this.value-0.5*this.imgfg.width,0.5*-this.imgfg.height+10))};e.prototype.onDrawForeground=function(d){this.onDrawImage(d)};e.prototype.onExecute=function(){this.properties.value=this.properties.min+(this.properties.max-this.properties.min)*this.value;this.setOutputData(0,this.properties.value);this.boxcolor=v.colorToString([this.value,this.value,this.value])};e.prototype.onMouseDown=function(d){if(0>d.canvasY-this.pos[1])return!1;this.oldmouse=[d.canvasX-this.pos[0],d.canvasY-this.pos[1]]; +this.captureInput(!0);return!0};e.prototype.onMouseMove=function(d){if(this.oldmouse){d=[d.canvasX-this.pos[0],d.canvasY-this.pos[1]];var e=this.value,e=e+(d[0]-this.oldmouse[0])/this.size[0];1e&&(e=0);this.value=e;this.oldmouse=d;this.setDirtyCanvas(!0)}};e.prototype.onMouseUp=function(d){this.oldmouse=null;this.captureInput(!1)};e.prototype.onMouseLeave=function(d){};e.prototype.onPropertyChanged=function(d,e){if("wcolor"==d)this.properties[d]=e;else return!1;return!0};v.registerNodeType("widget/hslider", +e);t.title="Progress";t.desc="Shows data in linear progress";t.prototype.onExecute=function(){var d=this.getInputData(0);void 0!=d&&(this.properties.value=d)};t.prototype.onDrawForeground=function(d){d.lineWidth=1;d.fillStyle=this.properties.wcolor;var e=(this.properties.value-this.properties.min)/(this.properties.max-this.properties.min),e=Math.min(1,e),e=Math.max(0,e);d.fillRect(2,2,(this.size[0]-4)*e,this.size[1]-4)};v.registerNodeType("widget/progress",t);p.title="Text";p.desc="Shows the input value"; +p.widgets=[{name:"resize",text:"Resize box",type:"button"},{name:"led_text",text:"LED",type:"minibutton"},{name:"normal_text",text:"Normal",type:"minibutton"}];p.prototype.onDrawForeground=function(d){d.fillStyle=this.properties.color;var e=this.properties.value;this.properties.glowSize?(d.shadowColor=this.properties.color,d.shadowOffsetX=0,d.shadowOffsetY=0,d.shadowBlur=this.properties.glowSize):d.shadowColor="transparent";var l=this.properties.fontsize;d.textAlign=this.properties.align;d.font=l.toString()+ +"px "+this.properties.font;this.str="number"==typeof e?e.toFixed(this.properties.decimals):e;if("string"==typeof this.str){var e=this.str.split("\\n"),a;for(a in e)d.fillText(e[a],"left"==this.properties.align?15:this.size[0]-15,-0.15*l+l*(parseInt(a)+1))}d.shadowColor="transparent";this.last_ctx=d;d.textAlign="left"};p.prototype.onExecute=function(){var d=this.getInputData(0);null!=d&&(this.properties.value=d)};p.prototype.resize=function(){if(this.last_ctx){var d=this.str.split("\\n");this.last_ctx.font= +this.properties.fontsize+"px "+this.properties.font;var e=0,l;for(l in d){var a=this.last_ctx.measureText(d[l]).width;ef?e.xbox.axes.lx:0,this._left_axis[1]=Math.abs(e.xbox.axes.ly)>f?e.xbox.axes.ly:0,this._right_axis[0]=Math.abs(e.xbox.axes.rx)>f?e.xbox.axes.rx:0,this._right_axis[1]=Math.abs(e.xbox.axes.ry)>f?e.xbox.axes.ry:0,this._triggers[0]=Math.abs(e.xbox.axes.ltrigger)>f?e.xbox.axes.ltrigger:0,this._triggers[1]=Math.abs(e.xbox.axes.rtrigger)>f?e.xbox.axes.rtrigger:0);if(this.outputs)for(f= +0;fe;e++)if(f[e]){e=f[e];f=this.xbox_mapping;f||(f=this.xbox_mapping= +{axes:[],buttons:{},hat:""});f.axes.lx=e.axes[0];f.axes.ly=e.axes[1];f.axes.rx=e.axes[2];f.axes.ry=e.axes[3];f.axes.ltrigger=e.buttons[6].value;f.axes.rtrigger=e.buttons[7].value;for(var g=0;g","string",{values:k.values}); +this.size=[60,40]}function r(){this.addInput("inc","number");this.addOutput("total","number");this.addProperty("increment",1);this.addProperty("value",0)}function n(){this.addInput("v","number");this.addOutput("sin","number");this.addProperty("amplitude",1);this.addProperty("offset",0);this.bgImageUrl="nodes/imgs/icon-sin.png"}function A(){this.addInput("vec2","vec2");this.addOutput("x","number");this.addOutput("y","number")}function z(){this.addInputs([["x","number"],["y","number"]]);this.addOutput("vec2", +"vec2");this.properties={x:0,y:0};this._data=new Float32Array(2)}function B(){this.addInput("vec3","vec3");this.addOutput("x","number");this.addOutput("y","number");this.addOutput("z","number")}function w(){this.addInputs([["x","number"],["y","number"],["z","number"]]);this.addOutput("vec3","vec3");this.properties={x:0,y:0,z:0};this._data=new Float32Array(3)}function y(){this.addInput("vec4","vec4");this.addOutput("x","number");this.addOutput("y","number");this.addOutput("z","number");this.addOutput("w", +"number")}function D(){this.addInputs([["x","number"],["y","number"],["z","number"],["w","number"]]);this.addOutput("vec4","vec4");this.properties={x:0,y:0,z:0,w:0};this._data=new Float32Array(4)}var x=q.LiteGraph;g.title="Converter";g.desc="type A to type B";g.prototype.onExecute=function(){var a=this.getInputData(0);if(null!=a&&this.outputs)for(var b=0;bb&&(this._current=0);for(var c=a=0;cb&&(b=1);this.properties.samples=Math.round(b);var c=this._values;this._values=new Float32Array(this.properties.samples); +c.length<=this._values.length?this._values.set(c):this._values.set(c.subarray(0,this._values.length))};x.registerNodeType("math/average",b);c.values="+-*/%^".split("");c.title="Operation";c.desc="Easy math operators";c["@OP"]={type:"enum",title:"operation",values:c.values};c.prototype.setValue=function(a){"string"==typeof a&&(a=parseFloat(a));this.properties.value=a};c.prototype.onExecute=function(){var a=this.getInputData(0),b=this.getInputData(1);null!=a?this.properties.A=a:a=this.properties.A; +null!=b?this.properties.B=b:b=this.properties.B;var c=0;switch(this.properties.OP){case "+":c=a+b;break;case "-":c=a-b;break;case "x":case "X":case "*":c=a*b;break;case "/":c=a/b;break;case "%":c=a%b;break;case "^":c=Math.pow(a,b);break;default:console.warn("Unknown operation: "+this.properties.OP)}this.setOutputData(0,c)};c.prototype.onDrawBackground=function(a){this.flags.collapsed||(a.font="40px Arial",a.fillStyle="black",a.textAlign="center",a.fillText(this.properties.OP,0.5*this.size[0],0.5* +this.size[1]+x.NODE_TITLE_HEIGHT),a.textAlign="left")};x.registerNodeType("math/operation",c);h.title="Compare";h.desc="compares between two values";h.prototype.onExecute=function(){var a=this.getInputData(0),b=this.getInputData(1);void 0!==a?this.properties.A=a:a=this.properties.A;void 0!==b?this.properties.B=b:b=this.properties.B;for(var c=0,d=this.outputs.length;cB":value= +a>b;break;case "A=B":value=a>=b}this.setOutputData(c,value)}}};h.prototype.onGetOutputs=function(){return[["A==B","boolean"],["A!=B","boolean"],["A>B","boolean"],["A=B","boolean"],["A<=B","boolean"]]};x.registerNodeType("math/compare",h);k.values="> < == != <= >=".split(" ");k["@OP"]={type:"enum",title:"operation",values:k.values};k.title="Condition";k.desc="evaluates condition between A and B";k.prototype.onExecute=function(){var a= +this.getInputData(0);void 0===a?a=this.properties.A:this.properties.A=a;var b=this.getInputData(1);void 0===b?b=this.properties.B:this.properties.B=b;var c=!0;switch(this.properties.OP){case ">":c=a>b;break;case "<":c=a=":c=a>=b}this.setOutputData(0,c)};x.registerNodeType("math/condition",k);r.title="Accumulate";r.desc="Increments a value every time";r.prototype.onExecute=function(){null===this.properties.value&& +(this.properties.value=0);var a=this.getInputData(0);this.properties.value=null!==a?this.properties.value+a:this.properties.value+this.properties.increment;this.setOutputData(0,this.properties.value)};x.registerNodeType("math/accumulate",r);n.title="Trigonometry";n.desc="Sin Cos Tan";n.filter="shader";n.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=0);var b=this.properties.amplitude,c=this.findInputSlot("amplitude");-1!=c&&(b=this.getInputData(c));var d=this.properties.offset, c=this.findInputSlot("offset");-1!=c&&(d=this.getInputData(c));for(var c=0,e=this.outputs.length;cXY";y.desc="vector 2 to components";y.prototype.onExecute=function(){var a=this.getInputData(0);null!=a&&(this.setOutputData(0, -a[0]),this.setOutputData(1,a[1]))};w.registerNodeType("math3d/vec2-to-xyz",y);x.title="XY->Vec2";x.desc="components to vector2";x.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=this.properties.x);var b=this.getInputData(1);null==b&&(b=this.properties.y);var c=this._data;c[0]=a;c[1]=b;this.setOutputData(0,c)};w.registerNodeType("math3d/xy-to-vec2",x);z.title="Vec3->XYZ";z.desc="vector 3 to components";z.prototype.onExecute=function(){var a=this.getInputData(0);null!=a&&(this.setOutputData(0, -a[0]),this.setOutputData(1,a[1]),this.setOutputData(2,a[2]))};w.registerNodeType("math3d/vec3-to-xyz",z);A.title="XYZ->Vec3";A.desc="components to vector3";A.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=this.properties.x);var b=this.getInputData(1);null==b&&(b=this.properties.y);var c=this.getInputData(2);null==c&&(c=this.properties.z);var d=this._data;d[0]=a;d[1]=b;d[2]=c;this.setOutputData(0,d)};w.registerNodeType("math3d/xyz-to-vec3",A);C.title="Vec4->XYZW";C.desc="vector 4 to components"; -C.prototype.onExecute=function(){var a=this.getInputData(0);null!=a&&(this.setOutputData(0,a[0]),this.setOutputData(1,a[1]),this.setOutputData(2,a[2]),this.setOutputData(3,a[3]))};w.registerNodeType("math3d/vec4-to-xyzw",C);D.title="XYZW->Vec4";D.desc="components to vector4";D.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=this.properties.x);var b=this.getInputData(1);null==b&&(b=this.properties.y);var c=this.getInputData(2);null==c&&(c=this.properties.z);var d=this.getInputData(3); -null==d&&(d=this.properties.w);var e=this._data;e[0]=a;e[1]=b;e[2]=c;e[3]=d;this.setOutputData(0,e)};w.registerNodeType("math3d/xyzw-to-vec4",D);r.glMatrix&&(r=function(){this.addOutput("quat","quat");this.properties={x:0,y:0,z:0,w:1};this._value=quat.create()},r.title="Quaternion",r.desc="quaternion",r.prototype.onExecute=function(){this._value[0]=this.properties.x;this._value[1]=this.properties.y;this._value[2]=this.properties.z;this._value[3]=this.properties.w;this.setOutputData(0,this._value)}, -w.registerNodeType("math3d/quaternion",r),r=function(){this.addInputs([["degrees","number"],["axis","vec3"]]);this.addOutput("quat","quat");this.properties={angle:90,axis:vec3.fromValues(0,1,0)};this._value=quat.create()},r.title="Rotation",r.desc="quaternion rotation",r.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=this.properties.angle);var b=this.getInputData(1);null==b&&(b=this.properties.axis);a=quat.setAxisAngle(this._value,b,0.0174532925*a);this.setOutputData(0,a)}, -w.registerNodeType("math3d/rotation",r),r=function(){this.addInputs([["vec3","vec3"],["quat","quat"]]);this.addOutput("result","vec3");this.properties={vec:[0,0,1]}},r.title="Rot. Vec3",r.desc="rotate a point",r.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=this.properties.vec);var b=this.getInputData(1);null==b?this.setOutputData(a):this.setOutputData(0,vec3.transformQuat(vec3.create(),a,b))},w.registerNodeType("math3d/rotate_vec3",r),r=function(){this.addInputs([["A","quat"], -["B","quat"]]);this.addOutput("A*B","quat");this._value=quat.create()},r.title="Mult. Quat",r.desc="rotate quaternion",r.prototype.onExecute=function(){var a=this.getInputData(0);if(null!=a){var b=this.getInputData(1);null!=b&&(a=quat.multiply(this._value,a,b),this.setOutputData(0,a))}},w.registerNodeType("math3d/mult-quat",r),r=function(){this.addInputs([["A","quat"],["B","quat"],["factor","number"]]);this.addOutput("slerp","quat");this.addProperty("factor",0.5);this._value=quat.create()},r.title= -"Quat Slerp",r.desc="quaternion spherical interpolation",r.prototype.onExecute=function(){var a=this.getInputData(0);if(null!=a){var b=this.getInputData(1);if(null!=b){var c=this.properties.factor;null!=this.getInputData(2)&&(c=this.getInputData(2));a=quat.slerp(this._value,a,b,c);this.setOutputData(0,a)}}},w.registerNodeType("math3d/quat-slerp",r))})(this); -(function(r){function e(){this.addInput("sel","boolean");this.addOutput("value","number");this.properties={A:0,B:1};this.size=[60,20]}r=r.LiteGraph;e.title="Selector";e.desc="outputs A if selector is true, B if selector is false";e.prototype.onExecute=function(){var e=this.getInputData(0);if(void 0!==e){for(var d=1;da&&(a=0);if(0!=d.length){var b=[0,0,0];if(0==a)b=d[0];else if(1==a)b=d[d.length-1];else{var c=(d.length-1)*a,a=d[Math.floor(c)],d=d[Math.floor(c)+1],c=c-Math.floor(c);b[0]=a[0]*(1-c)+d[0]*c;b[1]=a[1]*(1-c)+d[1]*c;b[2]=a[2]*(1-c)+d[2]*c}for(var e in b)b[e]/=255;this.boxcolor=colorToString(b);this.setOutputData(0,b)}};f.registerNodeType("color/palette",g);d.title="Frame";d.desc="Frame viewerew";d.widgets=[{name:"resize", -text:"Resize box",type:"button"},{name:"view",text:"View Image",type:"button"}];d.prototype.onDrawBackground=function(d){this.frame&&d.drawImage(this.frame,0,0,this.size[0],this.size[1])};d.prototype.onExecute=function(){this.frame=this.getInputData(0);this.setDirtyCanvas(!0)};d.prototype.onWidget=function(d,a){if("resize"==a.name&&this.frame){var b=this.frame.width,c=this.frame.height;b||null==this.frame.videoWidth||(b=this.frame.videoWidth,c=this.frame.videoHeight);b&&c&&(this.size=[b,c]);this.setDirtyCanvas(!0, -!0)}else"view"==a.name&&this.show()};d.prototype.show=function(){showElement&&this.frame&&showElement(this.frame)};f.registerNodeType("graphics/frame",d);q.title="Image fade";q.desc="Fades between images";q.widgets=[{name:"resizeA",text:"Resize to A",type:"button"},{name:"resizeB",text:"Resize to B",type:"button"}];q.prototype.onAdded=function(){this.createCanvas();var d=this.canvas.getContext("2d");d.fillStyle="#000";d.fillRect(0,0,this.properties.width,this.properties.height)};q.prototype.createCanvas= -function(){this.canvas=document.createElement("canvas");this.canvas.width=this.properties.width;this.canvas.height=this.properties.height};q.prototype.onExecute=function(){var d=this.canvas.getContext("2d");this.canvas.width=this.canvas.width;var a=this.getInputData(0);null!=a&&d.drawImage(a,0,0,this.canvas.width,this.canvas.height);a=this.getInputData(2);null==a?a=this.properties.fade:this.properties.fade=a;d.globalAlpha=a;a=this.getInputData(1);null!=a&&d.drawImage(a,0,0,this.canvas.width,this.canvas.height); -d.globalAlpha=1;this.setOutputData(0,this.canvas);this.setDirtyCanvas(!0)};f.registerNodeType("graphics/imagefade",q);l.title="Crop";l.desc="Crop Image";l.prototype.onAdded=function(){this.createCanvas()};l.prototype.createCanvas=function(){this.canvas=document.createElement("canvas");this.canvas.width=this.properties.width;this.canvas.height=this.properties.height};l.prototype.onExecute=function(){var d=this.getInputData(0);d&&(d.width?(this.canvas.getContext("2d").drawImage(d,-this.properties.x, --this.properties.y,d.width*this.properties.scale,d.height*this.properties.scale),this.setOutputData(0,this.canvas)):this.setOutputData(0,null))};l.prototype.onDrawBackground=function(d){this.flags.collapsed||this.canvas&&d.drawImage(this.canvas,0,0,this.canvas.width,this.canvas.height,0,0,this.size[0],this.size[1])};l.prototype.onPropertyChanged=function(d,a){this.properties[d]=a;"scale"==d?(this.properties[d]=parseFloat(a),0==this.properties[d]&&(this.trace("Error in scale"),this.properties[d]=1)): -this.properties[d]=parseInt(a);this.createCanvas();return!0};f.registerNodeType("graphics/cropImage",l);t.title="Video";t.desc="Video playback";t.widgets=[{name:"play",text:"PLAY",type:"minibutton"},{name:"stop",text:"STOP",type:"minibutton"},{name:"demo",text:"Demo video",type:"button"},{name:"mute",text:"Mute video",type:"button"}];t.prototype.onExecute=function(){if(this.properties.url&&(this.properties.url!=this._video_url&&this.loadVideo(this.properties.url),this._video&&0!=this._video.width)){var d= -this.getInputData(0);d&&0<=d&&1>=d&&(this._video.currentTime=d*this._video.duration,this._video.pause());this._video.dirty=!0;this.setOutputData(0,this._video);this.setOutputData(1,this._video.currentTime);this.setOutputData(2,this._video.duration);this.setDirtyCanvas(!0)}};t.prototype.onStart=function(){this.play()};t.prototype.onStop=function(){this.stop()};t.prototype.loadVideo=function(d){this._video_url=d;this._video=document.createElement("video");this._video.src=d;this._video.type="type=video/mp4"; -this._video.muted=!0;this._video.autoplay=!0;var a=this;this._video.addEventListener("loadedmetadata",function(b){a.trace("Duration: "+this.duration+" seconds");a.trace("Size: "+this.videoWidth+","+this.videoHeight);a.setDirtyCanvas(!0);this.width=this.videoWidth;this.height=this.videoHeight});this._video.addEventListener("progress",function(a){});this._video.addEventListener("error",function(b){console.log("Error loading video: "+this.src);a.trace("Error loading video: "+this.src);if(this.error)switch(this.error.code){case this.error.MEDIA_ERR_ABORTED:a.trace("You stopped the video."); -break;case this.error.MEDIA_ERR_NETWORK:a.trace("Network error - please try again later.");break;case this.error.MEDIA_ERR_DECODE:a.trace("Video is broken..");break;case this.error.MEDIA_ERR_SRC_NOT_SUPPORTED:a.trace("Sorry, your browser can't play this video.")}});this._video.addEventListener("ended",function(b){a.trace("Ended.");this.play()})};t.prototype.onPropertyChanged=function(d,a){this.properties[d]=a;"url"==d&&""!=a&&this.loadVideo(a);return!0};t.prototype.play=function(){this._video&&this._video.play()}; -t.prototype.playPause=function(){this._video&&(this._video.paused?this.play():this.pause())};t.prototype.stop=function(){this._video&&(this._video.pause(),this._video.currentTime=0)};t.prototype.pause=function(){this._video&&(this.trace("Video paused"),this._video.pause())};t.prototype.onWidget=function(d,a){};f.registerNodeType("graphics/video",t);u.title="Webcam";u.desc="Webcam image";u.prototype.openStream=function(){function d(b){console.log("Webcam rejected",b);a._webcam_stream=!1;a.box_color= -"red"}navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia;window.URL=window.URL||window.webkitURL;if(navigator.getUserMedia){this._waiting_confirmation=!0;navigator.getUserMedia({video:!0},this.streamReady.bind(this),d);var a=this}};u.prototype.onRemoved=function(){this._webcam_stream&&(this._webcam_stream.stop(),this._video=this._webcam_stream=null)};u.prototype.streamReady=function(d){this._webcam_stream=d;var a=this._video; -a||(a=document.createElement("video"),a.autoplay=!0,a.src=window.URL.createObjectURL(d),this._video=a,a.onloadedmetadata=function(a){console.log(a)})};u.prototype.onExecute=function(){null!=this._webcam_stream||this._waiting_confirmation||this.openStream();this._video&&this._video.videoWidth&&(this._video.width=this._video.videoWidth,this._video.height=this._video.videoHeight,this.setOutputData(0,this._video))};u.prototype.getExtraMenuOptions=function(d){var a=this;return[{content:a.properties.show? -"Hide Frame":"Show Frame",callback:function(){a.properties.show=!a.properties.show}}]};u.prototype.onDrawBackground=function(d){this.flags.collapsed||20>=this.size[1]||!this.properties.show||!this._video||(d.save(),d.drawImage(this._video,0,0,this.size[0],this.size[1]),d.restore())};f.registerNodeType("graphics/webcam",u)})(this); -(function(r){var e=r.LiteGraph;r.LGraphTexture=null;if("undefined"!=typeof GL){var g=function(){this.addOutput("Texture","Texture");this.properties={name:"",filter:!0};this.size=[g.image_preview_size,g.image_preview_size]};r.LGraphTexture=g;g.title="Texture";g.desc="Texture";g.widgets_info={name:{widget:"texture"},filter:{widget:"checkbox"}};g.loadTextureCallback=null;g.image_preview_size=256;g.PASS_THROUGH=1;g.COPY=2;g.LOW=3;g.HIGH=4;g.REUSE=5;g.DEFAULT=2;g.MODE_VALUES={"pass through":g.PASS_THROUGH, -copy:g.COPY,low:g.LOW,high:g.HIGH,reuse:g.REUSE,"default":g.DEFAULT};g.getTexturesContainer=function(){return gl.textures};g.loadTexture=function(a,b){b=b||{};var c=a;"http://"==c.substr(0,7)&&e.proxy&&(c=e.proxy+c.substr(7));return g.getTexturesContainer()[a]=GL.Texture.fromURL(c,b)};g.getTexture=function(a){var b=this.getTexturesContainer();if(!b)throw"Cannot load texture, container of textures not found";b=b[a];return!b&&a&&":"!=a[0]?this.loadTexture(a):b};g.getTargetTexture=function(a,b,c){if(!a)throw"LGraphTexture.getTargetTexture expects a reference texture"; -var d=null;switch(c){case g.LOW:d=gl.UNSIGNED_BYTE;break;case g.HIGH:d=gl.HIGH_PRECISION_FORMAT;break;case g.REUSE:return a;default:d=a?a.type:gl.UNSIGNED_BYTE}b&&b.width==a.width&&b.height==a.height&&b.type==d||(b=new GL.Texture(a.width,a.height,{type:d,format:gl.RGBA,filter:gl.LINEAR}));return b};g.getNoiseTexture=function(){if(this._noise_texture)return this._noise_texture;for(var a=new Uint8Array(1048576),b=0;1048576>b;++b)a[b]=255*Math.random();return this._noise_texture=a=GL.Texture.fromMemory(512, -512,a,{format:gl.RGBA,wrap:gl.REPEAT,filter:gl.NEAREST})};g.prototype.onDropFile=function(a,b,c){if(a){var d=null;"string"==typeof a?d=GL.Texture.fromURL(a):-1!=b.toLowerCase().indexOf(".dds")?d=GL.Texture.fromDDSInMemory(a):(a=new Blob([c]),a=URL.createObjectURL(a),d=GL.Texture.fromURL(a));this._drop_texture=d;this.properties.name=b}else this._drop_texture=null,this.properties.name=""};g.prototype.getExtraMenuOptions=function(a){var b=this;if(this._drop_texture)return[{content:"Clear",callback:function(){b._drop_texture= -null;b.properties.name=""}}]};g.prototype.onExecute=function(){var a=null;this.isOutputConnected(1)&&(a=this.getInputData(0));!a&&this._drop_texture&&(a=this._drop_texture);!a&&this.properties.name&&(a=g.getTexture(this.properties.name));if(a){this._last_tex=a;!1===this.properties.filter?a.setParameter(gl.TEXTURE_MAG_FILTER,gl.NEAREST):a.setParameter(gl.TEXTURE_MAG_FILTER,gl.LINEAR);this.setOutputData(0,a);for(var b=1;b=this.size[1]))if(this._drop_texture&&a.webgl)a.drawImage(this._drop_texture,0,0,this.size[0],this.size[1]);else{if(this._last_preview_tex!=this._last_tex)if(a.webgl)this._canvas=this._last_tex;else{var b=g.generateLowResTexturePreview(this._last_tex); -if(!b)return;this._last_preview_tex=this._last_tex;this._canvas=cloneCanvas(b)}this._canvas&&(a.save(),a.webgl||(a.translate(0,this.size[1]),a.scale(1,-1)),a.drawImage(this._canvas,0,0,this.size[0],this.size[1]),a.restore())}};g.generateLowResTexturePreview=function(a){if(!a)return null;var b=g.image_preview_size,c=a;if(a.format==gl.DEPTH_COMPONENT)return null;if(a.width>b||a.height>b)c=this._preview_temp_tex,this._preview_temp_tex||(this._preview_temp_tex=c=new GL.Texture(b,b,{minFilter:gl.NEAREST})), -a.copyTo(c);a=this._preview_canvas;a||(this._preview_canvas=a=createCanvas(b,b));c&&c.toCanvas(a);return a};g.prototype.getResources=function(a){a[this.properties.name]=GL.Texture;return a};g.prototype.onGetInputs=function(){return[["in","Texture"]]};g.prototype.onGetOutputs=function(){return[["width","number"],["height","number"],["aspect","number"]]};e.registerNodeType("texture/texture",g);var d=function(){this.addInput("Texture","Texture");this.properties={flipY:!1};this.size=[g.image_preview_size, -g.image_preview_size]};d.title="Preview";d.desc="Show a texture in the graph canvas";d.allow_preview=!1;d.prototype.onDrawBackground=function(a){if(!this.flags.collapsed&&(a.webgl||d.allow_preview)){var b=this.getInputData(0);if(b){var c=null,c=!b.handle&&a.webgl?b:g.generateLowResTexturePreview(b);a.save();this.properties.flipY&&(a.translate(0,this.size[1]),a.scale(1,-1));a.drawImage(c,0,0,this.size[0],this.size[1]);a.restore()}}};e.registerNodeType("texture/preview",d);r=function(){this.addInput("Texture", -"Texture");this.addOutput("","Texture");this.properties={name:""}};r.title="Save";r.desc="Save a texture in the repository";r.prototype.onExecute=function(){var a=this.getInputData(0);a&&(this.properties.name&&(g.storeTexture?g.storeTexture(this.properties.name,a):g.getTexturesContainer()[this.properties.name]=a),this.setOutputData(0,a))};e.registerNodeType("texture/save",r);var q=function(){this.addInput("Texture","Texture");this.addInput("TextureB","Texture");this.addInput("value","number");this.addOutput("Texture", -"Texture");this.help="

pixelcode must be vec3

\t\t\t

uvcode must be vec2, is optional

\t\t\t

uv: tex. coords

color: texture

colorB: textureB

time: scene time

value: input value

";this.properties={value:1,uvcode:"",pixelcode:"color + colorB * value",precision:g.DEFAULT}};q.widgets_info={uvcode:{widget:"textarea",height:100},pixelcode:{widget:"textarea",height:100},precision:{widget:"combo", -values:g.MODE_VALUES}};q.title="Operation";q.desc="Texture shader operation";q.prototype.getExtraMenuOptions=function(a){var b=this;return[{content:b.properties.show?"Hide Texture":"Show Texture",callback:function(){b.properties.show=!b.properties.show}}]};q.prototype.onDrawBackground=function(a){this.flags.collapsed||20>=this.size[1]||!this.properties.show||!this._tex||this._tex.gl!=a||(a.save(),a.drawImage(this._tex,0,0,this.size[0],this.size[1]),a.restore())};q.prototype.onExecute=function(){var a= -this.getInputData(0);if(this.isOutputConnected(0))if(this.properties.precision===g.PASS_THROUGH)this.setOutputData(0,a);else{var b=this.getInputData(1);if(this.properties.uvcode||this.properties.pixelcode){var c=512,d=512;a?(c=a.width,d=a.height):b&&(c=b.width,d=b.height);this._tex=a||this._tex?g.getTargetTexture(a||this._tex,this._tex,this.properties.precision):new GL.Texture(c,d,{type:this.precision===g.LOW?gl.UNSIGNED_BYTE:gl.HIGH_PRECISION_FORMAT,format:gl.RGBA,filter:gl.LINEAR});var e="";this.properties.uvcode&& -(e="uv = "+this.properties.uvcode,-1!=this.properties.uvcode.indexOf(";")&&(e=this.properties.uvcode));var f="";this.properties.pixelcode&&(f="result = "+this.properties.pixelcode,-1!=this.properties.pixelcode.indexOf(";")&&(f=this.properties.pixelcode));var h=this._shader;if(!h||this._shader_code!=e+"|"+f){try{this._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,q.pixel_shader,{UV_CODE:e,PIXEL_CODE:f}),this.boxcolor="#00FF00"}catch(n){console.log("Error compiling shader: ",n);this.boxcolor="#FF0000"; -return}this.boxcolor="#FF0000";this._shader_code=e+"|"+f;h=this._shader}if(h){this.boxcolor="green";var l=this.getInputData(2);null!=l?this.properties.value=l:l=parseFloat(this.properties.value);var k=this.graph.getTime();this._tex.drawTo(function(){gl.disable(gl.DEPTH_TEST);gl.disable(gl.CULL_FACE);gl.disable(gl.BLEND);a&&a.bind(0);b&&b.bind(1);var e=Mesh.getScreenQuad();h.uniforms({u_texture:0,u_textureB:1,value:l,texSize:[c,d],time:k}).draw(e)});this.setOutputData(0,this._tex)}else this.boxcolor= -"red"}}};q.pixel_shader="precision highp float;\n\t\t\t\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform sampler2D u_textureB;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform vec2 texSize;\n\t\t\tuniform float time;\n\t\t\tuniform float value;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec2 uv = v_coord;\n\t\t\t\tUV_CODE;\n\t\t\t\tvec4 color4 = texture2D(u_texture, uv);\n\t\t\t\tvec3 color = color4.rgb;\n\t\t\t\tvec4 color4B = texture2D(u_textureB, uv);\n\t\t\t\tvec3 colorB = color4B.rgb;\n\t\t\t\tvec3 result = color;\n\t\t\t\tfloat alpha = 1.0;\n\t\t\t\tPIXEL_CODE;\n\t\t\t\tgl_FragColor = vec4(result, alpha);\n\t\t\t}\n\t\t\t"; -e.registerNodeType("texture/operation",q);var l=function(){this.addOutput("Texture","Texture");this.properties={code:"",width:512,height:512};this.properties.code="\nvoid main() {\n vec2 uv = v_coord;\n vec3 color = vec3(0.0);\n//your code here\n\ngl_FragColor = vec4(color, 1.0);\n}\n"};l.title="Shader";l.desc="Texture shader";l.widgets_info={code:{type:"code"},precision:{widget:"combo",values:g.MODE_VALUES}};l.prototype.onPropertyChanged=function(a,b){if("code"==a){var c=this.getShader();if(c){var d= -c.uniformInfo;if(this.inputs)for(var e={},f=0;fXY";A.desc="vector 2 to components";A.prototype.onExecute=function(){var a=this.getInputData(0);null!=a&&(this.setOutputData(0, +a[0]),this.setOutputData(1,a[1]))};x.registerNodeType("math3d/vec2-to-xyz",A);z.title="XY->Vec2";z.desc="components to vector2";z.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=this.properties.x);var b=this.getInputData(1);null==b&&(b=this.properties.y);var c=this._data;c[0]=a;c[1]=b;this.setOutputData(0,c)};x.registerNodeType("math3d/xy-to-vec2",z);B.title="Vec3->XYZ";B.desc="vector 3 to components";B.prototype.onExecute=function(){var a=this.getInputData(0);null!=a&&(this.setOutputData(0, +a[0]),this.setOutputData(1,a[1]),this.setOutputData(2,a[2]))};x.registerNodeType("math3d/vec3-to-xyz",B);w.title="XYZ->Vec3";w.desc="components to vector3";w.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=this.properties.x);var b=this.getInputData(1);null==b&&(b=this.properties.y);var c=this.getInputData(2);null==c&&(c=this.properties.z);var d=this._data;d[0]=a;d[1]=b;d[2]=c;this.setOutputData(0,d)};x.registerNodeType("math3d/xyz-to-vec3",w);y.title="Vec4->XYZW";y.desc="vector 4 to components"; +y.prototype.onExecute=function(){var a=this.getInputData(0);null!=a&&(this.setOutputData(0,a[0]),this.setOutputData(1,a[1]),this.setOutputData(2,a[2]),this.setOutputData(3,a[3]))};x.registerNodeType("math3d/vec4-to-xyzw",y);D.title="XYZW->Vec4";D.desc="components to vector4";D.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=this.properties.x);var b=this.getInputData(1);null==b&&(b=this.properties.y);var c=this.getInputData(2);null==c&&(c=this.properties.z);var d=this.getInputData(3); +null==d&&(d=this.properties.w);var e=this._data;e[0]=a;e[1]=b;e[2]=c;e[3]=d;this.setOutputData(0,e)};x.registerNodeType("math3d/xyzw-to-vec4",D);q.glMatrix&&(q=function(){this.addOutput("quat","quat");this.properties={x:0,y:0,z:0,w:1};this._value=quat.create()},q.title="Quaternion",q.desc="quaternion",q.prototype.onExecute=function(){this._value[0]=this.properties.x;this._value[1]=this.properties.y;this._value[2]=this.properties.z;this._value[3]=this.properties.w;this.setOutputData(0,this._value)}, +x.registerNodeType("math3d/quaternion",q),q=function(){this.addInputs([["degrees","number"],["axis","vec3"]]);this.addOutput("quat","quat");this.properties={angle:90,axis:vec3.fromValues(0,1,0)};this._value=quat.create()},q.title="Rotation",q.desc="quaternion rotation",q.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=this.properties.angle);var b=this.getInputData(1);null==b&&(b=this.properties.axis);a=quat.setAxisAngle(this._value,b,0.0174532925*a);this.setOutputData(0,a)}, +x.registerNodeType("math3d/rotation",q),q=function(){this.addInputs([["vec3","vec3"],["quat","quat"]]);this.addOutput("result","vec3");this.properties={vec:[0,0,1]}},q.title="Rot. Vec3",q.desc="rotate a point",q.prototype.onExecute=function(){var a=this.getInputData(0);null==a&&(a=this.properties.vec);var b=this.getInputData(1);null==b?this.setOutputData(a):this.setOutputData(0,vec3.transformQuat(vec3.create(),a,b))},x.registerNodeType("math3d/rotate_vec3",q),q=function(){this.addInputs([["A","quat"], +["B","quat"]]);this.addOutput("A*B","quat");this._value=quat.create()},q.title="Mult. Quat",q.desc="rotate quaternion",q.prototype.onExecute=function(){var a=this.getInputData(0);if(null!=a){var b=this.getInputData(1);null!=b&&(a=quat.multiply(this._value,a,b),this.setOutputData(0,a))}},x.registerNodeType("math3d/mult-quat",q),q=function(){this.addInputs([["A","quat"],["B","quat"],["factor","number"]]);this.addOutput("slerp","quat");this.addProperty("factor",0.5);this._value=quat.create()},q.title= +"Quat Slerp",q.desc="quaternion spherical interpolation",q.prototype.onExecute=function(){var a=this.getInputData(0);if(null!=a){var b=this.getInputData(1);if(null!=b){var c=this.properties.factor;null!=this.getInputData(2)&&(c=this.getInputData(2));a=quat.slerp(this._value,a,b,c);this.setOutputData(0,a)}}},x.registerNodeType("math3d/quat-slerp",q))})(this); +(function(q){function g(){this.addInput("sel","boolean");this.addOutput("value","number");this.properties={A:0,B:1};this.size=[60,20]}q=q.LiteGraph;g.title="Selector";g.desc="outputs A if selector is true, B if selector is false";g.prototype.onExecute=function(){var f=this.getInputData(0);if(void 0!==f){for(var e=1;ee&&(e=0);if(0!=d.length){var a=[0,0,0];if(0==e)a=d[0];else if(1==e)a=d[d.length-1];else{var b=(d.length-1)*e,e=d[Math.floor(b)],d=d[Math.floor(b)+1],b=b-Math.floor(b);a[0]=e[0]*(1-b)+d[0]*b;a[1]=e[1]*(1-b)+d[1]*b;a[2]=e[2]*(1-b)+d[2]*b}for(var c in a)a[c]/=255;this.boxcolor=colorToString(a);this.setOutputData(0,a)}};d.registerNodeType("color/palette",f);e.title="Frame";e.desc="Frame viewerew";e.widgets=[{name:"resize", +text:"Resize box",type:"button"},{name:"view",text:"View Image",type:"button"}];e.prototype.onDrawBackground=function(d){this.frame&&d.drawImage(this.frame,0,0,this.size[0],this.size[1])};e.prototype.onExecute=function(){this.frame=this.getInputData(0);this.setDirtyCanvas(!0)};e.prototype.onWidget=function(d,e){if("resize"==e.name&&this.frame){var a=this.frame.width,b=this.frame.height;a||null==this.frame.videoWidth||(a=this.frame.videoWidth,b=this.frame.videoHeight);a&&b&&(this.size=[a,b]);this.setDirtyCanvas(!0, +!0)}else"view"==e.name&&this.show()};e.prototype.show=function(){showElement&&this.frame&&showElement(this.frame)};d.registerNodeType("graphics/frame",e);t.title="Image fade";t.desc="Fades between images";t.widgets=[{name:"resizeA",text:"Resize to A",type:"button"},{name:"resizeB",text:"Resize to B",type:"button"}];t.prototype.onAdded=function(){this.createCanvas();var d=this.canvas.getContext("2d");d.fillStyle="#000";d.fillRect(0,0,this.properties.width,this.properties.height)};t.prototype.createCanvas= +function(){this.canvas=document.createElement("canvas");this.canvas.width=this.properties.width;this.canvas.height=this.properties.height};t.prototype.onExecute=function(){var d=this.canvas.getContext("2d");this.canvas.width=this.canvas.width;var e=this.getInputData(0);null!=e&&d.drawImage(e,0,0,this.canvas.width,this.canvas.height);e=this.getInputData(2);null==e?e=this.properties.fade:this.properties.fade=e;d.globalAlpha=e;e=this.getInputData(1);null!=e&&d.drawImage(e,0,0,this.canvas.width,this.canvas.height); +d.globalAlpha=1;this.setOutputData(0,this.canvas);this.setDirtyCanvas(!0)};d.registerNodeType("graphics/imagefade",t);p.title="Crop";p.desc="Crop Image";p.prototype.onAdded=function(){this.createCanvas()};p.prototype.createCanvas=function(){this.canvas=document.createElement("canvas");this.canvas.width=this.properties.width;this.canvas.height=this.properties.height};p.prototype.onExecute=function(){var d=this.getInputData(0);d&&(d.width?(this.canvas.getContext("2d").drawImage(d,-this.properties.x, +-this.properties.y,d.width*this.properties.scale,d.height*this.properties.scale),this.setOutputData(0,this.canvas)):this.setOutputData(0,null))};p.prototype.onDrawBackground=function(d){this.flags.collapsed||this.canvas&&d.drawImage(this.canvas,0,0,this.canvas.width,this.canvas.height,0,0,this.size[0],this.size[1])};p.prototype.onPropertyChanged=function(d,e){this.properties[d]=e;"scale"==d?(this.properties[d]=parseFloat(e),0==this.properties[d]&&(this.trace("Error in scale"),this.properties[d]=1)): +this.properties[d]=parseInt(e);this.createCanvas();return!0};d.registerNodeType("graphics/cropImage",p);u.title="Video";u.desc="Video playback";u.widgets=[{name:"play",text:"PLAY",type:"minibutton"},{name:"stop",text:"STOP",type:"minibutton"},{name:"demo",text:"Demo video",type:"button"},{name:"mute",text:"Mute video",type:"button"}];u.prototype.onExecute=function(){if(this.properties.url&&(this.properties.url!=this._video_url&&this.loadVideo(this.properties.url),this._video&&0!=this._video.width)){var d= +this.getInputData(0);d&&0<=d&&1>=d&&(this._video.currentTime=d*this._video.duration,this._video.pause());this._video.dirty=!0;this.setOutputData(0,this._video);this.setOutputData(1,this._video.currentTime);this.setOutputData(2,this._video.duration);this.setDirtyCanvas(!0)}};u.prototype.onStart=function(){this.play()};u.prototype.onStop=function(){this.stop()};u.prototype.loadVideo=function(d){this._video_url=d;this._video=document.createElement("video");this._video.src=d;this._video.type="type=video/mp4"; +this._video.muted=!0;this._video.autoplay=!0;var e=this;this._video.addEventListener("loadedmetadata",function(a){e.trace("Duration: "+this.duration+" seconds");e.trace("Size: "+this.videoWidth+","+this.videoHeight);e.setDirtyCanvas(!0);this.width=this.videoWidth;this.height=this.videoHeight});this._video.addEventListener("progress",function(a){});this._video.addEventListener("error",function(a){console.log("Error loading video: "+this.src);e.trace("Error loading video: "+this.src);if(this.error)switch(this.error.code){case this.error.MEDIA_ERR_ABORTED:e.trace("You stopped the video."); +break;case this.error.MEDIA_ERR_NETWORK:e.trace("Network error - please try again later.");break;case this.error.MEDIA_ERR_DECODE:e.trace("Video is broken..");break;case this.error.MEDIA_ERR_SRC_NOT_SUPPORTED:e.trace("Sorry, your browser can't play this video.")}});this._video.addEventListener("ended",function(a){e.trace("Ended.");this.play()})};u.prototype.onPropertyChanged=function(d,e){this.properties[d]=e;"url"==d&&""!=e&&this.loadVideo(e);return!0};u.prototype.play=function(){this._video&&this._video.play()}; +u.prototype.playPause=function(){this._video&&(this._video.paused?this.play():this.pause())};u.prototype.stop=function(){this._video&&(this._video.pause(),this._video.currentTime=0)};u.prototype.pause=function(){this._video&&(this.trace("Video paused"),this._video.pause())};u.prototype.onWidget=function(d,e){};d.registerNodeType("graphics/video",u);v.title="Webcam";v.desc="Webcam image";v.prototype.openStream=function(){function d(a){console.log("Webcam rejected",a);e._webcam_stream=!1;e.box_color= +"red"}navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia;window.URL=window.URL||window.webkitURL;if(navigator.getUserMedia){this._waiting_confirmation=!0;navigator.getUserMedia({video:!0},this.streamReady.bind(this),d);var e=this}};v.prototype.onRemoved=function(){this._webcam_stream&&(this._webcam_stream.stop(),this._video=this._webcam_stream=null)};v.prototype.streamReady=function(d){this._webcam_stream=d;var e=this._video; +e||(e=document.createElement("video"),e.autoplay=!0,e.src=window.URL.createObjectURL(d),this._video=e,e.onloadedmetadata=function(a){console.log(a)})};v.prototype.onExecute=function(){null!=this._webcam_stream||this._waiting_confirmation||this.openStream();this._video&&this._video.videoWidth&&(this._video.width=this._video.videoWidth,this._video.height=this._video.videoHeight,this.setOutputData(0,this._video))};v.prototype.getExtraMenuOptions=function(d){var e=this;return[{content:e.properties.show? +"Hide Frame":"Show Frame",callback:function(){e.properties.show=!e.properties.show}}]};v.prototype.onDrawBackground=function(d){this.flags.collapsed||20>=this.size[1]||!this.properties.show||!this._video||(d.save(),d.drawImage(this._video,0,0,this.size[0],this.size[1]),d.restore())};d.registerNodeType("graphics/webcam",v)})(this); +(function(q){var g=q.LiteGraph;q.LGraphTexture=null;if("undefined"!=typeof GL){var f=function(){this.addOutput("Texture","Texture");this.properties={name:"",filter:!0};this.size=[f.image_preview_size,f.image_preview_size]};q.LGraphTexture=f;f.title="Texture";f.desc="Texture";f.widgets_info={name:{widget:"texture"},filter:{widget:"checkbox"}};f.loadTextureCallback=null;f.image_preview_size=256;f.PASS_THROUGH=1;f.COPY=2;f.LOW=3;f.HIGH=4;f.REUSE=5;f.DEFAULT=2;f.MODE_VALUES={"pass through":f.PASS_THROUGH, +copy:f.COPY,low:f.LOW,high:f.HIGH,reuse:f.REUSE,"default":f.DEFAULT};f.getTexturesContainer=function(){return gl.textures};f.loadTexture=function(a,b){b=b||{};var c=a;"http://"==c.substr(0,7)&&g.proxy&&(c=g.proxy+c.substr(7));return f.getTexturesContainer()[a]=GL.Texture.fromURL(c,b)};f.getTexture=function(a){var b=this.getTexturesContainer();if(!b)throw"Cannot load texture, container of textures not found";b=b[a];return!b&&a&&":"!=a[0]?this.loadTexture(a):b};f.getTargetTexture=function(a,b,c){if(!a)throw"LGraphTexture.getTargetTexture expects a reference texture"; +var d=null;switch(c){case f.LOW:d=gl.UNSIGNED_BYTE;break;case f.HIGH:d=gl.HIGH_PRECISION_FORMAT;break;case f.REUSE:return a;default:d=a?a.type:gl.UNSIGNED_BYTE}b&&b.width==a.width&&b.height==a.height&&b.type==d||(b=new GL.Texture(a.width,a.height,{type:d,format:gl.RGBA,filter:gl.LINEAR}));return b};f.getNoiseTexture=function(){if(this._noise_texture)return this._noise_texture;for(var a=new Uint8Array(1048576),b=0;1048576>b;++b)a[b]=255*Math.random();return this._noise_texture=a=GL.Texture.fromMemory(512, +512,a,{format:gl.RGBA,wrap:gl.REPEAT,filter:gl.NEAREST})};f.prototype.onDropFile=function(a,b,c){if(a){var d=null;"string"==typeof a?d=GL.Texture.fromURL(a):-1!=b.toLowerCase().indexOf(".dds")?d=GL.Texture.fromDDSInMemory(a):(a=new Blob([c]),a=URL.createObjectURL(a),d=GL.Texture.fromURL(a));this._drop_texture=d;this.properties.name=b}else this._drop_texture=null,this.properties.name=""};f.prototype.getExtraMenuOptions=function(a){var b=this;if(this._drop_texture)return[{content:"Clear",callback:function(){b._drop_texture= +null;b.properties.name=""}}]};f.prototype.onExecute=function(){var a=null;this.isOutputConnected(1)&&(a=this.getInputData(0));!a&&this._drop_texture&&(a=this._drop_texture);!a&&this.properties.name&&(a=f.getTexture(this.properties.name));if(a){this._last_tex=a;!1===this.properties.filter?a.setParameter(gl.TEXTURE_MAG_FILTER,gl.NEAREST):a.setParameter(gl.TEXTURE_MAG_FILTER,gl.LINEAR);this.setOutputData(0,a);for(var b=1;b=this.size[1]))if(this._drop_texture&&a.webgl)a.drawImage(this._drop_texture,0,0,this.size[0],this.size[1]);else{if(this._last_preview_tex!=this._last_tex)if(a.webgl)this._canvas=this._last_tex;else{var b=f.generateLowResTexturePreview(this._last_tex); +if(!b)return;this._last_preview_tex=this._last_tex;this._canvas=cloneCanvas(b)}this._canvas&&(a.save(),a.webgl||(a.translate(0,this.size[1]),a.scale(1,-1)),a.drawImage(this._canvas,0,0,this.size[0],this.size[1]),a.restore())}};f.generateLowResTexturePreview=function(a){if(!a)return null;var b=f.image_preview_size,c=a;if(a.format==gl.DEPTH_COMPONENT)return null;if(a.width>b||a.height>b)c=this._preview_temp_tex,this._preview_temp_tex||(this._preview_temp_tex=c=new GL.Texture(b,b,{minFilter:gl.NEAREST})), +a.copyTo(c);a=this._preview_canvas;a||(this._preview_canvas=a=createCanvas(b,b));c&&c.toCanvas(a);return a};f.prototype.getResources=function(a){a[this.properties.name]=GL.Texture;return a};f.prototype.onGetInputs=function(){return[["in","Texture"]]};f.prototype.onGetOutputs=function(){return[["width","number"],["height","number"],["aspect","number"]]};g.registerNodeType("texture/texture",f);var e=function(){this.addInput("Texture","Texture");this.properties={flipY:!1};this.size=[f.image_preview_size, +f.image_preview_size]};e.title="Preview";e.desc="Show a texture in the graph canvas";e.allow_preview=!1;e.prototype.onDrawBackground=function(a){if(!this.flags.collapsed&&(a.webgl||e.allow_preview)){var b=this.getInputData(0);if(b){var c=null,c=!b.handle&&a.webgl?b:f.generateLowResTexturePreview(b);a.save();this.properties.flipY&&(a.translate(0,this.size[1]),a.scale(1,-1));a.drawImage(c,0,0,this.size[0],this.size[1]);a.restore()}}};g.registerNodeType("texture/preview",e);q=function(){this.addInput("Texture", +"Texture");this.addOutput("","Texture");this.properties={name:""}};q.title="Save";q.desc="Save a texture in the repository";q.prototype.onExecute=function(){var a=this.getInputData(0);a&&(this.properties.name&&(f.storeTexture?f.storeTexture(this.properties.name,a):f.getTexturesContainer()[this.properties.name]=a),this.setOutputData(0,a))};g.registerNodeType("texture/save",q);var t=function(){this.addInput("Texture","Texture");this.addInput("TextureB","Texture");this.addInput("value","number");this.addOutput("Texture", +"Texture");this.help="

pixelcode must be vec3

\t\t\t

uvcode must be vec2, is optional

\t\t\t

uv: tex. coords

color: texture

colorB: textureB

time: scene time

value: input value

";this.properties={value:1,uvcode:"",pixelcode:"color + colorB * value",precision:f.DEFAULT}};t.widgets_info={uvcode:{widget:"textarea",height:100},pixelcode:{widget:"textarea",height:100},precision:{widget:"combo", +values:f.MODE_VALUES}};t.title="Operation";t.desc="Texture shader operation";t.prototype.getExtraMenuOptions=function(a){var b=this;return[{content:b.properties.show?"Hide Texture":"Show Texture",callback:function(){b.properties.show=!b.properties.show}}]};t.prototype.onDrawBackground=function(a){this.flags.collapsed||20>=this.size[1]||!this.properties.show||!this._tex||this._tex.gl!=a||(a.save(),a.drawImage(this._tex,0,0,this.size[0],this.size[1]),a.restore())};t.prototype.onExecute=function(){var a= +this.getInputData(0);if(this.isOutputConnected(0))if(this.properties.precision===f.PASS_THROUGH)this.setOutputData(0,a);else{var b=this.getInputData(1);if(this.properties.uvcode||this.properties.pixelcode){var c=512,d=512;a?(c=a.width,d=a.height):b&&(c=b.width,d=b.height);this._tex=a||this._tex?f.getTargetTexture(a||this._tex,this._tex,this.properties.precision):new GL.Texture(c,d,{type:this.precision===f.LOW?gl.UNSIGNED_BYTE:gl.HIGH_PRECISION_FORMAT,format:gl.RGBA,filter:gl.LINEAR});var e="";this.properties.uvcode&& +(e="uv = "+this.properties.uvcode,-1!=this.properties.uvcode.indexOf(";")&&(e=this.properties.uvcode));var n="";this.properties.pixelcode&&(n="result = "+this.properties.pixelcode,-1!=this.properties.pixelcode.indexOf(";")&&(n=this.properties.pixelcode));var l=this._shader;if(!l||this._shader_code!=e+"|"+n){try{this._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,t.pixel_shader,{UV_CODE:e,PIXEL_CODE:n}),this.boxcolor="#00FF00"}catch(g){console.log("Error compiling shader: ",g);this.boxcolor="#FF0000"; +return}this.boxcolor="#FF0000";this._shader_code=e+"|"+n;l=this._shader}if(l){this.boxcolor="green";var h=this.getInputData(2);null!=h?this.properties.value=h:h=parseFloat(this.properties.value);var k=this.graph.getTime();this._tex.drawTo(function(){gl.disable(gl.DEPTH_TEST);gl.disable(gl.CULL_FACE);gl.disable(gl.BLEND);a&&a.bind(0);b&&b.bind(1);var e=Mesh.getScreenQuad();l.uniforms({u_texture:0,u_textureB:1,value:h,texSize:[c,d],time:k}).draw(e)});this.setOutputData(0,this._tex)}else this.boxcolor= +"red"}}};t.pixel_shader="precision highp float;\n\t\t\t\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform sampler2D u_textureB;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform vec2 texSize;\n\t\t\tuniform float time;\n\t\t\tuniform float value;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec2 uv = v_coord;\n\t\t\t\tUV_CODE;\n\t\t\t\tvec4 color4 = texture2D(u_texture, uv);\n\t\t\t\tvec3 color = color4.rgb;\n\t\t\t\tvec4 color4B = texture2D(u_textureB, uv);\n\t\t\t\tvec3 colorB = color4B.rgb;\n\t\t\t\tvec3 result = color;\n\t\t\t\tfloat alpha = 1.0;\n\t\t\t\tPIXEL_CODE;\n\t\t\t\tgl_FragColor = vec4(result, alpha);\n\t\t\t}\n\t\t\t"; +g.registerNodeType("texture/operation",t);var p=function(){this.addOutput("Texture","Texture");this.properties={code:"",width:512,height:512};this.properties.code="\nvoid main() {\n vec2 uv = v_coord;\n vec3 color = vec3(0.0);\n//your code here\n\ngl_FragColor = vec4(color, 1.0);\n}\n"};p.title="Shader";p.desc="Texture shader";p.widgets_info={code:{type:"code"},precision:{widget:"combo",values:f.MODE_VALUES}};p.prototype.onPropertyChanged=function(a,b){if("code"==a){var c=this.getShader();if(c){var d= +c.uniformInfo;if(this.inputs)for(var e={},f=0;f lumaMax))\n\t\t\t\t\tcolor = vec4(rgbA, 1.0);\n\t\t\t\telse\n\t\t\t\t\tcolor = vec4(rgbB, 1.0);\n\t\t\t\tif(u_igamma != 1.0)\n\t\t\t\t\tcolor.xyz = pow( color.xyz, vec3(u_igamma) );\n\t\t\t\treturn color;\n\t\t\t}\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t gl_FragColor = applyFXAA( u_texture, v_coord * uViewportSize) ;\n\t\t\t}\n\t\t\t"; -f.gamma_pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform float u_igamma;\n\t\t\tvoid main() {\n\t\t\t\tvec4 color = texture2D( u_texture, v_coord);\n\t\t\t\tcolor.xyz = pow(color.xyz, vec3(u_igamma) );\n\t\t\t gl_FragColor = color;\n\t\t\t}\n\t\t\t";e.registerNodeType("texture/toviewport",f);r=function(){this.addInput("Texture","Texture");this.addOutput("","Texture");this.properties={size:0,generate_mipmaps:!1, -precision:g.DEFAULT}};r.title="Copy";r.desc="Copy Texture";r.widgets_info={size:{widget:"combo",values:[0,32,64,128,256,512,1024,2048]},precision:{widget:"combo",values:g.MODE_VALUES}};r.prototype.onExecute=function(){var a=this.getInputData(0);if((a||this._temp_texture)&&this.isOutputConnected(0)){if(a){var b=a.width,c=a.height;0!=this.properties.size&&(c=b=this.properties.size);var d=this._temp_texture,e=a.type;this.properties.precision===g.LOW?e=gl.UNSIGNED_BYTE:this.properties.precision===g.HIGH&& -(e=gl.HIGH_PRECISION_FORMAT);d&&d.width==b&&d.height==c&&d.type==e||(d=gl.LINEAR,this.properties.generate_mipmaps&&isPowerOfTwo(b)&&isPowerOfTwo(c)&&(d=gl.LINEAR_MIPMAP_LINEAR),this._temp_texture=new GL.Texture(b,c,{type:e,format:gl.RGBA,minFilter:d,magFilter:gl.LINEAR}));a.copyTo(this._temp_texture);this.properties.generate_mipmaps&&(this._temp_texture.bind(0),gl.generateMipmap(this._temp_texture.texture_type),this._temp_texture.unbind(0))}this.setOutputData(0,this._temp_texture)}};e.registerNodeType("texture/copy", -r);var p=function(){this.addInput("Texture","Texture");this.addOutput("","Texture");this.properties={iterations:1,generate_mipmaps:!1,precision:g.DEFAULT}};p.title="Downsample";p.desc="Downsample Texture";p.widgets_info={iterations:{type:"number",step:1,precision:0,min:1},precision:{widget:"combo",values:g.MODE_VALUES}};p.prototype.onExecute=function(){var a=this.getInputData(0);if((a||this._temp_texture)&&this.isOutputConnected(0)&&a&&a.texture_type===GL.TEXTURE_2D){var b=p._shader;b||(p._shader= -b=new GL.Shader(GL.Shader.SCREEN_VERTEX_SHADER,p.pixel_shader));var c=a.width|0,d=a.height|0,e=a.type;this.properties.precision===g.LOW?e=gl.UNSIGNED_BYTE:this.properties.precision===g.HIGH&&(e=gl.HIGH_PRECISION_FORMAT);var f=this.properties.iterations||1,h=a,n=null,l=[],a={type:e,format:a.format},e=vec2.create(),k={u_offset:e};this._texture&&GL.Texture.releaseTemporary(this._texture);for(var t=0;t>1||0;d=d>>1||0;n=GL.Texture.getTemporary(c,d,a);l.push(n);h.setParameter(GL.TEXTURE_MAG_FILTER, -GL.NEAREST);h.copyTo(n,b,k);if(1==c&&1==d)break;h=n}this._texture=l.pop();for(t=0;td;++d)c[d]=Math.random();a._shader.uniforms({u_samples_a:c.subarray(0,16),u_samples_b:c.subarray(16,32)})}c=this._temp_texture;d=this.properties.low_precision?gl.UNSIGNED_BYTE:b.type;c&&c.type==d||(this._temp_texture=new GL.Texture(1,1,{type:d,format:gl.RGBA,filter:gl.NEAREST}));var e=a._shader,f=this._uniforms;f.u_mipmap_offset=this.properties.mipmap_offset;this._temp_texture.drawTo(function(){b.toViewport(e,f)});this.setOutputData(0,this._temp_texture)}}; -a.pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tuniform mat4 u_samples_a;\n\t\t\tuniform mat4 u_samples_b;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform float u_mipmap_offset;\n\t\t\tvarying vec2 v_coord;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec4 color = vec4(0.0);\n\t\t\t\tfor(int i = 0; i < 4; ++i)\n\t\t\t\t\tfor(int j = 0; j < 4; ++j)\n\t\t\t\t\t{\n\t\t\t\t\t\tcolor += texture2D(u_texture, vec2( u_samples_a[i][j], u_samples_b[i][j] ), u_mipmap_offset );\n\t\t\t\t\t\tcolor += texture2D(u_texture, vec2( 1.0 - u_samples_a[i][j], 1.0 - u_samples_b[i][j] ), u_mipmap_offset );\n\t\t\t\t\t}\n\t\t\t gl_FragColor = color * 0.03125;\n\t\t\t}\n\t\t\t"; -e.registerNodeType("texture/average",a);r=function(){this.addInput("Image","image");this.addOutput("","Texture");this.properties={}};r.title="Image to Texture";r.desc="Uploads an image to the GPU";r.prototype.onExecute=function(){var a=this.getInputData(0);if(a){var b=a.videoWidth||a.width,c=a.videoHeight||a.height;if(a.gltexture)this.setOutputData(0,a.gltexture);else{var d=this._temp_texture;d&&d.width==b&&d.height==c||(this._temp_texture=new GL.Texture(b,c,{format:gl.RGBA,filter:gl.LINEAR}));try{this._temp_texture.uploadImage(a)}catch(e){console.error("image comes from an unsafe location, cannot be uploaded to webgl"); -return}this.setOutputData(0,this._temp_texture)}}};e.registerNodeType("texture/imageToTexture",r);var b=function(){this.addInput("Texture","Texture");this.addInput("LUT","Texture");this.addInput("Intensity","number");this.addOutput("","Texture");this.properties={intensity:1,precision:g.DEFAULT,texture:null};b._shader||(b._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,b.pixel_shader))};b.widgets_info={precision:{widget:"combo",values:g.MODE_VALUES}};b.title="LUT";b.desc="Apply LUT to Texture";b.widgets_info= -{texture:{widget:"texture"}};b.prototype.onExecute=function(){if(this.isOutputConnected(0)){var a=this.getInputData(0);if(this.properties.precision===g.PASS_THROUGH)this.setOutputData(0,a);else if(a){var c=this.getInputData(1);c||(c=g.getTexture(this.properties.texture));if(c){c.bind(0);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);gl.bindTexture(gl.TEXTURE_2D, -null);var d=this.properties.intensity;this.isInputConnected(2)&&(this.properties.intensity=d=this.getInputData(2));this._tex=g.getTargetTexture(a,this._tex,this.properties.precision);this._tex.drawTo(function(){c.bind(1);a.toViewport(b._shader,{u_texture:0,u_textureB:1,u_amount:d})});this.setOutputData(0,this._tex)}else this.setOutputData(0,a)}}};b.pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform sampler2D u_textureB;\n\t\t\tuniform float u_amount;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\t lowp vec4 textureColor = clamp( texture2D(u_texture, v_coord), vec4(0.0), vec4(1.0) );\n\t\t\t\t mediump float blueColor = textureColor.b * 63.0;\n\t\t\t\t mediump vec2 quad1;\n\t\t\t\t quad1.y = floor(floor(blueColor) / 8.0);\n\t\t\t\t quad1.x = floor(blueColor) - (quad1.y * 8.0);\n\t\t\t\t mediump vec2 quad2;\n\t\t\t\t quad2.y = floor(ceil(blueColor) / 8.0);\n\t\t\t\t quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n\t\t\t\t highp vec2 texPos1;\n\t\t\t\t texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n\t\t\t\t texPos1.y = 1.0 - ((quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g));\n\t\t\t\t highp vec2 texPos2;\n\t\t\t\t texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n\t\t\t\t texPos2.y = 1.0 - ((quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g));\n\t\t\t\t lowp vec4 newColor1 = texture2D(u_textureB, texPos1);\n\t\t\t\t lowp vec4 newColor2 = texture2D(u_textureB, texPos2);\n\t\t\t\t lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n\t\t\t\t gl_FragColor = vec4( mix( textureColor.rgb, newColor.rgb, u_amount), textureColor.w);\n\t\t\t}\n\t\t\t"; -e.registerNodeType("texture/LUT",b);var c=function(){this.addInput("Texture","Texture");this.addOutput("R","Texture");this.addOutput("G","Texture");this.addOutput("B","Texture");this.addOutput("A","Texture");this.properties={};c._shader||(c._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,c.pixel_shader))};c.title="Texture to Channels";c.desc="Split texture channels";c.prototype.onExecute=function(){var a=this.getInputData(0);if(a){this._channels||(this._channels=Array(4));for(var b=0,d=0;4>d;d++)this.isOutputConnected(d)? -(this._channels[d]&&this._channels[d].width==a.width&&this._channels[d].height==a.height&&this._channels[d].type==a.type||(this._channels[d]=new GL.Texture(a.width,a.height,{type:a.type,format:gl.RGBA,filter:gl.LINEAR})),b++):this._channels[d]=null;if(b){gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);for(var e=Mesh.getScreenQuad(),f=c._shader,h=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]],d=0;4>d;d++)this._channels[d]&&(this._channels[d].drawTo(function(){a.bind(0);f.uniforms({u_texture:0,u_mask:h[d]}).draw(e)}), -this.setOutputData(d,this._channels[d]))}}};c.pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform vec4 u_mask;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t gl_FragColor = vec4( vec3( length( texture2D(u_texture, v_coord) * u_mask )), 1.0 );\n\t\t\t}\n\t\t\t";e.registerNodeType("texture/textureChannels",c);var h=function(){this.addInput("R","Texture");this.addInput("G","Texture");this.addInput("B","Texture");this.addInput("A", -"Texture");this.addOutput("Texture","Texture");this.properties={};h._shader||(h._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,h.pixel_shader))};h.title="Channels to Texture";h.desc="Split texture channels";h.prototype.onExecute=function(){var a=[this.getInputData(0),this.getInputData(1),this.getInputData(2),this.getInputData(3)];if(a[0]&&a[1]&&a[2]&&a[3]){gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);var b=Mesh.getScreenQuad(),c=h._shader;this._tex=g.getTargetTexture(a[0],this._tex);this._tex.drawTo(function(){a[0].bind(0); -a[1].bind(1);a[2].bind(2);a[3].bind(3);c.uniforms({u_textureR:0,u_textureG:1,u_textureB:2,u_textureA:3}).draw(b)});this.setOutputData(0,this._tex)}};h.pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_textureR;\n\t\t\tuniform sampler2D u_textureG;\n\t\t\tuniform sampler2D u_textureB;\n\t\t\tuniform sampler2D u_textureA;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t gl_FragColor = vec4( \t\t\t\t\t\ttexture2D(u_textureR, v_coord).r,\t\t\t\t\t\ttexture2D(u_textureG, v_coord).r,\t\t\t\t\t\ttexture2D(u_textureB, v_coord).r,\t\t\t\t\t\ttexture2D(u_textureA, v_coord).r);\n\t\t\t}\n\t\t\t"; -e.registerNodeType("texture/channelsTexture",h);var k=function(){this.addInput("A","color");this.addInput("B","color");this.addOutput("Texture","Texture");this.properties={angle:0,scale:1,A:[0,0,0],B:[1,1,1],texture_size:32};k._shader||(k._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,k.pixel_shader));this._uniforms={u_angle:0,u_colorA:vec3.create(),u_colorB:vec3.create()}};k.title="Gradient";k.desc="Generates a gradient";k["@A"]={type:"color"};k["@B"]={type:"color"};k["@texture_size"]={type:"enum", -values:[32,64,128,256,512]};k.prototype.onExecute=function(){gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);var a=GL.Mesh.getScreenQuad(),b=k._shader,c=this.getInputData(0);c||(c=this.properties.A);var d=this.getInputData(1);d||(d=this.properties.B);for(var e=2;e lumaMax))\n\t\t\t\t\tcolor = vec4(rgbA, 1.0);\n\t\t\t\telse\n\t\t\t\t\tcolor = vec4(rgbB, 1.0);\n\t\t\t\tif(u_igamma != 1.0)\n\t\t\t\t\tcolor.xyz = pow( color.xyz, vec3(u_igamma) );\n\t\t\t\treturn color;\n\t\t\t}\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t gl_FragColor = applyFXAA( u_texture, v_coord * uViewportSize) ;\n\t\t\t}\n\t\t\t"; +d.gamma_pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform float u_igamma;\n\t\t\tvoid main() {\n\t\t\t\tvec4 color = texture2D( u_texture, v_coord);\n\t\t\t\tcolor.xyz = pow(color.xyz, vec3(u_igamma) );\n\t\t\t gl_FragColor = color;\n\t\t\t}\n\t\t\t";g.registerNodeType("texture/toviewport",d);q=function(){this.addInput("Texture","Texture");this.addOutput("","Texture");this.properties={size:0,generate_mipmaps:!1, +precision:f.DEFAULT}};q.title="Copy";q.desc="Copy Texture";q.widgets_info={size:{widget:"combo",values:[0,32,64,128,256,512,1024,2048]},precision:{widget:"combo",values:f.MODE_VALUES}};q.prototype.onExecute=function(){var a=this.getInputData(0);if((a||this._temp_texture)&&this.isOutputConnected(0)){if(a){var b=a.width,c=a.height;0!=this.properties.size&&(c=b=this.properties.size);var d=this._temp_texture,e=a.type;this.properties.precision===f.LOW?e=gl.UNSIGNED_BYTE:this.properties.precision===f.HIGH&& +(e=gl.HIGH_PRECISION_FORMAT);d&&d.width==b&&d.height==c&&d.type==e||(d=gl.LINEAR,this.properties.generate_mipmaps&&isPowerOfTwo(b)&&isPowerOfTwo(c)&&(d=gl.LINEAR_MIPMAP_LINEAR),this._temp_texture=new GL.Texture(b,c,{type:e,format:gl.RGBA,minFilter:d,magFilter:gl.LINEAR}));a.copyTo(this._temp_texture);this.properties.generate_mipmaps&&(this._temp_texture.bind(0),gl.generateMipmap(this._temp_texture.texture_type),this._temp_texture.unbind(0))}this.setOutputData(0,this._temp_texture)}};g.registerNodeType("texture/copy", +q);var s=function(){this.addInput("Texture","Texture");this.addOutput("","Texture");this.properties={iterations:1,generate_mipmaps:!1,precision:f.DEFAULT}};s.title="Downsample";s.desc="Downsample Texture";s.widgets_info={iterations:{type:"number",step:1,precision:0,min:1},precision:{widget:"combo",values:f.MODE_VALUES}};s.prototype.onExecute=function(){var a=this.getInputData(0);if((a||this._temp_texture)&&this.isOutputConnected(0)&&a&&a.texture_type===GL.TEXTURE_2D){var b=s._shader;b||(s._shader= +b=new GL.Shader(GL.Shader.SCREEN_VERTEX_SHADER,s.pixel_shader));var c=a.width|0,d=a.height|0,e=a.type;this.properties.precision===f.LOW?e=gl.UNSIGNED_BYTE:this.properties.precision===f.HIGH&&(e=gl.HIGH_PRECISION_FORMAT);var n=this.properties.iterations||1,l=a,h=null,g=[],a={type:e,format:a.format},e=vec2.create(),k={u_offset:e};this._texture&&GL.Texture.releaseTemporary(this._texture);for(var u=0;u>1||0;d=d>>1||0;h=GL.Texture.getTemporary(c,d,a);g.push(h);l.setParameter(GL.TEXTURE_MAG_FILTER, +GL.NEAREST);l.copyTo(h,b,k);if(1==c&&1==d)break;l=h}this._texture=g.pop();for(u=0;uc;++c)b[c]=Math.random();l._shader.uniforms({u_samples_a:b.subarray(0,16),u_samples_b:b.subarray(16,32)})}b=this._temp_texture;c=this.properties.low_precision?gl.UNSIGNED_BYTE:a.type;b&&b.type==c||(this._temp_texture=new GL.Texture(1,1,{type:c,format:gl.RGBA,filter:gl.NEAREST}));var d=l._shader,e=this._uniforms;e.u_mipmap_offset=this.properties.mipmap_offset;this._temp_texture.drawTo(function(){a.toViewport(d,e)});this.setOutputData(0,this._temp_texture)}}; +l.pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tuniform mat4 u_samples_a;\n\t\t\tuniform mat4 u_samples_b;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform float u_mipmap_offset;\n\t\t\tvarying vec2 v_coord;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec4 color = vec4(0.0);\n\t\t\t\tfor(int i = 0; i < 4; ++i)\n\t\t\t\t\tfor(int j = 0; j < 4; ++j)\n\t\t\t\t\t{\n\t\t\t\t\t\tcolor += texture2D(u_texture, vec2( u_samples_a[i][j], u_samples_b[i][j] ), u_mipmap_offset );\n\t\t\t\t\t\tcolor += texture2D(u_texture, vec2( 1.0 - u_samples_a[i][j], 1.0 - u_samples_b[i][j] ), u_mipmap_offset );\n\t\t\t\t\t}\n\t\t\t gl_FragColor = color * 0.03125;\n\t\t\t}\n\t\t\t"; +g.registerNodeType("texture/average",l);q=function(){this.addInput("Image","image");this.addOutput("","Texture");this.properties={}};q.title="Image to Texture";q.desc="Uploads an image to the GPU";q.prototype.onExecute=function(){var a=this.getInputData(0);if(a){var b=a.videoWidth||a.width,c=a.videoHeight||a.height;if(a.gltexture)this.setOutputData(0,a.gltexture);else{var d=this._temp_texture;d&&d.width==b&&d.height==c||(this._temp_texture=new GL.Texture(b,c,{format:gl.RGBA,filter:gl.LINEAR}));try{this._temp_texture.uploadImage(a)}catch(e){console.error("image comes from an unsafe location, cannot be uploaded to webgl"); +return}this.setOutputData(0,this._temp_texture)}}};g.registerNodeType("texture/imageToTexture",q);var a=function(){this.addInput("Texture","Texture");this.addInput("LUT","Texture");this.addInput("Intensity","number");this.addOutput("","Texture");this.properties={intensity:1,precision:f.DEFAULT,texture:null};a._shader||(a._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,a.pixel_shader))};a.widgets_info={precision:{widget:"combo",values:f.MODE_VALUES}};a.title="LUT";a.desc="Apply LUT to Texture";a.widgets_info= +{texture:{widget:"texture"}};a.prototype.onExecute=function(){if(this.isOutputConnected(0)){var b=this.getInputData(0);if(this.properties.precision===f.PASS_THROUGH)this.setOutputData(0,b);else if(b){var c=this.getInputData(1);c||(c=f.getTexture(this.properties.texture));if(c){c.bind(0);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);gl.bindTexture(gl.TEXTURE_2D, +null);var d=this.properties.intensity;this.isInputConnected(2)&&(this.properties.intensity=d=this.getInputData(2));this._tex=f.getTargetTexture(b,this._tex,this.properties.precision);this._tex.drawTo(function(){c.bind(1);b.toViewport(a._shader,{u_texture:0,u_textureB:1,u_amount:d})});this.setOutputData(0,this._tex)}else this.setOutputData(0,b)}}};a.pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform sampler2D u_textureB;\n\t\t\tuniform float u_amount;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\t lowp vec4 textureColor = clamp( texture2D(u_texture, v_coord), vec4(0.0), vec4(1.0) );\n\t\t\t\t mediump float blueColor = textureColor.b * 63.0;\n\t\t\t\t mediump vec2 quad1;\n\t\t\t\t quad1.y = floor(floor(blueColor) / 8.0);\n\t\t\t\t quad1.x = floor(blueColor) - (quad1.y * 8.0);\n\t\t\t\t mediump vec2 quad2;\n\t\t\t\t quad2.y = floor(ceil(blueColor) / 8.0);\n\t\t\t\t quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n\t\t\t\t highp vec2 texPos1;\n\t\t\t\t texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n\t\t\t\t texPos1.y = 1.0 - ((quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g));\n\t\t\t\t highp vec2 texPos2;\n\t\t\t\t texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n\t\t\t\t texPos2.y = 1.0 - ((quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g));\n\t\t\t\t lowp vec4 newColor1 = texture2D(u_textureB, texPos1);\n\t\t\t\t lowp vec4 newColor2 = texture2D(u_textureB, texPos2);\n\t\t\t\t lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n\t\t\t\t gl_FragColor = vec4( mix( textureColor.rgb, newColor.rgb, u_amount), textureColor.w);\n\t\t\t}\n\t\t\t"; +g.registerNodeType("texture/LUT",a);var b=function(){this.addInput("Texture","Texture");this.addOutput("R","Texture");this.addOutput("G","Texture");this.addOutput("B","Texture");this.addOutput("A","Texture");this.properties={};b._shader||(b._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,b.pixel_shader))};b.title="Texture to Channels";b.desc="Split texture channels";b.prototype.onExecute=function(){var a=this.getInputData(0);if(a){this._channels||(this._channels=Array(4));for(var c=0,d=0;4>d;d++)this.isOutputConnected(d)? +(this._channels[d]&&this._channels[d].width==a.width&&this._channels[d].height==a.height&&this._channels[d].type==a.type||(this._channels[d]=new GL.Texture(a.width,a.height,{type:a.type,format:gl.RGBA,filter:gl.LINEAR})),c++):this._channels[d]=null;if(c){gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);for(var e=Mesh.getScreenQuad(),f=b._shader,n=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]],d=0;4>d;d++)this._channels[d]&&(this._channels[d].drawTo(function(){a.bind(0);f.uniforms({u_texture:0,u_mask:n[d]}).draw(e)}), +this.setOutputData(d,this._channels[d]))}}};b.pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform vec4 u_mask;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t gl_FragColor = vec4( vec3( length( texture2D(u_texture, v_coord) * u_mask )), 1.0 );\n\t\t\t}\n\t\t\t";g.registerNodeType("texture/textureChannels",b);var c=function(){this.addInput("R","Texture");this.addInput("G","Texture");this.addInput("B","Texture");this.addInput("A", +"Texture");this.addOutput("Texture","Texture");this.properties={};c._shader||(c._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,c.pixel_shader))};c.title="Channels to Texture";c.desc="Split texture channels";c.prototype.onExecute=function(){var a=[this.getInputData(0),this.getInputData(1),this.getInputData(2),this.getInputData(3)];if(a[0]&&a[1]&&a[2]&&a[3]){gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);var b=Mesh.getScreenQuad(),d=c._shader;this._tex=f.getTargetTexture(a[0],this._tex);this._tex.drawTo(function(){a[0].bind(0); +a[1].bind(1);a[2].bind(2);a[3].bind(3);d.uniforms({u_textureR:0,u_textureG:1,u_textureB:2,u_textureA:3}).draw(b)});this.setOutputData(0,this._tex)}};c.pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_textureR;\n\t\t\tuniform sampler2D u_textureG;\n\t\t\tuniform sampler2D u_textureB;\n\t\t\tuniform sampler2D u_textureA;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t gl_FragColor = vec4( \t\t\t\t\t\ttexture2D(u_textureR, v_coord).r,\t\t\t\t\t\ttexture2D(u_textureG, v_coord).r,\t\t\t\t\t\ttexture2D(u_textureB, v_coord).r,\t\t\t\t\t\ttexture2D(u_textureA, v_coord).r);\n\t\t\t}\n\t\t\t"; +g.registerNodeType("texture/channelsTexture",c);var h=function(){this.addInput("A","color");this.addInput("B","color");this.addOutput("Texture","Texture");this.properties={angle:0,scale:1,A:[0,0,0],B:[1,1,1],texture_size:32};h._shader||(h._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,h.pixel_shader));this._uniforms={u_angle:0,u_colorA:vec3.create(),u_colorB:vec3.create()}};h.title="Gradient";h.desc="Generates a gradient";h["@A"]={type:"color"};h["@B"]={type:"color"};h["@texture_size"]={type:"enum", +values:[32,64,128,256,512]};h.prototype.onExecute=function(){gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);var a=GL.Mesh.getScreenQuad(),b=h._shader,c=this.getInputData(0);c||(c=this.properties.A);var d=this.getInputData(1);d||(d=this.properties.B);for(var e=2;e=this.size[1]|| -!this._video||(a.save(),a.webgl?this._temp_texture&&a.drawImage(this._temp_texture,0,0,this.size[0],this.size[1]):(a.translate(0,this.size[1]),a.scale(1,-1),a.drawImage(this._video,0,0,this.size[0],this.size[1])),a.restore())};r.prototype.onExecute=function(){null!=this._webcam_stream||this._waiting_confirmation||this.openStream();if(this._video&&this._video.videoWidth){var a=this._video.videoWidth,b=this._video.videoHeight,c=this._temp_texture;c&&c.width==a&&c.height==b||(this._temp_texture=new GL.Texture(a, -b,{format:gl.RGB,filter:gl.LINEAR}));this._temp_texture.uploadImage(this._video);this.properties.texture_name&&(g.getTexturesContainer()[this.properties.texture_name]=this._temp_texture);this.setOutputData(0,this._temp_texture)}};e.registerNodeType("texture/webcam",r);var z=function(){this.addInput("in","Texture");this.addOutput("out","Texture");this.properties={key_color:vec3.fromValues(0,1,0),threshold:0.8,slope:0.2,precision:g.DEFAULT};z._shader||(z._shader=new GL.Shader(GL.Shader.SCREEN_VERTEX_SHADER, -z.pixel_shader))};z.title="Matte";z.desc="Extracts background";z.widgets_info={key_color:{widget:"color"},precision:{widget:"combo",values:g.MODE_VALUES}};z.prototype.onExecute=function(){if(this.isOutputConnected(0)){var a=this.getInputData(0);if(this.properties.precision===g.PASS_THROUGH)this.setOutputData(0,a);else if(a){this._tex=g.getTargetTexture(a,this._tex,this.properties.precision);gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);this._uniforms||(this._uniforms={u_texture:0,u_key_color:this.properties.key_color, -u_threshold:1,u_slope:1});var b=this._uniforms,c=Mesh.getScreenQuad(),d=z._shader;b.u_key_color=this.properties.key_color;b.u_threshold=this.properties.threshold;b.u_slope=this.properties.slope;this._tex.drawTo(function(){a.bind(0);d.uniforms(b).draw(c)});this.setOutputData(0,this._tex)}}};z.pixel_shader="precision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform vec3 u_key_color;\n\t\t\tuniform float u_threshold;\n\t\t\tuniform float u_slope;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec3 color = texture2D( u_texture, v_coord ).xyz;\n\t\t\t\tfloat diff = length( normalize(color) - normalize(u_key_color) );\n\t\t\t\tfloat edge = u_threshold * (1.0 - u_slope);\n\t\t\t\tfloat alpha = smoothstep( edge, u_threshold, diff);\n\t\t\t\tgl_FragColor = vec4( color, alpha );\n\t\t\t}"; -e.registerNodeType("texture/matte",z);r=function(){this.addOutput("Cubemap","Cubemap");this.properties={name:""};this.size=[g.image_preview_size,g.image_preview_size]};r.title="Cubemap";r.prototype.onDropFile=function(a,b,c){a?(this._drop_texture="string"==typeof a?GL.Texture.fromURL(a):GL.Texture.fromDDSInMemory(a),this.properties.name=b):(this._drop_texture=null,this.properties.name="")};r.prototype.onExecute=function(){if(this._drop_texture)this.setOutputData(0,this._drop_texture);else if(this.properties.name){var a= -g.getTexture(this.properties.name);a&&(this._last_tex=a,this.setOutputData(0,a))}};r.prototype.onDrawBackground=function(a){this.flags.collapsed||20>=this.size[1]||a.webgl&&(gl.meshes.cube||(gl.meshes.cube=GL.Mesh.cube({size:1})))};e.registerNodeType("texture/cubemap",r)}})(this); -(function(r){var e=r.LiteGraph;if("undefined"!=typeof GL){var g=function(){this.addInput("Texture","Texture");this.addInput("Aberration","number");this.addInput("Distortion","number");this.addInput("Blur","number");this.addOutput("Texture","Texture");this.properties={aberration:1,distortion:1,blur:1,precision:LGraphTexture.DEFAULT};g._shader||(g._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,g.pixel_shader),g._texture=new GL.Texture(3,1,{format:gl.RGB,wrap:gl.CLAMP_TO_EDGE,magFilter:gl.LINEAR, -minFilter:gl.LINEAR,pixel_data:[255,0,0,0,255,0,0,0,255]}))};g.title="Lens";g.desc="Camera Lens distortion";g.widgets_info={precision:{widget:"combo",values:LGraphTexture.MODE_VALUES}};g.prototype.onExecute=function(){var d=this.getInputData(0);if(this.properties.precision===LGraphTexture.PASS_THROUGH)this.setOutputData(0,d);else if(d){this._tex=LGraphTexture.getTargetTexture(d,this._tex,this.properties.precision);var e=this.properties.aberration;this.isInputConnected(1)&&(e=this.getInputData(1), -this.properties.aberration=e);var f=this.properties.distortion;this.isInputConnected(2)&&(f=this.getInputData(2),this.properties.distortion=f);var l=this.properties.blur;this.isInputConnected(3)&&(l=this.getInputData(3),this.properties.blur=l);gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);var a=Mesh.getScreenQuad(),b=g._shader;this._tex.drawTo(function(){d.bind(0);b.uniforms({u_texture:0,u_aberration:e,u_distortion:f,u_blur:l}).draw(a)});this.setOutputData(0,this._tex)}};g.pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform vec2 u_camera_planes;\n\t\t\tuniform float u_aberration;\n\t\t\tuniform float u_distortion;\n\t\t\tuniform float u_blur;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec2 coord = v_coord;\n\t\t\t\tfloat dist = distance(vec2(0.5), coord);\n\t\t\t\tvec2 dist_coord = coord - vec2(0.5);\n\t\t\t\tfloat percent = 1.0 + ((0.5 - dist) / 0.5) * u_distortion;\n\t\t\t\tdist_coord *= percent;\n\t\t\t\tcoord = dist_coord + vec2(0.5);\n\t\t\t\tvec4 color = texture2D(u_texture,coord, u_blur * dist);\n\t\t\t\tcolor.r = texture2D(u_texture,vec2(0.5) + dist_coord * (1.0+0.01*u_aberration), u_blur * dist ).r;\n\t\t\t\tcolor.b = texture2D(u_texture,vec2(0.5) + dist_coord * (1.0-0.01*u_aberration), u_blur * dist ).b;\n\t\t\t\tgl_FragColor = color;\n\t\t\t}\n\t\t\t"; -e.registerNodeType("fx/lens",g);window.LGraphFXLens=g;var d=function(){this.addInput("Texture","Texture");this.addInput("Blurred","Texture");this.addInput("Mask","Texture");this.addInput("Threshold","number");this.addOutput("Texture","Texture");this.properties={shape:"",size:10,alpha:1,threshold:1,high_precision:!1}};d.title="Bokeh";d.desc="applies an Bokeh effect";d.widgets_info={shape:{widget:"texture"}};d.prototype.onExecute=function(){var e=this.getInputData(0),g=this.getInputData(1),f=this.getInputData(2); -if(e&&f&&this.properties.shape){g||(g=e);var l=LGraphTexture.getTexture(this.properties.shape);if(l){var a=this.properties.threshold;this.isInputConnected(3)&&(a=this.getInputData(3),this.properties.threshold=a);var b=gl.UNSIGNED_BYTE;this.properties.high_precision&&(b=gl.half_float_ext?gl.HALF_FLOAT_OES:gl.FLOAT);this._temp_texture&&this._temp_texture.type==b&&this._temp_texture.width==e.width&&this._temp_texture.height==e.height||(this._temp_texture=new GL.Texture(e.width,e.height,{type:b,format:gl.RGBA, -filter:gl.LINEAR}));var c=d._first_shader;c||(c=d._first_shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,d._first_pixel_shader));var h=d._second_shader;h||(h=d._second_shader=new GL.Shader(d._second_vertex_shader,d._second_pixel_shader));var k=this._points_mesh;k&&k._width==e.width&&k._height==e.height&&2==k._spacing||(k=this.createPointsMesh(e.width,e.height,2));var q=Mesh.getScreenQuad(),s=this.properties.size,n=this.properties.alpha;gl.disable(gl.DEPTH_TEST);gl.disable(gl.BLEND);this._temp_texture.drawTo(function(){e.bind(0); -g.bind(1);f.bind(2);c.uniforms({u_texture:0,u_texture_blur:1,u_mask:2,u_texsize:[e.width,e.height]}).draw(q)});this._temp_texture.drawTo(function(){gl.enable(gl.BLEND);gl.blendFunc(gl.ONE,gl.ONE);e.bind(0);l.bind(3);h.uniforms({u_texture:0,u_mask:2,u_shape:3,u_alpha:n,u_threshold:a,u_pointSize:s,u_itexsize:[1/e.width,1/e.height]}).draw(k,gl.POINTS)});this.setOutputData(0,this._temp_texture)}}else this.setOutputData(0,e)};d.prototype.createPointsMesh=function(d,e,f){for(var g=Math.round(d/f),a=Math.round(e/ -f),b=new Float32Array(g*a*2),c=-1,h=2/d*f,l=2/e*f,q=0;q=e.NOTEON||b<=e.NOTEOFF)this.channel=a&15};Object.defineProperty(e.prototype,"velocity",{get:function(){return this.cmd==e.NOTEON?this.data[2]: --1},set:function(a){this.data[2]=a},enumerable:!0});e.notes="A A# B C C# D D# E F F# G G#".split(" ");e.prototype.getPitch=function(){return 440*Math.pow(2,(this.data[1]-69)/12)};e.computePitch=function(a){return 440*Math.pow(2,(a-69)/12)};e.prototype.getCC=function(){return this.data[1]};e.prototype.getCCValue=function(){return this.data[2]};e.prototype.getPitchBend=function(){return this.data[1]+(this.data[2]<<7)-8192};e.computePitchBend=function(a,b){return a+(b<<7)-8192};e.prototype.setCommandFromString= -function(a){this.cmd=e.computeCommandFromString(a)};e.computeCommandFromString=function(a){if(!a)return 0;if(a&&a.constructor===Number)return a;a=a.toUpperCase();switch(a){case "NOTE ON":case "NOTEON":return e.NOTEON;case "NOTE OFF":case "NOTEOFF":return e.NOTEON;case "KEY PRESSURE":case "KEYPRESSURE":return e.KEYPRESSURE;case "CONTROLLER CHANGE":case "CONTROLLERCHANGE":case "CC":return e.CONTROLLERCHANGE;case "PROGRAM CHANGE":case "PROGRAMCHANGE":case "PC":return e.PROGRAMCHANGE;case "CHANNEL PRESSURE":case "CHANNELPRESSURE":return e.CHANNELPRESSURE; -case "PITCH BEND":case "PITCHBEND":return e.PITCHBEND;case "TIME TICK":case "TIMETICK":return e.TIMETICK;default:return Number(a)}};e.toNoteString=function(a){var b;b=(a-21)%12;0>b&&(b=12+b);return e.notes[b]+Math.floor((a-24)/12+1)};e.prototype.toString=function(){var a=""+this.channel+". ";switch(this.cmd){case e.NOTEON:a+="NOTEON "+e.toNoteString(this.data[1]);break;case e.NOTEOFF:a+="NOTEOFF "+e.toNoteString(this.data[1]);break;case e.CONTROLLERCHANGE:a+="CC "+this.data[1]+" "+this.data[2];break; -case e.PROGRAMCHANGE:a+="PC "+this.data[1];break;case e.PITCHBEND:a+="PITCHBEND "+this.getPitchBend();break;case e.KEYPRESSURE:a+="KEYPRESS "+this.data[1]}return a};e.prototype.toHexString=function(){for(var a="",b=0;bthis.properties.max_value||this.trigger("on_midi",b)};p.registerNodeType("midi/filter",t);u.title="MIDIEvent";u.desc="Create a MIDI Event";u.prototype.onAction=function(a,b){"assign"==a?(this.properties.channel=b.channel,this.properties.cmd=b.cmd,this.properties.value1= -b.data[1],this.properties.value2=b.data[2]):(b=new e,b.channel=this.properties.channel,this.properties.cmd&&this.properties.cmd.constructor===String?b.setCommandFromString(this.properties.cmd):b.cmd=this.properties.cmd,b.data[0]=b.cmd|b.channel,b.data[1]=Number(this.properties.value1),b.data[2]=Number(this.properties.value2),this.trigger("on_midi",b))};u.prototype.onExecute=function(){var a=this.properties;if(this.outputs)for(var b=0;b=this.size[0]&&(e=this.size[0]-1),a.strokeStyle="red",a.beginPath(),a.moveTo(e,d),a.lineTo(e,0),a.stroke())}};b.title="Visualization";b.desc="Audio Visualization";v.registerNodeType("audio/visualization", -b);c.prototype.onExecute=function(){if(this._freqs=this.getInputData(0)){var a=this.properties.band,b=this.getInputData(1);void 0!==b&&(a=b);b=s.getAudioContext().sampleRate/this._freqs.length;b=a/b*2;b>=this._freqs.length?b=this._freqs[this._freqs.length-1]:(a=b|0,b-=a,b=this._freqs[a]*(1-b)+this._freqs[a+1]*b);this.setOutputData(0,b/255*this.properties.amplitude)}};c.prototype.onGetInputs=function(){return[["band","number"]]};c.title="Signal";c.desc="extract the signal of some frequency";v.registerNodeType("audio/signal", -c);h.prototype.onAdded=function(a){a.status==LGraph.STATUS_RUNNING&&(this.audionode.onaudioprocess=this._callback)};h["@code"]={widget:"code"};h.prototype.onStart=function(){this.audionode.onaudioprocess=this._callback};h.prototype.onStop=function(){this.audionode.onaudioprocess=h._bypass_function};h.prototype.onPause=function(){this.audionode.onaudioprocess=h._bypass_function};h.prototype.onUnpause=function(){this.audionode.onaudioprocess=this._callback};h.prototype.onExecute=function(){};h.prototype.onRemoved= -function(){this.audionode.onaudioprocess=h._bypass_function};h.prototype.processCode=function(){try{this._script=new new Function("properties",this.properties.code)(this.properties),this._old_code=this.properties.code,this._callback=this._script.onaudioprocess}catch(a){console.error("Error in onaudioprocess code",a),this._callback=h._bypass_function,this.audionode.onaudioprocess=this._callback}};h.prototype.onPropertyChanged=function(a,b){"code"==a&&(this.properties.code=b,this.processCode(),this.graph&& -this.graph.status==LGraph.STATUS_RUNNING&&(this.audionode.onaudioprocess=this._callback))};h.default_function=function(){this.onaudioprocess=function(a){var b=a.inputBuffer;a=a.outputBuffer;for(var c=0;c=this.size[1]|| +!this._video||(a.save(),a.webgl?this._temp_texture&&a.drawImage(this._temp_texture,0,0,this.size[0],this.size[1]):(a.translate(0,this.size[1]),a.scale(1,-1),a.drawImage(this._video,0,0,this.size[0],this.size[1])),a.restore())};q.prototype.onExecute=function(){null!=this._webcam_stream||this._waiting_confirmation||this.openStream();if(this._video&&this._video.videoWidth){var a=this._video.videoWidth,b=this._video.videoHeight,c=this._temp_texture;c&&c.width==a&&c.height==b||(this._temp_texture=new GL.Texture(a, +b,{format:gl.RGB,filter:gl.LINEAR}));this._temp_texture.uploadImage(this._video);this.properties.texture_name&&(f.getTexturesContainer()[this.properties.texture_name]=this._temp_texture);this.setOutputData(0,this._temp_texture)}};g.registerNodeType("texture/webcam",q);var B=function(){this.addInput("in","Texture");this.addOutput("out","Texture");this.properties={key_color:vec3.fromValues(0,1,0),threshold:0.8,slope:0.2,precision:f.DEFAULT};B._shader||(B._shader=new GL.Shader(GL.Shader.SCREEN_VERTEX_SHADER, +B.pixel_shader))};B.title="Matte";B.desc="Extracts background";B.widgets_info={key_color:{widget:"color"},precision:{widget:"combo",values:f.MODE_VALUES}};B.prototype.onExecute=function(){if(this.isOutputConnected(0)){var a=this.getInputData(0);if(this.properties.precision===f.PASS_THROUGH)this.setOutputData(0,a);else if(a){this._tex=f.getTargetTexture(a,this._tex,this.properties.precision);gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);this._uniforms||(this._uniforms={u_texture:0,u_key_color:this.properties.key_color, +u_threshold:1,u_slope:1});var b=this._uniforms,c=Mesh.getScreenQuad(),d=B._shader;b.u_key_color=this.properties.key_color;b.u_threshold=this.properties.threshold;b.u_slope=this.properties.slope;this._tex.drawTo(function(){a.bind(0);d.uniforms(b).draw(c)});this.setOutputData(0,this._tex)}}};B.pixel_shader="precision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform vec3 u_key_color;\n\t\t\tuniform float u_threshold;\n\t\t\tuniform float u_slope;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec3 color = texture2D( u_texture, v_coord ).xyz;\n\t\t\t\tfloat diff = length( normalize(color) - normalize(u_key_color) );\n\t\t\t\tfloat edge = u_threshold * (1.0 - u_slope);\n\t\t\t\tfloat alpha = smoothstep( edge, u_threshold, diff);\n\t\t\t\tgl_FragColor = vec4( color, alpha );\n\t\t\t}"; +g.registerNodeType("texture/matte",B);q=function(){this.addOutput("Cubemap","Cubemap");this.properties={name:""};this.size=[f.image_preview_size,f.image_preview_size]};q.title="Cubemap";q.prototype.onDropFile=function(a,b,c){a?(this._drop_texture="string"==typeof a?GL.Texture.fromURL(a):GL.Texture.fromDDSInMemory(a),this.properties.name=b):(this._drop_texture=null,this.properties.name="")};q.prototype.onExecute=function(){if(this._drop_texture)this.setOutputData(0,this._drop_texture);else if(this.properties.name){var a= +f.getTexture(this.properties.name);a&&(this._last_tex=a,this.setOutputData(0,a))}};q.prototype.onDrawBackground=function(a){this.flags.collapsed||20>=this.size[1]||a.webgl&&(gl.meshes.cube||(gl.meshes.cube=GL.Mesh.cube({size:1})))};g.registerNodeType("texture/cubemap",q)}})(this); +(function(q){var g=q.LiteGraph;if("undefined"!=typeof GL){var f=function(){this.addInput("Texture","Texture");this.addInput("Aberration","number");this.addInput("Distortion","number");this.addInput("Blur","number");this.addOutput("Texture","Texture");this.properties={aberration:1,distortion:1,blur:1,precision:LGraphTexture.DEFAULT};f._shader||(f._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,f.pixel_shader),f._texture=new GL.Texture(3,1,{format:gl.RGB,wrap:gl.CLAMP_TO_EDGE,magFilter:gl.LINEAR, +minFilter:gl.LINEAR,pixel_data:[255,0,0,0,255,0,0,0,255]}))};f.title="Lens";f.desc="Camera Lens distortion";f.widgets_info={precision:{widget:"combo",values:LGraphTexture.MODE_VALUES}};f.prototype.onExecute=function(){var e=this.getInputData(0);if(this.properties.precision===LGraphTexture.PASS_THROUGH)this.setOutputData(0,e);else if(e){this._tex=LGraphTexture.getTargetTexture(e,this._tex,this.properties.precision);var g=this.properties.aberration;this.isInputConnected(1)&&(g=this.getInputData(1), +this.properties.aberration=g);var d=this.properties.distortion;this.isInputConnected(2)&&(d=this.getInputData(2),this.properties.distortion=d);var p=this.properties.blur;this.isInputConnected(3)&&(p=this.getInputData(3),this.properties.blur=p);gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);var l=Mesh.getScreenQuad(),a=f._shader;this._tex.drawTo(function(){e.bind(0);a.uniforms({u_texture:0,u_aberration:g,u_distortion:d,u_blur:p}).draw(l)});this.setOutputData(0,this._tex)}};f.pixel_shader="precision highp float;\n\t\t\tprecision highp float;\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform sampler2D u_texture;\n\t\t\tuniform vec2 u_camera_planes;\n\t\t\tuniform float u_aberration;\n\t\t\tuniform float u_distortion;\n\t\t\tuniform float u_blur;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec2 coord = v_coord;\n\t\t\t\tfloat dist = distance(vec2(0.5), coord);\n\t\t\t\tvec2 dist_coord = coord - vec2(0.5);\n\t\t\t\tfloat percent = 1.0 + ((0.5 - dist) / 0.5) * u_distortion;\n\t\t\t\tdist_coord *= percent;\n\t\t\t\tcoord = dist_coord + vec2(0.5);\n\t\t\t\tvec4 color = texture2D(u_texture,coord, u_blur * dist);\n\t\t\t\tcolor.r = texture2D(u_texture,vec2(0.5) + dist_coord * (1.0+0.01*u_aberration), u_blur * dist ).r;\n\t\t\t\tcolor.b = texture2D(u_texture,vec2(0.5) + dist_coord * (1.0-0.01*u_aberration), u_blur * dist ).b;\n\t\t\t\tgl_FragColor = color;\n\t\t\t}\n\t\t\t"; +g.registerNodeType("fx/lens",f);window.LGraphFXLens=f;var e=function(){this.addInput("Texture","Texture");this.addInput("Blurred","Texture");this.addInput("Mask","Texture");this.addInput("Threshold","number");this.addOutput("Texture","Texture");this.properties={shape:"",size:10,alpha:1,threshold:1,high_precision:!1}};e.title="Bokeh";e.desc="applies an Bokeh effect";e.widgets_info={shape:{widget:"texture"}};e.prototype.onExecute=function(){var f=this.getInputData(0),g=this.getInputData(1),d=this.getInputData(2); +if(f&&d&&this.properties.shape){g||(g=f);var p=LGraphTexture.getTexture(this.properties.shape);if(p){var l=this.properties.threshold;this.isInputConnected(3)&&(l=this.getInputData(3),this.properties.threshold=l);var a=gl.UNSIGNED_BYTE;this.properties.high_precision&&(a=gl.half_float_ext?gl.HALF_FLOAT_OES:gl.FLOAT);this._temp_texture&&this._temp_texture.type==a&&this._temp_texture.width==f.width&&this._temp_texture.height==f.height||(this._temp_texture=new GL.Texture(f.width,f.height,{type:a,format:gl.RGBA, +filter:gl.LINEAR}));var b=e._first_shader;b||(b=e._first_shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,e._first_pixel_shader));var c=e._second_shader;c||(c=e._second_shader=new GL.Shader(e._second_vertex_shader,e._second_pixel_shader));var h=this._points_mesh;h&&h._width==f.width&&h._height==f.height&&2==h._spacing||(h=this.createPointsMesh(f.width,f.height,2));var k=Mesh.getScreenQuad(),t=this.properties.size,n=this.properties.alpha;gl.disable(gl.DEPTH_TEST);gl.disable(gl.BLEND);this._temp_texture.drawTo(function(){f.bind(0); +g.bind(1);d.bind(2);b.uniforms({u_texture:0,u_texture_blur:1,u_mask:2,u_texsize:[f.width,f.height]}).draw(k)});this._temp_texture.drawTo(function(){gl.enable(gl.BLEND);gl.blendFunc(gl.ONE,gl.ONE);f.bind(0);p.bind(3);c.uniforms({u_texture:0,u_mask:2,u_shape:3,u_alpha:n,u_threshold:l,u_pointSize:t,u_itexsize:[1/f.width,1/f.height]}).draw(h,gl.POINTS)});this.setOutputData(0,this._temp_texture)}}else this.setOutputData(0,f)};e.prototype.createPointsMesh=function(e,f,d){for(var g=Math.round(e/d),l=Math.round(f/ +d),a=new Float32Array(g*l*2),b=-1,c=2/e*d,h=2/f*d,k=0;k=g.NOTEON||a<=g.NOTEOFF)this.channel=d&15};Object.defineProperty(g.prototype,"velocity",{get:function(){return this.cmd==g.NOTEON?this.data[2]: +-1},set:function(d){this.data[2]=d},enumerable:!0});g.notes="A A# B C C# D D# E F F# G G#".split(" ");g.prototype.getPitch=function(){return 440*Math.pow(2,(this.data[1]-69)/12)};g.computePitch=function(d){return 440*Math.pow(2,(d-69)/12)};g.prototype.getCC=function(){return this.data[1]};g.prototype.getCCValue=function(){return this.data[2]};g.prototype.getPitchBend=function(){return this.data[1]+(this.data[2]<<7)-8192};g.computePitchBend=function(d,a){return d+(a<<7)-8192};g.prototype.setCommandFromString= +function(d){this.cmd=g.computeCommandFromString(d)};g.computeCommandFromString=function(d){if(!d)return 0;if(d&&d.constructor===Number)return d;d=d.toUpperCase();switch(d){case "NOTE ON":case "NOTEON":return g.NOTEON;case "NOTE OFF":case "NOTEOFF":return g.NOTEON;case "KEY PRESSURE":case "KEYPRESSURE":return g.KEYPRESSURE;case "CONTROLLER CHANGE":case "CONTROLLERCHANGE":case "CC":return g.CONTROLLERCHANGE;case "PROGRAM CHANGE":case "PROGRAMCHANGE":case "PC":return g.PROGRAMCHANGE;case "CHANNEL PRESSURE":case "CHANNELPRESSURE":return g.CHANNELPRESSURE; +case "PITCH BEND":case "PITCHBEND":return g.PITCHBEND;case "TIME TICK":case "TIMETICK":return g.TIMETICK;default:return Number(d)}};g.toNoteString=function(d){var a;a=(d-21)%12;0>a&&(a=12+a);return g.notes[a]+Math.floor((d-24)/12+1)};g.prototype.toString=function(){var d=""+this.channel+". ";switch(this.cmd){case g.NOTEON:d+="NOTEON "+g.toNoteString(this.data[1]);break;case g.NOTEOFF:d+="NOTEOFF "+g.toNoteString(this.data[1]);break;case g.CONTROLLERCHANGE:d+="CC "+this.data[1]+" "+this.data[2];break; +case g.PROGRAMCHANGE:d+="PC "+this.data[1];break;case g.PITCHBEND:d+="PITCHBEND "+this.getPitchBend();break;case g.KEYPRESSURE:d+="KEYPRESS "+this.data[1]}return d};g.prototype.toHexString=function(){for(var d="",a=0;athis.properties.max_value||this.trigger("on_midi",a)};s.registerNodeType("midi/filter",u);v.title="MIDIEvent";v.desc="Create a MIDI Event";v.prototype.onAction=function(d,a){"assign"==d?(this.properties.channel=a.channel,this.properties.cmd=a.cmd,this.properties.value1= +a.data[1],this.properties.value2=a.data[2]):(a=new g,a.channel=this.properties.channel,this.properties.cmd&&this.properties.cmd.constructor===String?a.setCommandFromString(this.properties.cmd):a.cmd=this.properties.cmd,a.data[0]=a.cmd|a.channel,a.data[1]=Number(this.properties.value1),a.data[2]=Number(this.properties.value2),this.trigger("on_midi",a))};v.prototype.onExecute=function(){var d=this.properties;if(this.outputs)for(var a=0;a=this.size[0]&&(e=this.size[0]-1),a.strokeStyle="red",a.beginPath(),a.moveTo(e,d),a.lineTo(e,0),a.stroke())}};a.title="Visualization";a.desc="Audio Visualization";k.registerNodeType("audio/visualization", +a);b.prototype.onExecute=function(){if(this._freqs=this.getInputData(0)){var a=this.properties.band,b=this.getInputData(1);void 0!==b&&(a=b);b=r.getAudioContext().sampleRate/this._freqs.length;b=a/b*2;b>=this._freqs.length?b=this._freqs[this._freqs.length-1]:(a=b|0,b-=a,b=this._freqs[a]*(1-b)+this._freqs[a+1]*b);this.setOutputData(0,b/255*this.properties.amplitude)}};b.prototype.onGetInputs=function(){return[["band","number"]]};b.title="Signal";b.desc="extract the signal of some frequency";k.registerNodeType("audio/signal", +b);c.prototype.onAdded=function(a){a.status==LGraph.STATUS_RUNNING&&(this.audionode.onaudioprocess=this._callback)};c["@code"]={widget:"code"};c.prototype.onStart=function(){this.audionode.onaudioprocess=this._callback};c.prototype.onStop=function(){this.audionode.onaudioprocess=c._bypass_function};c.prototype.onPause=function(){this.audionode.onaudioprocess=c._bypass_function};c.prototype.onUnpause=function(){this.audionode.onaudioprocess=this._callback};c.prototype.onExecute=function(){};c.prototype.onRemoved= +function(){this.audionode.onaudioprocess=c._bypass_function};c.prototype.processCode=function(){try{this._script=new new Function("properties",this.properties.code)(this.properties),this._old_code=this.properties.code,this._callback=this._script.onaudioprocess}catch(a){console.error("Error in onaudioprocess code",a),this._callback=c._bypass_function,this.audionode.onaudioprocess=this._callback}};c.prototype.onPropertyChanged=function(a,b){"code"==a&&(this.properties.code=b,this.processCode(),this.graph&& +this.graph.status==LGraph.STATUS_RUNNING&&(this.audionode.onaudioprocess=this._callback))};c.default_function=function(){this.onaudioprocess=function(a){var b=a.inputBuffer;a=a.outputBuffer;for(var c=0;c - Defined in: ../src/litegraph.js:5876 + Defined in: ../src/litegraph.js:6083 @@ -123,7 +123,7 @@

Defined in - ../src/litegraph.js:5876 + ../src/litegraph.js:6083

diff --git a/doc/classes/LGraph.html b/doc/classes/LGraph.html index 84ace4183..b7416a56c 100644 --- a/doc/classes/LGraph.html +++ b/doc/classes/LGraph.html @@ -85,7 +85,7 @@
- Defined in: ../src/litegraph.js:377 + Defined in: ../src/litegraph.js:378
@@ -114,7 +114,7 @@

Defined in - ../src/litegraph.js:377 + ../src/litegraph.js:378

@@ -149,6 +149,10 @@
  • add +
  • +
  • + arrange +
  • attachCanvas @@ -269,7 +273,7 @@

    Defined in - ../src/litegraph.js:799 + ../src/litegraph.js:856

    @@ -301,6 +305,37 @@ +
    +
    +

    arrange

    + + () + + + + + + + + +
    +

    + Defined in + ../src/litegraph.js:736 +

    + + + +
    + +
    +

    Positions every node in a more readable manner

    + +
    + + + +

    attachCanvas

    @@ -323,7 +358,7 @@

    Defined in - ../src/litegraph.js:452 + ../src/litegraph.js:453

    @@ -370,7 +405,7 @@

    Defined in - ../src/litegraph.js:403 + ../src/litegraph.js:404

    @@ -407,7 +442,7 @@

    Defined in - ../src/litegraph.js:1298 + ../src/litegraph.js:1355

    @@ -461,7 +496,7 @@

    Defined in - ../src/litegraph.js:471 + ../src/litegraph.js:472

    @@ -517,7 +552,7 @@

    Defined in - ../src/litegraph.js:937 + ../src/litegraph.js:994

    @@ -583,7 +618,7 @@

    Defined in - ../src/litegraph.js:970 + ../src/litegraph.js:1027

    @@ -649,7 +684,7 @@

    Defined in - ../src/litegraph.js:953 + ../src/litegraph.js:1010

    @@ -709,7 +744,7 @@

    Defined in - ../src/litegraph.js:744 + ../src/litegraph.js:801

    @@ -753,7 +788,7 @@ if the nodes are using graphical actions

    Defined in - ../src/litegraph.js:733 + ../src/litegraph.js:790

    @@ -799,7 +834,7 @@ if the nodes are using graphical actions

    Defined in - ../src/litegraph.js:924 + ../src/litegraph.js:981

    @@ -861,7 +896,7 @@ if the nodes are using graphical actions

    Defined in - ../src/litegraph.js:986 + ../src/litegraph.js:1043

    @@ -943,7 +978,7 @@ if the nodes are using graphical actions

    Defined in - ../src/litegraph.js:722 + ../src/litegraph.js:780

    @@ -983,7 +1018,7 @@ if the nodes are using graphical actions

    Defined in - ../src/litegraph.js:1228 + ../src/litegraph.js:1285

    @@ -1020,7 +1055,7 @@ if the nodes are using graphical actions

    Defined in - ../src/litegraph.js:855 + ../src/litegraph.js:912

    @@ -1074,7 +1109,7 @@ if the nodes are using graphical actions

    Defined in - ../src/litegraph.js:539 + ../src/litegraph.js:540

    @@ -1131,7 +1166,7 @@ if the nodes are using graphical actions

    Defined in - ../src/litegraph.js:756 + ../src/litegraph.js:813

    @@ -1193,7 +1228,7 @@ if the nodes are using graphical actions

    Defined in - ../src/litegraph.js:1265 + ../src/litegraph.js:1322

    @@ -1242,7 +1277,7 @@ if the nodes are using graphical actions

    Defined in - ../src/litegraph.js:1173 + ../src/litegraph.js:1230

    @@ -1311,7 +1346,7 @@ can be easily accesed from the outside of the graph

    Defined in - ../src/litegraph.js:1188 + ../src/litegraph.js:1245

    @@ -1374,7 +1409,7 @@ can be easily accesed from the outside of the graph

    Defined in - ../src/litegraph.js:489 + ../src/litegraph.js:490

    @@ -1422,7 +1457,7 @@ can be easily accesed from the outside of the graph

    Defined in - ../src/litegraph.js:517 + ../src/litegraph.js:518

    @@ -1453,7 +1488,7 @@ can be easily accesed from the outside of the graph

    Defined in - ../src/litegraph.js:618 + ../src/litegraph.js:619

    diff --git a/doc/classes/LGraphCanvas.html b/doc/classes/LGraphCanvas.html index 9ed95d4c2..829f981df 100644 --- a/doc/classes/LGraphCanvas.html +++ b/doc/classes/LGraphCanvas.html @@ -85,7 +85,7 @@ @@ -126,7 +126,7 @@

    Defined in - ../src/litegraph.js:3134 + ../src/litegraph.js:3203

    @@ -254,7 +254,7 @@

    Defined in - ../src/litegraph.js:2793 + ../src/litegraph.js:2852

    @@ -291,7 +291,7 @@

    Defined in - ../src/litegraph.js:2886 + ../src/litegraph.js:2949

    @@ -342,7 +342,7 @@

    Defined in - ../src/litegraph.js:3150 + ../src/litegraph.js:3219

    @@ -388,7 +388,7 @@

    Defined in - ../src/litegraph.js:2859 + ../src/litegraph.js:2922

    @@ -441,7 +441,7 @@

    Defined in - ../src/litegraph.js:2902 + ../src/litegraph.js:2966

    @@ -495,7 +495,7 @@

    Defined in - ../src/litegraph.js:2828 + ../src/litegraph.js:2891

    @@ -542,7 +542,7 @@

    Defined in - ../src/litegraph.js:3164 + ../src/litegraph.js:3233

    @@ -573,7 +573,7 @@

    Defined in - ../src/litegraph.js:3188 + ../src/litegraph.js:3257

    diff --git a/doc/classes/LGraphNode.html b/doc/classes/LGraphNode.html index 7170ec0fe..e65669140 100644 --- a/doc/classes/LGraphNode.html +++ b/doc/classes/LGraphNode.html @@ -85,7 +85,7 @@ @@ -293,7 +293,7 @@

    Defined in - ../src/litegraph.js:2104 + ../src/litegraph.js:2161

    @@ -385,7 +385,7 @@

    Defined in - ../src/litegraph.js:2041 + ../src/litegraph.js:2098

    @@ -460,7 +460,7 @@

    Defined in - ../src/litegraph.js:2065 + ../src/litegraph.js:2122

    @@ -520,7 +520,7 @@

    Defined in - ../src/litegraph.js:1979 + ../src/litegraph.js:2036

    @@ -595,7 +595,7 @@

    Defined in - ../src/litegraph.js:2002 + ../src/litegraph.js:2059

    @@ -658,7 +658,7 @@

    Defined in - ../src/litegraph.js:1953 + ../src/litegraph.js:2010

    @@ -737,7 +737,7 @@

    Defined in - ../src/litegraph.js:2688 + ../src/litegraph.js:2745

    @@ -777,7 +777,7 @@

    Defined in - ../src/litegraph.js:2125 + ../src/litegraph.js:2182

    @@ -833,7 +833,7 @@

    Defined in - ../src/litegraph.js:1485 + ../src/litegraph.js:1542

    @@ -879,7 +879,7 @@

    Defined in - ../src/litegraph.js:2277 + ../src/litegraph.js:2335

    @@ -967,7 +967,7 @@

    Defined in - ../src/litegraph.js:2485 + ../src/litegraph.js:2543

    @@ -1036,7 +1036,7 @@

    Defined in - ../src/litegraph.js:2395 + ../src/litegraph.js:2453

    @@ -1113,7 +1113,7 @@

    Defined in - ../src/litegraph.js:2246 + ../src/litegraph.js:2304

    @@ -1179,7 +1179,7 @@

    Defined in - ../src/litegraph.js:2262 + ../src/litegraph.js:2320

    @@ -1239,7 +1239,7 @@

    Defined in - ../src/litegraph.js:2176 + ../src/litegraph.js:2233

    @@ -1247,7 +1247,8 @@
    -

    returns the bounding of the object, used for rendering purposes

    +

    returns the bounding of the object, used for rendering purposes +bounding is: [topleft_cornerx, topleft_cornery, width, height]

    @@ -1291,7 +1292,7 @@

    Defined in - ../src/litegraph.js:2554 + ../src/litegraph.js:2611

    @@ -1371,7 +1372,7 @@

    Defined in - ../src/litegraph.js:1718 + ../src/litegraph.js:1775

    @@ -1447,7 +1448,7 @@

    Defined in - ../src/litegraph.js:1767 + ../src/litegraph.js:1824

    @@ -1512,7 +1513,7 @@

    Defined in - ../src/litegraph.js:1782 + ../src/litegraph.js:1839

    @@ -1577,7 +1578,7 @@

    Defined in - ../src/litegraph.js:1803 + ../src/litegraph.js:1860

    @@ -1642,7 +1643,7 @@

    Defined in - ../src/litegraph.js:1821 + ../src/litegraph.js:1878

    @@ -1707,7 +1708,7 @@

    Defined in - ../src/litegraph.js:1850 + ../src/litegraph.js:1907

    @@ -1773,7 +1774,7 @@

    Defined in - ../src/litegraph.js:2215 + ../src/litegraph.js:2273

    @@ -1839,7 +1840,7 @@

    Defined in - ../src/litegraph.js:1669 + ../src/litegraph.js:1726

    @@ -1879,7 +1880,7 @@

    Defined in - ../src/litegraph.js:1754 + ../src/litegraph.js:1811

    @@ -1942,7 +1943,7 @@

    Defined in - ../src/litegraph.js:1837 + ../src/litegraph.js:1894

    @@ -2008,7 +2009,7 @@

    Defined in - ../src/litegraph.js:2191 + ../src/litegraph.js:2249

    @@ -2072,7 +2073,7 @@

    Defined in - ../src/litegraph.js:2701 + ../src/litegraph.js:2758

    @@ -2109,7 +2110,7 @@

    Defined in - ../src/litegraph.js:2090 + ../src/litegraph.js:2147

    @@ -2162,7 +2163,7 @@

    Defined in - ../src/litegraph.js:2027 + ../src/litegraph.js:2084

    @@ -2209,7 +2210,7 @@

    Defined in - ../src/litegraph.js:1581 + ../src/litegraph.js:1638

    @@ -2249,7 +2250,7 @@

    Defined in - ../src/litegraph.js:1682 + ../src/litegraph.js:1739

    @@ -2306,7 +2307,7 @@

    Defined in - ../src/litegraph.js:1657 + ../src/litegraph.js:1714

    @@ -2346,7 +2347,7 @@

    Defined in - ../src/litegraph.js:1883 + ../src/litegraph.js:1940

    @@ -2413,7 +2414,7 @@

    Defined in - ../src/litegraph.js:1906 + ../src/litegraph.js:1963

    diff --git a/doc/classes/LiteGraph.html b/doc/classes/LiteGraph.html index ee79943b7..5107d175d 100644 --- a/doc/classes/LiteGraph.html +++ b/doc/classes/LiteGraph.html @@ -205,7 +205,7 @@

    Defined in - ../src/litegraph.js:164 + ../src/litegraph.js:165

    @@ -265,7 +265,7 @@

    Defined in - ../src/litegraph.js:182 + ../src/litegraph.js:183

    @@ -344,7 +344,7 @@

    Defined in - ../src/litegraph.js:225 + ../src/litegraph.js:226

    @@ -410,7 +410,7 @@

    Defined in - ../src/litegraph.js:238 + ../src/litegraph.js:239

    @@ -470,7 +470,7 @@

    Defined in - ../src/litegraph.js:260 + ../src/litegraph.js:261

    @@ -601,7 +601,8 @@
    -

    create a new node type by passing a function, it wraps it with a propper class

    +

    Create a new node type by passing a function, it wraps it with a propper class and generates inputs according to the parameters of the function. +Useful to wrap simple methods that do not require properties, and that only process some input to generate an output.

    diff --git a/doc/data.json b/doc/data.json index bfa3d4f81..57ea0a337 100644 --- a/doc/data.json +++ b/doc/data.json @@ -39,7 +39,7 @@ "plugin_for": [], "extension_for": [], "file": "../src/litegraph.js", - "line": 377, + "line": 378, "description": "LGraph is the class that contain a full graph. We instantiate one and add nodes to it, and then we can run the execution loop.", "is_constructor": 1 }, @@ -52,7 +52,7 @@ "plugin_for": [], "extension_for": [], "file": "../src/litegraph.js", - "line": 1430, + "line": 1487, "description": "Base Class for all the node type classes", "params": [ { @@ -71,7 +71,7 @@ "plugin_for": [], "extension_for": [], "file": "../src/litegraph.js", - "line": 3134, + "line": 3203, "description": "marks as dirty the canvas, this way it will be rendered again", "is_constructor": 1, "params": [ @@ -102,7 +102,7 @@ "plugin_for": [], "extension_for": [], "file": "../src/litegraph.js", - "line": 5876, + "line": 6083, "description": "ContextMenu from LiteGUI", "is_constructor": 1, "params": [ @@ -144,7 +144,7 @@ { "file": "../src/litegraph.js", "line": 135, - "description": "create a new node type by passing a function, it wraps it with a propper class", + "description": "Create a new node type by passing a function, it wraps it with a propper class and generates inputs according to the parameters of the function.\nUseful to wrap simple methods that do not require properties, and that only process some input to generate an output.", "itemtype": "method", "name": "wrapFunctionAsNode", "params": [ @@ -173,7 +173,7 @@ }, { "file": "../src/litegraph.js", - "line": 164, + "line": 165, "description": "Adds this method to all nodetypes, existing and to be created\n(You can add it to LGraphNode.prototype but then existing node types wont have it)", "itemtype": "method", "name": "addNodeMethod", @@ -188,7 +188,7 @@ }, { "file": "../src/litegraph.js", - "line": 182, + "line": 183, "description": "Create a node of a given type with a name. The node is not attached to any graph yet.", "itemtype": "method", "name": "createNode", @@ -213,7 +213,7 @@ }, { "file": "../src/litegraph.js", - "line": 225, + "line": 226, "description": "Returns a registered node type with a given name", "itemtype": "method", "name": "getNodeType", @@ -232,7 +232,7 @@ }, { "file": "../src/litegraph.js", - "line": 238, + "line": 239, "description": "Returns a list of node types matching one category", "itemtype": "method", "name": "getNodeType", @@ -251,7 +251,7 @@ }, { "file": "../src/litegraph.js", - "line": 260, + "line": 261, "description": "Returns a list with all the node type categories", "itemtype": "method", "name": "getNodeTypesCategories", @@ -263,7 +263,7 @@ }, { "file": "../src/litegraph.js", - "line": 403, + "line": 404, "description": "Removes all nodes from this graph", "itemtype": "method", "name": "clear", @@ -271,7 +271,7 @@ }, { "file": "../src/litegraph.js", - "line": 452, + "line": 453, "description": "Attach Canvas to this graph", "itemtype": "method", "name": "attachCanvas", @@ -286,7 +286,7 @@ }, { "file": "../src/litegraph.js", - "line": 471, + "line": 472, "description": "Detach Canvas from this graph", "itemtype": "method", "name": "detachCanvas", @@ -301,7 +301,7 @@ }, { "file": "../src/litegraph.js", - "line": 489, + "line": 490, "description": "Starts running this graph every interval milliseconds.", "itemtype": "method", "name": "start", @@ -316,7 +316,7 @@ }, { "file": "../src/litegraph.js", - "line": 517, + "line": 518, "description": "Stops the execution loop of the graph", "itemtype": "method", "name": "stop execution", @@ -324,7 +324,7 @@ }, { "file": "../src/litegraph.js", - "line": 539, + "line": 540, "description": "Run N steps (cycles) of the graph", "itemtype": "method", "name": "runStep", @@ -339,7 +339,7 @@ }, { "file": "../src/litegraph.js", - "line": 618, + "line": 619, "description": "Updates the graph execution order according to relevance of the nodes (nodes with only outputs have more relevance than\nnodes with only inputs.", "itemtype": "method", "name": "updateExecutionOrder", @@ -347,7 +347,15 @@ }, { "file": "../src/litegraph.js", - "line": 722, + "line": 736, + "description": "Positions every node in a more readable manner", + "itemtype": "method", + "name": "arrange", + "class": "LGraph" + }, + { + "file": "../src/litegraph.js", + "line": 780, "description": "Returns the amount of time the graph has been running in milliseconds", "itemtype": "method", "name": "getTime", @@ -359,7 +367,7 @@ }, { "file": "../src/litegraph.js", - "line": 733, + "line": 790, "description": "Returns the amount of time accumulated using the fixedtime_lapse var. This is used in context where the time increments should be constant", "itemtype": "method", "name": "getFixedTime", @@ -371,7 +379,7 @@ }, { "file": "../src/litegraph.js", - "line": 744, + "line": 801, "description": "Returns the amount of time it took to compute the latest iteration. Take into account that this number could be not correct\nif the nodes are using graphical actions", "itemtype": "method", "name": "getElapsedTime", @@ -383,7 +391,7 @@ }, { "file": "../src/litegraph.js", - "line": 756, + "line": 813, "description": "Sends an event to all the nodes, useful to trigger stuff", "itemtype": "method", "name": "sendEventToAllNodes", @@ -403,7 +411,7 @@ }, { "file": "../src/litegraph.js", - "line": 799, + "line": 856, "description": "Adds a new node instasnce to this graph", "itemtype": "method", "name": "add", @@ -418,7 +426,7 @@ }, { "file": "../src/litegraph.js", - "line": 855, + "line": 912, "description": "Removes a node from the graph", "itemtype": "method", "name": "remove", @@ -433,7 +441,7 @@ }, { "file": "../src/litegraph.js", - "line": 924, + "line": 981, "description": "Returns a node by its id.", "itemtype": "method", "name": "getNodeById", @@ -448,7 +456,7 @@ }, { "file": "../src/litegraph.js", - "line": 937, + "line": 994, "description": "Returns a list of nodes that matches a class", "itemtype": "method", "name": "findNodesByClass", @@ -467,7 +475,7 @@ }, { "file": "../src/litegraph.js", - "line": 953, + "line": 1010, "description": "Returns a list of nodes that matches a type", "itemtype": "method", "name": "findNodesByType", @@ -486,7 +494,7 @@ }, { "file": "../src/litegraph.js", - "line": 970, + "line": 1027, "description": "Returns a list of nodes that matches a name", "itemtype": "method", "name": "findNodesByName", @@ -505,7 +513,7 @@ }, { "file": "../src/litegraph.js", - "line": 986, + "line": 1043, "description": "Returns the top-most node in this position of the canvas", "itemtype": "method", "name": "getNodeOnPos", @@ -534,7 +542,7 @@ }, { "file": "../src/litegraph.js", - "line": 1173, + "line": 1230, "description": "Assigns a value to all the nodes that matches this name. This is used to create global variables of the node that\ncan be easily accesed from the outside of the graph", "itemtype": "method", "name": "setInputData", @@ -554,7 +562,7 @@ }, { "file": "../src/litegraph.js", - "line": 1188, + "line": 1245, "description": "Returns the value of the first node with this name. This is used to access global variables of the graph from the outside", "itemtype": "method", "name": "setInputData", @@ -573,7 +581,7 @@ }, { "file": "../src/litegraph.js", - "line": 1228, + "line": 1285, "description": "returns if the graph is in live mode", "itemtype": "method", "name": "isLive", @@ -581,7 +589,7 @@ }, { "file": "../src/litegraph.js", - "line": 1265, + "line": 1322, "description": "Creates a Object containing all the info about this graph, it can be serialized", "itemtype": "method", "name": "serialize", @@ -593,7 +601,7 @@ }, { "file": "../src/litegraph.js", - "line": 1298, + "line": 1355, "description": "Configure a graph from a JSON string", "itemtype": "method", "name": "configure", @@ -608,7 +616,7 @@ }, { "file": "../src/litegraph.js", - "line": 1485, + "line": 1542, "description": "configure a node from an object containing the serialized info", "itemtype": "method", "name": "configure", @@ -616,7 +624,7 @@ }, { "file": "../src/litegraph.js", - "line": 1581, + "line": 1638, "description": "serialize the content", "itemtype": "method", "name": "serialize", @@ -624,7 +632,7 @@ }, { "file": "../src/litegraph.js", - "line": 1657, + "line": 1714, "description": "serialize and stringify", "itemtype": "method", "name": "toString", @@ -632,7 +640,7 @@ }, { "file": "../src/litegraph.js", - "line": 1669, + "line": 1726, "description": "get the title string", "itemtype": "method", "name": "getTitle", @@ -640,7 +648,7 @@ }, { "file": "../src/litegraph.js", - "line": 1682, + "line": 1739, "description": "sets the output data", "itemtype": "method", "name": "setOutputData", @@ -660,7 +668,7 @@ }, { "file": "../src/litegraph.js", - "line": 1718, + "line": 1775, "description": "retrieves the input data (data traveling through the connection) from one slot", "itemtype": "method", "name": "getInputData", @@ -684,7 +692,7 @@ }, { "file": "../src/litegraph.js", - "line": 1754, + "line": 1811, "description": "tells you if there is a connection in one input slot", "itemtype": "method", "name": "isInputConnected", @@ -703,7 +711,7 @@ }, { "file": "../src/litegraph.js", - "line": 1767, + "line": 1824, "description": "tells you info about an input connection (which node, type, etc)", "itemtype": "method", "name": "getInputInfo", @@ -722,7 +730,7 @@ }, { "file": "../src/litegraph.js", - "line": 1782, + "line": 1839, "description": "returns the node connected in the input slot", "itemtype": "method", "name": "getInputNode", @@ -741,7 +749,7 @@ }, { "file": "../src/litegraph.js", - "line": 1803, + "line": 1860, "description": "tells you the last output data that went in that slot", "itemtype": "method", "name": "getOutputData", @@ -760,7 +768,7 @@ }, { "file": "../src/litegraph.js", - "line": 1821, + "line": 1878, "description": "tells you info about an output connection (which node, type, etc)", "itemtype": "method", "name": "getOutputInfo", @@ -779,7 +787,7 @@ }, { "file": "../src/litegraph.js", - "line": 1837, + "line": 1894, "description": "tells you if there is a connection in one output slot", "itemtype": "method", "name": "isOutputConnected", @@ -798,7 +806,7 @@ }, { "file": "../src/litegraph.js", - "line": 1850, + "line": 1907, "description": "retrieves all the nodes connected to this output slot", "itemtype": "method", "name": "getOutputNodes", @@ -817,7 +825,7 @@ }, { "file": "../src/litegraph.js", - "line": 1883, + "line": 1940, "description": "Triggers an event in this node, this will trigger any output with the same name", "itemtype": "method", "name": "trigger", @@ -837,7 +845,7 @@ }, { "file": "../src/litegraph.js", - "line": 1906, + "line": 1963, "description": "Triggers an slot event in this node", "itemtype": "method", "name": "triggerSlot", @@ -857,7 +865,7 @@ }, { "file": "../src/litegraph.js", - "line": 1953, + "line": 2010, "description": "add a new property to this node", "itemtype": "method", "name": "addProperty", @@ -887,7 +895,7 @@ }, { "file": "../src/litegraph.js", - "line": 1979, + "line": 2036, "description": "add a new output slot to use in this node", "itemtype": "method", "name": "addOutput", @@ -912,7 +920,7 @@ }, { "file": "../src/litegraph.js", - "line": 2002, + "line": 2059, "description": "add a new output slot to use in this node", "itemtype": "method", "name": "addOutputs", @@ -927,7 +935,7 @@ }, { "file": "../src/litegraph.js", - "line": 2027, + "line": 2084, "description": "remove an existing output slot", "itemtype": "method", "name": "removeOutput", @@ -942,7 +950,7 @@ }, { "file": "../src/litegraph.js", - "line": 2041, + "line": 2098, "description": "add a new input slot to use in this node", "itemtype": "method", "name": "addInput", @@ -967,7 +975,7 @@ }, { "file": "../src/litegraph.js", - "line": 2065, + "line": 2122, "description": "add several new input slots in this node", "itemtype": "method", "name": "addInputs", @@ -982,7 +990,7 @@ }, { "file": "../src/litegraph.js", - "line": 2090, + "line": 2147, "description": "remove an existing input slot", "itemtype": "method", "name": "removeInput", @@ -997,7 +1005,7 @@ }, { "file": "../src/litegraph.js", - "line": 2104, + "line": 2161, "description": "add an special connection to this node (used for special kinds of graphs)", "itemtype": "method", "name": "addConnection", @@ -1027,7 +1035,7 @@ }, { "file": "../src/litegraph.js", - "line": 2125, + "line": 2182, "description": "computes the size of a node according to its inputs and output slots", "itemtype": "method", "name": "computeSize", @@ -1046,8 +1054,8 @@ }, { "file": "../src/litegraph.js", - "line": 2176, - "description": "returns the bounding of the object, used for rendering purposes", + "line": 2233, + "description": "returns the bounding of the object, used for rendering purposes\nbounding is: [topleft_cornerx, topleft_cornery, width, height]", "itemtype": "method", "name": "getBounding", "return": { @@ -1058,7 +1066,7 @@ }, { "file": "../src/litegraph.js", - "line": 2191, + "line": 2249, "description": "checks if a point is inside the shape of a node", "itemtype": "method", "name": "isPointInsideNode", @@ -1082,7 +1090,7 @@ }, { "file": "../src/litegraph.js", - "line": 2215, + "line": 2273, "description": "checks if a point is inside a node slot, and returns info about which slot", "itemtype": "method", "name": "getSlotInPosition", @@ -1106,7 +1114,7 @@ }, { "file": "../src/litegraph.js", - "line": 2246, + "line": 2304, "description": "returns the input slot with a given name (used for dynamic slots), -1 if not found", "itemtype": "method", "name": "findInputSlot", @@ -1125,7 +1133,7 @@ }, { "file": "../src/litegraph.js", - "line": 2262, + "line": 2320, "description": "returns the output slot with a given name (used for dynamic slots), -1 if not found", "itemtype": "method", "name": "findOutputSlot", @@ -1144,7 +1152,7 @@ }, { "file": "../src/litegraph.js", - "line": 2277, + "line": 2335, "description": "connect this node output to the input of another node", "itemtype": "method", "name": "connect", @@ -1173,7 +1181,7 @@ }, { "file": "../src/litegraph.js", - "line": 2395, + "line": 2453, "description": "disconnect one output to an specific node", "itemtype": "method", "name": "disconnectOutput", @@ -1197,7 +1205,7 @@ }, { "file": "../src/litegraph.js", - "line": 2485, + "line": 2543, "description": "disconnect one input", "itemtype": "method", "name": "disconnectInput", @@ -1216,7 +1224,7 @@ }, { "file": "../src/litegraph.js", - "line": 2554, + "line": 2611, "description": "returns the center of a connection point in canvas coords", "itemtype": "method", "name": "getConnectionPos", @@ -1240,7 +1248,7 @@ }, { "file": "../src/litegraph.js", - "line": 2688, + "line": 2745, "description": "Collapse the node to make it smaller on the canvas", "itemtype": "method", "name": "collapse", @@ -1248,7 +1256,7 @@ }, { "file": "../src/litegraph.js", - "line": 2701, + "line": 2758, "description": "Forces the node to do not move or realign on Z", "itemtype": "method", "name": "pin", @@ -1256,7 +1264,7 @@ }, { "file": "../src/litegraph.js", - "line": 2793, + "line": 2852, "description": "clears all the data inside", "itemtype": "method", "name": "clear", @@ -1264,7 +1272,7 @@ }, { "file": "../src/litegraph.js", - "line": 2828, + "line": 2891, "description": "assigns a graph, you can reasign graphs to the same canvas", "itemtype": "method", "name": "setGraph", @@ -1279,7 +1287,7 @@ }, { "file": "../src/litegraph.js", - "line": 2859, + "line": 2922, "description": "opens a graph contained inside a node in the current graph", "itemtype": "method", "name": "openSubgraph", @@ -1294,7 +1302,7 @@ }, { "file": "../src/litegraph.js", - "line": 2886, + "line": 2949, "description": "closes a subgraph contained inside a node", "itemtype": "method", "name": "closeSubgraph", @@ -1309,7 +1317,7 @@ }, { "file": "../src/litegraph.js", - "line": 2902, + "line": 2966, "description": "assigns a canvas", "itemtype": "method", "name": "setCanvas", @@ -1324,7 +1332,7 @@ }, { "file": "../src/litegraph.js", - "line": 3150, + "line": 3219, "description": "Used to attach the canvas in a popup", "itemtype": "method", "name": "getCanvasWindow", @@ -1336,7 +1344,7 @@ }, { "file": "../src/litegraph.js", - "line": 3164, + "line": 3233, "description": "starts rendering the content of the canvas when needed", "itemtype": "method", "name": "startRendering", @@ -1344,7 +1352,7 @@ }, { "file": "../src/litegraph.js", - "line": 3188, + "line": 3257, "description": "stops rendering the content of the canvas (to save resources)", "itemtype": "method", "name": "stopRendering", diff --git a/doc/files/.._src_litegraph.js.html b/doc/files/.._src_litegraph.js.html index c39b266aa..0eda72bcf 100644 --- a/doc/files/.._src_litegraph.js.html +++ b/doc/files/.._src_litegraph.js.html @@ -219,7 +219,8 @@ var LiteGraph = global.LiteGraph = { }, /** - * create a new node type by passing a function, it wraps it with a propper class + * Create a new node type by passing a function, it wraps it with a propper class and generates inputs according to the parameters of the function. + * Useful to wrap simple methods that do not require properties, and that only process some input to generate an output. * @method wrapFunctionAsNode * @param {String} name node name with namespace (p.e.: 'math/sum') * @param {Function} func @@ -716,7 +717,7 @@ LGraph.prototype.updateExecutionOrder = function() } //This is more internal, it computes the order and returns it -LGraph.prototype.computeExecutionOrder = function( only_onExecute ) +LGraph.prototype.computeExecutionOrder = function( only_onExecute, set_level ) { var L = []; var S = []; @@ -727,22 +728,30 @@ LGraph.prototype.computeExecutionOrder = function( only_onExecute ) //search for the nodes without inputs (starting nodes) for (var i = 0, l = this._nodes.length; i < l; ++i) { - var n = this._nodes[i]; - if( only_onExecute && !n.onExecute ) + var node = this._nodes[i]; + if( only_onExecute && !node.onExecute ) continue; - M[n.id] = n; //add to pending nodes + M[node.id] = node; //add to pending nodes var num = 0; //num of input connections - if(n.inputs) - for(var j = 0, l2 = n.inputs.length; j < l2; j++) - if(n.inputs[j] && n.inputs[j].link != null) + if(node.inputs) + for(var j = 0, l2 = node.inputs.length; j < l2; j++) + if(node.inputs[j] && node.inputs[j].link != null) num += 1; if(num == 0) //is a starting node - S.push(n); + { + S.push(node); + if(set_level) + node._level = 1; + } else //num of input links - remaining_links[n.id] = num; + { + if(set_level) + node._level = 0; + remaining_links[node.id] = num; + } } while(true) @@ -751,43 +760,49 @@ LGraph.prototype.computeExecutionOrder = function( only_onExecute ) break; //get an starting node - var n = S.shift(); - L.push(n); //add to ordered list - delete M[n.id]; //remove from the pending nodes + var node = S.shift(); + L.push(node); //add to ordered list + delete M[node.id]; //remove from the pending nodes + + if(!node.outputs) + continue; //for every output - if(n.outputs) - for(var i = 0; i < n.outputs.length; i++) + for(var i = 0; i < node.outputs.length; i++) + { + var output = node.outputs[i]; + //not connected + if(output == null || output.links == null || output.links.length == 0) + continue; + + //for every connection + for(var j = 0; j < output.links.length; j++) { - var output = n.outputs[i]; - //not connected - if(output == null || output.links == null || output.links.length == 0) + var link_id = output.links[j]; + var link = this.links[link_id]; + if(!link) continue; - //for every connection - for(var j = 0; j < output.links.length; j++) + //already visited link (ignore it) + if(visited_links[ link.id ]) + continue; + + var target_node = this.getNodeById( link.target_id ); + if(target_node == null) { - var link_id = output.links[j]; - var link = this.links[link_id]; - if(!link) continue; - - //already visited link (ignore it) - if(visited_links[ link.id ]) - continue; - - var target_node = this.getNodeById( link.target_id ); - if(target_node == null) - { - visited_links[ link.id ] = true; - continue; - } - - visited_links[link.id] = true; //mark as visited - remaining_links[target_node.id] -= 1; //reduce the number of links remaining - if (remaining_links[target_node.id] == 0) - S.push(target_node); //if no more links, then add to Starters array + visited_links[ link.id ] = true; + continue; } + + if(set_level && (!target_node._level || target_node._level <= node._level)) + target_node._level = node._level + 1; + + visited_links[link.id] = true; //mark as visited + remaining_links[target_node.id] -= 1; //reduce the number of links remaining + if (remaining_links[ target_node.id ] == 0) + S.push(target_node); //if no more links, then add to starters array } + } } //the remaining ones (loops) @@ -804,13 +819,55 @@ LGraph.prototype.computeExecutionOrder = function( only_onExecute ) return L; } +/** +* Positions every node in a more readable manner +* @method arrange +*/ +LGraph.prototype.arrange = function( margin ) +{ + margin = margin || 40; + + var nodes = this.computeExecutionOrder( false, true ); + var columns = []; + for(var i = 0; i < nodes.length; ++i) + { + var node = nodes[i]; + var col = node._level || 1; + if(!columns[col]) + columns[col] = []; + columns[col].push( node ); + } + + var x = margin; + + for(var i = 0; i < columns.length; ++i) + { + var column = columns[i]; + if(!column) + continue; + var max_size = 100; + var y = margin; + for(var j = 0; j < column.length; ++j) + { + var node = column[j]; + node.pos[0] = x; + node.pos[1] = y; + if(node.size[0] > max_size) + max_size = node.size[0]; + y += node.size[1] + margin; + } + x += max_size + margin; + } + + this.setDirtyCanvas(true,true); +} + /** * Returns the amount of time the graph has been running in milliseconds * @method getTime * @return {number} number of milliseconds the graph has been running */ - LGraph.prototype.getTime = function() { return this.globaltime; @@ -2261,6 +2318,7 @@ LGraphNode.prototype.computeSize = function( minHeight, out ) /** * returns the bounding of the object, used for rendering purposes +* bounding is: [topleft_cornerx, topleft_cornery, width, height] * @method getBounding * @return {Float32Array[4]} the total size */ @@ -2269,8 +2327,8 @@ LGraphNode.prototype.getBounding = function( out ) out = out || new Float32Array(4); out[0] = this.pos[0] - 4; out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT; - out[2] = this.pos[0] + this.size[0] + 4; - out[3] = this.pos[1] + this.size[1] + LGraph.NODE_TITLE_HEIGHT; + out[2] = this.size[0] + 4; + out[3] = this.size[1] + LiteGraph.NODE_TITLE_HEIGHT; return out; } @@ -2616,8 +2674,7 @@ LGraphNode.prototype.disconnectInput = function( slot ) //search in the inputs list for this link for(var i = 0, l = output.links.length; i < l; i++) { - var link_id = output.links[i]; - if( link_info.target_id == this.id ) + if( output.links[i] == link_id ) { output.links.splice(i,1); break; @@ -2825,7 +2882,7 @@ function LGraphCanvas( canvas, graph, options ) //if(graph === undefined) // throw ("No graph assigned"); - this.background_image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII=' + this.background_image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII=' if(canvas && canvas.constructor === String ) canvas = document.querySelector( canvas ); @@ -2849,6 +2906,8 @@ function LGraphCanvas( canvas, graph, options ) this.allow_dragcanvas = true; this.allow_dragnodes = true; this.allow_interaction = true; //allow to control widgets, buttons, collapse, etc + this.drag_mode = false; + this.dragging_rectangle = null; this.always_render_background = false; this.render_connections_shadows = false; //too much cpu @@ -2891,11 +2950,15 @@ LGraphCanvas.prototype.clear = function() this.scale = 1; this.offset = [0,0]; + this.dragging_rectangle = null; + this.selected_nodes = {}; + this.visible_nodes = []; this.node_dragged = null; this.node_over = null; this.node_capturing_input = null; this.connecting_node = null; + this.highlighted_links = {}; this.dirty_canvas = true; this.dirty_bgcanvas = true; @@ -2981,6 +3044,7 @@ LGraphCanvas.prototype.closeSubgraph = function() return; var graph = this._graph_stack.pop(); this.selected_nodes = {}; + this.highlighted_links = {}; graph.attachCanvas(this); this.setDirty(true,true); } @@ -3068,6 +3132,8 @@ LGraphCanvas.prototype.bindEvents = function() } var canvas = this.canvas; + var ref_window = this.getCanvasWindow(); + var document = ref_window.document; //hack used when moving canvas between windows this._mousedown_callback = this.processMouseDown.bind(this); this._mousewheel_callback = this.processMouseWheel.bind(this); @@ -3091,8 +3157,8 @@ LGraphCanvas.prototype.bindEvents = function() //Keyboard ****************** this._key_callback = this.processKey.bind(this); - canvas.addEventListener("keydown", this._key_callback ); - canvas.addEventListener("keyup", this._key_callback ); + canvas.addEventListener("keydown", this._key_callback, true ); + document.addEventListener("keyup", this._key_callback, true ); //in document, otherwise it doesnt fire keyup //Droping Stuff over nodes ************************************ this._ondrop_callback = this.processDrop.bind(this); @@ -3113,11 +3179,14 @@ LGraphCanvas.prototype.unbindEvents = function() return; } + var ref_window = this.getCanvasWindow(); + var document = ref_window.document; + this.canvas.removeEventListener( "mousedown", this._mousedown_callback ); this.canvas.removeEventListener( "mousewheel", this._mousewheel_callback ); this.canvas.removeEventListener( "DOMMouseScroll", this._mousewheel_callback ); this.canvas.removeEventListener( "keydown", this._key_callback ); - this.canvas.removeEventListener( "keyup", this._key_callback ); + document.removeEventListener( "keyup", this._key_callback ); this.canvas.removeEventListener( "contextmenu", this._doNothing ); this.canvas.removeEventListener( "drop", this._ondrop_callback ); this.canvas.removeEventListener( "dragenter", this._doReturnTrue ); @@ -3308,34 +3377,30 @@ LGraphCanvas.prototype.processMouseDown = function(e) var n = this.graph.getNodeOnPos( e.canvasX, e.canvasY, this.visible_nodes ); var skip_dragging = false; + var skip_action = false; LiteGraph.closeAllContextMenus( ref_window ); if(e.which == 1) //left button mouse { - if(!e.shiftKey) //REFACTOR: integrate with function + if( e.ctrlKey ) { - //no node or another node selected - if (!n || !this.selected_nodes[n.id]) { - - var todeselect = []; - for (var i in this.selected_nodes) - if (this.selected_nodes[i] != n) - todeselect.push(this.selected_nodes[i]); - //two passes to avoid problems modifying the container - for (var i in todeselect) - this.processNodeDeselected(todeselect[i]); - } + this.dragging_rectangle = new Float32Array(4); + this.dragging_rectangle[0] = e.canvasX; + this.dragging_rectangle[1] = e.canvasY; + this.dragging_rectangle[2] = 1; + this.dragging_rectangle[3] = 1; + skip_action = true; } + var clicking_canvas_bg = false; //when clicked on top of a node //and it is not interactive - if(n && this.allow_interaction ) + if( n && this.allow_interaction && !skip_action ) { if(!this.live_mode && !n.flags.pinned) this.bringToFront(n); //if it wasnt selected? - var skip_action = false; //not dragging mouse to connect two slots if(!this.connecting_node && !n.flags.collapsed && !this.live_mode) @@ -3432,7 +3497,7 @@ LGraphCanvas.prototype.processMouseDown = function(e) else clicking_canvas_bg = true; - if(clicking_canvas_bg && this.allow_dragcanvas) + if(!skip_action && clicking_canvas_bg && this.allow_dragcanvas) { this.dragging_canvas = true; } @@ -3488,7 +3553,13 @@ LGraphCanvas.prototype.processMouseMove = function(e) this.last_mouse = mouse; this.canvas_mouse = [e.canvasX, e.canvasY]; - if(this.dragging_canvas) + if( this.dragging_rectangle ) + { + this.dragging_rectangle[2] = e.canvasX - this.dragging_rectangle[0]; + this.dragging_rectangle[3] = e.canvasY - this.dragging_rectangle[1]; + this.dirty_canvas = true; + } + else if(this.dragging_canvas) { this.offset[0] += delta[0] / this.scale; this.offset[1] += delta[1] / this.scale; @@ -3501,7 +3572,7 @@ LGraphCanvas.prototype.processMouseMove = function(e) this.dirty_canvas = true; //get node over - var n = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes); + var n = this.graph.getNodeOnPos( e.canvasX, e.canvasY, this.visible_nodes ); //remove mouseover flag for(var i = 0, l = this.graph._nodes.length; i < l; ++i) @@ -3640,8 +3711,32 @@ LGraphCanvas.prototype.processMouseUp = function(e) if (e.which == 1) //left button { - //dragging a connection - if(this.connecting_node) + if( this.dragging_rectangle ) + { + if(this.graph) + { + var nodes = this.graph._nodes; + var node_bounding = new Float32Array(4); + this.deselectAllNodes(); + if( this.dragging_rectangle[2] < 0 ) //flip if negative width + this.dragging_rectangle[0] += this.dragging_rectangle[2]; + if( this.dragging_rectangle[3] < 0 ) //flip if negative height + this.dragging_rectangle[1] += this.dragging_rectangle[3]; + this.dragging_rectangle[2] = Math.abs( this.dragging_rectangle[2] * this.scale ); //abs to convert negative width + this.dragging_rectangle[3] = Math.abs( this.dragging_rectangle[3] * this.scale ); //abs to convert negative height + + for(var i = 0; i < nodes.length; ++i) + { + var node = nodes[i]; + node.getBounding( node_bounding ); + if(!overlapBounding( this.dragging_rectangle, node_bounding )) + continue; //out of the visible area + this.selectNode( node, true ); + } + } + this.dragging_rectangle = null; + } + else if(this.connecting_node) //dragging a connection { this.dirty_canvas = true; this.dirty_bgcanvas = true; @@ -3700,6 +3795,13 @@ LGraphCanvas.prototype.processMouseUp = function(e) } else //no node being dragged { + //get node over + var node = this.graph.getNodeOnPos( e.canvasX, e.canvasY, this.visible_nodes ); + + var now = LiteGraph.getTime(); + if ( !node && (now - this.last_mouseclick) < 300 ) + this.deselectAllNodes(); + this.dirty_canvas = true; this.dragging_canvas = false; @@ -3798,18 +3900,23 @@ LGraphCanvas.prototype.processKey = function(e) return; var block_default = false; + //console.log(e); //debug if(e.target.localName == "input") return; if(e.type == "keydown") { - //console.log(e); //debug + if(e.keyCode == 32) + { + this.dragging_canvas = true; + block_default = true; + } //select all Control A if(e.keyCode == 65 && e.ctrlKey) { - this.selectAllNodes(); + this.selectNodes(); block_default = true; } @@ -3817,36 +3924,16 @@ LGraphCanvas.prototype.processKey = function(e) { if(this.selected_nodes) { - var nodes_data = []; - for(var i in this.selected_nodes) - nodes_data.push( this.selected_nodes[i].serialize() ); - localStorage.setItem( "litegrapheditor_clipboard", JSON.stringify(nodes_data) ); + this.copyToClipboard(); block_default = true; } } if(e.code == "KeyV" && (e.metaKey || e.ctrlKey) && !e.shiftKey ) //paste { - var data = localStorage.getItem( "litegrapheditor_clipboard" ); - if(data) - { - var nodes_data = JSON.parse(data); - for(var i = 0; i < nodes_data.length; ++i) - { - var node_data = nodes_data[i]; - var node = LiteGraph.createNode( node_data.type ); - if(node) - { - node.configure(node_data); - node.pos[0] += 5; - node.pos[1] += 5; - this.graph.add( node ); - } - } - } + this.pasteFromClipboard(); } - //delete or backspace if(e.keyCode == 46 || e.keyCode == 8) { @@ -3865,6 +3952,9 @@ LGraphCanvas.prototype.processKey = function(e) } else if( e.type == "keyup" ) { + if(e.keyCode == 32) + this.dragging_canvas = false; + if(this.selected_nodes) for (var i in this.selected_nodes) if(this.selected_nodes[i].onKeyUp) @@ -3880,6 +3970,79 @@ LGraphCanvas.prototype.processKey = function(e) } } +LGraphCanvas.prototype.copyToClipboard = function() +{ + var clipboard_info = { + nodes: [], + links: [] + }; + var index = 0; + var selected_nodes_array = []; + for(var i in this.selected_nodes) + { + var node = this.selected_nodes[i]; + node._relative_id = index; + selected_nodes_array.push( node ); + index += 1; + } + + for(var i = 0; i < selected_nodes_array.length; ++i) + { + var node = selected_nodes_array[i]; + clipboard_info.nodes.push( node.clone().serialize() ); + if(node.inputs && node.inputs.length) + for(var j = 0; j < node.inputs.length; ++j) + { + var input = node.inputs[j]; + if(!input || input.link == null) + continue; + var link_info = this.graph.links[ input.link ]; + if(!link_info) + continue; + var target_node = this.graph.getNodeById( link_info.origin_id ); + if(!target_node || !this.selected_nodes[ target_node.id ] ) //improve this by allowing connections to non-selected nodes + continue; //not selected + clipboard_info.links.push([ target_node._relative_id, j, node._relative_id, link_info.target_slot ]); + } + } + localStorage.setItem( "litegrapheditor_clipboard", JSON.stringify( clipboard_info ) ); +} + +LGraphCanvas.prototype.pasteFromClipboard = function() +{ + var data = localStorage.getItem( "litegrapheditor_clipboard" ); + if(!data) + return; + + //create nodes + var clipboard_info = JSON.parse(data); + var nodes = []; + for(var i = 0; i < clipboard_info.nodes.length; ++i) + { + var node_data = clipboard_info.nodes[i]; + var node = LiteGraph.createNode( node_data.type ); + if(node) + { + node.configure(node_data); + node.pos[0] += 5; + node.pos[1] += 5; + this.graph.add( node ); + nodes.push( node ); + } + } + + //create links + for(var i = 0; i < clipboard_info.links.length; ++i) + { + var link_info = clipboard_info.links[i]; + var origin_node = nodes[ link_info[0] ]; + var target_node = nodes[ link_info[2] ]; + origin_node.connect( link_info[1], target_node, link_info[3] ); + } + + this.selectNodes( nodes ); +} + LGraphCanvas.prototype.processDrop = function(e) { e.preventDefault(); @@ -3969,42 +4132,6 @@ LGraphCanvas.prototype.checkDropItem = function(e) } -LGraphCanvas.prototype.processNodeSelected = function(n,e) -{ - n.selected = true; - if (n.onSelected) - n.onSelected(); - - if(e && e.shiftKey) //add to selection - this.selected_nodes[n.id] = n; - else - { - this.selected_nodes = {}; - this.selected_nodes[ n.id ] = n; - } - - this.dirty_canvas = true; - - if(this.onNodeSelected) - this.onNodeSelected(n); - - //if(this.node_in_panel) this.showNodePanel(n); -} - -LGraphCanvas.prototype.processNodeDeselected = function(n) -{ - n.selected = false; - if(n.onDeselected) - n.onDeselected(); - - delete this.selected_nodes[n.id]; - - if(this.onNodeDeselected) - this.onNodeDeselected(n); - - this.dirty_canvas = true; -} - LGraphCanvas.prototype.processNodeDblClicked = function(n) { if(this.onShowNodePanel) @@ -4016,44 +4143,100 @@ LGraphCanvas.prototype.processNodeDblClicked = function(n) this.setDirty(true); } -LGraphCanvas.prototype.selectNode = function(node) +LGraphCanvas.prototype.processNodeSelected = function(node,e) { - this.deselectAllNodes(); - - if(!node) - return; - - if(!node.selected && node.onSelected) - node.onSelected(); - node.selected = true; - this.selected_nodes[ node.id ] = node; - this.setDirty(true); + this.selectNode( node, e && e.shiftKey ); + if(this.onNodeSelected) + this.onNodeSelected(node); } -LGraphCanvas.prototype.selectAllNodes = function() +LGraphCanvas.prototype.processNodeDeselected = function(node) { - for(var i = 0; i < this.graph._nodes.length; ++i) + this.deselectNode(node); + if(this.onNodeDeselected) + this.onNodeDeselected(node); +} + +LGraphCanvas.prototype.selectNode = function( node, add_to_current_selection ) +{ + if(node == null) + this.deselectAllNodes(); + else + this.selectNodes([node], add_to_current_selection ); +} + +LGraphCanvas.prototype.selectNodes = function( nodes, add_to_current_selection ) +{ + if(!add_to_current_selection) + this.deselectAllNodes(); + + nodes = nodes || this.graph._nodes; + for(var i = 0; i < nodes.length; ++i) { - var n = this.graph._nodes[i]; - if(!n.selected && n.onSelected) - n.onSelected(); - n.selected = true; - this.selected_nodes[this.graph._nodes[i].id] = n; + var node = nodes[i]; + if(node.selected) + continue; + + if( !node.selected && node.onSelected ) + node.onSelected(); + node.selected = true; + this.selected_nodes[ node.id ] = node; + + if(node.inputs) + for(var i = 0; i < node.inputs.length; ++i) + this.highlighted_links[ node.inputs[i].link ] = true; + if(node.outputs) + for(var i = 0; i < node.outputs.length; ++i) + { + var out = node.outputs[i]; + if( out.links ) + for(var j = 0; j < out.links.length; ++j) + this.highlighted_links[ out.links[j] ] = true; + } + } this.setDirty(true); } +LGraphCanvas.prototype.deselectNode = function( node ) +{ + if(!node.selected) + return; + if(node.onDeselected) + node.onDeselected(); + node.selected = false; + + //remove highlighted + if(node.inputs) + for(var i = 0; i < node.inputs.length; ++i) + delete this.highlighted_links[ node.inputs[i].link ]; + if(node.outputs) + for(var i = 0; i < node.outputs.length; ++i) + { + var out = node.outputs[i]; + if( out.links ) + for(var j = 0; j < out.links.length; ++j) + delete this.highlighted_links[ out.links[j] ]; + } +} + LGraphCanvas.prototype.deselectAllNodes = function() { - for(var i in this.selected_nodes) + if(!this.graph) + return; + var nodes = this.graph._nodes; + for(var i = 0, l = nodes.length; i < l; ++i) { - var n = this.selected_nodes; - if(n.onDeselected) - n.onDeselected(); - n.selected = false; + var node = nodes[i]; + if(!node.selected) + continue; + if(node.onDeselected) + node.onDeselected(); + node.selected = false; } this.selected_nodes = {}; + this.highlighted_links = {}; this.setDirty(true); } @@ -4066,6 +4249,7 @@ LGraphCanvas.prototype.deleteSelectedNodes = function() this.graph.remove(m); } this.selected_nodes = {}; + this.highlighted_links = {}; this.setDirty(true); } @@ -4110,20 +4294,25 @@ LGraphCanvas.prototype.setZoom = function(value, zooming_center) this.dirty_bgcanvas = true; } -LGraphCanvas.prototype.convertOffsetToCanvas = function(pos) +LGraphCanvas.prototype.convertOffsetToCanvas = function( pos, out ) { - return [pos[0] / this.scale - this.offset[0], pos[1] / this.scale - this.offset[1]]; + out = out || []; + out[0] = pos[0] / this.scale - this.offset[0]; + out[1] = pos[1] / this.scale - this.offset[1]; + return out; } -LGraphCanvas.prototype.convertCanvasToOffset = function(pos) +LGraphCanvas.prototype.convertCanvasToOffset = function( pos, out ) { - return [(pos[0] + this.offset[0]) * this.scale, - (pos[1] + this.offset[1]) * this.scale ]; + out = out || []; + out[0] = (pos[0] + this.offset[0]) * this.scale; + out[1] = (pos[1] + this.offset[1]) * this.scale; + return out; } LGraphCanvas.prototype.convertEventToCanvas = function(e) { - var rect = this.canvas.getClientRects()[0]; + var rect = this.canvas.getBoundingClientRect(); return this.convertOffsetToCanvas([e.pageX - rect.left,e.pageY - rect.top]); } @@ -4150,14 +4339,16 @@ LGraphCanvas.prototype.sendToBack = function(n) /* LGraphCanvas render */ +var temp = new Float32Array(4); -LGraphCanvas.prototype.computeVisibleNodes = function() +LGraphCanvas.prototype.computeVisibleNodes = function( nodes, out ) { - var temp = new Float32Array(4); - var visible_nodes = []; - for(var i = 0, l = this.graph._nodes.length; i < l; ++i) + var visible_nodes = out || []; + visible_nodes.length = 0; + nodes = nodes || this.graph._nodes; + for(var i = 0, l = nodes.length; i < l; ++i) { - var n = this.graph._nodes[i]; + var n = nodes[i]; //skip rendering nodes in live mode if(this.live_mode && !n.onDrawBackground && !n.onDrawForeground) @@ -4185,7 +4376,7 @@ LGraphCanvas.prototype.draw = function(force_canvas, force_bgcanvas) { var start = [-this.offset[0], -this.offset[1] ]; var end = [start[0] + this.canvas.width / this.scale, start[1] + this.canvas.height / this.scale]; - this.visible_area = new Float32Array([start[0],start[1],end[0],end[1]]); + this.visible_area = new Float32Array([ start[0], start[1], end[0] - start[0], end[1] - start[1] ]); } if(this.dirty_bgcanvas || force_bgcanvas || this.always_render_background || (this.graph && this.graph._last_trigger_time && (now - this.graph._last_trigger_time) < 1000) ) @@ -4252,8 +4443,7 @@ LGraphCanvas.prototype.drawFrontCanvas = function() //draw nodes var drawn_nodes = 0; - var visible_nodes = this.computeVisibleNodes(); - this.visible_nodes = visible_nodes; + var visible_nodes = this.computeVisibleNodes( null, this.visible_nodes ); for (var i = 0; i < visible_nodes.length; ++i) { @@ -4305,6 +4495,14 @@ LGraphCanvas.prototype.drawFrontCanvas = function() ctx.fill(); } } + + if( this.dragging_rectangle ) + { + ctx.strokeStyle = "#FFF"; + ctx.strokeRect( this.dragging_rectangle[0], this.dragging_rectangle[1], this.dragging_rectangle[2], this.dragging_rectangle[3] ); + } + + ctx.restore(); } @@ -4409,7 +4607,7 @@ LGraphCanvas.prototype.drawBackCanvas = function() if(pattern) { ctx.fillStyle = pattern; - ctx.fillRect(this.visible_area[0],this.visible_area[1],this.visible_area[2]-this.visible_area[0],this.visible_area[3]-this.visible_area[1]); + ctx.fillRect(this.visible_area[0],this.visible_area[1],this.visible_area[2],this.visible_area[3]); ctx.fillStyle = "transparent"; } @@ -4422,7 +4620,7 @@ LGraphCanvas.prototype.drawBackCanvas = function() //DEBUG: show clipping area //ctx.fillStyle = "red"; - //ctx.fillRect( this.visible_area[0] + 10, this.visible_area[1] + 10, this.visible_area[2] - this.visible_area[0] - 20, this.visible_area[3] - this.visible_area[1] - 20); + //ctx.fillRect( this.visible_area[0] + 10, this.visible_area[1] + 10, this.visible_area[2] - 20, this.visible_area[3] - 20); //bg ctx.strokeStyle = "#235"; @@ -4900,6 +5098,9 @@ LGraphCanvas.prototype.renderLink = function( ctx, a, b, link, skip_border, flow if(!color) color = this.default_link_color; + if( link != null && this.highlighted_links[ link.id ] ) + color = "#FFF"; + //begin line shape ctx.beginPath(); @@ -5509,7 +5710,7 @@ LGraphCanvas.prototype.createDialog = function( html, options ) dialog.className = "graphdialog"; dialog.innerHTML = html; - var rect = this.canvas.getClientRects()[0]; + var rect = this.canvas.getBoundingClientRect(); var offsetx = -20; var offsety = -20; if(rect) @@ -5645,7 +5846,8 @@ LGraphCanvas.onMenuNodeClone = function( value, options, e, menu, node ) { if(node.clonable == false) return; var newnode = node.clone(); - if(!newnode) return; + if(!newnode) + return; newnode.pos = [node.pos[0]+5,node.pos[1]+5]; node.graph.add(newnode); node.setDirtyCanvas(true,true); @@ -5907,13 +6109,18 @@ function isInsideBounding(p,bb) } LiteGraph.isInsideBounding = isInsideBounding; -//boundings overlap, format: [start,end] +//boundings overlap, format: [ startx, starty, width, height ] function overlapBounding(a,b) { - if ( a[0] > b[2] || - a[1] > b[3] || - a[2] < b[0] || - a[3] < b[1]) + var A_end_x = a[0] + a[2]; + var A_end_y = a[1] + a[3]; + var B_end_x = b[0] + b[2]; + var B_end_y = b[1] + b[3]; + + if ( a[0] > B_end_x || + a[1] > B_end_y || + A_end_x < b[0] || + A_end_y < b[1]) return false; return true; } diff --git a/src/litegraph-editor.js b/src/litegraph-editor.js index 8df40aab6..35c9f027b 100755 --- a/src/litegraph-editor.js +++ b/src/litegraph-editor.js @@ -184,6 +184,7 @@ Editor.prototype.addMiniWindow = function(w,h) var canvas = miniwindow.querySelector("canvas"); var graphcanvas = new LGraphCanvas(canvas, this.graph); + graphcanvas.show_info = false; graphcanvas.background_image = "imgs/grid.png"; graphcanvas.scale = 0.25; graphcanvas.allow_dragnodes = false; diff --git a/src/litegraph.js b/src/litegraph.js index d61882546..4b03238ce 100755 --- a/src/litegraph.js +++ b/src/litegraph.js @@ -133,7 +133,8 @@ var LiteGraph = global.LiteGraph = { }, /** - * create a new node type by passing a function, it wraps it with a propper class + * Create a new node type by passing a function, it wraps it with a propper class and generates inputs according to the parameters of the function. + * Useful to wrap simple methods that do not require properties, and that only process some input to generate an output. * @method wrapFunctionAsNode * @param {String} name node name with namespace (p.e.: 'math/sum') * @param {Function} func @@ -630,7 +631,7 @@ LGraph.prototype.updateExecutionOrder = function() } //This is more internal, it computes the order and returns it -LGraph.prototype.computeExecutionOrder = function( only_onExecute ) +LGraph.prototype.computeExecutionOrder = function( only_onExecute, set_level ) { var L = []; var S = []; @@ -641,22 +642,30 @@ LGraph.prototype.computeExecutionOrder = function( only_onExecute ) //search for the nodes without inputs (starting nodes) for (var i = 0, l = this._nodes.length; i < l; ++i) { - var n = this._nodes[i]; - if( only_onExecute && !n.onExecute ) + var node = this._nodes[i]; + if( only_onExecute && !node.onExecute ) continue; - M[n.id] = n; //add to pending nodes + M[node.id] = node; //add to pending nodes var num = 0; //num of input connections - if(n.inputs) - for(var j = 0, l2 = n.inputs.length; j < l2; j++) - if(n.inputs[j] && n.inputs[j].link != null) + if(node.inputs) + for(var j = 0, l2 = node.inputs.length; j < l2; j++) + if(node.inputs[j] && node.inputs[j].link != null) num += 1; if(num == 0) //is a starting node - S.push(n); + { + S.push(node); + if(set_level) + node._level = 1; + } else //num of input links - remaining_links[n.id] = num; + { + if(set_level) + node._level = 0; + remaining_links[node.id] = num; + } } while(true) @@ -665,43 +674,49 @@ LGraph.prototype.computeExecutionOrder = function( only_onExecute ) break; //get an starting node - var n = S.shift(); - L.push(n); //add to ordered list - delete M[n.id]; //remove from the pending nodes + var node = S.shift(); + L.push(node); //add to ordered list + delete M[node.id]; //remove from the pending nodes + + if(!node.outputs) + continue; //for every output - if(n.outputs) - for(var i = 0; i < n.outputs.length; i++) + for(var i = 0; i < node.outputs.length; i++) + { + var output = node.outputs[i]; + //not connected + if(output == null || output.links == null || output.links.length == 0) + continue; + + //for every connection + for(var j = 0; j < output.links.length; j++) { - var output = n.outputs[i]; - //not connected - if(output == null || output.links == null || output.links.length == 0) + var link_id = output.links[j]; + var link = this.links[link_id]; + if(!link) continue; - //for every connection - for(var j = 0; j < output.links.length; j++) + //already visited link (ignore it) + if(visited_links[ link.id ]) + continue; + + var target_node = this.getNodeById( link.target_id ); + if(target_node == null) { - var link_id = output.links[j]; - var link = this.links[link_id]; - if(!link) continue; - - //already visited link (ignore it) - if(visited_links[ link.id ]) - continue; - - var target_node = this.getNodeById( link.target_id ); - if(target_node == null) - { - visited_links[ link.id ] = true; - continue; - } - - visited_links[link.id] = true; //mark as visited - remaining_links[target_node.id] -= 1; //reduce the number of links remaining - if (remaining_links[target_node.id] == 0) - S.push(target_node); //if no more links, then add to Starters array + visited_links[ link.id ] = true; + continue; } + + if(set_level && (!target_node._level || target_node._level <= node._level)) + target_node._level = node._level + 1; + + visited_links[link.id] = true; //mark as visited + remaining_links[target_node.id] -= 1; //reduce the number of links remaining + if (remaining_links[ target_node.id ] == 0) + S.push(target_node); //if no more links, then add to starters array } + } } //the remaining ones (loops) @@ -718,13 +733,55 @@ LGraph.prototype.computeExecutionOrder = function( only_onExecute ) return L; } +/** +* Positions every node in a more readable manner +* @method arrange +*/ +LGraph.prototype.arrange = function( margin ) +{ + margin = margin || 40; + + var nodes = this.computeExecutionOrder( false, true ); + var columns = []; + for(var i = 0; i < nodes.length; ++i) + { + var node = nodes[i]; + var col = node._level || 1; + if(!columns[col]) + columns[col] = []; + columns[col].push( node ); + } + + var x = margin; + + for(var i = 0; i < columns.length; ++i) + { + var column = columns[i]; + if(!column) + continue; + var max_size = 100; + var y = margin; + for(var j = 0; j < column.length; ++j) + { + var node = column[j]; + node.pos[0] = x; + node.pos[1] = y; + if(node.size[0] > max_size) + max_size = node.size[0]; + y += node.size[1] + margin; + } + x += max_size + margin; + } + + this.setDirtyCanvas(true,true); +} + /** * Returns the amount of time the graph has been running in milliseconds * @method getTime * @return {number} number of milliseconds the graph has been running */ - LGraph.prototype.getTime = function() { return this.globaltime; @@ -2175,6 +2232,7 @@ LGraphNode.prototype.computeSize = function( minHeight, out ) /** * returns the bounding of the object, used for rendering purposes +* bounding is: [topleft_cornerx, topleft_cornery, width, height] * @method getBounding * @return {Float32Array[4]} the total size */ @@ -2183,8 +2241,8 @@ LGraphNode.prototype.getBounding = function( out ) out = out || new Float32Array(4); out[0] = this.pos[0] - 4; out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT; - out[2] = this.pos[0] + this.size[0] + 4; - out[3] = this.pos[1] + this.size[1] + LGraph.NODE_TITLE_HEIGHT; + out[2] = this.size[0] + 4; + out[3] = this.size[1] + LiteGraph.NODE_TITLE_HEIGHT; return out; } @@ -2530,8 +2588,7 @@ LGraphNode.prototype.disconnectInput = function( slot ) //search in the inputs list for this link for(var i = 0, l = output.links.length; i < l; i++) { - var link_id = output.links[i]; - if( link_info.target_id == this.id ) + if( output.links[i] == link_id ) { output.links.splice(i,1); break; @@ -2739,7 +2796,7 @@ function LGraphCanvas( canvas, graph, options ) //if(graph === undefined) // throw ("No graph assigned"); - this.background_image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII=' + this.background_image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII=' if(canvas && canvas.constructor === String ) canvas = document.querySelector( canvas ); @@ -2763,6 +2820,8 @@ function LGraphCanvas( canvas, graph, options ) this.allow_dragcanvas = true; this.allow_dragnodes = true; this.allow_interaction = true; //allow to control widgets, buttons, collapse, etc + this.drag_mode = false; + this.dragging_rectangle = null; this.always_render_background = false; this.render_connections_shadows = false; //too much cpu @@ -2805,11 +2864,15 @@ LGraphCanvas.prototype.clear = function() this.scale = 1; this.offset = [0,0]; + this.dragging_rectangle = null; + this.selected_nodes = {}; + this.visible_nodes = []; this.node_dragged = null; this.node_over = null; this.node_capturing_input = null; this.connecting_node = null; + this.highlighted_links = {}; this.dirty_canvas = true; this.dirty_bgcanvas = true; @@ -2895,6 +2958,7 @@ LGraphCanvas.prototype.closeSubgraph = function() return; var graph = this._graph_stack.pop(); this.selected_nodes = {}; + this.highlighted_links = {}; graph.attachCanvas(this); this.setDirty(true,true); } @@ -2982,6 +3046,8 @@ LGraphCanvas.prototype.bindEvents = function() } var canvas = this.canvas; + var ref_window = this.getCanvasWindow(); + var document = ref_window.document; //hack used when moving canvas between windows this._mousedown_callback = this.processMouseDown.bind(this); this._mousewheel_callback = this.processMouseWheel.bind(this); @@ -3005,8 +3071,8 @@ LGraphCanvas.prototype.bindEvents = function() //Keyboard ****************** this._key_callback = this.processKey.bind(this); - canvas.addEventListener("keydown", this._key_callback ); - canvas.addEventListener("keyup", this._key_callback ); + canvas.addEventListener("keydown", this._key_callback, true ); + document.addEventListener("keyup", this._key_callback, true ); //in document, otherwise it doesnt fire keyup //Droping Stuff over nodes ************************************ this._ondrop_callback = this.processDrop.bind(this); @@ -3027,11 +3093,14 @@ LGraphCanvas.prototype.unbindEvents = function() return; } + var ref_window = this.getCanvasWindow(); + var document = ref_window.document; + this.canvas.removeEventListener( "mousedown", this._mousedown_callback ); this.canvas.removeEventListener( "mousewheel", this._mousewheel_callback ); this.canvas.removeEventListener( "DOMMouseScroll", this._mousewheel_callback ); this.canvas.removeEventListener( "keydown", this._key_callback ); - this.canvas.removeEventListener( "keyup", this._key_callback ); + document.removeEventListener( "keyup", this._key_callback ); this.canvas.removeEventListener( "contextmenu", this._doNothing ); this.canvas.removeEventListener( "drop", this._ondrop_callback ); this.canvas.removeEventListener( "dragenter", this._doReturnTrue ); @@ -3222,34 +3291,30 @@ LGraphCanvas.prototype.processMouseDown = function(e) var n = this.graph.getNodeOnPos( e.canvasX, e.canvasY, this.visible_nodes ); var skip_dragging = false; + var skip_action = false; LiteGraph.closeAllContextMenus( ref_window ); if(e.which == 1) //left button mouse { - if(!e.shiftKey) //REFACTOR: integrate with function + if( e.ctrlKey ) { - //no node or another node selected - if (!n || !this.selected_nodes[n.id]) { - - var todeselect = []; - for (var i in this.selected_nodes) - if (this.selected_nodes[i] != n) - todeselect.push(this.selected_nodes[i]); - //two passes to avoid problems modifying the container - for (var i in todeselect) - this.processNodeDeselected(todeselect[i]); - } + this.dragging_rectangle = new Float32Array(4); + this.dragging_rectangle[0] = e.canvasX; + this.dragging_rectangle[1] = e.canvasY; + this.dragging_rectangle[2] = 1; + this.dragging_rectangle[3] = 1; + skip_action = true; } + var clicking_canvas_bg = false; //when clicked on top of a node //and it is not interactive - if(n && this.allow_interaction ) + if( n && this.allow_interaction && !skip_action ) { if(!this.live_mode && !n.flags.pinned) this.bringToFront(n); //if it wasnt selected? - var skip_action = false; //not dragging mouse to connect two slots if(!this.connecting_node && !n.flags.collapsed && !this.live_mode) @@ -3346,7 +3411,7 @@ LGraphCanvas.prototype.processMouseDown = function(e) else clicking_canvas_bg = true; - if(clicking_canvas_bg && this.allow_dragcanvas) + if(!skip_action && clicking_canvas_bg && this.allow_dragcanvas) { this.dragging_canvas = true; } @@ -3402,7 +3467,13 @@ LGraphCanvas.prototype.processMouseMove = function(e) this.last_mouse = mouse; this.canvas_mouse = [e.canvasX, e.canvasY]; - if(this.dragging_canvas) + if( this.dragging_rectangle ) + { + this.dragging_rectangle[2] = e.canvasX - this.dragging_rectangle[0]; + this.dragging_rectangle[3] = e.canvasY - this.dragging_rectangle[1]; + this.dirty_canvas = true; + } + else if(this.dragging_canvas) { this.offset[0] += delta[0] / this.scale; this.offset[1] += delta[1] / this.scale; @@ -3415,7 +3486,7 @@ LGraphCanvas.prototype.processMouseMove = function(e) this.dirty_canvas = true; //get node over - var n = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes); + var n = this.graph.getNodeOnPos( e.canvasX, e.canvasY, this.visible_nodes ); //remove mouseover flag for(var i = 0, l = this.graph._nodes.length; i < l; ++i) @@ -3554,8 +3625,32 @@ LGraphCanvas.prototype.processMouseUp = function(e) if (e.which == 1) //left button { - //dragging a connection - if(this.connecting_node) + if( this.dragging_rectangle ) + { + if(this.graph) + { + var nodes = this.graph._nodes; + var node_bounding = new Float32Array(4); + this.deselectAllNodes(); + if( this.dragging_rectangle[2] < 0 ) //flip if negative width + this.dragging_rectangle[0] += this.dragging_rectangle[2]; + if( this.dragging_rectangle[3] < 0 ) //flip if negative height + this.dragging_rectangle[1] += this.dragging_rectangle[3]; + this.dragging_rectangle[2] = Math.abs( this.dragging_rectangle[2] * this.scale ); //abs to convert negative width + this.dragging_rectangle[3] = Math.abs( this.dragging_rectangle[3] * this.scale ); //abs to convert negative height + + for(var i = 0; i < nodes.length; ++i) + { + var node = nodes[i]; + node.getBounding( node_bounding ); + if(!overlapBounding( this.dragging_rectangle, node_bounding )) + continue; //out of the visible area + this.selectNode( node, true ); + } + } + this.dragging_rectangle = null; + } + else if(this.connecting_node) //dragging a connection { this.dirty_canvas = true; this.dirty_bgcanvas = true; @@ -3614,6 +3709,13 @@ LGraphCanvas.prototype.processMouseUp = function(e) } else //no node being dragged { + //get node over + var node = this.graph.getNodeOnPos( e.canvasX, e.canvasY, this.visible_nodes ); + + var now = LiteGraph.getTime(); + if ( !node && (now - this.last_mouseclick) < 300 ) + this.deselectAllNodes(); + this.dirty_canvas = true; this.dragging_canvas = false; @@ -3712,18 +3814,23 @@ LGraphCanvas.prototype.processKey = function(e) return; var block_default = false; + //console.log(e); //debug if(e.target.localName == "input") return; if(e.type == "keydown") { - //console.log(e); //debug + if(e.keyCode == 32) + { + this.dragging_canvas = true; + block_default = true; + } //select all Control A if(e.keyCode == 65 && e.ctrlKey) { - this.selectAllNodes(); + this.selectNodes(); block_default = true; } @@ -3731,36 +3838,16 @@ LGraphCanvas.prototype.processKey = function(e) { if(this.selected_nodes) { - var nodes_data = []; - for(var i in this.selected_nodes) - nodes_data.push( this.selected_nodes[i].serialize() ); - localStorage.setItem( "litegrapheditor_clipboard", JSON.stringify(nodes_data) ); + this.copyToClipboard(); block_default = true; } } if(e.code == "KeyV" && (e.metaKey || e.ctrlKey) && !e.shiftKey ) //paste { - var data = localStorage.getItem( "litegrapheditor_clipboard" ); - if(data) - { - var nodes_data = JSON.parse(data); - for(var i = 0; i < nodes_data.length; ++i) - { - var node_data = nodes_data[i]; - var node = LiteGraph.createNode( node_data.type ); - if(node) - { - node.configure(node_data); - node.pos[0] += 5; - node.pos[1] += 5; - this.graph.add( node ); - } - } - } + this.pasteFromClipboard(); } - //delete or backspace if(e.keyCode == 46 || e.keyCode == 8) { @@ -3779,6 +3866,9 @@ LGraphCanvas.prototype.processKey = function(e) } else if( e.type == "keyup" ) { + if(e.keyCode == 32) + this.dragging_canvas = false; + if(this.selected_nodes) for (var i in this.selected_nodes) if(this.selected_nodes[i].onKeyUp) @@ -3794,6 +3884,79 @@ LGraphCanvas.prototype.processKey = function(e) } } +LGraphCanvas.prototype.copyToClipboard = function() +{ + var clipboard_info = { + nodes: [], + links: [] + }; + var index = 0; + var selected_nodes_array = []; + for(var i in this.selected_nodes) + { + var node = this.selected_nodes[i]; + node._relative_id = index; + selected_nodes_array.push( node ); + index += 1; + } + + for(var i = 0; i < selected_nodes_array.length; ++i) + { + var node = selected_nodes_array[i]; + clipboard_info.nodes.push( node.clone().serialize() ); + if(node.inputs && node.inputs.length) + for(var j = 0; j < node.inputs.length; ++j) + { + var input = node.inputs[j]; + if(!input || input.link == null) + continue; + var link_info = this.graph.links[ input.link ]; + if(!link_info) + continue; + var target_node = this.graph.getNodeById( link_info.origin_id ); + if(!target_node || !this.selected_nodes[ target_node.id ] ) //improve this by allowing connections to non-selected nodes + continue; //not selected + clipboard_info.links.push([ target_node._relative_id, j, node._relative_id, link_info.target_slot ]); + } + } + localStorage.setItem( "litegrapheditor_clipboard", JSON.stringify( clipboard_info ) ); +} + +LGraphCanvas.prototype.pasteFromClipboard = function() +{ + var data = localStorage.getItem( "litegrapheditor_clipboard" ); + if(!data) + return; + + //create nodes + var clipboard_info = JSON.parse(data); + var nodes = []; + for(var i = 0; i < clipboard_info.nodes.length; ++i) + { + var node_data = clipboard_info.nodes[i]; + var node = LiteGraph.createNode( node_data.type ); + if(node) + { + node.configure(node_data); + node.pos[0] += 5; + node.pos[1] += 5; + this.graph.add( node ); + nodes.push( node ); + } + } + + //create links + for(var i = 0; i < clipboard_info.links.length; ++i) + { + var link_info = clipboard_info.links[i]; + var origin_node = nodes[ link_info[0] ]; + var target_node = nodes[ link_info[2] ]; + origin_node.connect( link_info[1], target_node, link_info[3] ); + } + + this.selectNodes( nodes ); +} + LGraphCanvas.prototype.processDrop = function(e) { e.preventDefault(); @@ -3883,42 +4046,6 @@ LGraphCanvas.prototype.checkDropItem = function(e) } -LGraphCanvas.prototype.processNodeSelected = function(n,e) -{ - n.selected = true; - if (n.onSelected) - n.onSelected(); - - if(e && e.shiftKey) //add to selection - this.selected_nodes[n.id] = n; - else - { - this.selected_nodes = {}; - this.selected_nodes[ n.id ] = n; - } - - this.dirty_canvas = true; - - if(this.onNodeSelected) - this.onNodeSelected(n); - - //if(this.node_in_panel) this.showNodePanel(n); -} - -LGraphCanvas.prototype.processNodeDeselected = function(n) -{ - n.selected = false; - if(n.onDeselected) - n.onDeselected(); - - delete this.selected_nodes[n.id]; - - if(this.onNodeDeselected) - this.onNodeDeselected(n); - - this.dirty_canvas = true; -} - LGraphCanvas.prototype.processNodeDblClicked = function(n) { if(this.onShowNodePanel) @@ -3930,44 +4057,100 @@ LGraphCanvas.prototype.processNodeDblClicked = function(n) this.setDirty(true); } -LGraphCanvas.prototype.selectNode = function(node) +LGraphCanvas.prototype.processNodeSelected = function(node,e) { - this.deselectAllNodes(); - - if(!node) - return; - - if(!node.selected && node.onSelected) - node.onSelected(); - node.selected = true; - this.selected_nodes[ node.id ] = node; - this.setDirty(true); + this.selectNode( node, e && e.shiftKey ); + if(this.onNodeSelected) + this.onNodeSelected(node); } -LGraphCanvas.prototype.selectAllNodes = function() +LGraphCanvas.prototype.processNodeDeselected = function(node) { - for(var i = 0; i < this.graph._nodes.length; ++i) + this.deselectNode(node); + if(this.onNodeDeselected) + this.onNodeDeselected(node); +} + +LGraphCanvas.prototype.selectNode = function( node, add_to_current_selection ) +{ + if(node == null) + this.deselectAllNodes(); + else + this.selectNodes([node], add_to_current_selection ); +} + +LGraphCanvas.prototype.selectNodes = function( nodes, add_to_current_selection ) +{ + if(!add_to_current_selection) + this.deselectAllNodes(); + + nodes = nodes || this.graph._nodes; + for(var i = 0; i < nodes.length; ++i) { - var n = this.graph._nodes[i]; - if(!n.selected && n.onSelected) - n.onSelected(); - n.selected = true; - this.selected_nodes[this.graph._nodes[i].id] = n; + var node = nodes[i]; + if(node.selected) + continue; + + if( !node.selected && node.onSelected ) + node.onSelected(); + node.selected = true; + this.selected_nodes[ node.id ] = node; + + if(node.inputs) + for(var i = 0; i < node.inputs.length; ++i) + this.highlighted_links[ node.inputs[i].link ] = true; + if(node.outputs) + for(var i = 0; i < node.outputs.length; ++i) + { + var out = node.outputs[i]; + if( out.links ) + for(var j = 0; j < out.links.length; ++j) + this.highlighted_links[ out.links[j] ] = true; + } + } this.setDirty(true); } +LGraphCanvas.prototype.deselectNode = function( node ) +{ + if(!node.selected) + return; + if(node.onDeselected) + node.onDeselected(); + node.selected = false; + + //remove highlighted + if(node.inputs) + for(var i = 0; i < node.inputs.length; ++i) + delete this.highlighted_links[ node.inputs[i].link ]; + if(node.outputs) + for(var i = 0; i < node.outputs.length; ++i) + { + var out = node.outputs[i]; + if( out.links ) + for(var j = 0; j < out.links.length; ++j) + delete this.highlighted_links[ out.links[j] ]; + } +} + LGraphCanvas.prototype.deselectAllNodes = function() { - for(var i in this.selected_nodes) + if(!this.graph) + return; + var nodes = this.graph._nodes; + for(var i = 0, l = nodes.length; i < l; ++i) { - var n = this.selected_nodes; - if(n.onDeselected) - n.onDeselected(); - n.selected = false; + var node = nodes[i]; + if(!node.selected) + continue; + if(node.onDeselected) + node.onDeselected(); + node.selected = false; } this.selected_nodes = {}; + this.highlighted_links = {}; this.setDirty(true); } @@ -3980,6 +4163,7 @@ LGraphCanvas.prototype.deleteSelectedNodes = function() this.graph.remove(m); } this.selected_nodes = {}; + this.highlighted_links = {}; this.setDirty(true); } @@ -4024,20 +4208,25 @@ LGraphCanvas.prototype.setZoom = function(value, zooming_center) this.dirty_bgcanvas = true; } -LGraphCanvas.prototype.convertOffsetToCanvas = function(pos) +LGraphCanvas.prototype.convertOffsetToCanvas = function( pos, out ) { - return [pos[0] / this.scale - this.offset[0], pos[1] / this.scale - this.offset[1]]; + out = out || []; + out[0] = pos[0] / this.scale - this.offset[0]; + out[1] = pos[1] / this.scale - this.offset[1]; + return out; } -LGraphCanvas.prototype.convertCanvasToOffset = function(pos) +LGraphCanvas.prototype.convertCanvasToOffset = function( pos, out ) { - return [(pos[0] + this.offset[0]) * this.scale, - (pos[1] + this.offset[1]) * this.scale ]; + out = out || []; + out[0] = (pos[0] + this.offset[0]) * this.scale; + out[1] = (pos[1] + this.offset[1]) * this.scale; + return out; } LGraphCanvas.prototype.convertEventToCanvas = function(e) { - var rect = this.canvas.getClientRects()[0]; + var rect = this.canvas.getBoundingClientRect(); return this.convertOffsetToCanvas([e.pageX - rect.left,e.pageY - rect.top]); } @@ -4064,14 +4253,16 @@ LGraphCanvas.prototype.sendToBack = function(n) /* LGraphCanvas render */ +var temp = new Float32Array(4); -LGraphCanvas.prototype.computeVisibleNodes = function() +LGraphCanvas.prototype.computeVisibleNodes = function( nodes, out ) { - var temp = new Float32Array(4); - var visible_nodes = []; - for(var i = 0, l = this.graph._nodes.length; i < l; ++i) + var visible_nodes = out || []; + visible_nodes.length = 0; + nodes = nodes || this.graph._nodes; + for(var i = 0, l = nodes.length; i < l; ++i) { - var n = this.graph._nodes[i]; + var n = nodes[i]; //skip rendering nodes in live mode if(this.live_mode && !n.onDrawBackground && !n.onDrawForeground) @@ -4099,7 +4290,7 @@ LGraphCanvas.prototype.draw = function(force_canvas, force_bgcanvas) { var start = [-this.offset[0], -this.offset[1] ]; var end = [start[0] + this.canvas.width / this.scale, start[1] + this.canvas.height / this.scale]; - this.visible_area = new Float32Array([start[0],start[1],end[0],end[1]]); + this.visible_area = new Float32Array([ start[0], start[1], end[0] - start[0], end[1] - start[1] ]); } if(this.dirty_bgcanvas || force_bgcanvas || this.always_render_background || (this.graph && this.graph._last_trigger_time && (now - this.graph._last_trigger_time) < 1000) ) @@ -4166,8 +4357,7 @@ LGraphCanvas.prototype.drawFrontCanvas = function() //draw nodes var drawn_nodes = 0; - var visible_nodes = this.computeVisibleNodes(); - this.visible_nodes = visible_nodes; + var visible_nodes = this.computeVisibleNodes( null, this.visible_nodes ); for (var i = 0; i < visible_nodes.length; ++i) { @@ -4219,6 +4409,14 @@ LGraphCanvas.prototype.drawFrontCanvas = function() ctx.fill(); } } + + if( this.dragging_rectangle ) + { + ctx.strokeStyle = "#FFF"; + ctx.strokeRect( this.dragging_rectangle[0], this.dragging_rectangle[1], this.dragging_rectangle[2], this.dragging_rectangle[3] ); + } + + ctx.restore(); } @@ -4323,7 +4521,7 @@ LGraphCanvas.prototype.drawBackCanvas = function() if(pattern) { ctx.fillStyle = pattern; - ctx.fillRect(this.visible_area[0],this.visible_area[1],this.visible_area[2]-this.visible_area[0],this.visible_area[3]-this.visible_area[1]); + ctx.fillRect(this.visible_area[0],this.visible_area[1],this.visible_area[2],this.visible_area[3]); ctx.fillStyle = "transparent"; } @@ -4336,7 +4534,7 @@ LGraphCanvas.prototype.drawBackCanvas = function() //DEBUG: show clipping area //ctx.fillStyle = "red"; - //ctx.fillRect( this.visible_area[0] + 10, this.visible_area[1] + 10, this.visible_area[2] - this.visible_area[0] - 20, this.visible_area[3] - this.visible_area[1] - 20); + //ctx.fillRect( this.visible_area[0] + 10, this.visible_area[1] + 10, this.visible_area[2] - 20, this.visible_area[3] - 20); //bg ctx.strokeStyle = "#235"; @@ -4814,6 +5012,9 @@ LGraphCanvas.prototype.renderLink = function( ctx, a, b, link, skip_border, flow if(!color) color = this.default_link_color; + if( link != null && this.highlighted_links[ link.id ] ) + color = "#FFF"; + //begin line shape ctx.beginPath(); @@ -5423,7 +5624,7 @@ LGraphCanvas.prototype.createDialog = function( html, options ) dialog.className = "graphdialog"; dialog.innerHTML = html; - var rect = this.canvas.getClientRects()[0]; + var rect = this.canvas.getBoundingClientRect(); var offsetx = -20; var offsety = -20; if(rect) @@ -5559,7 +5760,8 @@ LGraphCanvas.onMenuNodeClone = function( value, options, e, menu, node ) { if(node.clonable == false) return; var newnode = node.clone(); - if(!newnode) return; + if(!newnode) + return; newnode.pos = [node.pos[0]+5,node.pos[1]+5]; node.graph.add(newnode); node.setDirtyCanvas(true,true); @@ -5821,13 +6023,18 @@ function isInsideBounding(p,bb) } LiteGraph.isInsideBounding = isInsideBounding; -//boundings overlap, format: [start,end] +//boundings overlap, format: [ startx, starty, width, height ] function overlapBounding(a,b) { - if ( a[0] > b[2] || - a[1] > b[3] || - a[2] < b[0] || - a[3] < b[1]) + var A_end_x = a[0] + a[2]; + var A_end_y = a[1] + a[3]; + var B_end_x = b[0] + b[2]; + var B_end_y = b[1] + b[3]; + + if ( a[0] > B_end_x || + a[1] > B_end_y || + A_end_x < b[0] || + A_end_y < b[1]) return false; return true; }