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 pixelcode must be vec3 uvcode must be vec2, is optional uv: tex. coords color: texture colorB: textureB time: scene time value: input value pixelcode must be vec3 uvcode must be vec2, is optional uv: tex. coords color: texture colorB: textureB time: scene time value: input value../src/litegraph.js:2429
+ Defined in: ../src/litegraph.js:2551
@@ -163,7 +163,7 @@
- ../src/litegraph.js:2429
+ ../src/litegraph.js:2551
../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 @@
../src/litegraph.js:1156
+ Defined in: ../src/litegraph.js:1166
../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 @@
+
+
+
+ getSlotInPositionx
+
+ y
+
+ checks if a point is inside a node slot, and returns info about which slot
+ +x
+ Number
+
+
+
+
+ y
+ Number
+
+
+
+
+ if found the object contains { input|output: slot object, slot: number, link_pos: [x,y] }
+ + +../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()