diff --git a/build/litegraph.js b/build/litegraph.js index 17a58dea1..c55d96863 100644 --- a/build/litegraph.js +++ b/build/litegraph.js @@ -1159,7 +1159,9 @@ LGraph.prototype.onNodeTrace = function(node, msg, color) + onSerialize + onSelected + onDeselected - + onDropFile + + onDropItem : DOM item dropped over the node + + onDropFile : file dropped over the node + + onConnectInput : if returns false the incoming connection will be canceled */ /** @@ -1179,7 +1181,23 @@ LGraphNode.prototype._ctor = function( title ) this.size = [LiteGraph.NODE_WIDTH,60]; this.graph = null; - this.pos = [10,10]; + this._pos = new Float32Array(10,10); + + Object.defineProperty( this, "pos", { + set: function(v) + { + if(!v || !v.length < 2) + return; + this._pos[0] = v[0]; + this._pos[1] = v[1]; + }, + get: function() + { + return this._pos; + }, + enumerable: true + }); + this.id = -1; //not know till not added this.type = null; @@ -1769,8 +1787,14 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) return false; } + if(node && node.constructor === Number) + node = this.graph.getNodeById( node ); + if(!node) + throw("Node not found"); + //avoid loopback - if(node == this) return false; + if(node == this) + return false; //if( node.constructor != LGraphNode ) throw ("LGraphNode.connect: node is not of type LGraphNode"); if(target_slot.constructor === String) @@ -1793,9 +1817,18 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) //if there is something already plugged there, disconnect if(target_slot != -1 && node.inputs[target_slot].link != null) node.disconnectInput(target_slot); + + this.setDirtyCanvas(false,true); + this.graph.onConnectionChange(); //special case: -1 means node-connection, used for triggers var output = this.outputs[slot]; + + //allows nodes to block connection even if all test passes + if(node.onConnectInput) + if( node.onConnectInput( target_slot, output.type, output ) === false) + return false; + if(target_slot == -1) { if( output.links == null ) @@ -1816,8 +1849,6 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) output.links.push( link.id ); node.inputs[target_slot].link = link.id; - this.setDirtyCanvas(false,true); - this.graph.onConnectionChange(); } return true; } @@ -1855,6 +1886,11 @@ LGraphNode.prototype.disconnectOutput = function(slot, target_node) if(target_node) { + if(target_node.constructor === Number) + target_node = this.graph.getNodeById( target_node ); + if(!target_node) + throw("Target Node not found"); + for(var i = 0, l = output.links.length; i < l; i++) { var link_id = output.links[i]; @@ -2352,7 +2388,8 @@ LGraphCanvas.prototype.setCanvas = function( canvas, skip_events ) } //used in some events to capture them -LGraphCanvas.prototype._doNothing = function doNothing() { return false; }; +LGraphCanvas.prototype._doNothing = function doNothing(e) { e.preventDefault(); return false; }; +LGraphCanvas.prototype._doReturnTrue = function doNothing(e) { e.preventDefault(); return true; }; LGraphCanvas.prototype.bindEvents = function() { @@ -2395,6 +2432,7 @@ LGraphCanvas.prototype.bindEvents = function() canvas.addEventListener("dragover", this._doNothing, false ); canvas.addEventListener("dragend", this._doNothing, false ); canvas.addEventListener("drop", this._ondrop_callback, false ); + canvas.addEventListener("dragenter", this._doReturnTrue, false ); this._events_binded = true; } @@ -2414,6 +2452,7 @@ LGraphCanvas.prototype.unbindEvents = function() 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 ); @@ -3098,35 +3137,57 @@ LGraphCanvas.prototype.processDrop = function(e) e.preventDefault(); this.adjustMouseEvent(e); + var pos = [e.canvasX,e.canvasY]; var node = this.graph.getNodeOnPos(pos[0],pos[1]); + if(!node) + { + if(this.onDropItem) + this.onDropItem( event ); return; + } - if(!node.onDropFile) - return; + if(node.onDropFile) + { + var files = e.dataTransfer.files; + if(files && files.length) + { + for(var i=0; i < files.length; i++) + { + var file = e.dataTransfer.files[0]; + var filename = file.name; + var ext = LGraphCanvas.getFileExtension( filename ); + //console.log(file); - var file = e.dataTransfer.files[0]; - var filename = file.name; - var ext = LGraphCanvas.getFileExtension( filename ); - //console.log(file); + //prepare reader + var reader = new FileReader(); + reader.onload = function (event) { + //console.log(event.target); + var data = event.target.result; + node.onDropFile( data, filename, file ); + }; - //prepare reader - var reader = new FileReader(); - reader.onload = function (event) { - //console.log(event.target); - var data = event.target.result; - node.onDropFile( data, filename, file ); - }; + //read data + var type = file.type.split("/")[0]; + if(type == "text" || type == "") + reader.readAsText(file); + else if (type == "image") + reader.readAsDataURL(file); + else + reader.readAsArrayBuffer(file); + } + } + } - //read data - var type = file.type.split("/")[0]; - if(type == "text" || type == "") - reader.readAsText(file); - else if (type == "image") - reader.readAsDataURL(file); - else - reader.readAsArrayBuffer(file); + if(node.onDropItem) + { + if( node.onDropItem( event ) ) + return true; + } + + if(this.onDropItem) + return this.onDropItem( event ); return false; } @@ -4476,6 +4537,7 @@ LGraphCanvas.prototype.processContextualMenu = function(node, event) var win = this.getCanvasWindow(); var menu_info = null; + var options = {event: event, callback: inner_option_clicked}; //check if mouse is in input var slot = null; @@ -4483,15 +4545,19 @@ LGraphCanvas.prototype.processContextualMenu = function(node, event) slot = node.getSlotInPosition( event.canvasX, event.canvasY ); if(slot) + { menu_info = slot.locked ? [ "Cannot remove" ] : { "Remove Slot": slot }; + options.title = slot.input ? slot.input.type : slot.output.type; + } else menu_info = node ? this.getNodeMenuOptions(node) : this.getCanvasMenuOptions(); + //show menu if(!menu_info) return; - var menu = LiteGraph.createContextualMenu( menu_info, {event: event, callback: inner_option_clicked}, win); + var menu = LiteGraph.createContextualMenu( menu_info, options, win); function inner_option_clicked(v,e) { @@ -4664,6 +4730,15 @@ LiteGraph.createContextualMenu = function(values,options, ref_window) style.borderBottom = "2px solid #AAF"; style.backgroundColor = "#444"; + //title + if(options.title) + { + var element = document.createElement("div"); + element.className = "graphcontextualmenu-title"; + element.innerHTML = options.title; + root.appendChild(element); + } + //avoid a context menu in a context menu root.addEventListener("contextmenu", function(e) { e.preventDefault(); return false; }); @@ -5948,8 +6023,6 @@ GamepadInput.prototype.onExecute = function() { //get gamepad var gamepad = this.getGamepad(); - if(!gamepad) - return; if(this.outputs) { @@ -5957,23 +6030,44 @@ GamepadInput.prototype.onExecute = function() { var output = this.outputs[i]; var v = null; - switch( output.name ) + + if(gamepad) { - case "left_x_axis": v = gamepad.xbox.axes["lx"]; break; - case "left_y_axis": v = gamepad.xbox.axes["ly"]; break; - case "right_x_axis": v = gamepad.xbox.axes["rx"]; break; - case "right_y_axis": v = gamepad.xbox.axes["ry"]; break; - case "a_button": v = gamepad.xbox.buttons["a"] ? 1 : 0; break; - case "b_button": v = gamepad.xbox.buttons["b"] ? 1 : 0; break; - case "x_button": v = gamepad.xbox.buttons["x"] ? 1 : 0; break; - case "y_button": v = gamepad.xbox.buttons["y"] ? 1 : 0; break; - case "lb_button": v = gamepad.xbox.buttons["lb"] ? 1 : 0; break; - case "rb_button": v = gamepad.xbox.buttons["rb"] ? 1 : 0; break; - case "ls_button": v = gamepad.xbox.buttons["ls"] ? 1 : 0; break; - case "rs_button": v = gamepad.xbox.buttons["rs"] ? 1 : 0; break; - case "start_button": v = gamepad.xbox.buttons["start"] ? 1 : 0; break; - case "back_button": v = gamepad.xbox.buttons["back"] ? 1 : 0; break; - default: break; + switch( output.name ) + { + case "left_axis": v = [ gamepad.xbox.axes["lx"], gamepad.xbox.axes["ly"]]; break; + case "right_axis": v = [ gamepad.xbox.axes["rx"], gamepad.xbox.axes["ry"]]; break; + case "left_x_axis": v = gamepad.xbox.axes["lx"]; break; + case "left_y_axis": v = gamepad.xbox.axes["ly"]; break; + case "right_x_axis": v = gamepad.xbox.axes["rx"]; break; + case "right_y_axis": v = gamepad.xbox.axes["ry"]; break; + case "trigger_left": v = gamepad.xbox.axes["ltrigger"]; break; + case "trigger_right": v = gamepad.xbox.axes["rtrigger"]; break; + case "a_button": v = gamepad.xbox.buttons["a"] ? 1 : 0; break; + case "b_button": v = gamepad.xbox.buttons["b"] ? 1 : 0; break; + case "x_button": v = gamepad.xbox.buttons["x"] ? 1 : 0; break; + case "y_button": v = gamepad.xbox.buttons["y"] ? 1 : 0; break; + case "lb_button": v = gamepad.xbox.buttons["lb"] ? 1 : 0; break; + case "rb_button": v = gamepad.xbox.buttons["rb"] ? 1 : 0; break; + case "ls_button": v = gamepad.xbox.buttons["ls"] ? 1 : 0; break; + case "rs_button": v = gamepad.xbox.buttons["rs"] ? 1 : 0; break; + case "start_button": v = gamepad.xbox.buttons["start"] ? 1 : 0; break; + case "back_button": v = gamepad.xbox.buttons["back"] ? 1 : 0; break; + default: break; + } + } + else + { + //if no gamepad is connected, output 0 + switch( output.name ) + { + case "left_axis": + case "right_axis": + v = [0,0]; + break; + default: + v = 0; + } } this.setOutputData(i,v); } @@ -6003,7 +6097,8 @@ GamepadInput.prototype.getGamepad = function() xbox.axes["ly"] = gamepad.axes[1]; xbox.axes["rx"] = gamepad.axes[2]; xbox.axes["ry"] = gamepad.axes[3]; - xbox.axes["triggers"] = gamepad.axes[4]; + xbox.axes["ltrigger"] = gamepad.buttons[6].value; + xbox.axes["rtrigger"] = gamepad.buttons[7].value; for(var i = 0; i < gamepad.buttons.length; i++) { @@ -6043,11 +6138,14 @@ GamepadInput.prototype.onDrawBackground = function(ctx) GamepadInput.prototype.onGetOutputs = function() { return [ + ["left_axis","vec2"], + ["right_axis","vec2"], ["left_x_axis","number"], ["left_y_axis","number"], ["right_x_axis","number"], ["right_y_axis","number"], - ["trigger","number"], + ["trigger_left","number"], + ["trigger_right","number"], ["a_button","number"], ["b_button","number"], ["x_button","number"], @@ -6066,6 +6164,138 @@ LiteGraph.registerNodeType("input/gamepad", GamepadInput ); })(); (function(){ +//Converter +function Converter() +{ + this.addInput("in","*"); + this.size = [60,20]; +} + +Converter.title = "Converter"; +Converter.desc = "type A to type B"; + +Converter.prototype.onExecute = function() +{ + var v = this.getInputData(0); + if(v == null) + return; + + if(this.outputs) + for(var i = 0; i < this.outputs.length; i++) + { + var output = this.outputs[i]; + if(!output.links || !output.links.length) + continue; + + var result = null; + switch( output.name ) + { + case "number": result = v.length ? v[0] : parseFloat(v); break; + case "vec2": + case "vec3": + case "vec4": + var result = null; + var count = 1; + switch(output.name) + { + case "vec2": count = 2; break; + case "vec3": count = 3; break; + case "vec4": count = 4; break; + } + + var result = new Float32Array( count ); + if( v.length ) + { + for(var j = 0; j < v.length && j < result.length; j++) + result[j] = v[j]; + } + else + result[0] = parseFloat(v); + break; + } + this.setOutputData(i, result); + } +} + +Converter.prototype.onGetOutputs = function() { + return [["number","number"],["vec2","vec2"],["vec3","vec3"],["vec4","vec4"]]; +} + +LiteGraph.registerNodeType("math/converter", Converter ); + + +//Bypass +function Bypass() +{ + this.addInput("in"); + this.addOutput("out"); + this.size = [60,20]; +} + +Bypass.title = "Bypass"; +Bypass.desc = "removes the type"; + +Bypass.prototype.onExecute = function() +{ + var v = this.getInputData(0); + this.setOutputData(0, v); +} + +LiteGraph.registerNodeType("math/bypass", Bypass ); + + + +function MathRange() +{ + this.addInput("in","number",{locked:true}); + this.addOutput("out","number",{locked:true}); + this.properties = { "in": 0, in_min:0, in_max:1, out_min: 0, out_max: 1 }; +} + +MathRange.title = "Range"; +MathRange.desc = "Convert a number from one range to another"; + +MathRange.prototype.onExecute = function() +{ + if(this.inputs) + for(var i = 0; i < this.inputs.length; i++) + { + var input = this.inputs[i]; + var v = this.getInputData(i); + if(v === undefined) + continue; + this.properties[ input.name ] = v; + } + + var v = this.properties["in"]; + if(v === undefined || v === null || v.constructor !== Number) + v = 0; + + var in_min = this.properties.in_min; + var in_max = this.properties.in_max; + var out_min = this.properties.out_min; + var out_max = this.properties.out_max; + + this._last_v = ((v - in_min) / (in_max - in_min)) * (out_max - out_min) + out_min; + this.setOutputData(0, this._last_v ); +} + +MathRange.prototype.onDrawBackground = function(ctx) +{ + //show the current value + if(this._last_v) + this.outputs[0].label = this._last_v.toFixed(3); + else + this.outputs[0].label = "?"; +} + +MathRange.prototype.onGetInputs = function() { + return [["in_min","number"],["in_max","number"],["out_min","number"],["out_max","number"]]; +} + +LiteGraph.registerNodeType("math/range", MathRange); + + function MathRand() { @@ -6538,56 +6768,179 @@ if(window.math) } +function Math3DVec2ToXYZ() +{ + this.addInput("vec2","vec2"); + this.addOutput("x","number"); + this.addOutput("y","number"); +} + +Math3DVec2ToXYZ.title = "Vec2->XY"; +Math3DVec2ToXYZ.desc = "vector 2 to components"; + +Math3DVec2ToXYZ.prototype.onExecute = function() +{ + var v = this.getInputData(0); + if(v == null) return; + + this.setOutputData( 0, v[0] ); + this.setOutputData( 1, v[1] ); +} + +LiteGraph.registerNodeType("math3d/vec2-to-xyz", Math3DVec2ToXYZ ); + + +function Math3DXYToVec2() +{ + this.addInputs([["x","number"],["y","number"]]); + this.addOutput("vec2","vec2"); + this.properties = {x:0, y:0}; + this._data = new Float32Array(2); +} + +Math3DXYToVec2.title = "XY->Vec2"; +Math3DXYToVec2.desc = "components to vector2"; + +Math3DXYToVec2.prototype.onExecute = function() +{ + var x = this.getInputData(0); + if(x == null) x = this.properties.x; + var y = this.getInputData(1); + if(y == null) y = this.properties.y; + + var data = this._data; + data[0] = x; + data[1] = y; + + this.setOutputData( 0, data ); +} + +LiteGraph.registerNodeType("math3d/xy-to-vec2", Math3DXYToVec2 ); + + + + +function Math3DVec3ToXYZ() +{ + this.addInput("vec3","vec3"); + this.addOutput("x","number"); + this.addOutput("y","number"); + this.addOutput("z","number"); +} + +Math3DVec3ToXYZ.title = "Vec3->XYZ"; +Math3DVec3ToXYZ.desc = "vector 3 to components"; + +Math3DVec3ToXYZ.prototype.onExecute = function() +{ + var v = this.getInputData(0); + if(v == null) return; + + this.setOutputData( 0, v[0] ); + this.setOutputData( 1, v[1] ); + this.setOutputData( 2, v[2] ); +} + +LiteGraph.registerNodeType("math3d/vec3-to-xyz", Math3DVec3ToXYZ ); + + +function Math3DXYZToVec3() +{ + 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); +} + +Math3DXYZToVec3.title = "XYZ->Vec3"; +Math3DXYZToVec3.desc = "components to vector3"; + +Math3DXYZToVec3.prototype.onExecute = function() +{ + var x = this.getInputData(0); + if(x == null) x = this.properties.x; + var y = this.getInputData(1); + if(y == null) y = this.properties.y; + var z = this.getInputData(2); + if(z == null) z = this.properties.z; + + var data = this._data; + data[0] = x; + data[1] = y; + data[2] = z; + + this.setOutputData( 0, data ); +} + +LiteGraph.registerNodeType("math3d/xyz-to-vec3", Math3DXYZToVec3 ); + + + +function Math3DVec4ToXYZW() +{ + this.addInput("vec4","vec4"); + this.addOutput("x","number"); + this.addOutput("y","number"); + this.addOutput("z","number"); + this.addOutput("w","number"); +} + +Math3DVec4ToXYZW.title = "Vec4->XYZW"; +Math3DVec4ToXYZW.desc = "vector 4 to components"; + +Math3DVec4ToXYZW.prototype.onExecute = function() +{ + var v = this.getInputData(0); + if(v == null) return; + + this.setOutputData( 0, v[0] ); + this.setOutputData( 1, v[1] ); + this.setOutputData( 2, v[2] ); + this.setOutputData( 3, v[3] ); +} + +LiteGraph.registerNodeType("math3d/vec4-to-xyzw", Math3DVec4ToXYZW ); + + +function Math3DXYZWToVec4() +{ + 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); +} + +Math3DXYZWToVec4.title = "XYZW->Vec4"; +Math3DXYZWToVec4.desc = "components to vector4"; + +Math3DXYZWToVec4.prototype.onExecute = function() +{ + var x = this.getInputData(0); + if(x == null) x = this.properties.x; + var y = this.getInputData(1); + if(y == null) y = this.properties.y; + var z = this.getInputData(2); + if(z == null) z = this.properties.z; + var w = this.getInputData(3); + if(w == null) w = this.properties.w; + + var data = this._data; + data[0] = x; + data[1] = y; + data[2] = z; + data[3] = w; + + this.setOutputData( 0, data ); +} + +LiteGraph.registerNodeType("math3d/xyzw-to-vec4", Math3DXYZWToVec4 ); + + + + //if glMatrix is installed... if(window.glMatrix) { - function Math3DVec3ToXYZ() - { - this.addInput("vec3","vec3"); - this.addOutput("x","number"); - this.addOutput("y","number"); - this.addOutput("z","number"); - } - - Math3DVec3ToXYZ.title = "Vec3->XYZ"; - Math3DVec3ToXYZ.desc = "vector 3 to components"; - - Math3DVec3ToXYZ.prototype.onExecute = function() - { - var v = this.getInputData(0); - if(v == null) return; - - this.setOutputData( 0, v[0] ); - this.setOutputData( 1, v[1] ); - this.setOutputData( 2, v[2] ); - } - - LiteGraph.registerNodeType("math3d/vec3-to-xyz", Math3DVec3ToXYZ ); - - - function Math3DXYZToVec3() - { - this.addInputs([["x","number"],["y","number"],["z","number"]]); - this.addOutput("vec3","vec3"); - this.properties = {x:0, y:0, z:0}; - } - - Math3DXYZToVec3.title = "XYZ->Vec3"; - Math3DXYZToVec3.desc = "components to vector3"; - - Math3DXYZToVec3.prototype.onExecute = function() - { - var x = this.getInputData(0); - if(x == null) x = this.properties.x; - var y = this.getInputData(1); - if(y == null) y = this.properties.y; - var z = this.getInputData(2); - if(z == null) z = this.properties.z; - - this.setOutputData( 0, vec3.fromValues(x,y,z) ); - } - - LiteGraph.registerNodeType("math3d/xyz-to-vec3", Math3DXYZToVec3 ); function Math3DRotation() @@ -7557,21 +7910,36 @@ if(typeof(LiteGraph) != "undefined") LGraphTexture.prototype.onExecute = function() { - if(this._drop_texture) - { - this.setOutputData(0, this._drop_texture); - return; - } + var tex = null; + if(this.isOutputConnected(1)) + tex = this.getInputData(0); - if(!this.properties.name) - return; + if(!tex && this._drop_texture) + tex = this._drop_texture; + + if(!tex && this.properties.name) + tex = LGraphTexture.getTexture( this.properties.name ); - var tex = LGraphTexture.getTexture( this.properties.name ); if(!tex) return; this._last_tex = tex; this.setOutputData(0, tex); + + for(var i = 1; i < this.outputs.length; i++) + { + var output = this.outputs[i]; + if(!output) + continue; + var v = null; + if(output.name == "width") + v = tex.width; + else if(output.name == "height") + v = tex.height; + else if(output.name == "aspect") + v = tex.width / tex.height; + this.setOutputData(i, v); + } } LGraphTexture.prototype.onResourceRenamed = function(old_name,new_name) @@ -7629,7 +7997,8 @@ if(typeof(LiteGraph) != "undefined") //very slow, used at your own risk LGraphTexture.generateLowResTexturePreview = function(tex) { - if(!tex) return null; + if(!tex) + return null; var size = LGraphTexture.image_preview_size; var temp_tex = tex; @@ -7665,6 +8034,17 @@ if(typeof(LiteGraph) != "undefined") return tex_canvas; } + LGraphTexture.prototype.onGetInputs = function() + { + return [["in","Texture"]]; + } + + + LGraphTexture.prototype.onGetOutputs = function() + { + return [["width","number"],["height","number"],["aspect","number"]]; + } + LiteGraph.registerNodeType("texture/texture", LGraphTexture ); //************************** @@ -7680,7 +8060,8 @@ if(typeof(LiteGraph) != "undefined") LGraphTexturePreview.prototype.onDrawBackground = function(ctx) { - if(this.flags.collapsed) return; + if(this.flags.collapsed) + return; var tex = this.getInputData(0); if(!tex) return; @@ -8012,15 +8393,202 @@ if(typeof(LiteGraph) != "undefined") LiteGraph.registerNodeType("texture/shader", LGraphTextureShader ); + // Texture Scale Offset + + function LGraphTextureScaleOffset() + { + this.addInput("in","Texture"); + this.addInput("scale","vec2"); + this.addInput("offset","vec2"); + this.addOutput("out","Texture"); + this.properties = { offset: vec2.fromValues(0,0), scale: vec2.fromValues(1,1), precision: LGraphTexture.DEFAULT }; + } + + LGraphTextureScaleOffset.widgets_info = { + "precision": { widget:"combo", values: LGraphTexture.MODE_VALUES } + }; + + LGraphTextureScaleOffset.title = "Scale/Offset"; + LGraphTextureScaleOffset.desc = "Applies an scaling and offseting"; + + LGraphTextureScaleOffset.prototype.onExecute = function() + { + var tex = this.getInputData(0); + + if(!this.isOutputConnected(0) || !tex) + return; //saves work + + if(this.properties.precision === LGraphTexture.PASS_THROUGH) + { + this.setOutputData(0, tex); + return; + } + + var width = tex.width; + var height = tex.height; + var type = this.precision === LGraphTexture.LOW ? gl.UNSIGNED_BYTE : gl.HIGH_PRECISION_FORMAT; + if (this.precision === LGraphTexture.DEFAULT) + type = tex.type; + + if(!this._tex || this._tex.width != width || this._tex.height != height || this._tex.type != type ) + this._tex = new GL.Texture( width, height, { type: type, format: gl.RGBA, filter: gl.LINEAR }); + + var shader = this._shader; + + if(!shader) + shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureScaleOffset.pixel_shader ); + + var scale = this.getInputData(1); + if(scale) + { + this.properties.scale[0] = scale[0]; + this.properties.scale[1] = scale[1]; + } + else + scale = this.properties.scale; + + var offset = this.getInputData(2); + if(offset) + { + this.properties.offset[0] = offset[0]; + this.properties.offset[1] = offset[1]; + } + else + offset = this.properties.offset; + + this._tex.drawTo(function() { + gl.disable( gl.DEPTH_TEST ); + gl.disable( gl.CULL_FACE ); + gl.disable( gl.BLEND ); + tex.bind(0); + var mesh = Mesh.getScreenQuad(); + shader.uniforms({u_texture:0, u_scale: scale, u_offset: offset}).draw( mesh ); + }); + + this.setOutputData( 0, this._tex ); + } + + LGraphTextureScaleOffset.pixel_shader = "precision highp float;\n\ + \n\ + uniform sampler2D u_texture;\n\ + uniform sampler2D u_textureB;\n\ + varying vec2 v_coord;\n\ + uniform vec2 u_scale;\n\ + uniform vec2 u_offset;\n\ + \n\ + void main() {\n\ + vec2 uv = v_coord;\n\ + uv = uv / u_scale - u_offset;\n\ + gl_FragColor = texture2D(u_texture, uv);\n\ + }\n\ + "; + + LiteGraph.registerNodeType("texture/scaleOffset", LGraphTextureScaleOffset ); + + + + // Warp (distort a texture) ************************* + + function LGraphTextureWarp() + { + this.addInput("in","Texture"); + this.addInput("warp","Texture"); + this.addInput("factor","number"); + this.addOutput("out","Texture"); + this.properties = { factor: 0.01, precision: LGraphTexture.DEFAULT }; + } + + LGraphTextureWarp.widgets_info = { + "precision": { widget:"combo", values: LGraphTexture.MODE_VALUES } + }; + + LGraphTextureWarp.title = "Warp"; + LGraphTextureWarp.desc = "Texture warp operation"; + + LGraphTextureWarp.prototype.onExecute = function() + { + var tex = this.getInputData(0); + + if(!this.isOutputConnected(0)) + return; //saves work + + if(this.properties.precision === LGraphTexture.PASS_THROUGH) + { + this.setOutputData(0, tex); + return; + } + + var texB = this.getInputData(1); + + var width = 512; + var height = 512; + var type = gl.UNSIGNED_BYTE; + if(tex) + { + width = tex.width; + height = tex.height; + type = tex.type; + } + else if (texB) + { + width = texB.width; + height = texB.height; + type = texB.type; + } + + if(!tex && !this._tex ) + this._tex = new GL.Texture( width, height, { type: this.precision === LGraphTexture.LOW ? gl.UNSIGNED_BYTE : gl.HIGH_PRECISION_FORMAT, format: gl.RGBA, filter: gl.LINEAR }); + else + this._tex = LGraphTexture.getTargetTexture( tex || this._tex, this._tex, this.properties.precision ); + + var shader = this._shader; + + if(!shader) + shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureWarp.pixel_shader ); + + var factor = this.getInputData(2); + if(factor != null) + this.properties.factor = factor; + else + factor = parseFloat( this.properties.factor ); + + this._tex.drawTo(function() { + gl.disable( gl.DEPTH_TEST ); + gl.disable( gl.CULL_FACE ); + gl.disable( gl.BLEND ); + if(tex) tex.bind(0); + if(texB) texB.bind(1); + var mesh = Mesh.getScreenQuad(); + shader.uniforms({u_texture:0, u_textureB:1, u_factor: factor }).draw( mesh ); + }); + + this.setOutputData(0, this._tex); + } + + LGraphTextureWarp.pixel_shader = "precision highp float;\n\ + \n\ + uniform sampler2D u_texture;\n\ + uniform sampler2D u_textureB;\n\ + varying vec2 v_coord;\n\ + uniform float u_factor;\n\ + \n\ + void main() {\n\ + vec2 uv = v_coord;\n\ + uv += texture2D(u_textureB, uv).rg * u_factor;\n\ + gl_FragColor = texture2D(u_texture, uv);\n\ + }\n\ + "; + + LiteGraph.registerNodeType("texture/warp", LGraphTextureWarp ); + + //**************************************************** + // Texture to Viewport ***************************************** function LGraphTextureToViewport() { this.addInput("Texture","Texture"); - this.properties = { additive: false, antialiasing: false, disable_alpha: false }; + this.properties = { additive: false, antialiasing: false, disable_alpha: false, gamma: 1.0 }; this.size[0] = 130; - - if(!LGraphTextureToViewport._shader) - LGraphTextureToViewport._shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER, LGraphTextureToViewport.pixel_shader ); } LGraphTextureToViewport.title = "to Viewport"; @@ -8044,23 +8612,46 @@ if(typeof(LiteGraph) != "undefined") } gl.disable( gl.DEPTH_TEST ); + var gamma = this.properties.gamma || 1.0; + if( this.isInputConnected(1) ) + gamma = this.getInputData(1); + + if(this.properties.antialiasing) { + if(!LGraphTextureToViewport._shader) + LGraphTextureToViewport._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureToViewport.aa_pixel_shader ); + var viewport = gl.getViewport(); //gl.getParameter(gl.VIEWPORT); var mesh = Mesh.getScreenQuad(); tex.bind(0); - LGraphTextureToViewport._shader.uniforms({u_texture:0, uViewportSize:[tex.width,tex.height], inverseVP: [1/tex.width,1/tex.height] }).draw(mesh); + LGraphTextureToViewport._shader.uniforms({u_texture:0, uViewportSize:[tex.width,tex.height], u_igamma: 1 / gamma, inverseVP: [1/tex.width,1/tex.height] }).draw(mesh); } else - tex.toViewport(); + { + if(gamma != 1.0) + { + if(!LGraphTextureToViewport._gamma_shader) + LGraphTextureToViewport._gamma_shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER, LGraphTextureToViewport.gamma_pixel_shader ); + tex.toViewport(LGraphTextureToViewport._gamma_shader, { u_texture:0, u_igamma: 1 / gamma }); + } + else + tex.toViewport(); + } } - LGraphTextureToViewport.pixel_shader = "precision highp float;\n\ + LGraphTextureToViewport.prototype.onGetInputs = function() + { + return [["gamma","number"]]; + } + + LGraphTextureToViewport.aa_pixel_shader = "precision highp float;\n\ precision highp float;\n\ varying vec2 v_coord;\n\ uniform sampler2D u_texture;\n\ uniform vec2 uViewportSize;\n\ uniform vec2 inverseVP;\n\ + uniform float u_igamma;\n\ #define FXAA_REDUCE_MIN (1.0/ 128.0)\n\ #define FXAA_REDUCE_MUL (1.0 / 8.0)\n\ #define FXAA_SPAN_MAX 8.0\n\ @@ -8098,12 +8689,14 @@ if(typeof(LiteGraph) != "undefined") vec3 rgbB = rgbA * 0.5 + 0.25 * (texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + \n\ texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);\n\ \n\ - return vec4(rgbA,1.0);\n\ + //return vec4(rgbA,1.0);\n\ float lumaB = dot(rgbB, luma);\n\ if ((lumaB < lumaMin) || (lumaB > lumaMax))\n\ color = vec4(rgbA, 1.0);\n\ else\n\ color = vec4(rgbB, 1.0);\n\ + if(u_igamma != 1.0)\n\ + color.xyz = pow( color.xyz, vec3(u_igamma) );\n\ return color;\n\ }\n\ \n\ @@ -8112,6 +8705,18 @@ if(typeof(LiteGraph) != "undefined") }\n\ "; + LGraphTextureToViewport.gamma_pixel_shader = "precision highp float;\n\ + precision highp float;\n\ + varying vec2 v_coord;\n\ + uniform sampler2D u_texture;\n\ + uniform float u_igamma;\n\ + void main() {\n\ + vec4 color = texture2D( u_texture, v_coord);\n\ + color.xyz = pow(color.xyz, vec3(u_igamma) );\n\ + gl_FragColor = color;\n\ + }\n\ + "; + LiteGraph.registerNodeType("texture/toviewport", LGraphTextureToViewport ); @@ -8828,8 +9433,8 @@ if(typeof(LiteGraph) != "undefined") var shader = LGraphTextureDepthRange._shader; //TODO: this asumes we have LiteScene, change it - var camera = Renderer._current_camera; - var planes = [Renderer._current_camera.near,Renderer._current_camera.far]; + var camera = LS.Renderer._current_camera; + var planes = [LS.Renderer._current_camera.near, LS.Renderer._current_camera.far]; this._temp_texture.drawTo( function() { tex.bind(0); @@ -9028,7 +9633,7 @@ if(typeof(LiteGraph) != "undefined") { video = document.createElement("video"); video.autoplay = true; - video.src = window.URL.createObjectURL(localMediaStream); + video.src = window.URL.createObjectURL( localMediaStream ); this._video = video; //document.body.appendChild( video ); //debug //when video info is loaded (size and so) @@ -9227,7 +9832,7 @@ if(typeof(LiteGraph) != "undefined") gl.disable( gl.DEPTH_TEST ); var mesh = Mesh.getScreenQuad(); var shader = LGraphFXLens._shader; - var camera = Renderer._current_camera; + var camera = LS.Renderer._current_camera; this._tex.drawTo( function() { tex.bind(0); @@ -9489,13 +10094,16 @@ if(typeof(LiteGraph) != "undefined") LGraphFXGeneric.desc = "applies an FX from a list"; LGraphFXGeneric.widgets_info = { - "fx": { widget:"combo", values:["halftone","pixelate","lowpalette","noise"] }, + "fx": { widget:"combo", values:["halftone","pixelate","lowpalette","noise","gamma"] }, "precision": { widget:"combo", values: LGraphTexture.MODE_VALUES } }; LGraphFXGeneric.shaders = {}; LGraphFXGeneric.prototype.onExecute = function() { + if(!this.isOutputConnected(0)) + return; //saves work + var tex = this.getInputData(0); if(this.properties.precision === LGraphTexture.PASS_THROUGH ) { @@ -9503,7 +10111,8 @@ if(typeof(LiteGraph) != "undefined") return; } - if(!tex) return; + if(!tex) + return; this._tex = LGraphTexture.getTargetTexture( tex, this._tex, this.properties.precision ); @@ -9537,7 +10146,7 @@ if(typeof(LiteGraph) != "undefined") gl.disable( gl.BLEND ); gl.disable( gl.DEPTH_TEST ); var mesh = Mesh.getScreenQuad(); - var camera = Renderer._current_camera; + var camera = LS.Renderer._current_camera; var noise = null; if(fx == "noise") @@ -9548,7 +10157,7 @@ if(typeof(LiteGraph) != "undefined") if(fx == "noise") noise.bind(1); - shader.uniforms({u_texture:0, u_noise:1, u_size: [tex.width, tex.height], u_rand:[ Math.random(), Math.random() ], u_value1: value1, u_value2: value2, u_camera_planes: [Renderer._current_camera.near,Renderer._current_camera.far] }) + shader.uniforms({u_texture:0, u_noise:1, u_size: [tex.width, tex.height], u_rand:[ Math.random(), Math.random() ], u_value1: value1, u_value2: value2, u_camera_planes: [LS.Renderer._current_camera.near, LS.Renderer._current_camera.far] }) .draw(mesh); }); @@ -9620,6 +10229,17 @@ if(typeof(LiteGraph) != "undefined") gl_FragColor = vec4( color.xyz + noise * u_value1, color.a );\n\ }\n"; + LGraphFXGeneric.pixel_shader_gamma = "precision highp float;\n\ + varying vec2 v_coord;\n\ + uniform sampler2D u_texture;\n\ + uniform float u_value1;\n\ + \n\ + void main() {\n\ + vec4 color = texture2D(u_texture, v_coord);\n\ + float gamma = 1.0 / u_value1;\n\ + gl_FragColor = vec4( pow( color.xyz, vec3(gamma) ), color.a );\n\ + }\n"; + LiteGraph.registerNodeType("fx/generic", LGraphFXGeneric ); window.LGraphFXGeneric = LGraphFXGeneric; diff --git a/build/litegraph.min.js b/build/litegraph.min.js index a5fc8e4fe..91a6e727a 100755 --- a/build/litegraph.min.js +++ b/build/litegraph.min.js @@ -10,8 +10,8 @@ LGraph.prototype.start=function(a){if(this.status!=LGraph.STATUS_RUNNING){this.s LGraph.prototype.stop=function(){if(this.status!=LGraph.STATUS_STOPPED){this.status=LGraph.STATUS_STOPPED;if(this.onStopEvent)this.onStopEvent();null!=this.execution_timer_id&&clearInterval(this.execution_timer_id);this.execution_timer_id=null;this.sendEventToAllNodes("onStop")}}; LGraph.prototype.runStep=function(a){a=a||1;var b=LiteGraph.getTime();this.globaltime=0.001*(b-this.starttime);try{for(var c=0;c=LiteGraph.MAX_NUMBER_OF_NODES)throw"LiteGraph: max number of nodes in a graph reached";if(null==a.id||-1==a.id)a.id=this.last_node_id++;a.graph=this;this._nodes.push(a);this._nodes_by_id[a.id]=a;if(a.onAdded)a.onAdded();this.config.align_to_grid&&a.alignToGrid();b||this.updateExecutionOrder();if(this.onNodeAdded)this.onNodeAdded(a);this.setDirtyCanvas(!0);this.change();return a}}; LGraph.prototype.remove=function(a){if(null!=this._nodes_by_id[a.id]&&!a.ignore_remove){if(a.inputs)for(var b=0;b!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.data=null;this.flags={}}; LGraphNode.prototype.configure=function(a){for(var b in a)if("console"!=b)if("properties"==b)for(var c in a.properties)this.properties[c]=a.properties[c];else null!=a[b]&&("object"==typeof a[b]?this[b]&&this[b].configure?this[b].configure(a[b]):this[b]=LiteGraph.cloneObject(a[b],this[b]):this[b]=a[b]);for(var d in this.inputs)c=this.inputs[d],c.link&&c.link.length&&(a=c.link,"object"==typeof a&&(c.link=a[0],this.graph.links[a[0]]={id:a[0],origin_id:a[1],origin_slot:a[2],target_id:a[3],target_slot:a[4]})); for(d in this.outputs)if(c=this.outputs[d],c.links&&0!=c.links.length)for(b in c.links)a=c.links[b],"object"==typeof a&&(c.links[b]=a[0])}; LGraphNode.prototype.serialize=function(){var a={id:this.id,title:this.title,type:this.type,pos:this.pos,size:this.size,data:this.data,flags:LiteGraph.cloneObject(this.flags),inputs:this.inputs,outputs:this.outputs};this.properties&&(a.properties=LiteGraph.cloneObject(this.properties));a.type||(a.type=this.constructor.type);this.color&&(a.color=this.color);this.bgcolor&&(a.bgcolor=this.bgcolor);this.boxcolor&&(a.boxcolor=this.boxcolor);this.shape&&(a.shape=this.shape);if(this.onSerialize)this.onSerialize(a); @@ -44,11 +44,11 @@ f+10,c);a[0]=Math.max(a[0],LiteGraph.NODE_WIDTH);return a};LGraphNode.prototype. LGraphNode.prototype.isPointInsideNode=function(a,b,c){c=c||0;var d=this.graph&&this.graph.isLive()?0:20;if(this.flags.collapsed){if(isInsideRectangle(a,b,this.pos[0]-c,this.pos[1]-LiteGraph.NODE_TITLE_HEIGHT-c,LiteGraph.NODE_COLLAPSED_WIDTH+2*c,LiteGraph.NODE_TITLE_HEIGHT+2*c))return!0}else if(this.pos[0]-4-ca&&this.pos[1]-d-cb)return!0;return!1}; LGraphNode.prototype.getSlotInPosition=function(a,b){if(this.inputs)for(var c=0,d=this.inputs.length;c=this.outputs.length)return LiteGraph.debug&&console.log("Connect: Error, slot number not found"),!1;if(b==this)return!1;if(c.constructor===String){if(c=b.findInputSlot(c),-1==c)return LiteGraph.debug&&console.log("Connect: Error, no slot of name "+c),!1}else if(!b.inputs||c>=b.inputs.length)return LiteGraph.debug&& -console.log("Connect: Error, slot number not found"),!1;-1!=c&&null!=b.inputs[c].link&&b.disconnectInput(c);var d=this.outputs[a];-1==c?(null==d.links&&(d.links=[]),d.links.push({id:b.id,slot:-1})):d.type&&b.inputs[c].type&&d.type.toLowerCase()!=b.inputs[c].type.toLowerCase()||(a={id:this.graph.last_link_id++,origin_id:this.id,origin_slot:a,target_id:b.id,target_slot:c},this.graph.links[a.id]=a,null==d.links&&(d.links=[]),d.links.push(a.id),b.inputs[c].link=a.id,this.setDirtyCanvas(!1,!0),this.graph.onConnectionChange()); -return!0}; -LGraphNode.prototype.disconnectOutput=function(a,b){if(a.constructor===String){if(a=this.findOutputSlot(a),-1==a)return LiteGraph.debug&&console.log("Connect: Error, no slot of name "+a),!1}else if(!this.outputs||a>=this.outputs.length)return LiteGraph.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)for(var d=0,e=c.links.length;d=this.outputs.length)return LiteGraph.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 LiteGraph.debug&& +console.log("Connect: Error, no slot of name "+c),!1}else if(!b.inputs||c>=b.inputs.length)return LiteGraph.debug&&console.log("Connect: Error, slot number not found"),!1;-1!=c&&null!=b.inputs[c].link&&b.disconnectInput(c);this.setDirtyCanvas(!1,!0);this.graph.onConnectionChange();var d=this.outputs[a];if(b.onConnectInput&&!1===b.onConnectInput(c,d.type,d))return!1;-1==c?(null==d.links&&(d.links=[]),d.links.push({id:b.id,slot:-1})):d.type&&b.inputs[c].type&&d.type.toLowerCase()!=b.inputs[c].type.toLowerCase()|| +(a={id:this.graph.last_link_id++,origin_id:this.id,origin_slot:a,target_id:b.id,target_slot:c},this.graph.links[a.id]=a,null==d.links&&(d.links=[]),d.links.push(a.id),b.inputs[c].link=a.id);return!0}; +LGraphNode.prototype.disconnectOutput=function(a,b){if(a.constructor===String){if(a=this.findOutputSlot(a),-1==a)return LiteGraph.debug&&console.log("Connect: Error, no slot of name "+a),!1}else if(!this.outputs||a>=this.outputs.length)return LiteGraph.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 d=0,e=c.links.length;d< +e;d++){var f=c.links[d],g=this.graph.links[f];if(g.target_id==b.id){c.links.splice(d,1);b.inputs[g.target_slot].link=null;delete this.graph.links[f];break}}}else{d=0;for(e=c.links.length;d=this.inputs.length)return LiteGraph.debug&&console.log("Connect: Error, slot number not found"),!1;if(!this.inputs[a])return!1;var b=this.inputs[a].link;this.inputs[a].link=null;if(b=this.graph.links[b]){a=this.graph.getNodeById(b.origin_id);if(!a)return!1;a=a.outputs[b.origin_slot];if(!a|| !a.links||0==a.links.length)return!1;for(var c=0,d=a.links.length;cb&&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]]: @@ -61,12 +61,12 @@ LGraphCanvas.prototype.clear=function(){this.fps=this.render_time=this.last_draw this.dirty_area=null;this.last_mouse=[0,0];this.last_mouseclick=0;this.title_text_font="bold 14px Arial";this.inner_text_font="normal 12px Arial";this.render_connections_shadows=!1;this.render_connection_arrows=this.render_curved_connections=this.render_connections_border=!0;this.connections_width=4;if(this.onClear)this.onClear()};LGraphCanvas.prototype.setGraph=function(a,b){this.graph!=a&&(b||this.clear(),!a&&this.graph?this.graph.detachCanvas(this):(a.attachCanvas(this),this.setDirty(!0,!0)))}; LGraphCanvas.prototype.openSubgraph=function(a){if(!a)throw"graph cannot be null";if(this.graph==a)throw"graph cannot be the same";this.clear();this.graph&&(this._graph_stack||(this._graph_stack=[]),this._graph_stack.push(this.graph));a.attachCanvas(this);this.setDirty(!0,!0)};LGraphCanvas.prototype.closeSubgraph=function(){this._graph_stack&&0!=this._graph_stack.length&&(this._graph_stack.pop().attachCanvas(this),this.setDirty(!0,!0))}; LGraphCanvas.prototype.setCanvas=function(a,b){if(a&&a.constructor===String&&(a=document.getElementById(a),!a))throw"Error creating LiteGraph canvas: Canvas not found";if(a!==this.canvas&&(!a&&this.canvas&&(b||this.unbindEvents()),this.canvas=a)){a.className+=" lgraphcanvas";a.data=this;this.bgcanvas=null;this.bgcanvas||(this.bgcanvas=document.createElement("canvas"),this.bgcanvas.width=this.canvas.width,this.bgcanvas.height=this.canvas.height);if(null==a.getContext)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()}};LGraphCanvas.prototype._doNothing=function(){return!1}; +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()}};LGraphCanvas.prototype._doNothing=function(a){a.preventDefault();return!1};LGraphCanvas.prototype._doReturnTrue=function(a){a.preventDefault();return!0}; LGraphCanvas.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);this._events_binded=!0}}; +this._doNothing,!1);a.addEventListener("drop",this._ondrop_callback,!1);a.addEventListener("dragenter",this._doReturnTrue,!1);this._events_binded=!0}}; LGraphCanvas.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("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")}; +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")}; LGraphCanvas.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()};LGraphCanvas.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}; LGraphCanvas.prototype.setDirty=function(a,b){a&&(this.dirty_canvas=!0);b&&(this.dirty_bgcanvas=!0)};LGraphCanvas.prototype.getCanvasWindow=function(){var a=this.canvas.ownerDocument;return a.defaultView||a.parentWindow};LGraphCanvas.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))}; LGraphCanvas.prototype.stopRendering=function(){this.is_rendering=!1}; @@ -86,12 +86,13 @@ Math.round(this.node_dragged.pos[0]),this.node_dragged.pos[1]=Math.round(this.no !0,this.dragging_canvas=!1);this.graph.change();a.stopPropagation();a.preventDefault();return!1}};LGraphCanvas.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}}; LGraphCanvas.prototype.isOverNodeInput=function(a,b,c,d){if(a.inputs)for(var e=0,f=a.inputs.length;ethis.max_zoom?this.scale=this.max_zoom:this.scalec&&0.01>b.editor_alpha&&(clearInterval(d),1>c&&(b.live_mode=!0));1"+e+""})}LiteGraph.createContextualMenu(d,{event:b,callback:function(b){a&&(b=LGraphCanvas.node_colors[b.value])&&(a.color=b.color,a.bgcolor=b.bgcolor,a.setDirtyCanvas(!0))},from:c});return!1}; @@ -132,15 +133,16 @@ LGraphCanvas.node_colors={red:{color:"#FAA",bgcolor:"#A44"},green:{color:"#AFA", LGraphCanvas.prototype.getCanvasMenuOptions=function(){var a=null;this.getMenuOptions?a=this.getMenuOptions():(a=[{content:"Add Node",is_menu:!0,callback:LGraphCanvas.onMenuAdd}],this._graph_stack&&0a&&db?!0:!1}function growBounding(a,b,c){ba[2]&&(a[2]=b);ca[3]&&(a[3]=c)} function isInsideBounding(a,b){return a[0]b[1][0]||a[1]>b[1][1]?!1:!0}function overlapBounding(a,b){return a[0]>b[2]||a[1]>b[3]||a[2]f;f+=2)d="0123456789ABCDEF".indexOf(a.charAt(f)),e="0123456789ABCDEF".indexOf(a.charAt(f+1)),b[c]=16*d+e,c++;return b} function num2hex(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} LiteGraph.createContextualMenu=function(a,b,c){function d(a){var c=!0;b.callback&&(a=b.callback.call(e,this.data,a),void 0!==a&&(c=a));c&&LiteGraph.closeAllContextualMenus()}this.options=b=b||{};c=c||window;b.from||LiteGraph.closeAllContextualMenus();var e=c.document.createElement("div");e.className="graphcontextualmenu graphmenubar-panel";this.root=e;var f=e.style;f.minWidth="100px";f.minHeight="20px";f.position="fixed";f.top="100px";f.left="100px";f.color="#AAF";f.padding="2px";f.borderBottom="2px solid #AAF"; -f.backgroundColor="#444";e.addEventListener("contextmenu",function(a){a.preventDefault();return!1});for(var g in a){var f=a[g],h=c.document.createElement("div");h.className="graphmenu-entry";null==f?h.className="graphmenu-entry separator":(f.is_menu&&(h.className+=" submenu"),f.disabled&&(h.className+=" disabled"),h.style.cursor="pointer",h.dataset.value="string"==typeof f?f:f.value,h.data=f,h.innerHTML="string"==typeof f?a.constructor==Array?a[g]:g:f.content?f.content:g,h.addEventListener("click", -d));e.appendChild(h)}e.addEventListener("mouseover",function(a){this.mouse_inside=!0});e.addEventListener("mouseout",function(a){for(a=a.toElement;a!=this&&a!=c.document;)a=a.parentNode;a!=this&&(this.mouse_inside=!1,this.block_close||this.closeMenu())});c.document.body.appendChild(e);a=e.getClientRects()[0];b.from&&(b.from.block_close=!0);h=b.left||0;g=b.top||0;b.event&&(h=b.event.pageX-10,g=b.event.pageY-10,b.left&&(h=b.left),f=c.document.body.getClientRects()[0],b.from&&(h=b.from.getClientRects()[0], -h=h.left+h.width),h>f.width-a.width-10&&(h=f.width-a.width-10),g>f.height-a.height-10&&(g=f.height-a.height-10));e.style.left=h+"px";e.style.top=g+"px";e.closeMenu=function(){b.from&&(b.from.block_close=!1,b.from.mouse_inside||b.from.closeMenu());this.parentNode&&c.document.body.removeChild(this)};return e};LiteGraph.closeAllContextualMenus=function(){var a=document.querySelectorAll(".graphcontextualmenu");if(a.length){for(var b=[],c=0;cf.width-a.width-10&&(h=f.width-a.width-10),g>f.height-a.height-10&&(g=f.height-a.height-10));e.style.left=h+"px";e.style.top=g+"px";e.closeMenu=function(){b.from&&(b.from.block_close=!1,b.from.mouse_inside||b.from.closeMenu());this.parentNode&&c.document.body.removeChild(this)};return e}; +LiteGraph.closeAllContextualMenus=function(){var a=document.querySelectorAll(".graphcontextualmenu");if(a.length){for(var b=[],c=0;cd;d++)if(c[d]){a=c[d];c=this.xbox_mapping;c||(c=this.xbox_mapping={axes:[],buttons:{},hat:""});c.axes.lx=a.axes[0];c.axes.ly=a.axes[1];c.axes.rx=a.axes[2];c.axes.ry=a.axes[3];c.axes.triggers=a.axes[4];for(d=0;d"};this.size=[60,40]}function p(){this.addInput("inc","number");this.addOutput("total","number");this.properties={increment:0,value:0}}function q(){this.addInput("v","number");this.addOutput("sin","number");this.properties={amplitude:1,offset:0};this.bgImageUrl="nodes/imgs/icon-sin.png"}a.title="Rand";a.desc="Random number";a.prototype.onExecute=function(){if(this.inputs)for(var a= -0;aB":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"]]};LiteGraph.registerNodeType("math/compare",k);n["@OP"]={type:"enum",title:"operation",values:"> < == != <= >=".split(" ")};n.title="Condition";n.desc="evaluates condition between A and B";n.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)};LiteGraph.registerNodeType("math/condition",n);p.title="Accumulate";p.desc="Increments a value every time";p.prototype.onExecute=function(){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)};LiteGraph.registerNodeType("math/accumulate",p);q.title="Trigonometry";q.desc="Sin Cos Tan";q.filter="shader";q.prototype.onExecute=function(){var a=this.getInputData(0),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;c< -e;++c){switch(this.outputs[c].name){case "sin":value=Math.sin(a);break;case "cos":value=Math.cos(a);break;case "tan":value=Math.tan(a);break;case "asin":value=Math.asin(a);break;case "acos":value=Math.acos(a);break;case "atan":value=Math.atan(a)}this.setOutputData(c,b*value+d)}};q.prototype.onGetInputs=function(){return[["v","number"],["amplitude","number"],["offset","number"]]};q.prototype.onGetOutputs=function(){return[["sin","number"],["cos","number"],["tan","number"],["asin","number"],["acos", -"number"],["atan","number"]]};LiteGraph.registerNodeType("math/trigonometry",q);if(window.math){var l=function(){this.addInputs("x","number");this.addInputs("y","number");this.addOutputs("","number");this.properties={x:1,y:1,formula:"x+y"}};l.title="Formula";l.desc="Compute safe formula";l.prototype.onExecute=function(){var a=this.getInputData(0),b=this.getInputData(1);null!=a?this.properties.x=a:a=this.properties.x;null!=b?this.properties.y=b:b=this.properties.y;a=math.eval(this.properties.formula, -{x:a,y:b,T:this.graph.globaltime});this.setOutputData(0,a)};l.prototype.onDrawBackground=function(){this.outputs[0].label=this.properties.formula};l.prototype.onGetOutputs=function(){return[["A-B","number"],["A*B","number"],["A/B","number"]]};LiteGraph.registerNodeType("math/formula",l)}window.glMatrix&&(l=function(){this.addInput("vec3","vec3");this.addOutput("x","number");this.addOutput("y","number");this.addOutput("z","number")},l.title="Vec3->XYZ",l.desc="vector 3 to components",l.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]))},LiteGraph.registerNodeType("math3d/vec3-to-xyz",l),l=function(){this.addInputs([["x","number"],["y","number"],["z","number"]]);this.addOutput("vec3","vec3");this.properties={x:0,y:0,z:0}},l.title="XYZ->Vec3",l.desc="components to vector3",l.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);this.setOutputData(0,vec3.fromValues(a,b,c))},LiteGraph.registerNodeType("math3d/xyz-to-vec3",l),l=function(){this.addInputs([["degrees","number"],["axis","vec3"]]);this.addOutput("quat","quat");this.properties={angle:90,axis:vec3.fromValues(0,1,0)}},l.title="Rotation",l.desc="quaternion rotation",l.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(quat.create(),b,0.0174532925*a);this.setOutputData(0,a)},LiteGraph.registerNodeType("math3d/rotation",l),l=function(){this.addInputs([["vec3","vec3"],["quat","quat"]]);this.addOutput("result","vec3");this.properties={vec:[0,0,1]}},l.title="Rot. Vec3",l.desc="rotate a point",l.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))},LiteGraph.registerNodeType("math3d/rotate_vec3",l),l=function(){this.addInputs([["A","quat"],["B","quat"]]);this.addOutput("A*B","quat")},l.title="Mult. Quat",l.desc="rotate quaternion",l.prototype.onExecute=function(){var a=this.getInputData(0);if(null!=a){var b=this.getInputData(1);null!=b&&(a=quat.multiply(quat.create(),a,b),this.setOutputData(0,a))}},LiteGraph.registerNodeType("math3d/mult-quat",l))})(); -function Selector(){this.addInput("sel","boolean");this.addOutput("value","number");this.properties={A:0,B:1};this.size=[60,20]}Selector.title="Selector";Selector.desc="outputs A if selector is true, B if selector is false";Selector.prototype.onExecute=function(){var a=this.getInputData(0);if(void 0!==a){for(var b=1;bd;d++)if(c[d]){a=c[d];c=this.xbox_mapping;c||(c=this.xbox_mapping= +{axes:[],buttons:{},hat:""});c.axes.lx=a.axes[0];c.axes.ly=a.axes[1];c.axes.rx=a.axes[2];c.axes.ry=a.axes[3];c.axes.ltrigger=a.buttons[6].value;c.axes.rtrigger=a.buttons[7].value;for(d=0;d"};this.size=[60,40]}function t(){this.addInput("inc", +"number");this.addOutput("total","number");this.properties={increment:0,value:0}}function s(){this.addInput("v","number");this.addOutput("sin","number");this.properties={amplitude:1,offset:0};this.bgImageUrl="nodes/imgs/icon-sin.png"}function u(){this.addInput("vec2","vec2");this.addOutput("x","number");this.addOutput("y","number")}function v(){this.addInputs([["x","number"],["y","number"]]);this.addOutput("vec2","vec2");this.properties={x:0,y:0};this._data=new Float32Array(2)}function w(){this.addInput("vec3", +"vec3");this.addOutput("x","number");this.addOutput("y","number");this.addOutput("z","number")}function x(){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 z(){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)}a.title="Converter";a.desc="type A to type B";a.prototype.onExecute=function(){var a=this.getInputData(0);if(null!=a&&this.outputs)for(var b=0;bB":value=a>b;break;case "A=B":value=a>=b}this.setOutputData(c,value)}}};q.prototype.onGetOutputs=function(){return[["A==B","boolean"],["A!=B","boolean"],["A>B","boolean"],["A=B","boolean"],["A<=B","boolean"]]}; +LiteGraph.registerNodeType("math/compare",q);r["@OP"]={type:"enum",title:"operation",values:"> < == != <= >=".split(" ")};r.title="Condition";r.desc="evaluates condition between A and B";r.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)};LiteGraph.registerNodeType("math/condition",r);t.title="Accumulate";t.desc="Increments a value every time";t.prototype.onExecute=function(){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)};LiteGraph.registerNodeType("math/accumulate",t);s.title="Trigonometry";s.desc="Sin Cos Tan";s.filter="shader";s.prototype.onExecute=function(){var a= +this.getInputData(0),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;cVec2";v.desc="components to vector2";v.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)};LiteGraph.registerNodeType("math3d/xy-to-vec2", +v);w.title="Vec3->XYZ";w.desc="vector 3 to components";w.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]))};LiteGraph.registerNodeType("math3d/vec3-to-xyz",w);x.title="XYZ->Vec3";x.desc="components to vector3";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.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)};LiteGraph.registerNodeType("math3d/xyz-to-vec3",x);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]))};LiteGraph.registerNodeType("math3d/vec4-to-xyzw",y);z.title="XYZW->Vec4";z.desc="components to vector4";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.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)};LiteGraph.registerNodeType("math3d/xyzw-to-vec4",z);window.glMatrix&&(n=function(){this.addInputs([["degrees","number"],["axis","vec3"]]);this.addOutput("quat","quat");this.properties={angle:90,axis:vec3.fromValues(0,1,0)}},n.title= +"Rotation",n.desc="quaternion rotation",n.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(quat.create(),b,0.0174532925*a);this.setOutputData(0,a)},LiteGraph.registerNodeType("math3d/rotation",n),n=function(){this.addInputs([["vec3","vec3"],["quat","quat"]]);this.addOutput("result","vec3");this.properties={vec:[0,0,1]}},n.title="Rot. Vec3",n.desc="rotate a point",n.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))},LiteGraph.registerNodeType("math3d/rotate_vec3",n),n=function(){this.addInputs([["A","quat"],["B","quat"]]);this.addOutput("A*B","quat")},n.title="Mult. Quat",n.desc="rotate quaternion",n.prototype.onExecute=function(){var a=this.getInputData(0);if(null!=a){var b=this.getInputData(1);null!=b&&(a=quat.multiply(quat.create(), +a,b),this.setOutputData(0,a))}},LiteGraph.registerNodeType("math3d/mult-quat",n))})();function Selector(){this.addInput("sel","boolean");this.addOutput("value","number");this.properties={A:0,B:1};this.size=[60,20]}Selector.title="Selector";Selector.desc="outputs A if selector is true, B if selector is false"; +Selector.prototype.onExecute=function(){var a=this.getInputData(0);if(void 0!==a){for(var b=1;bb;++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})};LGraphTexture.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=""};LGraphTexture.prototype.getExtraMenuOptions=function(a){var b=this;if(this._drop_texture)return[{content:"Clear",callback:function(){b._drop_texture=null;b.properties.name=""}}]};LGraphTexture.prototype.onExecute=function(){if(this._drop_texture)this.setOutputData(0,this._drop_texture); -else if(this.properties.name){var a=LGraphTexture.getTexture(this.properties.name);a&&(this._last_tex=a,this.setOutputData(0,a))}};LGraphTexture.prototype.onResourceRenamed=function(a,b){this.properties.name==a&&(this.properties.name=b)};LGraphTexture.prototype.onDrawBackground=function(a){if(!(this.flags.collapsed||20>=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=LGraphTexture.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())}};LGraphTexture.generateLowResTexturePreview=function(a){if(!a)return null;var b=LGraphTexture.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};LiteGraph.registerNodeType("texture/texture",LGraphTexture);var LGraphTexturePreview=function(){this.addInput("Texture","Texture");this.properties={flipY:!1};this.size=[LGraphTexture.image_preview_size,LGraphTexture.image_preview_size]};LGraphTexturePreview.title="Preview";LGraphTexturePreview.desc= -"Show a texture in the graph canvas";LGraphTexturePreview.prototype.onDrawBackground=function(a){if(!this.flags.collapsed){var b=this.getInputData(0);if(b){var c=null,c=!b.handle&&a.webgl?b:LGraphTexture.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()}}};LiteGraph.registerNodeType("texture/preview",LGraphTexturePreview);var LGraphTextureSave=function(){this.addInput("Texture","Texture"); -this.addOutput("","Texture");this.properties={name:""}};LGraphTextureSave.title="Save";LGraphTextureSave.desc="Save a texture in the repository";LGraphTextureSave.prototype.onExecute=function(){var a=this.getInputData(0);a&&(this.properties.name&&(LGraphTexture.getTexturesContainer()[this.properties.name]=a),this.setOutputData(0,a))};LiteGraph.registerNodeType("texture/save",LGraphTextureSave);var LGraphTextureOperation=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:LGraphTexture.DEFAULT}};LGraphTextureOperation.widgets_info={uvcode:{widget:"textarea", -height:100},pixelcode:{widget:"textarea",height:100},precision:{widget:"combo",values:LGraphTexture.MODE_VALUES}};LGraphTextureOperation.title="Operation";LGraphTextureOperation.desc="Texture shader operation";LGraphTextureOperation.prototype.getExtraMenuOptions=function(a){var b=this;return[{content:b.properties.show?"Hide Texture":"Show Texture",callback:function(){b.properties.show=!b.properties.show}}]};LGraphTextureOperation.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())};LGraphTextureOperation.prototype.onExecute=function(){var a=this.getInputData(0);if(this.isOutputConnected(0))if(this.properties.precision===LGraphTexture.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?LGraphTexture.getTargetTexture(a|| -this._tex,this._tex,this.properties.precision):new GL.Texture(c,d,{type:this.precision===LGraphTexture.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 g=this._shader;if(!g||this._shader_code!= -e+"|"+f){try{this._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,LGraphTextureOperation.pixel_shader,{UV_CODE:e,PIXEL_CODE:f}),this.boxcolor="#00FF00"}catch(h){console.log("Error compiling shader: ",h);this.boxcolor="#FF0000";return}this._shader_code=e+"|"+f;g=this._shader}if(g){this.boxcolor="green";var k=this.getInputData(2);null!=k?this.properties.value=k:k=parseFloat(this.properties.value);var n=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();g.uniforms({u_texture:0,u_textureB:1,value:k,texSize:[c,d],time:n}).draw(e)});this.setOutputData(0,this._tex)}else this.boxcolor="red"}}};LGraphTextureOperation.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\tvec3 color = texture2D(u_texture, uv).rgb;\n\t\t\t\tvec3 colorB = texture2D(u_textureB, uv).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"; +-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=""};LGraphTexture.prototype.getExtraMenuOptions=function(a){var b=this;if(this._drop_texture)return[{content:"Clear",callback:function(){b._drop_texture=null;b.properties.name=""}}]};LGraphTexture.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=LGraphTexture.getTexture(this.properties.name));if(a){this._last_tex=a;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=LGraphTexture.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())}};LGraphTexture.generateLowResTexturePreview=function(a){if(!a)return null;var b=LGraphTexture.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};LGraphTexture.prototype.onGetInputs=function(){return[["in", +"Texture"]]};LGraphTexture.prototype.onGetOutputs=function(){return[["width","number"],["height","number"],["aspect","number"]]};LiteGraph.registerNodeType("texture/texture",LGraphTexture);var LGraphTexturePreview=function(){this.addInput("Texture","Texture");this.properties={flipY:!1};this.size=[LGraphTexture.image_preview_size,LGraphTexture.image_preview_size]};LGraphTexturePreview.title="Preview";LGraphTexturePreview.desc="Show a texture in the graph canvas";LGraphTexturePreview.prototype.onDrawBackground= +function(a){if(!this.flags.collapsed){var b=this.getInputData(0);if(b){var c=null,c=!b.handle&&a.webgl?b:LGraphTexture.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()}}};LiteGraph.registerNodeType("texture/preview",LGraphTexturePreview);var LGraphTextureSave=function(){this.addInput("Texture","Texture");this.addOutput("","Texture");this.properties={name:""}};LGraphTextureSave.title= +"Save";LGraphTextureSave.desc="Save a texture in the repository";LGraphTextureSave.prototype.onExecute=function(){var a=this.getInputData(0);a&&(this.properties.name&&(LGraphTexture.getTexturesContainer()[this.properties.name]=a),this.setOutputData(0,a))};LiteGraph.registerNodeType("texture/save",LGraphTextureSave);var LGraphTextureOperation=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:LGraphTexture.DEFAULT}};LGraphTextureOperation.widgets_info={uvcode:{widget:"textarea",height:100},pixelcode:{widget:"textarea",height:100}, +precision:{widget:"combo",values:LGraphTexture.MODE_VALUES}};LGraphTextureOperation.title="Operation";LGraphTextureOperation.desc="Texture shader operation";LGraphTextureOperation.prototype.getExtraMenuOptions=function(a){var b=this;return[{content:b.properties.show?"Hide Texture":"Show Texture",callback:function(){b.properties.show=!b.properties.show}}]};LGraphTextureOperation.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())};LGraphTextureOperation.prototype.onExecute=function(){var a=this.getInputData(0);if(this.isOutputConnected(0))if(this.properties.precision===LGraphTexture.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?LGraphTexture.getTargetTexture(a||this._tex,this._tex, +this.properties.precision):new GL.Texture(c,d,{type:this.precision===LGraphTexture.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 g=this._shader;if(!g||this._shader_code!=e+"|"+ +f){try{this._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,LGraphTextureOperation.pixel_shader,{UV_CODE:e,PIXEL_CODE:f}),this.boxcolor="#00FF00"}catch(h){console.log("Error compiling shader: ",h);this.boxcolor="#FF0000";return}this._shader_code=e+"|"+f;g=this._shader}if(g){this.boxcolor="green";var k=this.getInputData(2);null!=k?this.properties.value=k:k=parseFloat(this.properties.value);var l=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();g.uniforms({u_texture:0,u_textureB:1,value:k,texSize:[c,d],time:l}).draw(e)});this.setOutputData(0,this._tex)}else this.boxcolor="red"}}};LGraphTextureOperation.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\tvec3 color = texture2D(u_texture, uv).rgb;\n\t\t\t\tvec3 colorB = texture2D(u_textureB, uv).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"; LiteGraph.registerNodeType("texture/operation",LGraphTextureOperation);var LGraphTextureShader=function(){this.addOutput("Texture","Texture");this.properties={code:"",width:512,height:512};this.properties.code="\nvoid main() {\n vec2 uv = coord;\n vec3 color = vec3(0.0);\n//your code here\n\ngl_FragColor = vec4(color, 1.0);\n}\n"};LGraphTextureShader.title="Shader";LGraphTextureShader.desc="Texture shader";LGraphTextureShader.widgets_info={code:{type:"code"},precision:{widget:"combo",values:LGraphTexture.MODE_VALUES}}; LGraphTextureShader.prototype.onExecute=function(){if(this.isOutputConnected(0)){if(this._shader_code!=this.properties.code)if(this._shader_code=this.properties.code,this._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,LGraphTextureShader.pixel_shader+this.properties.code))this.boxcolor="green";else{this.boxcolor="red";return}this._tex&&this._tex.width==this.properties.width&&this._tex.height==this.properties.height||(this._tex=new GL.Texture(this.properties.width,this.properties.height,{format:gl.RGBA, -filter:gl.LINEAR}));var a=this._tex,b=this._shader,c=this.graph.getTime();a.drawTo(function(){b.uniforms({texSize:[a.width,a.height],time:c}).draw(Mesh.getScreenQuad())});this.setOutputData(0,this._tex)}};LGraphTextureShader.pixel_shader="precision highp float;\n\t\t\t\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform float time;\n\t\t\t";LiteGraph.registerNodeType("texture/shader",LGraphTextureShader);var LGraphTextureToViewport=function(){this.addInput("Texture","Texture");this.properties={additive:!1, -antialiasing:!1,disable_alpha:!1};this.size[0]=130;LGraphTextureToViewport._shader||(LGraphTextureToViewport._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,LGraphTextureToViewport.pixel_shader))};LGraphTextureToViewport.title="to Viewport";LGraphTextureToViewport.desc="Texture to viewport";LGraphTextureToViewport.prototype.onExecute=function(){var a=this.getInputData(0);if(a)if(this.properties.disable_alpha?gl.disable(gl.BLEND):(gl.enable(gl.BLEND),this.properties.additive?gl.blendFunc(gl.SRC_ALPHA, -gl.ONE):gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA)),gl.disable(gl.DEPTH_TEST),this.properties.antialiasing){gl.getViewport();var b=Mesh.getScreenQuad();a.bind(0);LGraphTextureToViewport._shader.uniforms({u_texture:0,uViewportSize:[a.width,a.height],inverseVP:[1/a.width,1/a.height]}).draw(b)}else a.toViewport()};LGraphTextureToViewport.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 uViewportSize;\n\t\t\tuniform vec2 inverseVP;\n\t\t\t#define FXAA_REDUCE_MIN (1.0/ 128.0)\n\t\t\t#define FXAA_REDUCE_MUL (1.0 / 8.0)\n\t\t\t#define FXAA_SPAN_MAX 8.0\n\t\t\t\n\t\t\t/* from mitsuhiko/webgl-meincraft based on the code on geeks3d.com */\n\t\t\tvec4 applyFXAA(sampler2D tex, vec2 fragCoord)\n\t\t\t{\n\t\t\t\tvec4 color = vec4(0.0);\n\t\t\t\t/*vec2 inverseVP = vec2(1.0 / uViewportSize.x, 1.0 / uViewportSize.y);*/\n\t\t\t\tvec3 rgbNW = texture2D(tex, (fragCoord + vec2(-1.0, -1.0)) * inverseVP).xyz;\n\t\t\t\tvec3 rgbNE = texture2D(tex, (fragCoord + vec2(1.0, -1.0)) * inverseVP).xyz;\n\t\t\t\tvec3 rgbSW = texture2D(tex, (fragCoord + vec2(-1.0, 1.0)) * inverseVP).xyz;\n\t\t\t\tvec3 rgbSE = texture2D(tex, (fragCoord + vec2(1.0, 1.0)) * inverseVP).xyz;\n\t\t\t\tvec3 rgbM = texture2D(tex, fragCoord * inverseVP).xyz;\n\t\t\t\tvec3 luma = vec3(0.299, 0.587, 0.114);\n\t\t\t\tfloat lumaNW = dot(rgbNW, luma);\n\t\t\t\tfloat lumaNE = dot(rgbNE, luma);\n\t\t\t\tfloat lumaSW = dot(rgbSW, luma);\n\t\t\t\tfloat lumaSE = dot(rgbSE, luma);\n\t\t\t\tfloat lumaM = dot(rgbM, luma);\n\t\t\t\tfloat lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));\n\t\t\t\tfloat lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));\n\t\t\t\t\n\t\t\t\tvec2 dir;\n\t\t\t\tdir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n\t\t\t\tdir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n\t\t\t\t\n\t\t\t\tfloat dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);\n\t\t\t\t\n\t\t\t\tfloat rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);\n\t\t\t\tdir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * inverseVP;\n\t\t\t\t\n\t\t\t\tvec3 rgbA = 0.5 * (texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + \n\t\t\t\t\ttexture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);\n\t\t\t\tvec3 rgbB = rgbA * 0.5 + 0.25 * (texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + \n\t\t\t\t\ttexture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);\n\t\t\t\t\n\t\t\t\treturn vec4(rgbA,1.0);\n\t\t\t\tfloat lumaB = dot(rgbB, luma);\n\t\t\t\tif ((lumaB < lumaMin) || (lumaB > 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\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"; -LiteGraph.registerNodeType("texture/toviewport",LGraphTextureToViewport);var LGraphTextureCopy=function(){this.addInput("Texture","Texture");this.addOutput("","Texture");this.properties={size:0,generate_mipmaps:!1,precision:LGraphTexture.DEFAULT}};LGraphTextureCopy.title="Copy";LGraphTextureCopy.desc="Copy Texture";LGraphTextureCopy.widgets_info={size:{widget:"combo",values:[0,32,64,128,256,512,1024,2048]},precision:{widget:"combo",values:LGraphTexture.MODE_VALUES}};LGraphTextureCopy.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===LGraphTexture.LOW?e=gl.UNSIGNED_BYTE:this.properties.precision===LGraphTexture.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)}};LiteGraph.registerNodeType("texture/copy",LGraphTextureCopy);var LGraphTextureAverage=function(){this.addInput("Texture","Texture");this.addOutput("","Texture");this.properties={low_precision:!1}};LGraphTextureAverage.title= -"Average";LGraphTextureAverage.desc="Compute the total average of a texture and stores it as a 1x1 pixel texture";LGraphTextureAverage.prototype.onExecute=function(){var a=this.getInputData(0);if(a&&this.isOutputConnected(0)){if(!LGraphTextureAverage._shader){LGraphTextureAverage._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,LGraphTextureAverage.pixel_shader);for(var b=new Float32Array(32),c=0;32>c;++c)b[c]=Math.random();LGraphTextureAverage._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=LGraphTextureAverage._shader;this._temp_texture.drawTo(function(){a.toViewport(d,{u_texture:0})});this.setOutputData(0,this._temp_texture)}};LGraphTextureAverage.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\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] ) );\n\t\t\t\t\t\tcolor += texture2D(u_texture, vec2( 1.0 - u_samples_a[i][j], u_samples_b[i][j] ) );\n\t\t\t\t\t}\n\t\t\t gl_FragColor = color * 0.03125;\n\t\t\t}\n\t\t\t"; +filter:gl.LINEAR}));var a=this._tex,b=this._shader,c=this.graph.getTime();a.drawTo(function(){b.uniforms({texSize:[a.width,a.height],time:c}).draw(Mesh.getScreenQuad())});this.setOutputData(0,this._tex)}};LGraphTextureShader.pixel_shader="precision highp float;\n\t\t\t\n\t\t\tvarying vec2 v_coord;\n\t\t\tuniform float time;\n\t\t\t";LiteGraph.registerNodeType("texture/shader",LGraphTextureShader);var LGraphTextureScaleOffset=function(){this.addInput("in","Texture");this.addInput("scale","vec2");this.addInput("offset", +"vec2");this.addOutput("out","Texture");this.properties={offset:vec2.fromValues(0,0),scale:vec2.fromValues(1,1),precision:LGraphTexture.DEFAULT}};LGraphTextureScaleOffset.widgets_info={precision:{widget:"combo",values:LGraphTexture.MODE_VALUES}};LGraphTextureScaleOffset.title="Scale/Offset";LGraphTextureScaleOffset.desc="Applies an scaling and offseting";LGraphTextureScaleOffset.prototype.onExecute=function(){var a=this.getInputData(0);if(this.isOutputConnected(0)&&a)if(this.properties.precision=== +LGraphTexture.PASS_THROUGH)this.setOutputData(0,a);else{var b=a.width,c=a.height,d=this.precision===LGraphTexture.LOW?gl.UNSIGNED_BYTE:gl.HIGH_PRECISION_FORMAT;this.precision===LGraphTexture.DEFAULT&&(d=a.type);this._tex&&this._tex.width==b&&this._tex.height==c&&this._tex.type==d||(this._tex=new GL.Texture(b,c,{type:d,format:gl.RGBA,filter:gl.LINEAR}));var e=this._shader;e||(e=new GL.Shader(GL.Shader.SCREEN_VERTEX_SHADER,LGraphTextureScaleOffset.pixel_shader));var f=this.getInputData(1);f?(this.properties.scale[0]= +f[0],this.properties.scale[1]=f[1]):f=this.properties.scale;var g=this.getInputData(2);g?(this.properties.offset[0]=g[0],this.properties.offset[1]=g[1]):g=this.properties.offset;this._tex.drawTo(function(){gl.disable(gl.DEPTH_TEST);gl.disable(gl.CULL_FACE);gl.disable(gl.BLEND);a.bind(0);var b=Mesh.getScreenQuad();e.uniforms({u_texture:0,u_scale:f,u_offset:g}).draw(b)});this.setOutputData(0,this._tex)}};LGraphTextureScaleOffset.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 u_scale;\n\t\t\tuniform vec2 u_offset;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec2 uv = v_coord;\n\t\t\t\tuv = uv / u_scale - u_offset;\n\t\t\t\tgl_FragColor = texture2D(u_texture, uv);\n\t\t\t}\n\t\t\t"; +LiteGraph.registerNodeType("texture/scaleOffset",LGraphTextureScaleOffset);var LGraphTextureWarp=function(){this.addInput("in","Texture");this.addInput("warp","Texture");this.addInput("factor","number");this.addOutput("out","Texture");this.properties={factor:0.01,precision:LGraphTexture.DEFAULT}};LGraphTextureWarp.widgets_info={precision:{widget:"combo",values:LGraphTexture.MODE_VALUES}};LGraphTextureWarp.title="Warp";LGraphTextureWarp.desc="Texture warp operation";LGraphTextureWarp.prototype.onExecute= +function(){var a=this.getInputData(0);if(this.isOutputConnected(0))if(this.properties.precision===LGraphTexture.PASS_THROUGH)this.setOutputData(0,a);else{var b=this.getInputData(1),c=512,d=512;a?(c=a.width,d=a.height):b&&(c=b.width,d=b.height);this._tex=a||this._tex?LGraphTexture.getTargetTexture(a||this._tex,this._tex,this.properties.precision):new GL.Texture(c,d,{type:this.precision===LGraphTexture.LOW?gl.UNSIGNED_BYTE:gl.HIGH_PRECISION_FORMAT,format:gl.RGBA,filter:gl.LINEAR});var e=this._shader; +e||(e=new GL.Shader(GL.Shader.SCREEN_VERTEX_SHADER,LGraphTextureWarp.pixel_shader));var f=this.getInputData(2);null!=f?this.properties.factor=f:f=parseFloat(this.properties.factor);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 c=Mesh.getScreenQuad();e.uniforms({u_texture:0,u_textureB:1,u_factor:f}).draw(c)});this.setOutputData(0,this._tex)}};LGraphTextureWarp.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 float u_factor;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec2 uv = v_coord;\n\t\t\t\tuv += texture2D(u_textureB, uv).rg * u_factor;\n\t\t\t\tgl_FragColor = texture2D(u_texture, uv);\n\t\t\t}\n\t\t\t"; +LiteGraph.registerNodeType("texture/warp",LGraphTextureWarp);var LGraphTextureToViewport=function(){this.addInput("Texture","Texture");this.properties={additive:!1,antialiasing:!1,disable_alpha:!1,gamma:1};this.size[0]=130};LGraphTextureToViewport.title="to Viewport";LGraphTextureToViewport.desc="Texture to viewport";LGraphTextureToViewport.prototype.onExecute=function(){var a=this.getInputData(0);if(a){this.properties.disable_alpha?gl.disable(gl.BLEND):(gl.enable(gl.BLEND),this.properties.additive? +gl.blendFunc(gl.SRC_ALPHA,gl.ONE):gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA));gl.disable(gl.DEPTH_TEST);var b=this.properties.gamma||1;this.isInputConnected(1)&&(b=this.getInputData(1));if(this.properties.antialiasing){LGraphTextureToViewport._shader||(LGraphTextureToViewport._shader=new GL.Shader(GL.Shader.SCREEN_VERTEX_SHADER,LGraphTextureToViewport.aa_pixel_shader));gl.getViewport();var c=Mesh.getScreenQuad();a.bind(0);LGraphTextureToViewport._shader.uniforms({u_texture:0,uViewportSize:[a.width, +a.height],u_igamma:1/b,inverseVP:[1/a.width,1/a.height]}).draw(c)}else 1!=b?(LGraphTextureToViewport._gamma_shader||(LGraphTextureToViewport._gamma_shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,LGraphTextureToViewport.gamma_pixel_shader)),a.toViewport(LGraphTextureToViewport._gamma_shader,{u_texture:0,u_igamma:1/b})):a.toViewport()}};LGraphTextureToViewport.prototype.onGetInputs=function(){return[["gamma","number"]]};LGraphTextureToViewport.aa_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 uViewportSize;\n\t\t\tuniform vec2 inverseVP;\n\t\t\tuniform float u_igamma;\n\t\t\t#define FXAA_REDUCE_MIN (1.0/ 128.0)\n\t\t\t#define FXAA_REDUCE_MUL (1.0 / 8.0)\n\t\t\t#define FXAA_SPAN_MAX 8.0\n\t\t\t\n\t\t\t/* from mitsuhiko/webgl-meincraft based on the code on geeks3d.com */\n\t\t\tvec4 applyFXAA(sampler2D tex, vec2 fragCoord)\n\t\t\t{\n\t\t\t\tvec4 color = vec4(0.0);\n\t\t\t\t/*vec2 inverseVP = vec2(1.0 / uViewportSize.x, 1.0 / uViewportSize.y);*/\n\t\t\t\tvec3 rgbNW = texture2D(tex, (fragCoord + vec2(-1.0, -1.0)) * inverseVP).xyz;\n\t\t\t\tvec3 rgbNE = texture2D(tex, (fragCoord + vec2(1.0, -1.0)) * inverseVP).xyz;\n\t\t\t\tvec3 rgbSW = texture2D(tex, (fragCoord + vec2(-1.0, 1.0)) * inverseVP).xyz;\n\t\t\t\tvec3 rgbSE = texture2D(tex, (fragCoord + vec2(1.0, 1.0)) * inverseVP).xyz;\n\t\t\t\tvec3 rgbM = texture2D(tex, fragCoord * inverseVP).xyz;\n\t\t\t\tvec3 luma = vec3(0.299, 0.587, 0.114);\n\t\t\t\tfloat lumaNW = dot(rgbNW, luma);\n\t\t\t\tfloat lumaNE = dot(rgbNE, luma);\n\t\t\t\tfloat lumaSW = dot(rgbSW, luma);\n\t\t\t\tfloat lumaSE = dot(rgbSE, luma);\n\t\t\t\tfloat lumaM = dot(rgbM, luma);\n\t\t\t\tfloat lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));\n\t\t\t\tfloat lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));\n\t\t\t\t\n\t\t\t\tvec2 dir;\n\t\t\t\tdir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n\t\t\t\tdir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n\t\t\t\t\n\t\t\t\tfloat dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);\n\t\t\t\t\n\t\t\t\tfloat rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);\n\t\t\t\tdir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * inverseVP;\n\t\t\t\t\n\t\t\t\tvec3 rgbA = 0.5 * (texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + \n\t\t\t\t\ttexture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);\n\t\t\t\tvec3 rgbB = rgbA * 0.5 + 0.25 * (texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + \n\t\t\t\t\ttexture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);\n\t\t\t\t\n\t\t\t\t//return vec4(rgbA,1.0);\n\t\t\t\tfloat lumaB = dot(rgbB, luma);\n\t\t\t\tif ((lumaB < lumaMin) || (lumaB > 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"; +LGraphTextureToViewport.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";LiteGraph.registerNodeType("texture/toviewport",LGraphTextureToViewport);var LGraphTextureCopy=function(){this.addInput("Texture", +"Texture");this.addOutput("","Texture");this.properties={size:0,generate_mipmaps:!1,precision:LGraphTexture.DEFAULT}};LGraphTextureCopy.title="Copy";LGraphTextureCopy.desc="Copy Texture";LGraphTextureCopy.widgets_info={size:{widget:"combo",values:[0,32,64,128,256,512,1024,2048]},precision:{widget:"combo",values:LGraphTexture.MODE_VALUES}};LGraphTextureCopy.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===LGraphTexture.LOW?e=gl.UNSIGNED_BYTE:this.properties.precision===LGraphTexture.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)}};LiteGraph.registerNodeType("texture/copy",LGraphTextureCopy);var LGraphTextureAverage=function(){this.addInput("Texture","Texture");this.addOutput("","Texture");this.properties={low_precision:!1}};LGraphTextureAverage.title="Average";LGraphTextureAverage.desc="Compute the total average of a texture and stores it as a 1x1 pixel texture"; +LGraphTextureAverage.prototype.onExecute=function(){var a=this.getInputData(0);if(a&&this.isOutputConnected(0)){if(!LGraphTextureAverage._shader){LGraphTextureAverage._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,LGraphTextureAverage.pixel_shader);for(var b=new Float32Array(32),c=0;32>c;++c)b[c]=Math.random();LGraphTextureAverage._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=LGraphTextureAverage._shader;this._temp_texture.drawTo(function(){a.toViewport(d,{u_texture:0})});this.setOutputData(0,this._temp_texture)}};LGraphTextureAverage.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\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] ) );\n\t\t\t\t\t\tcolor += texture2D(u_texture, vec2( 1.0 - u_samples_a[i][j], u_samples_b[i][j] ) );\n\t\t\t\t\t}\n\t\t\t gl_FragColor = color * 0.03125;\n\t\t\t}\n\t\t\t"; LiteGraph.registerNodeType("texture/average",LGraphTextureAverage);var LGraphImageToTexture=function(){this.addInput("Image","image");this.addOutput("","Texture");this.properties={}};LGraphImageToTexture.title="Image to Texture";LGraphImageToTexture.desc="Uploads an image to the GPU";LGraphImageToTexture.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)}}};LiteGraph.registerNodeType("texture/imageToTexture",LGraphImageToTexture);var LGraphTextureLUT=function(){this.addInput("Texture","Texture");this.addInput("LUT","Texture");this.addInput("Intensity","number");this.addOutput("", "Texture");this.properties={intensity:1,precision:LGraphTexture.DEFAULT,texture:null};LGraphTextureLUT._shader||(LGraphTextureLUT._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,LGraphTextureLUT.pixel_shader))};LGraphTextureLUT.widgets_info={precision:{widget:"combo",values:LGraphTexture.MODE_VALUES}};LGraphTextureLUT.title="LUT";LGraphTextureLUT.desc="Apply LUT to Texture";LGraphTextureLUT.widgets_info={texture:{widget:"texture"}};LGraphTextureLUT.prototype.onExecute=function(){if(this.isOutputConnected(0)){var a= @@ -267,8 +286,8 @@ LGraphTextureEdges.prototype.onExecute=function(){if(this.isOutputConnected(0)){ a.width,1/a.height],u_factor:e,u_invert:d?1:0}).draw(b)});this.setOutputData(0,this._tex)}}};LGraphTextureEdges.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_isize;\n\t\t\tuniform int u_invert;\n\t\t\tuniform float u_factor;\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tvec4 center = texture2D(u_texture, v_coord);\n\t\t\t\tvec4 up = texture2D(u_texture, v_coord + u_isize * vec2(0.0,1.0) );\n\t\t\t\tvec4 down = texture2D(u_texture, v_coord + u_isize * vec2(0.0,-1.0) );\n\t\t\t\tvec4 left = texture2D(u_texture, v_coord + u_isize * vec2(1.0,0.0) );\n\t\t\t\tvec4 right = texture2D(u_texture, v_coord + u_isize * vec2(-1.0,0.0) );\n\t\t\t\tvec4 diff = abs(center - up) + abs(center - down) + abs(center - left) + abs(center - right);\n\t\t\t\tdiff *= u_factor;\n\t\t\t\tif(u_invert == 1)\n\t\t\t\t\tdiff.xyz = vec3(1.0) - diff.xyz;\n\t\t\t gl_FragColor = vec4( diff.xyz, center.a );\n\t\t\t}\n\t\t\t"; LiteGraph.registerNodeType("texture/edges",LGraphTextureEdges);var LGraphTextureDepthRange=function(){this.addInput("Texture","Texture");this.addInput("Distance","number");this.addInput("Range","number");this.addOutput("Texture","Texture");this.properties={distance:100,range:50,high_precision:!1};LGraphTextureDepthRange._shader||(LGraphTextureDepthRange._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,LGraphTextureDepthRange.pixel_shader))};LGraphTextureDepthRange.title="Depth Range";LGraphTextureDepthRange.desc= "Generates a texture with a depth range";LGraphTextureDepthRange.prototype.onExecute=function(){if(this.isOutputConnected(0)){var a=this.getInputData(0);if(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==a.width&&this._temp_texture.height==a.height||(this._temp_texture=new GL.Texture(a.width,a.height,{type:b,format:gl.RGBA,filter:gl.LINEAR}));var c=this.properties.distance; -this.isInputConnected(1)&&(c=this.getInputData(1),this.properties.distance=c);var d=this.properties.range;this.isInputConnected(2)&&(d=this.getInputData(2),this.properties.range=d);gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);var e=Mesh.getScreenQuad(),f=LGraphTextureDepthRange._shader,g=[Renderer._current_camera.near,Renderer._current_camera.far];this._temp_texture.drawTo(function(){a.bind(0);f.uniforms({u_texture:0,u_distance:c,u_range:d,u_camera_planes:g}).draw(e)});this.setOutputData(0,this._temp_texture)}}}; -LGraphTextureDepthRange.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_distance;\n\t\t\tuniform float u_range;\n\t\t\t\n\t\t\tfloat LinearDepth()\n\t\t\t{\n\t\t\t\tfloat n = u_camera_planes.x;\n\t\t\t\tfloat f = u_camera_planes.y;\n\t\t\t\treturn (2.0 * n) / (f + n - texture2D(u_texture, v_coord).x * (f - n));\n\t\t\t}\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tfloat diff = abs(LinearDepth() * u_camera_planes.y - u_distance);\n\t\t\t\tfloat dof = 1.0;\n\t\t\t\tif(diff <= u_range)\n\t\t\t\t\tdof = diff / u_range;\n\t\t\t gl_FragColor = vec4(dof);\n\t\t\t}\n\t\t\t"; +this.isInputConnected(1)&&(c=this.getInputData(1),this.properties.distance=c);var d=this.properties.range;this.isInputConnected(2)&&(d=this.getInputData(2),this.properties.range=d);gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);var e=Mesh.getScreenQuad(),f=LGraphTextureDepthRange._shader,g=[LS.Renderer._current_camera.near,LS.Renderer._current_camera.far];this._temp_texture.drawTo(function(){a.bind(0);f.uniforms({u_texture:0,u_distance:c,u_range:d,u_camera_planes:g}).draw(e)});this.setOutputData(0, +this._temp_texture)}}};LGraphTextureDepthRange.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_distance;\n\t\t\tuniform float u_range;\n\t\t\t\n\t\t\tfloat LinearDepth()\n\t\t\t{\n\t\t\t\tfloat n = u_camera_planes.x;\n\t\t\t\tfloat f = u_camera_planes.y;\n\t\t\t\treturn (2.0 * n) / (f + n - texture2D(u_texture, v_coord).x * (f - n));\n\t\t\t}\n\t\t\t\n\t\t\tvoid main() {\n\t\t\t\tfloat diff = abs(LinearDepth() * u_camera_planes.y - u_distance);\n\t\t\t\tfloat dof = 1.0;\n\t\t\t\tif(diff <= u_range)\n\t\t\t\t\tdof = diff / u_range;\n\t\t\t gl_FragColor = vec4(dof);\n\t\t\t}\n\t\t\t"; LiteGraph.registerNodeType("texture/depth_range",LGraphTextureDepthRange);var LGraphTextureBlur=function(){this.addInput("Texture","Texture");this.addInput("Iterations","number");this.addInput("Intensity","number");this.addOutput("Blurred","Texture");this.properties={intensity:1,iterations:1,preserve_aspect:!1,scale:[1,1]};LGraphTextureBlur._shader||(LGraphTextureBlur._shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,LGraphTextureBlur.pixel_shader))};LGraphTextureBlur.title="Blur";LGraphTextureBlur.desc= "Blur a texture";LGraphTextureBlur.max_iterations=20;LGraphTextureBlur.prototype.onExecute=function(){var a=this.getInputData(0);if(a&&this.isOutputConnected(0)){var b=this._temp_texture;b&&b.width==a.width&&b.height==a.height&&b.type==a.type||(this._temp_texture=new GL.Texture(a.width,a.height,{type:a.type,format:gl.RGBA,filter:gl.LINEAR}),this._final_texture=new GL.Texture(a.width,a.height,{type:a.type,format:gl.RGBA,filter:gl.LINEAR}));b=this.properties.iterations;this.isInputConnected(1)&&(b= this.getInputData(1),this.properties.iterations=b);b=Math.min(Math.floor(b),LGraphTextureBlur.max_iterations);if(0==b)this.setOutputData(0,a);else{var c=this.properties.intensity;this.isInputConnected(2)&&(c=this.getInputData(2),this.properties.intensity=c);gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);var d=Mesh.getScreenQuad(),e=LGraphTextureBlur._shader,f=this.properties.scale||[1,1],g=LiteGraph.camera_aspect;g||void 0===window.gl||(g=gl.canvas.height/gl.canvas.width);g||(g=1);for(var h=a,g=this.properties.preserve_aspect? @@ -285,17 +304,19 @@ LGraphFXLens.widgets_info={precision:{widget:"combo",values:LGraphTexture.MODE_V LiteGraph.registerNodeType("fx/lens",LGraphFXLens);window.LGraphFXLens=LGraphFXLens;var LGraphFXBokeh=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}};LGraphFXBokeh.title="Bokeh";LGraphFXBokeh.desc="applies an Bokeh effect";LGraphFXBokeh.widgets_info={shape:{widget:"texture"}};LGraphFXBokeh.prototype.onExecute= function(){var a=this.getInputData(0),b=this.getInputData(1),c=this.getInputData(2);if(a&&c&&this.properties.shape){b||(b=a);var d=LGraphTexture.getTexture(this.properties.shape);if(d){var e=this.properties.threshold;this.isInputConnected(3)&&(e=this.getInputData(3),this.properties.threshold=e);var f=gl.UNSIGNED_BYTE;this.properties.high_precision&&(f=gl.half_float_ext?gl.HALF_FLOAT_OES:gl.FLOAT);this._temp_texture&&this._temp_texture.type==f&&this._temp_texture.width==a.width&&this._temp_texture.height== a.height||(this._temp_texture=new GL.Texture(a.width,a.height,{type:f,format:gl.RGBA,filter:gl.LINEAR}));var g=LGraphFXBokeh._first_shader;g||(g=LGraphFXBokeh._first_shader=new GL.Shader(Shader.SCREEN_VERTEX_SHADER,LGraphFXBokeh._first_pixel_shader));var h=LGraphFXBokeh._second_shader;h||(h=LGraphFXBokeh._second_shader=new GL.Shader(LGraphFXBokeh._second_vertex_shader,LGraphFXBokeh._second_pixel_shader));var k=this._points_mesh;k&&k._width==a.width&&k._height==a.height&&2==k._spacing||(k=this.createPointsMesh(a.width, -a.height,2));var n=Mesh.getScreenQuad(),p=this.properties.size,q=this.properties.alpha;gl.disable(gl.DEPTH_TEST);gl.disable(gl.BLEND);this._temp_texture.drawTo(function(){a.bind(0);b.bind(1);c.bind(2);g.uniforms({u_texture:0,u_texture_blur:1,u_mask:2,u_texsize:[a.width,a.height]}).draw(n)});this._temp_texture.drawTo(function(){gl.enable(gl.BLEND);gl.blendFunc(gl.ONE,gl.ONE);a.bind(0);d.bind(3);h.uniforms({u_texture:0,u_mask:2,u_shape:3,u_alpha:q,u_threshold:e,u_pointSize:p,u_itexsize:[1/a.width,1/ -a.height]}).draw(k,gl.POINTS)});this.setOutputData(0,this._temp_texture)}}else this.setOutputData(0,a)};LGraphFXBokeh.prototype.createPointsMesh=function(a,b,c){for(var d=Math.round(a/c),e=Math.round(b/c),f=new Float32Array(d*e*2),g=-1,h=2/a*c,k=2/b*c,n=0;n - Defined in: ../src/litegraph.js:2429 + Defined in: ../src/litegraph.js:2551 @@ -163,7 +163,7 @@ - ../src/litegraph.js:2429 + ../src/litegraph.js:2551

@@ -353,7 +353,7 @@ - ../src/litegraph.js:2073 + ../src/litegraph.js:2192

@@ -418,7 +418,7 @@ - ../src/litegraph.js:2187 + ../src/litegraph.js:2306

@@ -501,7 +501,7 @@ - ../src/litegraph.js:2445 + ../src/litegraph.js:2567

@@ -580,7 +580,7 @@ - ../src/litegraph.js:2160 + ../src/litegraph.js:2279

@@ -668,7 +668,7 @@ - ../src/litegraph.js:2202 + ../src/litegraph.js:2321

@@ -757,7 +757,7 @@ - ../src/litegraph.js:2129 + ../src/litegraph.js:2248

@@ -835,7 +835,7 @@ - ../src/litegraph.js:2457 + ../src/litegraph.js:2579

@@ -890,7 +890,7 @@ - ../src/litegraph.js:2480 + ../src/litegraph.js:2602

diff --git a/doc/classes/LGraphNode.html b/doc/classes/LGraphNode.html old mode 100755 new mode 100644 index 340df53ec..f11cc8f66 --- a/doc/classes/LGraphNode.html +++ b/doc/classes/LGraphNode.html @@ -96,7 +96,7 @@ @@ -267,6 +267,13 @@ + + +
  • + getSlotInPosition + + +
  • @@ -415,7 +422,7 @@ - ../src/litegraph.js:1570 + ../src/litegraph.js:1600

    @@ -563,7 +570,7 @@ - ../src/litegraph.js:1509 + ../src/litegraph.js:1538

    @@ -683,7 +690,7 @@ - ../src/litegraph.js:1531 + ../src/litegraph.js:1561

    @@ -784,7 +791,7 @@ - ../src/litegraph.js:1449 + ../src/litegraph.js:1478

    @@ -904,7 +911,7 @@ - ../src/litegraph.js:1470 + ../src/litegraph.js:1499

    @@ -983,7 +990,7 @@ - ../src/litegraph.js:2002 + ../src/litegraph.js:2121

    @@ -1052,7 +1059,7 @@ - ../src/litegraph.js:1583 + ../src/litegraph.js:1613

    @@ -1144,7 +1151,7 @@ - ../src/litegraph.js:1191 + ../src/litegraph.js:1217

    @@ -1225,7 +1232,7 @@ - ../src/litegraph.js:1663 + ../src/litegraph.js:1759

    @@ -1364,7 +1371,7 @@ - ../src/litegraph.js:1813 + ../src/litegraph.js:1927

    @@ -1477,7 +1484,7 @@ - ../src/litegraph.js:1746 + ../src/litegraph.js:1855

    @@ -1600,7 +1607,7 @@ - ../src/litegraph.js:1633 + ../src/litegraph.js:1729

    @@ -1707,7 +1714,7 @@ - ../src/litegraph.js:1648 + ../src/litegraph.js:1744

    @@ -1804,7 +1811,7 @@ - ../src/litegraph.js:1601 + ../src/litegraph.js:1664

    @@ -1893,7 +1900,7 @@ - ../src/litegraph.js:1870 + ../src/litegraph.js:1989

    @@ -2016,7 +2023,7 @@ - ../src/litegraph.js:1350 + ../src/litegraph.js:1376

    @@ -2065,7 +2072,7 @@ : -

    data

    +

    data or if it is not connected returns undefined

    @@ -2122,7 +2129,7 @@ - ../src/litegraph.js:1378 + ../src/litegraph.js:1404

    @@ -2171,6 +2178,8 @@ Object: +

    object or null

    + @@ -2226,7 +2235,7 @@ - ../src/litegraph.js:1393 + ../src/litegraph.js:1420

    @@ -2275,6 +2284,8 @@ Object: +

    object or null

    + @@ -2330,7 +2341,7 @@ - ../src/litegraph.js:1420 + ../src/litegraph.js:1449

    @@ -2385,6 +2396,133 @@ + + + +
    +

    getSlotInPosition

    + + +
    + (
      + +
    • + + x + +
    • + +
    • + + y + +
    • + +
    ) +
    + + + + + Object + + + + + + + + + + + + + + + +
    + + + +

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

    + + + + + +
    + +
    +

    checks if a point is inside a node slot, and returns info about which slot

    + +
    + + +
    +

    Parameters:

    + +
      + +
    • + + x + Number + + + + +
      + +
      + + +
    • + +
    • + + y + Number + + + + +
      + +
      + + +
    • + +
    +
    + + + +
    +

    Returns:

    + +
    + + + Object: + +

    if found the object contains { input|output: slot object, slot: number, link_pos: [x,y] }

    + + +
    +
    + + +
    @@ -2420,7 +2558,7 @@ - ../src/litegraph.js:1316 + ../src/litegraph.js:1342

    @@ -2489,7 +2627,7 @@ - ../src/litegraph.js:1365 + ../src/litegraph.js:1391

    @@ -2593,7 +2731,7 @@ - ../src/litegraph.js:1408 + ../src/litegraph.js:1436

    @@ -2703,7 +2841,7 @@ - ../src/litegraph.js:1611 + ../src/litegraph.js:1674

    @@ -2808,7 +2946,7 @@ - ../src/litegraph.js:2015 + ../src/litegraph.js:2134

    @@ -2873,7 +3011,7 @@ - ../src/litegraph.js:1556 + ../src/litegraph.js:1586

    @@ -2961,7 +3099,7 @@ - ../src/litegraph.js:1495 + ../src/litegraph.js:1524

    @@ -3039,7 +3177,7 @@ - ../src/litegraph.js:1250 + ../src/litegraph.js:1276

    @@ -3110,7 +3248,7 @@ - ../src/litegraph.js:1329 + ../src/litegraph.js:1355

    @@ -3203,7 +3341,7 @@ - ../src/litegraph.js:1304 + ../src/litegraph.js:1330

    diff --git a/doc/classes/LiteGraph.html b/doc/classes/LiteGraph.html old mode 100755 new mode 100644 diff --git a/doc/classes/index.html b/doc/classes/index.html old mode 100755 new mode 100644 diff --git a/doc/data.json b/doc/data.json old mode 100755 new mode 100644 index 3affa1f0c..3f421e7dd --- a/doc/data.json +++ b/doc/data.json @@ -51,7 +51,7 @@ "plugin_for": [], "extension_for": [], "file": "../src/litegraph.js", - "line": 1156, + "line": 1166, "description": "Base Class for all the node type classes", "params": [ { @@ -70,7 +70,7 @@ "plugin_for": [], "extension_for": [], "file": "../src/litegraph.js", - "line": 2429, + "line": 2551, "description": "marks as dirty the canvas, this way it will be rendered again", "is_constructor": 1, "params": [ @@ -531,7 +531,7 @@ }, { "file": "../src/litegraph.js", - "line": 1191, + "line": 1217, "description": "configure a node from an object containing the serialized info", "itemtype": "method", "name": "configure", @@ -539,7 +539,7 @@ }, { "file": "../src/litegraph.js", - "line": 1250, + "line": 1276, "description": "serialize the content", "itemtype": "method", "name": "serialize", @@ -547,7 +547,7 @@ }, { "file": "../src/litegraph.js", - "line": 1304, + "line": 1330, "description": "serialize and stringify", "itemtype": "method", "name": "toString", @@ -555,7 +555,7 @@ }, { "file": "../src/litegraph.js", - "line": 1316, + "line": 1342, "description": "get the title string", "itemtype": "method", "name": "getTitle", @@ -563,7 +563,7 @@ }, { "file": "../src/litegraph.js", - "line": 1329, + "line": 1355, "description": "sets the output data", "itemtype": "method", "name": "setOutputData", @@ -583,7 +583,7 @@ }, { "file": "../src/litegraph.js", - "line": 1350, + "line": 1376, "description": "retrieves the input data (data traveling through the connection) from one slot", "itemtype": "method", "name": "getInputData", @@ -595,14 +595,14 @@ } ], "return": { - "description": "data", + "description": "data or if it is not connected returns undefined", "type": "*" }, "class": "LGraphNode" }, { "file": "../src/litegraph.js", - "line": 1365, + "line": 1391, "description": "tells you if there is a connection in one input slot", "itemtype": "method", "name": "isInputConnected", @@ -621,7 +621,7 @@ }, { "file": "../src/litegraph.js", - "line": 1378, + "line": 1404, "description": "tells you info about an input connection (which node, type, etc)", "itemtype": "method", "name": "getInputInfo", @@ -633,14 +633,14 @@ } ], "return": { - "description": "", + "description": "object or null", "type": "Object" }, "class": "LGraphNode" }, { "file": "../src/litegraph.js", - "line": 1393, + "line": 1420, "description": "tells you info about an output connection (which node, type, etc)", "itemtype": "method", "name": "getOutputInfo", @@ -652,14 +652,14 @@ } ], "return": { - "description": "", + "description": "object or null", "type": "Object" }, "class": "LGraphNode" }, { "file": "../src/litegraph.js", - "line": 1408, + "line": 1436, "description": "tells you if there is a connection in one output slot", "itemtype": "method", "name": "isOutputConnected", @@ -678,7 +678,7 @@ }, { "file": "../src/litegraph.js", - "line": 1420, + "line": 1449, "description": "retrieves all the nodes connected to this output slot", "itemtype": "method", "name": "getOutputNodes", @@ -697,7 +697,7 @@ }, { "file": "../src/litegraph.js", - "line": 1449, + "line": 1478, "description": "add a new output slot to use in this node", "itemtype": "method", "name": "addOutput", @@ -722,7 +722,7 @@ }, { "file": "../src/litegraph.js", - "line": 1470, + "line": 1499, "description": "add a new output slot to use in this node", "itemtype": "method", "name": "addOutputs", @@ -737,7 +737,7 @@ }, { "file": "../src/litegraph.js", - "line": 1495, + "line": 1524, "description": "remove an existing output slot", "itemtype": "method", "name": "removeOutput", @@ -752,7 +752,7 @@ }, { "file": "../src/litegraph.js", - "line": 1509, + "line": 1538, "description": "add a new input slot to use in this node", "itemtype": "method", "name": "addInput", @@ -777,7 +777,7 @@ }, { "file": "../src/litegraph.js", - "line": 1531, + "line": 1561, "description": "add several new input slots in this node", "itemtype": "method", "name": "addInputs", @@ -792,7 +792,7 @@ }, { "file": "../src/litegraph.js", - "line": 1556, + "line": 1586, "description": "remove an existing input slot", "itemtype": "method", "name": "removeInput", @@ -807,7 +807,7 @@ }, { "file": "../src/litegraph.js", - "line": 1570, + "line": 1600, "description": "add an special connection to this node (used for special kinds of graphs)", "itemtype": "method", "name": "addConnection", @@ -837,7 +837,7 @@ }, { "file": "../src/litegraph.js", - "line": 1583, + "line": 1613, "description": "computes the size of a node according to its inputs and output slots", "itemtype": "method", "name": "computeSize", @@ -856,7 +856,7 @@ }, { "file": "../src/litegraph.js", - "line": 1601, + "line": 1664, "description": "returns the bounding of the object, used for rendering purposes", "itemtype": "method", "name": "getBounding", @@ -868,7 +868,7 @@ }, { "file": "../src/litegraph.js", - "line": 1611, + "line": 1674, "description": "checks if a point is inside the shape of a node", "itemtype": "method", "name": "isPointInsideNode", @@ -892,7 +892,31 @@ }, { "file": "../src/litegraph.js", - "line": 1633, + "line": 1698, + "description": "checks if a point is inside a node slot, and returns info about which slot", + "itemtype": "method", + "name": "getSlotInPosition", + "params": [ + { + "name": "x", + "description": "", + "type": "Number" + }, + { + "name": "y", + "description": "", + "type": "Number" + } + ], + "return": { + "description": "if found the object contains { input|output: slot object, slot: number, link_pos: [x,y] }", + "type": "Object" + }, + "class": "LGraphNode" + }, + { + "file": "../src/litegraph.js", + "line": 1729, "description": "returns the input slot with a given name (used for dynamic slots), -1 if not found", "itemtype": "method", "name": "findInputSlot", @@ -911,7 +935,7 @@ }, { "file": "../src/litegraph.js", - "line": 1648, + "line": 1744, "description": "returns the output slot with a given name (used for dynamic slots), -1 if not found", "itemtype": "method", "name": "findOutputSlot", @@ -930,7 +954,7 @@ }, { "file": "../src/litegraph.js", - "line": 1663, + "line": 1759, "description": "connect this node output to the input of another node", "itemtype": "method", "name": "connect", @@ -959,7 +983,7 @@ }, { "file": "../src/litegraph.js", - "line": 1746, + "line": 1855, "description": "disconnect one output to an specific node", "itemtype": "method", "name": "disconnectOutput", @@ -983,7 +1007,7 @@ }, { "file": "../src/litegraph.js", - "line": 1813, + "line": 1927, "description": "disconnect one input", "itemtype": "method", "name": "disconnectInput", @@ -1002,7 +1026,7 @@ }, { "file": "../src/litegraph.js", - "line": 1870, + "line": 1989, "description": "returns the center of a connection point in canvas coords", "itemtype": "method", "name": "getConnectionPos", @@ -1026,7 +1050,7 @@ }, { "file": "../src/litegraph.js", - "line": 2002, + "line": 2121, "description": "Collapse the node to make it smaller on the canvas", "itemtype": "method", "name": "collapse", @@ -1034,7 +1058,7 @@ }, { "file": "../src/litegraph.js", - "line": 2015, + "line": 2134, "description": "Forces the node to do not move or realign on Z", "itemtype": "method", "name": "pin", @@ -1042,7 +1066,7 @@ }, { "file": "../src/litegraph.js", - "line": 2073, + "line": 2192, "description": "clears all the data inside", "itemtype": "method", "name": "clear", @@ -1050,7 +1074,7 @@ }, { "file": "../src/litegraph.js", - "line": 2129, + "line": 2248, "description": "assigns a graph, you can reasign graphs to the same canvas", "itemtype": "method", "name": "setGraph", @@ -1065,7 +1089,7 @@ }, { "file": "../src/litegraph.js", - "line": 2160, + "line": 2279, "description": "opens a graph contained inside a node in the current graph", "itemtype": "method", "name": "openSubgraph", @@ -1080,7 +1104,7 @@ }, { "file": "../src/litegraph.js", - "line": 2187, + "line": 2306, "description": "closes a subgraph contained inside a node", "itemtype": "method", "name": "closeSubgraph", @@ -1095,7 +1119,7 @@ }, { "file": "../src/litegraph.js", - "line": 2202, + "line": 2321, "description": "assigns a canvas", "itemtype": "method", "name": "setCanvas", @@ -1110,7 +1134,7 @@ }, { "file": "../src/litegraph.js", - "line": 2445, + "line": 2567, "description": "Used to attach the canvas in a popup", "itemtype": "method", "name": "getCanvasWindow", @@ -1122,7 +1146,7 @@ }, { "file": "../src/litegraph.js", - "line": 2457, + "line": 2579, "description": "starts rendering the content of the canvas when needed", "itemtype": "method", "name": "startRendering", @@ -1130,7 +1154,7 @@ }, { "file": "../src/litegraph.js", - "line": 2480, + "line": 2602, "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 old mode 100755 new mode 100644 index 246040aa1..c432c2c8c --- a/doc/files/.._src_litegraph.js.html +++ b/doc/files/.._src_litegraph.js.html @@ -878,7 +878,7 @@ LGraph.prototype.getNodeOnPos = function(x,y, nodes_list) for (var i = nodes_list.length - 1; i >= 0; i--) { var n = nodes_list[i]; - if(n.isPointInsideNode(x,y)) + if(n.isPointInsideNode( x, y, 2 )) return n; } return null; @@ -1219,7 +1219,15 @@ LGraph.prototype.onNodeTrace = function(node, msg, color) // Node CLASS ******* // ************************************************************* -/* flags: +/* + title: string + pos: [x,y] + size: [x,y] + + input|output: every connection + + { name:string, type:string, pos: [x,y]=Optional, direction: "input"|"output", links: Array }); + + flags: + skip_title_render + clip_area + unsafe_execution: not allowed for safe execution @@ -1244,7 +1252,9 @@ LGraph.prototype.onNodeTrace = function(node, msg, color) + onSerialize + onSelected + onDeselected - + onDropFile + + onDropItem : DOM item dropped over the node + + onDropFile : file dropped over the node + + onConnectInput : if returns false the incoming connection will be canceled */ /** @@ -1264,7 +1274,23 @@ LGraphNode.prototype._ctor = function( title ) this.size = [LiteGraph.NODE_WIDTH,60]; this.graph = null; - this.pos = [10,10]; + this._pos = new Float32Array(10,10); + + Object.defineProperty( this, "pos", { + set: function(v) + { + if(!v || !v.length < 2) + return; + this._pos[0] = v[0]; + this._pos[1] = v[1]; + }, + get: function() + { + return this._pos; + }, + enumerable: true + }); + this.id = -1; //not know till not added this.type = null; @@ -1445,7 +1471,7 @@ LGraphNode.prototype.setOutputData = function(slot,data) * retrieves the input data (data traveling through the connection) from one slot * @method getInputData * @param {number} slot -* @return {*} data +* @return {*} data or if it is not connected returns undefined */ LGraphNode.prototype.getInputData = function(slot) { @@ -1473,11 +1499,12 @@ LGraphNode.prototype.isInputConnected = function(slot) * tells you info about an input connection (which node, type, etc) * @method getInputInfo * @param {number} slot -* @return {Object} +* @return {Object} object or null */ LGraphNode.prototype.getInputInfo = function(slot) { - if(!this.inputs) return null; + if(!this.inputs) + return null; if(slot < this.inputs.length) return this.inputs[slot]; return null; @@ -1488,11 +1515,12 @@ LGraphNode.prototype.getInputInfo = function(slot) * tells you info about an output connection (which node, type, etc) * @method getOutputInfo * @param {number} slot -* @return {Object} +* @return {Object} object or null */ LGraphNode.prototype.getOutputInfo = function(slot) { - if(!this.outputs) return null; + if(!this.outputs) + return null; if(slot < this.outputs.length) return this.outputs[slot]; return null; @@ -1507,7 +1535,8 @@ LGraphNode.prototype.getOutputInfo = function(slot) */ LGraphNode.prototype.isOutputConnected = function(slot) { - if(!this.outputs) return null; + if(!this.outputs) + return null; return (slot < this.outputs.length && this.outputs[slot].links && this.outputs[slot].links.length); } @@ -1615,7 +1644,8 @@ LGraphNode.prototype.addInput = function(name,type,extra_info) for(var i in extra_info) o[i] = extra_info[i]; - if(!this.inputs) this.inputs = []; + if(!this.inputs) + this.inputs = []; this.inputs.push(o); this.size = this.computeSize(); if(this.onInputAdded) @@ -1684,11 +1714,44 @@ LGraphNode.prototype.computeSize = function(minHeight) { var rows = Math.max( this.inputs ? this.inputs.length : 1, this.outputs ? this.outputs.length : 1); var size = new Float32Array([0,0]); + rows = Math.max(rows, 1); size[1] = rows * 14 + 6; - if(!this.inputs || this.inputs.length == 0 || !this.outputs || this.outputs.length == 0) - size[0] = LiteGraph.NODE_WIDTH * 0.5; - else - size[0] = LiteGraph.NODE_WIDTH; + + var font_size = 14; + var title_width = compute_text_size( this.title ); + var input_width = 0; + var output_width = 0; + + if(this.inputs) + for(var i = 0, l = this.inputs.length; i < l; ++i) + { + var input = this.inputs[i]; + var text = input.label || input.name || ""; + var text_width = compute_text_size( text ); + if(input_width < text_width) + input_width = text_width; + } + + if(this.outputs) + for(var i = 0, l = this.outputs.length; i < l; ++i) + { + var output = this.outputs[i]; + var text = output.label || output.name || ""; + var text_width = compute_text_size( text ); + if(output_width < text_width) + output_width = text_width; + } + + size[0] = Math.max( input_width + output_width + 10, title_width ); + size[0] = Math.max( size[0], LiteGraph.NODE_WIDTH ); + + function compute_text_size( text ) + { + if(!text) + return 0; + return font_size * text.length * 0.6; + } + return size; } @@ -1709,21 +1772,54 @@ LGraphNode.prototype.getBounding = function() * @param {number} y * @return {boolean} */ -LGraphNode.prototype.isPointInsideNode = function(x,y) +LGraphNode.prototype.isPointInsideNode = function(x,y, margin) { + margin = margin || 0; + var margin_top = this.graph && this.graph.isLive() ? 0 : 20; if(this.flags.collapsed) { //if ( distance([x,y], [this.pos[0] + this.size[0]*0.5, this.pos[1] + this.size[1]*0.5]) < LiteGraph.NODE_COLLAPSED_RADIUS) - if( isInsideRectangle(x,y, this.pos[0], this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT, LiteGraph.NODE_COLLAPSED_WIDTH, LiteGraph.NODE_TITLE_HEIGHT) ) + if( isInsideRectangle( x, y, this.pos[0] - margin, this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT - margin, LiteGraph.NODE_COLLAPSED_WIDTH + 2 * margin, LiteGraph.NODE_TITLE_HEIGHT + 2 * margin ) ) return true; } - else if (this.pos[0] - 4 < x && (this.pos[0] + this.size[0] + 4) > x - && (this.pos[1] - margin_top) < y && (this.pos[1] + this.size[1]) > y) + else if ( (this.pos[0] - 4 - margin) < x && (this.pos[0] + this.size[0] + 4 + margin) > x + && (this.pos[1] - margin_top - margin) < y && (this.pos[1] + this.size[1] + margin) > y) return true; return false; } +/** +* checks if a point is inside a node slot, and returns info about which slot +* @method getSlotInPosition +* @param {number} x +* @param {number} y +* @return {Object} if found the object contains { input|output: slot object, slot: number, link_pos: [x,y] } +*/ +LGraphNode.prototype.getSlotInPosition = function( x, y ) +{ + //search for inputs + if(this.inputs) + for(var i = 0, l = this.inputs.length; i < l; ++i) + { + var input = this.inputs[i]; + var link_pos = this.getConnectionPos( true,i ); + if( isInsideRectangle(x, y, link_pos[0] - 10, link_pos[1] - 5, 20,10) ) + return { input: input, slot: i, link_pos: link_pos, locked: input.locked }; + } + + if(this.outputs) + for(var i = 0, l = this.outputs.length; i < l; ++i) + { + var output = this.outputs[i]; + var link_pos = this.getConnectionPos(false,i); + if( isInsideRectangle(x, y, link_pos[0] - 10, link_pos[1] - 5, 20,10) ) + return { output: output, slot: i, link_pos: link_pos, locked: output.locked }; + } + + return null; +} + /** * returns the input slot with a given name (used for dynamic slots), -1 if not found * @method findInputSlot @@ -1784,8 +1880,14 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) return false; } + if(node && node.constructor === Number) + node = this.graph.getNodeById( node ); + if(!node) + throw("Node not found"); + //avoid loopback - if(node == this) return false; + if(node == this) + return false; //if( node.constructor != LGraphNode ) throw ("LGraphNode.connect: node is not of type LGraphNode"); if(target_slot.constructor === String) @@ -1808,9 +1910,18 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) //if there is something already plugged there, disconnect if(target_slot != -1 && node.inputs[target_slot].link != null) node.disconnectInput(target_slot); + + this.setDirtyCanvas(false,true); + this.graph.onConnectionChange(); //special case: -1 means node-connection, used for triggers var output = this.outputs[slot]; + + //allows nodes to block connection even if all test passes + if(node.onConnectInput) + if( node.onConnectInput( target_slot, output.type, output ) === false) + return false; + if(target_slot == -1) { if( output.links == null ) @@ -1831,8 +1942,6 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) output.links.push( link.id ); node.inputs[target_slot].link = link.id; - this.setDirtyCanvas(false,true); - this.graph.onConnectionChange(); } return true; } @@ -1870,6 +1979,11 @@ LGraphNode.prototype.disconnectOutput = function(slot, target_node) if(target_node) { + if(target_node.constructor === Number) + target_node = this.graph.getNodeById( target_node ); + if(!target_node) + throw("Target Node not found"); + for(var i = 0, l = output.links.length; i < l; i++) { var link_id = output.links[i]; @@ -1931,28 +2045,33 @@ LGraphNode.prototype.disconnectInput = function(slot) } var input = this.inputs[slot]; - if(!input) return false; + if(!input) + return false; var link_id = this.inputs[slot].link; this.inputs[slot].link = null; //remove other side var link_info = this.graph.links[ link_id ]; - var node = this.graph.getNodeById( link_info.origin_id ); - if(!node) return false; - - var output = node.outputs[ link_info.origin_slot ]; - if(!output || !output.links || output.links.length == 0) - return false; - - //check outputs - for(var i = 0, l = output.links.length; i < l; i++) + if( link_info ) { - var link_id = output.links[i]; - var link_info = this.graph.links[ link_id ]; - if( link_info.target_id == this.id ) + var node = this.graph.getNodeById( link_info.origin_id ); + if(!node) + return false; + + var output = node.outputs[ link_info.origin_slot ]; + if(!output || !output.links || output.links.length == 0) + return false; + + //check outputs + for(var i = 0, l = output.links.length; i < l; i++) { - output.links.splice(i,1); - break; + var link_id = output.links[i]; + var link_info = this.graph.links[ link_id ]; + if( link_info.target_id == this.id ) + { + output.links.splice(i,1); + break; + } } } @@ -1968,7 +2087,7 @@ LGraphNode.prototype.disconnectInput = function(slot) * @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot) * @return {[x,y]} the position **/ -LGraphNode.prototype.getConnectionPos = function(is_input,slot_number) +LGraphNode.prototype.getConnectionPos = function(is_input, slot_number) { if(this.flags.collapsed) { @@ -2362,7 +2481,8 @@ LGraphCanvas.prototype.setCanvas = function( canvas, skip_events ) } //used in some events to capture them -LGraphCanvas.prototype._doNothing = function doNothing() { return false; }; +LGraphCanvas.prototype._doNothing = function doNothing(e) { e.preventDefault(); return false; }; +LGraphCanvas.prototype._doReturnTrue = function doNothing(e) { e.preventDefault(); return true; }; LGraphCanvas.prototype.bindEvents = function() { @@ -2405,6 +2525,7 @@ LGraphCanvas.prototype.bindEvents = function() canvas.addEventListener("dragover", this._doNothing, false ); canvas.addEventListener("dragend", this._doNothing, false ); canvas.addEventListener("drop", this._ondrop_callback, false ); + canvas.addEventListener("dragenter", this._doReturnTrue, false ); this._events_binded = true; } @@ -2424,6 +2545,7 @@ LGraphCanvas.prototype.unbindEvents = function() 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 ); @@ -2605,7 +2727,7 @@ LGraphCanvas.prototype.processMouseDown = function(e) ref_window.document.addEventListener("mousemove", this._mousemove_callback, true ); //catch for the entire window ref_window.document.addEventListener("mouseup", this._mouseup_callback, true ); - var n = this.graph.getNodeOnPos(e.canvasX, e.canvasY, this.visible_nodes); + var n = this.graph.getNodeOnPos( e.canvasX, e.canvasY, this.visible_nodes ); var skip_dragging = false; if(e.which == 1) //left button mouse @@ -3108,35 +3230,57 @@ LGraphCanvas.prototype.processDrop = function(e) e.preventDefault(); this.adjustMouseEvent(e); + var pos = [e.canvasX,e.canvasY]; var node = this.graph.getNodeOnPos(pos[0],pos[1]); + if(!node) + { + if(this.onDropItem) + this.onDropItem( event ); return; + } - if(!node.onDropFile) - return; + if(node.onDropFile) + { + var files = e.dataTransfer.files; + if(files && files.length) + { + for(var i=0; i < files.length; i++) + { + var file = e.dataTransfer.files[0]; + var filename = file.name; + var ext = LGraphCanvas.getFileExtension( filename ); + //console.log(file); - var file = e.dataTransfer.files[0]; - var filename = file.name; - var ext = LGraphCanvas.getFileExtension( filename ); - //console.log(file); + //prepare reader + var reader = new FileReader(); + reader.onload = function (event) { + //console.log(event.target); + var data = event.target.result; + node.onDropFile( data, filename, file ); + }; - //prepare reader - var reader = new FileReader(); - reader.onload = function (event) { - //console.log(event.target); - var data = event.target.result; - node.onDropFile( data, filename, file ); - }; + //read data + var type = file.type.split("/")[0]; + if(type == "text" || type == "") + reader.readAsText(file); + else if (type == "image") + reader.readAsDataURL(file); + else + reader.readAsArrayBuffer(file); + } + } + } - //read data - var type = file.type.split("/")[0]; - if(type == "text" || type == "") - reader.readAsText(file); - else if (type == "image") - reader.readAsDataURL(file); - else - reader.readAsArrayBuffer(file); + if(node.onDropItem) + { + if( node.onDropItem( event ) ) + return true; + } + + if(this.onDropItem) + return this.onDropItem( event ); return false; } @@ -4480,16 +4624,47 @@ LGraphCanvas.prototype.getNodeMenuOptions = function(node) return options; } -LGraphCanvas.prototype.processContextualMenu = function(node,event) +LGraphCanvas.prototype.processContextualMenu = function(node, event) { var that = this; var win = this.getCanvasWindow(); - var menu = LiteGraph.createContextualMenu(node ? this.getNodeMenuOptions(node) : this.getCanvasMenuOptions(), {event: event, callback: inner_option_clicked}, win); + var menu_info = null; + var options = {event: event, callback: inner_option_clicked}; + + //check if mouse is in input + var slot = null; + if(node) + slot = node.getSlotInPosition( event.canvasX, event.canvasY ); + + if(slot) + { + menu_info = slot.locked ? [ "Cannot remove" ] : { "Remove Slot": slot }; + options.title = slot.input ? slot.input.type : slot.output.type; + } + else + menu_info = node ? this.getNodeMenuOptions(node) : this.getCanvasMenuOptions(); + + + //show menu + if(!menu_info) + return; + + var menu = LiteGraph.createContextualMenu( menu_info, options, win); function inner_option_clicked(v,e) { - if(!v) return; + if(!v) + return; + + if(v == slot) + { + if(v.input) + node.removeInput( slot.slot ); + else if(v.output) + node.removeOutput( slot.slot ); + return; + } if(v.callback) return v.callback(node, e, menu, that, event ); @@ -4648,6 +4823,15 @@ LiteGraph.createContextualMenu = function(values,options, ref_window) style.borderBottom = "2px solid #AAF"; style.backgroundColor = "#444"; + //title + if(options.title) + { + var element = document.createElement("div"); + element.className = "graphcontextualmenu-title"; + element.innerHTML = options.title; + root.appendChild(element); + } + //avoid a context menu in a context menu root.addEventListener("contextmenu", function(e) { e.preventDefault(); return false; }); diff --git a/doc/files/index.html b/doc/files/index.html old mode 100755 new mode 100644 diff --git a/doc/index.html b/doc/index.html old mode 100755 new mode 100644 diff --git a/doc/modules/index.html b/doc/modules/index.html old mode 100755 new mode 100644 diff --git a/src/litegraph.js b/src/litegraph.js index 6a05a7242..1eb1e7fe5 100755 --- a/src/litegraph.js +++ b/src/litegraph.js @@ -1158,7 +1158,9 @@ LGraph.prototype.onNodeTrace = function(node, msg, color) + onSerialize + onSelected + onDeselected - + onDropFile + + onDropItem : DOM item dropped over the node + + onDropFile : file dropped over the node + + onConnectInput : if returns false the incoming connection will be canceled */ /** @@ -1178,7 +1180,23 @@ LGraphNode.prototype._ctor = function( title ) this.size = [LiteGraph.NODE_WIDTH,60]; this.graph = null; - this.pos = [10,10]; + this._pos = new Float32Array(10,10); + + Object.defineProperty( this, "pos", { + set: function(v) + { + if(!v || !v.length < 2) + return; + this._pos[0] = v[0]; + this._pos[1] = v[1]; + }, + get: function() + { + return this._pos; + }, + enumerable: true + }); + this.id = -1; //not know till not added this.type = null; @@ -1768,8 +1786,14 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) return false; } + if(node && node.constructor === Number) + node = this.graph.getNodeById( node ); + if(!node) + throw("Node not found"); + //avoid loopback - if(node == this) return false; + if(node == this) + return false; //if( node.constructor != LGraphNode ) throw ("LGraphNode.connect: node is not of type LGraphNode"); if(target_slot.constructor === String) @@ -1792,9 +1816,18 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) //if there is something already plugged there, disconnect if(target_slot != -1 && node.inputs[target_slot].link != null) node.disconnectInput(target_slot); + + this.setDirtyCanvas(false,true); + this.graph.onConnectionChange(); //special case: -1 means node-connection, used for triggers var output = this.outputs[slot]; + + //allows nodes to block connection even if all test passes + if(node.onConnectInput) + if( node.onConnectInput( target_slot, output.type, output ) === false) + return false; + if(target_slot == -1) { if( output.links == null ) @@ -1815,8 +1848,6 @@ LGraphNode.prototype.connect = function(slot, node, target_slot) output.links.push( link.id ); node.inputs[target_slot].link = link.id; - this.setDirtyCanvas(false,true); - this.graph.onConnectionChange(); } return true; } @@ -1854,6 +1885,11 @@ LGraphNode.prototype.disconnectOutput = function(slot, target_node) if(target_node) { + if(target_node.constructor === Number) + target_node = this.graph.getNodeById( target_node ); + if(!target_node) + throw("Target Node not found"); + for(var i = 0, l = output.links.length; i < l; i++) { var link_id = output.links[i]; @@ -2351,7 +2387,8 @@ LGraphCanvas.prototype.setCanvas = function( canvas, skip_events ) } //used in some events to capture them -LGraphCanvas.prototype._doNothing = function doNothing() { return false; }; +LGraphCanvas.prototype._doNothing = function doNothing(e) { e.preventDefault(); return false; }; +LGraphCanvas.prototype._doReturnTrue = function doNothing(e) { e.preventDefault(); return true; }; LGraphCanvas.prototype.bindEvents = function() { @@ -2394,6 +2431,7 @@ LGraphCanvas.prototype.bindEvents = function() canvas.addEventListener("dragover", this._doNothing, false ); canvas.addEventListener("dragend", this._doNothing, false ); canvas.addEventListener("drop", this._ondrop_callback, false ); + canvas.addEventListener("dragenter", this._doReturnTrue, false ); this._events_binded = true; } @@ -2413,6 +2451,7 @@ LGraphCanvas.prototype.unbindEvents = function() 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 ); @@ -3097,35 +3136,57 @@ LGraphCanvas.prototype.processDrop = function(e) e.preventDefault(); this.adjustMouseEvent(e); + var pos = [e.canvasX,e.canvasY]; var node = this.graph.getNodeOnPos(pos[0],pos[1]); + if(!node) + { + if(this.onDropItem) + this.onDropItem( event ); return; + } - if(!node.onDropFile) - return; + if(node.onDropFile) + { + var files = e.dataTransfer.files; + if(files && files.length) + { + for(var i=0; i < files.length; i++) + { + var file = e.dataTransfer.files[0]; + var filename = file.name; + var ext = LGraphCanvas.getFileExtension( filename ); + //console.log(file); - var file = e.dataTransfer.files[0]; - var filename = file.name; - var ext = LGraphCanvas.getFileExtension( filename ); - //console.log(file); + //prepare reader + var reader = new FileReader(); + reader.onload = function (event) { + //console.log(event.target); + var data = event.target.result; + node.onDropFile( data, filename, file ); + }; - //prepare reader - var reader = new FileReader(); - reader.onload = function (event) { - //console.log(event.target); - var data = event.target.result; - node.onDropFile( data, filename, file ); - }; + //read data + var type = file.type.split("/")[0]; + if(type == "text" || type == "") + reader.readAsText(file); + else if (type == "image") + reader.readAsDataURL(file); + else + reader.readAsArrayBuffer(file); + } + } + } - //read data - var type = file.type.split("/")[0]; - if(type == "text" || type == "") - reader.readAsText(file); - else if (type == "image") - reader.readAsDataURL(file); - else - reader.readAsArrayBuffer(file); + if(node.onDropItem) + { + if( node.onDropItem( event ) ) + return true; + } + + if(this.onDropItem) + return this.onDropItem( event ); return false; } @@ -4475,6 +4536,7 @@ LGraphCanvas.prototype.processContextualMenu = function(node, event) var win = this.getCanvasWindow(); var menu_info = null; + var options = {event: event, callback: inner_option_clicked}; //check if mouse is in input var slot = null; @@ -4482,15 +4544,19 @@ LGraphCanvas.prototype.processContextualMenu = function(node, event) slot = node.getSlotInPosition( event.canvasX, event.canvasY ); if(slot) + { menu_info = slot.locked ? [ "Cannot remove" ] : { "Remove Slot": slot }; + options.title = slot.input ? slot.input.type : slot.output.type; + } else menu_info = node ? this.getNodeMenuOptions(node) : this.getCanvasMenuOptions(); + //show menu if(!menu_info) return; - var menu = LiteGraph.createContextualMenu( menu_info, {event: event, callback: inner_option_clicked}, win); + var menu = LiteGraph.createContextualMenu( menu_info, options, win); function inner_option_clicked(v,e) { @@ -4663,6 +4729,15 @@ LiteGraph.createContextualMenu = function(values,options, ref_window) style.borderBottom = "2px solid #AAF"; style.backgroundColor = "#444"; + //title + if(options.title) + { + var element = document.createElement("div"); + element.className = "graphcontextualmenu-title"; + element.innerHTML = options.title; + root.appendChild(element); + } + //avoid a context menu in a context menu root.addEventListener("contextmenu", function(e) { e.preventDefault(); return false; }); diff --git a/src/nodes/glfx.js b/src/nodes/glfx.js index 1603cfaa8..5ff74a723 100755 --- a/src/nodes/glfx.js +++ b/src/nodes/glfx.js @@ -61,7 +61,7 @@ if(typeof(LiteGraph) != "undefined") gl.disable( gl.DEPTH_TEST ); var mesh = Mesh.getScreenQuad(); var shader = LGraphFXLens._shader; - var camera = Renderer._current_camera; + var camera = LS.Renderer._current_camera; this._tex.drawTo( function() { tex.bind(0); @@ -323,13 +323,16 @@ if(typeof(LiteGraph) != "undefined") LGraphFXGeneric.desc = "applies an FX from a list"; LGraphFXGeneric.widgets_info = { - "fx": { widget:"combo", values:["halftone","pixelate","lowpalette","noise"] }, + "fx": { widget:"combo", values:["halftone","pixelate","lowpalette","noise","gamma"] }, "precision": { widget:"combo", values: LGraphTexture.MODE_VALUES } }; LGraphFXGeneric.shaders = {}; LGraphFXGeneric.prototype.onExecute = function() { + if(!this.isOutputConnected(0)) + return; //saves work + var tex = this.getInputData(0); if(this.properties.precision === LGraphTexture.PASS_THROUGH ) { @@ -337,7 +340,8 @@ if(typeof(LiteGraph) != "undefined") return; } - if(!tex) return; + if(!tex) + return; this._tex = LGraphTexture.getTargetTexture( tex, this._tex, this.properties.precision ); @@ -371,7 +375,7 @@ if(typeof(LiteGraph) != "undefined") gl.disable( gl.BLEND ); gl.disable( gl.DEPTH_TEST ); var mesh = Mesh.getScreenQuad(); - var camera = Renderer._current_camera; + var camera = LS.Renderer._current_camera; var noise = null; if(fx == "noise") @@ -382,7 +386,7 @@ if(typeof(LiteGraph) != "undefined") if(fx == "noise") noise.bind(1); - shader.uniforms({u_texture:0, u_noise:1, u_size: [tex.width, tex.height], u_rand:[ Math.random(), Math.random() ], u_value1: value1, u_value2: value2, u_camera_planes: [Renderer._current_camera.near,Renderer._current_camera.far] }) + shader.uniforms({u_texture:0, u_noise:1, u_size: [tex.width, tex.height], u_rand:[ Math.random(), Math.random() ], u_value1: value1, u_value2: value2, u_camera_planes: [LS.Renderer._current_camera.near, LS.Renderer._current_camera.far] }) .draw(mesh); }); @@ -454,6 +458,17 @@ if(typeof(LiteGraph) != "undefined") gl_FragColor = vec4( color.xyz + noise * u_value1, color.a );\n\ }\n"; + LGraphFXGeneric.pixel_shader_gamma = "precision highp float;\n\ + varying vec2 v_coord;\n\ + uniform sampler2D u_texture;\n\ + uniform float u_value1;\n\ + \n\ + void main() {\n\ + vec4 color = texture2D(u_texture, v_coord);\n\ + float gamma = 1.0 / u_value1;\n\ + gl_FragColor = vec4( pow( color.xyz, vec3(gamma) ), color.a );\n\ + }\n"; + LiteGraph.registerNodeType("fx/generic", LGraphFXGeneric ); window.LGraphFXGeneric = LGraphFXGeneric; diff --git a/src/nodes/gltextures.js b/src/nodes/gltextures.js index 48c8aaab2..3033ae8a1 100755 --- a/src/nodes/gltextures.js +++ b/src/nodes/gltextures.js @@ -150,21 +150,36 @@ if(typeof(LiteGraph) != "undefined") LGraphTexture.prototype.onExecute = function() { - if(this._drop_texture) - { - this.setOutputData(0, this._drop_texture); - return; - } + var tex = null; + if(this.isOutputConnected(1)) + tex = this.getInputData(0); - if(!this.properties.name) - return; + if(!tex && this._drop_texture) + tex = this._drop_texture; + + if(!tex && this.properties.name) + tex = LGraphTexture.getTexture( this.properties.name ); - var tex = LGraphTexture.getTexture( this.properties.name ); if(!tex) return; this._last_tex = tex; this.setOutputData(0, tex); + + for(var i = 1; i < this.outputs.length; i++) + { + var output = this.outputs[i]; + if(!output) + continue; + var v = null; + if(output.name == "width") + v = tex.width; + else if(output.name == "height") + v = tex.height; + else if(output.name == "aspect") + v = tex.width / tex.height; + this.setOutputData(i, v); + } } LGraphTexture.prototype.onResourceRenamed = function(old_name,new_name) @@ -222,7 +237,8 @@ if(typeof(LiteGraph) != "undefined") //very slow, used at your own risk LGraphTexture.generateLowResTexturePreview = function(tex) { - if(!tex) return null; + if(!tex) + return null; var size = LGraphTexture.image_preview_size; var temp_tex = tex; @@ -258,6 +274,17 @@ if(typeof(LiteGraph) != "undefined") return tex_canvas; } + LGraphTexture.prototype.onGetInputs = function() + { + return [["in","Texture"]]; + } + + + LGraphTexture.prototype.onGetOutputs = function() + { + return [["width","number"],["height","number"],["aspect","number"]]; + } + LiteGraph.registerNodeType("texture/texture", LGraphTexture ); //************************** @@ -273,7 +300,8 @@ if(typeof(LiteGraph) != "undefined") LGraphTexturePreview.prototype.onDrawBackground = function(ctx) { - if(this.flags.collapsed) return; + if(this.flags.collapsed) + return; var tex = this.getInputData(0); if(!tex) return; @@ -605,15 +633,202 @@ if(typeof(LiteGraph) != "undefined") LiteGraph.registerNodeType("texture/shader", LGraphTextureShader ); + // Texture Scale Offset + + function LGraphTextureScaleOffset() + { + this.addInput("in","Texture"); + this.addInput("scale","vec2"); + this.addInput("offset","vec2"); + this.addOutput("out","Texture"); + this.properties = { offset: vec2.fromValues(0,0), scale: vec2.fromValues(1,1), precision: LGraphTexture.DEFAULT }; + } + + LGraphTextureScaleOffset.widgets_info = { + "precision": { widget:"combo", values: LGraphTexture.MODE_VALUES } + }; + + LGraphTextureScaleOffset.title = "Scale/Offset"; + LGraphTextureScaleOffset.desc = "Applies an scaling and offseting"; + + LGraphTextureScaleOffset.prototype.onExecute = function() + { + var tex = this.getInputData(0); + + if(!this.isOutputConnected(0) || !tex) + return; //saves work + + if(this.properties.precision === LGraphTexture.PASS_THROUGH) + { + this.setOutputData(0, tex); + return; + } + + var width = tex.width; + var height = tex.height; + var type = this.precision === LGraphTexture.LOW ? gl.UNSIGNED_BYTE : gl.HIGH_PRECISION_FORMAT; + if (this.precision === LGraphTexture.DEFAULT) + type = tex.type; + + if(!this._tex || this._tex.width != width || this._tex.height != height || this._tex.type != type ) + this._tex = new GL.Texture( width, height, { type: type, format: gl.RGBA, filter: gl.LINEAR }); + + var shader = this._shader; + + if(!shader) + shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureScaleOffset.pixel_shader ); + + var scale = this.getInputData(1); + if(scale) + { + this.properties.scale[0] = scale[0]; + this.properties.scale[1] = scale[1]; + } + else + scale = this.properties.scale; + + var offset = this.getInputData(2); + if(offset) + { + this.properties.offset[0] = offset[0]; + this.properties.offset[1] = offset[1]; + } + else + offset = this.properties.offset; + + this._tex.drawTo(function() { + gl.disable( gl.DEPTH_TEST ); + gl.disable( gl.CULL_FACE ); + gl.disable( gl.BLEND ); + tex.bind(0); + var mesh = Mesh.getScreenQuad(); + shader.uniforms({u_texture:0, u_scale: scale, u_offset: offset}).draw( mesh ); + }); + + this.setOutputData( 0, this._tex ); + } + + LGraphTextureScaleOffset.pixel_shader = "precision highp float;\n\ + \n\ + uniform sampler2D u_texture;\n\ + uniform sampler2D u_textureB;\n\ + varying vec2 v_coord;\n\ + uniform vec2 u_scale;\n\ + uniform vec2 u_offset;\n\ + \n\ + void main() {\n\ + vec2 uv = v_coord;\n\ + uv = uv / u_scale - u_offset;\n\ + gl_FragColor = texture2D(u_texture, uv);\n\ + }\n\ + "; + + LiteGraph.registerNodeType("texture/scaleOffset", LGraphTextureScaleOffset ); + + + + // Warp (distort a texture) ************************* + + function LGraphTextureWarp() + { + this.addInput("in","Texture"); + this.addInput("warp","Texture"); + this.addInput("factor","number"); + this.addOutput("out","Texture"); + this.properties = { factor: 0.01, precision: LGraphTexture.DEFAULT }; + } + + LGraphTextureWarp.widgets_info = { + "precision": { widget:"combo", values: LGraphTexture.MODE_VALUES } + }; + + LGraphTextureWarp.title = "Warp"; + LGraphTextureWarp.desc = "Texture warp operation"; + + LGraphTextureWarp.prototype.onExecute = function() + { + var tex = this.getInputData(0); + + if(!this.isOutputConnected(0)) + return; //saves work + + if(this.properties.precision === LGraphTexture.PASS_THROUGH) + { + this.setOutputData(0, tex); + return; + } + + var texB = this.getInputData(1); + + var width = 512; + var height = 512; + var type = gl.UNSIGNED_BYTE; + if(tex) + { + width = tex.width; + height = tex.height; + type = tex.type; + } + else if (texB) + { + width = texB.width; + height = texB.height; + type = texB.type; + } + + if(!tex && !this._tex ) + this._tex = new GL.Texture( width, height, { type: this.precision === LGraphTexture.LOW ? gl.UNSIGNED_BYTE : gl.HIGH_PRECISION_FORMAT, format: gl.RGBA, filter: gl.LINEAR }); + else + this._tex = LGraphTexture.getTargetTexture( tex || this._tex, this._tex, this.properties.precision ); + + var shader = this._shader; + + if(!shader) + shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureWarp.pixel_shader ); + + var factor = this.getInputData(2); + if(factor != null) + this.properties.factor = factor; + else + factor = parseFloat( this.properties.factor ); + + this._tex.drawTo(function() { + gl.disable( gl.DEPTH_TEST ); + gl.disable( gl.CULL_FACE ); + gl.disable( gl.BLEND ); + if(tex) tex.bind(0); + if(texB) texB.bind(1); + var mesh = Mesh.getScreenQuad(); + shader.uniforms({u_texture:0, u_textureB:1, u_factor: factor }).draw( mesh ); + }); + + this.setOutputData(0, this._tex); + } + + LGraphTextureWarp.pixel_shader = "precision highp float;\n\ + \n\ + uniform sampler2D u_texture;\n\ + uniform sampler2D u_textureB;\n\ + varying vec2 v_coord;\n\ + uniform float u_factor;\n\ + \n\ + void main() {\n\ + vec2 uv = v_coord;\n\ + uv += texture2D(u_textureB, uv).rg * u_factor;\n\ + gl_FragColor = texture2D(u_texture, uv);\n\ + }\n\ + "; + + LiteGraph.registerNodeType("texture/warp", LGraphTextureWarp ); + + //**************************************************** + // Texture to Viewport ***************************************** function LGraphTextureToViewport() { this.addInput("Texture","Texture"); - this.properties = { additive: false, antialiasing: false, disable_alpha: false }; + this.properties = { additive: false, antialiasing: false, disable_alpha: false, gamma: 1.0 }; this.size[0] = 130; - - if(!LGraphTextureToViewport._shader) - LGraphTextureToViewport._shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER, LGraphTextureToViewport.pixel_shader ); } LGraphTextureToViewport.title = "to Viewport"; @@ -637,23 +852,46 @@ if(typeof(LiteGraph) != "undefined") } gl.disable( gl.DEPTH_TEST ); + var gamma = this.properties.gamma || 1.0; + if( this.isInputConnected(1) ) + gamma = this.getInputData(1); + + if(this.properties.antialiasing) { + if(!LGraphTextureToViewport._shader) + LGraphTextureToViewport._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureToViewport.aa_pixel_shader ); + var viewport = gl.getViewport(); //gl.getParameter(gl.VIEWPORT); var mesh = Mesh.getScreenQuad(); tex.bind(0); - LGraphTextureToViewport._shader.uniforms({u_texture:0, uViewportSize:[tex.width,tex.height], inverseVP: [1/tex.width,1/tex.height] }).draw(mesh); + LGraphTextureToViewport._shader.uniforms({u_texture:0, uViewportSize:[tex.width,tex.height], u_igamma: 1 / gamma, inverseVP: [1/tex.width,1/tex.height] }).draw(mesh); } else - tex.toViewport(); + { + if(gamma != 1.0) + { + if(!LGraphTextureToViewport._gamma_shader) + LGraphTextureToViewport._gamma_shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER, LGraphTextureToViewport.gamma_pixel_shader ); + tex.toViewport(LGraphTextureToViewport._gamma_shader, { u_texture:0, u_igamma: 1 / gamma }); + } + else + tex.toViewport(); + } } - LGraphTextureToViewport.pixel_shader = "precision highp float;\n\ + LGraphTextureToViewport.prototype.onGetInputs = function() + { + return [["gamma","number"]]; + } + + LGraphTextureToViewport.aa_pixel_shader = "precision highp float;\n\ precision highp float;\n\ varying vec2 v_coord;\n\ uniform sampler2D u_texture;\n\ uniform vec2 uViewportSize;\n\ uniform vec2 inverseVP;\n\ + uniform float u_igamma;\n\ #define FXAA_REDUCE_MIN (1.0/ 128.0)\n\ #define FXAA_REDUCE_MUL (1.0 / 8.0)\n\ #define FXAA_SPAN_MAX 8.0\n\ @@ -691,12 +929,14 @@ if(typeof(LiteGraph) != "undefined") vec3 rgbB = rgbA * 0.5 + 0.25 * (texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + \n\ texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);\n\ \n\ - return vec4(rgbA,1.0);\n\ + //return vec4(rgbA,1.0);\n\ float lumaB = dot(rgbB, luma);\n\ if ((lumaB < lumaMin) || (lumaB > lumaMax))\n\ color = vec4(rgbA, 1.0);\n\ else\n\ color = vec4(rgbB, 1.0);\n\ + if(u_igamma != 1.0)\n\ + color.xyz = pow( color.xyz, vec3(u_igamma) );\n\ return color;\n\ }\n\ \n\ @@ -705,6 +945,18 @@ if(typeof(LiteGraph) != "undefined") }\n\ "; + LGraphTextureToViewport.gamma_pixel_shader = "precision highp float;\n\ + precision highp float;\n\ + varying vec2 v_coord;\n\ + uniform sampler2D u_texture;\n\ + uniform float u_igamma;\n\ + void main() {\n\ + vec4 color = texture2D( u_texture, v_coord);\n\ + color.xyz = pow(color.xyz, vec3(u_igamma) );\n\ + gl_FragColor = color;\n\ + }\n\ + "; + LiteGraph.registerNodeType("texture/toviewport", LGraphTextureToViewport ); @@ -1421,8 +1673,8 @@ if(typeof(LiteGraph) != "undefined") var shader = LGraphTextureDepthRange._shader; //TODO: this asumes we have LiteScene, change it - var camera = Renderer._current_camera; - var planes = [Renderer._current_camera.near,Renderer._current_camera.far]; + var camera = LS.Renderer._current_camera; + var planes = [LS.Renderer._current_camera.near, LS.Renderer._current_camera.far]; this._temp_texture.drawTo( function() { tex.bind(0); @@ -1621,7 +1873,7 @@ if(typeof(LiteGraph) != "undefined") { video = document.createElement("video"); video.autoplay = true; - video.src = window.URL.createObjectURL(localMediaStream); + video.src = window.URL.createObjectURL( localMediaStream ); this._video = video; //document.body.appendChild( video ); //debug //when video info is loaded (size and so) diff --git a/src/nodes/input.js b/src/nodes/input.js index 92e55436d..efed3f0ca 100755 --- a/src/nodes/input.js +++ b/src/nodes/input.js @@ -14,8 +14,6 @@ GamepadInput.prototype.onExecute = function() { //get gamepad var gamepad = this.getGamepad(); - if(!gamepad) - return; if(this.outputs) { @@ -23,23 +21,44 @@ GamepadInput.prototype.onExecute = function() { var output = this.outputs[i]; var v = null; - switch( output.name ) + + if(gamepad) { - case "left_x_axis": v = gamepad.xbox.axes["lx"]; break; - case "left_y_axis": v = gamepad.xbox.axes["ly"]; break; - case "right_x_axis": v = gamepad.xbox.axes["rx"]; break; - case "right_y_axis": v = gamepad.xbox.axes["ry"]; break; - case "a_button": v = gamepad.xbox.buttons["a"] ? 1 : 0; break; - case "b_button": v = gamepad.xbox.buttons["b"] ? 1 : 0; break; - case "x_button": v = gamepad.xbox.buttons["x"] ? 1 : 0; break; - case "y_button": v = gamepad.xbox.buttons["y"] ? 1 : 0; break; - case "lb_button": v = gamepad.xbox.buttons["lb"] ? 1 : 0; break; - case "rb_button": v = gamepad.xbox.buttons["rb"] ? 1 : 0; break; - case "ls_button": v = gamepad.xbox.buttons["ls"] ? 1 : 0; break; - case "rs_button": v = gamepad.xbox.buttons["rs"] ? 1 : 0; break; - case "start_button": v = gamepad.xbox.buttons["start"] ? 1 : 0; break; - case "back_button": v = gamepad.xbox.buttons["back"] ? 1 : 0; break; - default: break; + switch( output.name ) + { + case "left_axis": v = [ gamepad.xbox.axes["lx"], gamepad.xbox.axes["ly"]]; break; + case "right_axis": v = [ gamepad.xbox.axes["rx"], gamepad.xbox.axes["ry"]]; break; + case "left_x_axis": v = gamepad.xbox.axes["lx"]; break; + case "left_y_axis": v = gamepad.xbox.axes["ly"]; break; + case "right_x_axis": v = gamepad.xbox.axes["rx"]; break; + case "right_y_axis": v = gamepad.xbox.axes["ry"]; break; + case "trigger_left": v = gamepad.xbox.axes["ltrigger"]; break; + case "trigger_right": v = gamepad.xbox.axes["rtrigger"]; break; + case "a_button": v = gamepad.xbox.buttons["a"] ? 1 : 0; break; + case "b_button": v = gamepad.xbox.buttons["b"] ? 1 : 0; break; + case "x_button": v = gamepad.xbox.buttons["x"] ? 1 : 0; break; + case "y_button": v = gamepad.xbox.buttons["y"] ? 1 : 0; break; + case "lb_button": v = gamepad.xbox.buttons["lb"] ? 1 : 0; break; + case "rb_button": v = gamepad.xbox.buttons["rb"] ? 1 : 0; break; + case "ls_button": v = gamepad.xbox.buttons["ls"] ? 1 : 0; break; + case "rs_button": v = gamepad.xbox.buttons["rs"] ? 1 : 0; break; + case "start_button": v = gamepad.xbox.buttons["start"] ? 1 : 0; break; + case "back_button": v = gamepad.xbox.buttons["back"] ? 1 : 0; break; + default: break; + } + } + else + { + //if no gamepad is connected, output 0 + switch( output.name ) + { + case "left_axis": + case "right_axis": + v = [0,0]; + break; + default: + v = 0; + } } this.setOutputData(i,v); } @@ -69,7 +88,8 @@ GamepadInput.prototype.getGamepad = function() xbox.axes["ly"] = gamepad.axes[1]; xbox.axes["rx"] = gamepad.axes[2]; xbox.axes["ry"] = gamepad.axes[3]; - xbox.axes["triggers"] = gamepad.axes[4]; + xbox.axes["ltrigger"] = gamepad.buttons[6].value; + xbox.axes["rtrigger"] = gamepad.buttons[7].value; for(var i = 0; i < gamepad.buttons.length; i++) { @@ -109,11 +129,14 @@ GamepadInput.prototype.onDrawBackground = function(ctx) GamepadInput.prototype.onGetOutputs = function() { return [ + ["left_axis","vec2"], + ["right_axis","vec2"], ["left_x_axis","number"], ["left_y_axis","number"], ["right_x_axis","number"], ["right_y_axis","number"], - ["trigger","number"], + ["trigger_left","number"], + ["trigger_right","number"], ["a_button","number"], ["b_button","number"], ["x_button","number"], diff --git a/src/nodes/math.js b/src/nodes/math.js index 9619b1a73..e2677ad1d 100755 --- a/src/nodes/math.js +++ b/src/nodes/math.js @@ -1,5 +1,137 @@ (function(){ +//Converter +function Converter() +{ + this.addInput("in","*"); + this.size = [60,20]; +} + +Converter.title = "Converter"; +Converter.desc = "type A to type B"; + +Converter.prototype.onExecute = function() +{ + var v = this.getInputData(0); + if(v == null) + return; + + if(this.outputs) + for(var i = 0; i < this.outputs.length; i++) + { + var output = this.outputs[i]; + if(!output.links || !output.links.length) + continue; + + var result = null; + switch( output.name ) + { + case "number": result = v.length ? v[0] : parseFloat(v); break; + case "vec2": + case "vec3": + case "vec4": + var result = null; + var count = 1; + switch(output.name) + { + case "vec2": count = 2; break; + case "vec3": count = 3; break; + case "vec4": count = 4; break; + } + + var result = new Float32Array( count ); + if( v.length ) + { + for(var j = 0; j < v.length && j < result.length; j++) + result[j] = v[j]; + } + else + result[0] = parseFloat(v); + break; + } + this.setOutputData(i, result); + } +} + +Converter.prototype.onGetOutputs = function() { + return [["number","number"],["vec2","vec2"],["vec3","vec3"],["vec4","vec4"]]; +} + +LiteGraph.registerNodeType("math/converter", Converter ); + + +//Bypass +function Bypass() +{ + this.addInput("in"); + this.addOutput("out"); + this.size = [60,20]; +} + +Bypass.title = "Bypass"; +Bypass.desc = "removes the type"; + +Bypass.prototype.onExecute = function() +{ + var v = this.getInputData(0); + this.setOutputData(0, v); +} + +LiteGraph.registerNodeType("math/bypass", Bypass ); + + + +function MathRange() +{ + this.addInput("in","number",{locked:true}); + this.addOutput("out","number",{locked:true}); + this.properties = { "in": 0, in_min:0, in_max:1, out_min: 0, out_max: 1 }; +} + +MathRange.title = "Range"; +MathRange.desc = "Convert a number from one range to another"; + +MathRange.prototype.onExecute = function() +{ + if(this.inputs) + for(var i = 0; i < this.inputs.length; i++) + { + var input = this.inputs[i]; + var v = this.getInputData(i); + if(v === undefined) + continue; + this.properties[ input.name ] = v; + } + + var v = this.properties["in"]; + if(v === undefined || v === null || v.constructor !== Number) + v = 0; + + var in_min = this.properties.in_min; + var in_max = this.properties.in_max; + var out_min = this.properties.out_min; + var out_max = this.properties.out_max; + + this._last_v = ((v - in_min) / (in_max - in_min)) * (out_max - out_min) + out_min; + this.setOutputData(0, this._last_v ); +} + +MathRange.prototype.onDrawBackground = function(ctx) +{ + //show the current value + if(this._last_v) + this.outputs[0].label = this._last_v.toFixed(3); + else + this.outputs[0].label = "?"; +} + +MathRange.prototype.onGetInputs = function() { + return [["in_min","number"],["in_max","number"],["out_min","number"],["out_max","number"]]; +} + +LiteGraph.registerNodeType("math/range", MathRange); + + function MathRand() { @@ -472,56 +604,179 @@ if(window.math) } +function Math3DVec2ToXYZ() +{ + this.addInput("vec2","vec2"); + this.addOutput("x","number"); + this.addOutput("y","number"); +} + +Math3DVec2ToXYZ.title = "Vec2->XY"; +Math3DVec2ToXYZ.desc = "vector 2 to components"; + +Math3DVec2ToXYZ.prototype.onExecute = function() +{ + var v = this.getInputData(0); + if(v == null) return; + + this.setOutputData( 0, v[0] ); + this.setOutputData( 1, v[1] ); +} + +LiteGraph.registerNodeType("math3d/vec2-to-xyz", Math3DVec2ToXYZ ); + + +function Math3DXYToVec2() +{ + this.addInputs([["x","number"],["y","number"]]); + this.addOutput("vec2","vec2"); + this.properties = {x:0, y:0}; + this._data = new Float32Array(2); +} + +Math3DXYToVec2.title = "XY->Vec2"; +Math3DXYToVec2.desc = "components to vector2"; + +Math3DXYToVec2.prototype.onExecute = function() +{ + var x = this.getInputData(0); + if(x == null) x = this.properties.x; + var y = this.getInputData(1); + if(y == null) y = this.properties.y; + + var data = this._data; + data[0] = x; + data[1] = y; + + this.setOutputData( 0, data ); +} + +LiteGraph.registerNodeType("math3d/xy-to-vec2", Math3DXYToVec2 ); + + + + +function Math3DVec3ToXYZ() +{ + this.addInput("vec3","vec3"); + this.addOutput("x","number"); + this.addOutput("y","number"); + this.addOutput("z","number"); +} + +Math3DVec3ToXYZ.title = "Vec3->XYZ"; +Math3DVec3ToXYZ.desc = "vector 3 to components"; + +Math3DVec3ToXYZ.prototype.onExecute = function() +{ + var v = this.getInputData(0); + if(v == null) return; + + this.setOutputData( 0, v[0] ); + this.setOutputData( 1, v[1] ); + this.setOutputData( 2, v[2] ); +} + +LiteGraph.registerNodeType("math3d/vec3-to-xyz", Math3DVec3ToXYZ ); + + +function Math3DXYZToVec3() +{ + 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); +} + +Math3DXYZToVec3.title = "XYZ->Vec3"; +Math3DXYZToVec3.desc = "components to vector3"; + +Math3DXYZToVec3.prototype.onExecute = function() +{ + var x = this.getInputData(0); + if(x == null) x = this.properties.x; + var y = this.getInputData(1); + if(y == null) y = this.properties.y; + var z = this.getInputData(2); + if(z == null) z = this.properties.z; + + var data = this._data; + data[0] = x; + data[1] = y; + data[2] = z; + + this.setOutputData( 0, data ); +} + +LiteGraph.registerNodeType("math3d/xyz-to-vec3", Math3DXYZToVec3 ); + + + +function Math3DVec4ToXYZW() +{ + this.addInput("vec4","vec4"); + this.addOutput("x","number"); + this.addOutput("y","number"); + this.addOutput("z","number"); + this.addOutput("w","number"); +} + +Math3DVec4ToXYZW.title = "Vec4->XYZW"; +Math3DVec4ToXYZW.desc = "vector 4 to components"; + +Math3DVec4ToXYZW.prototype.onExecute = function() +{ + var v = this.getInputData(0); + if(v == null) return; + + this.setOutputData( 0, v[0] ); + this.setOutputData( 1, v[1] ); + this.setOutputData( 2, v[2] ); + this.setOutputData( 3, v[3] ); +} + +LiteGraph.registerNodeType("math3d/vec4-to-xyzw", Math3DVec4ToXYZW ); + + +function Math3DXYZWToVec4() +{ + 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); +} + +Math3DXYZWToVec4.title = "XYZW->Vec4"; +Math3DXYZWToVec4.desc = "components to vector4"; + +Math3DXYZWToVec4.prototype.onExecute = function() +{ + var x = this.getInputData(0); + if(x == null) x = this.properties.x; + var y = this.getInputData(1); + if(y == null) y = this.properties.y; + var z = this.getInputData(2); + if(z == null) z = this.properties.z; + var w = this.getInputData(3); + if(w == null) w = this.properties.w; + + var data = this._data; + data[0] = x; + data[1] = y; + data[2] = z; + data[3] = w; + + this.setOutputData( 0, data ); +} + +LiteGraph.registerNodeType("math3d/xyzw-to-vec4", Math3DXYZWToVec4 ); + + + + //if glMatrix is installed... if(window.glMatrix) { - function Math3DVec3ToXYZ() - { - this.addInput("vec3","vec3"); - this.addOutput("x","number"); - this.addOutput("y","number"); - this.addOutput("z","number"); - } - - Math3DVec3ToXYZ.title = "Vec3->XYZ"; - Math3DVec3ToXYZ.desc = "vector 3 to components"; - - Math3DVec3ToXYZ.prototype.onExecute = function() - { - var v = this.getInputData(0); - if(v == null) return; - - this.setOutputData( 0, v[0] ); - this.setOutputData( 1, v[1] ); - this.setOutputData( 2, v[2] ); - } - - LiteGraph.registerNodeType("math3d/vec3-to-xyz", Math3DVec3ToXYZ ); - - - function Math3DXYZToVec3() - { - this.addInputs([["x","number"],["y","number"],["z","number"]]); - this.addOutput("vec3","vec3"); - this.properties = {x:0, y:0, z:0}; - } - - Math3DXYZToVec3.title = "XYZ->Vec3"; - Math3DXYZToVec3.desc = "components to vector3"; - - Math3DXYZToVec3.prototype.onExecute = function() - { - var x = this.getInputData(0); - if(x == null) x = this.properties.x; - var y = this.getInputData(1); - if(y == null) y = this.properties.y; - var z = this.getInputData(2); - if(z == null) z = this.properties.z; - - this.setOutputData( 0, vec3.fromValues(x,y,z) ); - } - - LiteGraph.registerNodeType("math3d/xyz-to-vec3", Math3DXYZToVec3 ); function Math3DRotation()