mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-22 07:44:11 +00:00
Merge branch 'heads/upstream/master'
This commit is contained in:
255
src/litegraph.js
255
src/litegraph.js
@@ -84,7 +84,7 @@ var LiteGraph = global.LiteGraph = {
|
||||
console.log("Node registered: " + type);
|
||||
|
||||
var categories = type.split("/");
|
||||
var classname = base_class.constructor.name;
|
||||
var classname = base_class.name;
|
||||
|
||||
var pos = type.lastIndexOf("/");
|
||||
base_class.category = type.substr(0,pos);
|
||||
@@ -205,7 +205,7 @@ var LiteGraph = global.LiteGraph = {
|
||||
var node = new base_class( title );
|
||||
node.type = type;
|
||||
|
||||
if(!node.title) node.title = title;
|
||||
if(!node.title && title) node.title = title;
|
||||
if(!node.properties) node.properties = {};
|
||||
if(!node.properties_info) node.properties_info = [];
|
||||
if(!node.flags) node.flags = {};
|
||||
@@ -441,7 +441,7 @@ LGraph.prototype.clear = function()
|
||||
|
||||
this.catch_errors = true;
|
||||
|
||||
//globals
|
||||
//subgraph_data
|
||||
this.global_inputs = {};
|
||||
this.global_outputs = {};
|
||||
|
||||
@@ -1029,7 +1029,7 @@ LGraph.prototype.findNodesByType = function(type)
|
||||
|
||||
/**
|
||||
* Returns a list of nodes that matches a name
|
||||
* @method findNodesByName
|
||||
* @method findNodesByTitle
|
||||
* @param {String} name the name of the node to search
|
||||
* @return {Array} a list with all the nodes with this name
|
||||
*/
|
||||
@@ -1051,7 +1051,6 @@ LGraph.prototype.findNodesByTitle = function(title)
|
||||
* @param {Array} nodes_list a list with all the nodes to search from, by default is all the nodes in the graph
|
||||
* @return {Array} a list with all the nodes that intersect this coordinate
|
||||
*/
|
||||
|
||||
LGraph.prototype.getNodeOnPos = function(x,y, nodes_list)
|
||||
{
|
||||
nodes_list = nodes_list || this._nodes;
|
||||
@@ -1066,7 +1065,13 @@ LGraph.prototype.getNodeOnPos = function(x,y, nodes_list)
|
||||
|
||||
// ********** GLOBALS *****************
|
||||
|
||||
//Tell this graph has a global input of this type
|
||||
/**
|
||||
* Tell this graph it has a global graph input of this type
|
||||
* @method addGlobalInput
|
||||
* @param {String} name
|
||||
* @param {String} type
|
||||
* @param {*} value [optional]
|
||||
*/
|
||||
LGraph.prototype.addGlobalInput = function(name, type, value)
|
||||
{
|
||||
this.global_inputs[name] = { name: name, type: type, value: value };
|
||||
@@ -1078,7 +1083,12 @@ LGraph.prototype.addGlobalInput = function(name, type, value)
|
||||
this.onGlobalsChange();
|
||||
}
|
||||
|
||||
//assign a data to the global input
|
||||
/**
|
||||
* Assign a data to the global graph input
|
||||
* @method setGlobalInputData
|
||||
* @param {String} name
|
||||
* @param {*} data
|
||||
*/
|
||||
LGraph.prototype.setGlobalInputData = function(name, data)
|
||||
{
|
||||
var input = this.global_inputs[name];
|
||||
@@ -1087,7 +1097,21 @@ LGraph.prototype.setGlobalInputData = function(name, data)
|
||||
input.value = data;
|
||||
}
|
||||
|
||||
//assign a data to the global input
|
||||
/**
|
||||
* Assign a data to the global graph input (same as setGlobalInputData)
|
||||
* @method setInputData
|
||||
* @param {String} name
|
||||
* @param {*} data
|
||||
*/
|
||||
LGraph.prototype.setInputData = LGraph.prototype.setGlobalInputData;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current value of a global graph input
|
||||
* @method getGlobalInputData
|
||||
* @param {String} name
|
||||
* @return {*} the data
|
||||
*/
|
||||
LGraph.prototype.getGlobalInputData = function(name)
|
||||
{
|
||||
var input = this.global_inputs[name];
|
||||
@@ -1096,7 +1120,12 @@ LGraph.prototype.getGlobalInputData = function(name)
|
||||
return input.value;
|
||||
}
|
||||
|
||||
//rename the global input
|
||||
/**
|
||||
* Changes the name of a global graph input
|
||||
* @method renameGlobalInput
|
||||
* @param {String} old_name
|
||||
* @param {String} new_name
|
||||
*/
|
||||
LGraph.prototype.renameGlobalInput = function(old_name, name)
|
||||
{
|
||||
if(name == old_name)
|
||||
@@ -1121,6 +1150,12 @@ LGraph.prototype.renameGlobalInput = function(old_name, name)
|
||||
this.onGlobalsChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the type of a global graph input
|
||||
* @method changeGlobalInputType
|
||||
* @param {String} name
|
||||
* @param {String} type
|
||||
*/
|
||||
LGraph.prototype.changeGlobalInputType = function(name, type)
|
||||
{
|
||||
if(!this.global_inputs[name])
|
||||
@@ -1134,6 +1169,12 @@ LGraph.prototype.changeGlobalInputType = function(name, type)
|
||||
this.onGlobalInputTypeChanged(name, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a global graph input
|
||||
* @method removeGlobalInput
|
||||
* @param {String} name
|
||||
* @param {String} type
|
||||
*/
|
||||
LGraph.prototype.removeGlobalInput = function(name)
|
||||
{
|
||||
if(!this.global_inputs[name])
|
||||
@@ -1149,7 +1190,13 @@ LGraph.prototype.removeGlobalInput = function(name)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a global graph output
|
||||
* @method addGlobalOutput
|
||||
* @param {String} name
|
||||
* @param {String} type
|
||||
* @param {*} value
|
||||
*/
|
||||
LGraph.prototype.addGlobalOutput = function(name, type, value)
|
||||
{
|
||||
this.global_outputs[name] = { name: name, type: type, value: value };
|
||||
@@ -1161,7 +1208,12 @@ LGraph.prototype.addGlobalOutput = function(name, type, value)
|
||||
this.onGlobalsChange();
|
||||
}
|
||||
|
||||
//assign a data to the global output
|
||||
/**
|
||||
* Assign a data to the global output
|
||||
* @method setGlobalOutputData
|
||||
* @param {String} name
|
||||
* @param {String} value
|
||||
*/
|
||||
LGraph.prototype.setGlobalOutputData = function(name, value)
|
||||
{
|
||||
var output = this.global_outputs[ name ];
|
||||
@@ -1170,7 +1222,12 @@ LGraph.prototype.setGlobalOutputData = function(name, value)
|
||||
output.value = value;
|
||||
}
|
||||
|
||||
//assign a data to the global input
|
||||
/**
|
||||
* Returns the current value of a global graph output
|
||||
* @method getGlobalOutputData
|
||||
* @param {String} name
|
||||
* @return {*} the data
|
||||
*/
|
||||
LGraph.prototype.getGlobalOutputData = function(name)
|
||||
{
|
||||
var output = this.global_outputs[name];
|
||||
@@ -1179,8 +1236,21 @@ LGraph.prototype.getGlobalOutputData = function(name)
|
||||
return output.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value of a global graph output (sames as getGlobalOutputData)
|
||||
* @method getOutputData
|
||||
* @param {String} name
|
||||
* @return {*} the data
|
||||
*/
|
||||
LGraph.prototype.getOutputData = LGraph.prototype.getGlobalOutputData;
|
||||
|
||||
//rename the global output
|
||||
|
||||
/**
|
||||
* Renames a global graph output
|
||||
* @method renameGlobalOutput
|
||||
* @param {String} old_name
|
||||
* @param {String} new_name
|
||||
*/
|
||||
LGraph.prototype.renameGlobalOutput = function(old_name, name)
|
||||
{
|
||||
if(!this.global_outputs[old_name])
|
||||
@@ -1202,6 +1272,12 @@ LGraph.prototype.renameGlobalOutput = function(old_name, name)
|
||||
this.onGlobalsChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the type of a global graph output
|
||||
* @method changeGlobalOutputType
|
||||
* @param {String} name
|
||||
* @param {String} type
|
||||
*/
|
||||
LGraph.prototype.changeGlobalOutputType = function(name, type)
|
||||
{
|
||||
if(!this.global_outputs[name])
|
||||
@@ -1215,6 +1291,11 @@ LGraph.prototype.changeGlobalOutputType = function(name, type)
|
||||
this.onGlobalOutputTypeChanged(name, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a global graph output
|
||||
* @method removeGlobalOutput
|
||||
* @param {String} name
|
||||
*/
|
||||
LGraph.prototype.removeGlobalOutput = function(name)
|
||||
{
|
||||
if(!this.global_outputs[name])
|
||||
@@ -1229,49 +1310,16 @@ LGraph.prototype.removeGlobalOutput = function(name)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Assigns a value to all the nodes that matches this name. This is used to create global variables of the node that
|
||||
* can be easily accesed from the outside of the graph
|
||||
* @method setInputData
|
||||
* @param {String} name the name of the node
|
||||
* @param {*} value value to assign to this node
|
||||
*/
|
||||
|
||||
LGraph.prototype.setInputData = function(name,value)
|
||||
{
|
||||
var nodes = this.findNodesByName( name );
|
||||
for(var i = 0, l = nodes.length; i < l; ++i)
|
||||
nodes[i].setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the first node with this name. This is used to access global variables of the graph from the outside
|
||||
* @method setInputData
|
||||
* @param {String} name the name of the node
|
||||
* @return {*} value of the node
|
||||
*/
|
||||
|
||||
LGraph.prototype.getOutputData = function(name)
|
||||
{
|
||||
var n = this.findNodesByName(name);
|
||||
if(n.length)
|
||||
return m[0].getValue();
|
||||
return null;
|
||||
}
|
||||
|
||||
//This feature is not finished yet, is to create graphs where nodes are not executed unless a trigger message is received
|
||||
|
||||
LGraph.prototype.triggerInput = function(name,value)
|
||||
{
|
||||
var nodes = this.findNodesByName(name);
|
||||
var nodes = this.findNodesByTitle(name);
|
||||
for(var i = 0; i < nodes.length; ++i)
|
||||
nodes[i].onTrigger(value);
|
||||
}
|
||||
|
||||
LGraph.prototype.setCallback = function(name,func)
|
||||
{
|
||||
var nodes = this.findNodesByName(name);
|
||||
var nodes = this.findNodesByTitle(name);
|
||||
for(var i = 0; i < nodes.length; ++i)
|
||||
nodes[i].setTrigger(func);
|
||||
}
|
||||
@@ -1495,7 +1543,7 @@ LGraph.prototype.onNodeTrace = function(node, msg, color)
|
||||
|
||||
function LGraphNode(title)
|
||||
{
|
||||
this._ctor();
|
||||
this._ctor(title);
|
||||
}
|
||||
|
||||
global.LGraphNode = LiteGraph.LGraphNode = LGraphNode;
|
||||
@@ -1567,6 +1615,7 @@ LGraphNode.prototype.configure = function(info)
|
||||
|
||||
if(info[j] == null)
|
||||
continue;
|
||||
|
||||
else if (typeof(info[j]) == 'object') //object
|
||||
{
|
||||
if(this[j] && this[j].configure)
|
||||
@@ -1578,6 +1627,9 @@ LGraphNode.prototype.configure = function(info)
|
||||
this[j] = info[j];
|
||||
}
|
||||
|
||||
if(!info.title)
|
||||
this.title = this.constructor.title;
|
||||
|
||||
if(this.onConnectionsChange)
|
||||
{
|
||||
if(this.inputs)
|
||||
@@ -1645,25 +1697,31 @@ LGraphNode.prototype.configure = function(info)
|
||||
|
||||
LGraphNode.prototype.serialize = function()
|
||||
{
|
||||
//clear outputs last data (because data in connections is never serialized but stored inside the outputs info)
|
||||
if(this.outputs)
|
||||
for(var i = 0; i < this.outputs.length; i++)
|
||||
delete this.outputs[i]._data;
|
||||
|
||||
//create serialization object
|
||||
var o = {
|
||||
id: this.id,
|
||||
title: this.title,
|
||||
type: this.type,
|
||||
pos: this.pos,
|
||||
size: this.size,
|
||||
data: this.data,
|
||||
flags: LiteGraph.cloneObject(this.flags),
|
||||
inputs: this.inputs,
|
||||
outputs: this.outputs,
|
||||
mode: this.mode
|
||||
};
|
||||
|
||||
if(this.inputs)
|
||||
o.inputs = this.inputs;
|
||||
|
||||
if(this.outputs)
|
||||
{
|
||||
//clear outputs last data (because data in connections is never serialized but stored inside the outputs info)
|
||||
for(var i = 0; i < this.outputs.length; i++)
|
||||
delete this.outputs[i]._data;
|
||||
o.outputs = this.outputs;
|
||||
}
|
||||
|
||||
if( this.title && this.title != this.constructor.title )
|
||||
o.title = this.title;
|
||||
|
||||
if(this.properties)
|
||||
o.properties = LiteGraph.cloneObject(this.properties);
|
||||
|
||||
@@ -1776,7 +1834,7 @@ LGraphNode.prototype.setOutputData = function(slot, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieves the input data (data traveling through the connection) from one slot
|
||||
* Retrieves the input data (data traveling through the connection) from one slot
|
||||
* @method getInputData
|
||||
* @param {number} slot
|
||||
* @param {boolean} force_update if set to true it will force the connected node of this slot to output data into this link
|
||||
@@ -1795,10 +1853,10 @@ LGraphNode.prototype.getInputData = function( slot, force_update )
|
||||
if(!link) //bug: weird case but it happens sometimes
|
||||
return null;
|
||||
|
||||
//used to extract data from the incomming connection
|
||||
if(!force_update)
|
||||
return link.data;
|
||||
|
||||
//special case: used to extract data from the incomming connection before the graph has been executed
|
||||
var node = this.graph.getNodeById( link.origin_id );
|
||||
if(!node)
|
||||
return link.data;
|
||||
@@ -1811,6 +1869,22 @@ LGraphNode.prototype.getInputData = function( slot, force_update )
|
||||
return link.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the input data from one slot using its name instead of slot number
|
||||
* @method getInputDataByName
|
||||
* @param {String} slot_name
|
||||
* @param {boolean} force_update if set to true it will force the connected node of this slot to output data into this link
|
||||
* @return {*} data or if it is not connected returns null
|
||||
*/
|
||||
LGraphNode.prototype.getInputDataByName = function( slot_name, force_update )
|
||||
{
|
||||
var slot = this.findInputSlot( slot_name );
|
||||
if( slot == -1 )
|
||||
return null;
|
||||
return this.getInputData( slot, force_update );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tells you if there is a connection in one input slot
|
||||
* @method isInputConnected
|
||||
@@ -1860,6 +1934,31 @@ LGraphNode.prototype.getInputNode = function( slot )
|
||||
return this.graph.getNodeById( link_info.origin_id );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns the value of an input with this name, otherwise checks if there is a property with that name
|
||||
* @method getInputOrProperty
|
||||
* @param {string} name
|
||||
* @return {*} value
|
||||
*/
|
||||
LGraphNode.prototype.getInputOrProperty = function( name )
|
||||
{
|
||||
if(!this.inputs || !this.inputs.length)
|
||||
return this.properties ? this.properties[name] : null;
|
||||
|
||||
for(var i = 0, l = this.inputs.length; i < l; ++i)
|
||||
if(name == this.inputs[i].name)
|
||||
{
|
||||
var link_id = this.inputs[i].link;
|
||||
var link = this.graph.links[ link_id ];
|
||||
return link ? link.data : null;
|
||||
}
|
||||
return this.properties[name];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* tells you the last output data that went in that slot
|
||||
* @method getOutputData
|
||||
@@ -1903,10 +2002,26 @@ LGraphNode.prototype.getOutputInfo = function(slot)
|
||||
LGraphNode.prototype.isOutputConnected = function(slot)
|
||||
{
|
||||
if(!this.outputs)
|
||||
return null;
|
||||
return false;
|
||||
return (slot < this.outputs.length && this.outputs[slot].links && this.outputs[slot].links.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* tells you if there is any connection in the output slots
|
||||
* @method isAnyOutputConnected
|
||||
* @return {boolean}
|
||||
*/
|
||||
LGraphNode.prototype.isAnyOutputConnected = function()
|
||||
{
|
||||
if(!this.outputs)
|
||||
return false;
|
||||
for(var i = 0; i < this.outputs.length; ++i)
|
||||
if( this.outputs[i].links && this.outputs[i].links.length )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* retrieves all the nodes connected to this output slot
|
||||
* @method getOutputNodes
|
||||
@@ -2810,6 +2925,12 @@ function LGraphCanvas( canvas, graph, options )
|
||||
this.title_text_font = "bold 14px Arial";
|
||||
this.inner_text_font = "normal 12px Arial";
|
||||
this.default_link_color = "#AAC";
|
||||
this.default_connection_color = {
|
||||
input_off: "#AAB",
|
||||
input_on: "#7F7",
|
||||
output_off: "#AAB",
|
||||
output_on: "#7F7"
|
||||
};
|
||||
|
||||
this.highquality_render = true;
|
||||
this.editor_alpha = 1; //used for transition
|
||||
@@ -2827,6 +2948,7 @@ function LGraphCanvas( canvas, graph, options )
|
||||
this.dragging_rectangle = null;
|
||||
|
||||
this.always_render_background = false;
|
||||
this.render_canvas_area = true;
|
||||
this.render_connections_shadows = false; //too much cpu
|
||||
this.render_connections_border = true;
|
||||
this.render_curved_connections = true;
|
||||
@@ -4540,8 +4662,10 @@ LGraphCanvas.prototype.drawBackCanvas = function()
|
||||
//ctx.fillRect( this.visible_area[0] + 10, this.visible_area[1] + 10, this.visible_area[2] - 20, this.visible_area[3] - 20);
|
||||
|
||||
//bg
|
||||
ctx.strokeStyle = "#235";
|
||||
ctx.strokeRect(0,0,canvas.width,canvas.height);
|
||||
if (this.render_canvas_area) {
|
||||
ctx.strokeStyle = "#235";
|
||||
ctx.strokeRect(0,0,canvas.width,canvas.height);
|
||||
}
|
||||
|
||||
if(this.render_connections_shadows)
|
||||
{
|
||||
@@ -4693,7 +4817,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
|
||||
if ( this.connecting_node && LiteGraph.isValidConnection( slot.type && out_slot.type ) )
|
||||
ctx.globalAlpha = 0.4 * editor_alpha;
|
||||
|
||||
ctx.fillStyle = slot.link != null ? "#7F7" : "#AAA";
|
||||
ctx.fillStyle = slot.link != null ? this.default_connection_color.input_on : this.default_connection_color.input_off;
|
||||
|
||||
var pos = node.getConnectionPos(true,i);
|
||||
pos[0] -= node.pos[0];
|
||||
@@ -4737,7 +4861,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
|
||||
pos[0] -= node.pos[0];
|
||||
pos[1] -= node.pos[1];
|
||||
|
||||
ctx.fillStyle = slot.links && slot.links.length ? "#7F7" : "#AAA";
|
||||
ctx.fillStyle = slot.links && slot.links.length ? this.default_connection_color.output_on : this.default_connection_color.output_off;
|
||||
ctx.beginPath();
|
||||
//ctx.rect( node.size[0] - 14,i*14,10,10);
|
||||
|
||||
@@ -6442,6 +6566,7 @@ LiteGraph.extendClass = function ( target, origin )
|
||||
}
|
||||
}
|
||||
|
||||
//used to create nodes from wrapping functions
|
||||
LiteGraph.getParameterNames = function(func) {
|
||||
return (func + '')
|
||||
.replace(/[/][/].*$/mg,'') // strip single-line comments
|
||||
@@ -6452,6 +6577,8 @@ LiteGraph.getParameterNames = function(func) {
|
||||
.split(',').filter(Boolean); // split & filter [""]
|
||||
}
|
||||
|
||||
Math.clamp = function(v,a,b) { return (a > v ? a : (b < v ? b : v)); }
|
||||
|
||||
if( typeof(window) != "undefined" && !window["requestAnimationFrame"] )
|
||||
{
|
||||
window.requestAnimationFrame = window.webkitRequestAnimationFrame ||
|
||||
|
||||
@@ -40,7 +40,6 @@ function Subgraph()
|
||||
this.subgraph.onGlobalOutputRenamed = this.onSubgraphRenamedGlobalOutput.bind(this);
|
||||
this.subgraph.onGlobalOutputTypeChanged = this.onSubgraphTypeChangeGlobalOutput.bind(this);
|
||||
|
||||
|
||||
this.bgcolor = "#663";
|
||||
}
|
||||
|
||||
@@ -236,6 +235,8 @@ function GlobalOutput()
|
||||
|
||||
this.addInput(output_name, null);
|
||||
|
||||
this._value = null;
|
||||
|
||||
this.properties = {name: output_name, type: null };
|
||||
|
||||
var that = this;
|
||||
@@ -270,7 +271,7 @@ function GlobalOutput()
|
||||
});
|
||||
}
|
||||
|
||||
GlobalOutput.title = "Ouput";
|
||||
GlobalOutput.title = "Output";
|
||||
GlobalOutput.desc = "Output of the graph";
|
||||
|
||||
GlobalOutput.prototype.onAdded = function()
|
||||
@@ -278,9 +279,15 @@ GlobalOutput.prototype.onAdded = function()
|
||||
var name = this.graph.addGlobalOutput( this.properties.name, this.properties.type );
|
||||
}
|
||||
|
||||
GlobalOutput.prototype.getValue = function()
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
|
||||
GlobalOutput.prototype.onExecute = function()
|
||||
{
|
||||
this.graph.setGlobalOutputData( this.properties.name, this.getInputData(0) );
|
||||
this._value = this.getInputData(0);
|
||||
this.graph.setGlobalOutputData( this.properties.name, this._value );
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("graph/output", GlobalOutput);
|
||||
|
||||
@@ -17,7 +17,7 @@ if(typeof(GL) != "undefined")
|
||||
|
||||
if(!LGraphFXLens._shader)
|
||||
{
|
||||
LGraphFXLens._shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER, LGraphFXLens.pixel_shader );
|
||||
LGraphFXLens._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphFXLens.pixel_shader );
|
||||
LGraphFXLens._texture = new GL.Texture(3,1,{ format: gl.RGB, wrap: gl.CLAMP_TO_EDGE, magFilter: gl.LINEAR, minFilter: gl.LINEAR, pixel_data: [255,0,0, 0,255,0, 0,0,255] });
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,120 @@ if(typeof(GL) != "undefined")
|
||||
*/
|
||||
|
||||
LiteGraph.registerNodeType("fx/lens", LGraphFXLens );
|
||||
window.LGraphFXLens = LGraphFXLens;
|
||||
global.LGraphFXLens = LGraphFXLens;
|
||||
|
||||
/* not working yet
|
||||
function LGraphDepthOfField()
|
||||
{
|
||||
this.addInput("Color","Texture");
|
||||
this.addInput("Linear Depth","Texture");
|
||||
this.addInput("Camera","camera");
|
||||
this.addOutput("Texture","Texture");
|
||||
this.properties = { high_precision: false };
|
||||
}
|
||||
|
||||
LGraphDepthOfField.title = "Depth Of Field";
|
||||
LGraphDepthOfField.desc = "Applies a depth of field effect";
|
||||
|
||||
LGraphDepthOfField.prototype.onExecute = function()
|
||||
{
|
||||
var tex = this.getInputData(0);
|
||||
var depth = this.getInputData(1);
|
||||
var camera = this.getInputData(2);
|
||||
|
||||
if(!tex || !depth || !camera)
|
||||
{
|
||||
this.setOutputData(0, tex);
|
||||
return;
|
||||
}
|
||||
|
||||
var precision = gl.UNSIGNED_BYTE;
|
||||
if(this.properties.high_precision)
|
||||
precision = gl.half_float_ext ? gl.HALF_FLOAT_OES : gl.FLOAT;
|
||||
if(!this._temp_texture || this._temp_texture.type != precision ||
|
||||
this._temp_texture.width != tex.width || this._temp_texture.height != tex.height)
|
||||
this._temp_texture = new GL.Texture( tex.width, tex.height, { type: precision, format: gl.RGBA, filter: gl.LINEAR });
|
||||
|
||||
var shader = LGraphDepthOfField._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphDepthOfField._pixel_shader );
|
||||
|
||||
var screen_mesh = Mesh.getScreenQuad();
|
||||
|
||||
gl.disable( gl.DEPTH_TEST );
|
||||
gl.disable( gl.BLEND );
|
||||
|
||||
var camera_position = camera.getEye();
|
||||
var focus_point = camera.getCenter();
|
||||
var distance = vec3.distance( camera_position, focus_point );
|
||||
var far = camera.far;
|
||||
var focus_range = distance * 0.5;
|
||||
|
||||
this._temp_texture.drawTo( function() {
|
||||
tex.bind(0);
|
||||
depth.bind(1);
|
||||
shader.uniforms({u_texture:0, u_depth_texture:1, u_resolution: [1/tex.width, 1/tex.height], u_far: far, u_focus_point: distance, u_focus_scale: focus_range }).draw(screen_mesh);
|
||||
});
|
||||
|
||||
this.setOutputData(0, this._temp_texture);
|
||||
}
|
||||
|
||||
//from http://tuxedolabs.blogspot.com.es/2018/05/bokeh-depth-of-field-in-single-pass.html
|
||||
LGraphDepthOfField._pixel_shader = "\n\
|
||||
precision highp float;\n\
|
||||
varying vec2 v_coord;\n\
|
||||
uniform sampler2D u_texture; //Image to be processed\n\
|
||||
uniform sampler2D u_depth_texture; //Linear depth, where 1.0 == far plane\n\
|
||||
uniform vec2 u_iresolution; //The size of a pixel: vec2(1.0/width, 1.0/height)\n\
|
||||
uniform float u_far; // Far plane\n\
|
||||
uniform float u_focus_point;\n\
|
||||
uniform float u_focus_scale;\n\
|
||||
\n\
|
||||
const float GOLDEN_ANGLE = 2.39996323;\n\
|
||||
const float MAX_BLUR_SIZE = 20.0;\n\
|
||||
const float RAD_SCALE = 0.5; // Smaller = nicer blur, larger = faster\n\
|
||||
\n\
|
||||
float getBlurSize(float depth, float focusPoint, float focusScale)\n\
|
||||
{\n\
|
||||
float coc = clamp((1.0 / focusPoint - 1.0 / depth)*focusScale, -1.0, 1.0);\n\
|
||||
return abs(coc) * MAX_BLUR_SIZE;\n\
|
||||
}\n\
|
||||
\n\
|
||||
vec3 depthOfField(vec2 texCoord, float focusPoint, float focusScale)\n\
|
||||
{\n\
|
||||
float centerDepth = texture2D(u_depth_texture, texCoord).r * u_far;\n\
|
||||
float centerSize = getBlurSize(centerDepth, focusPoint, focusScale);\n\
|
||||
vec3 color = texture2D(u_texture, v_coord).rgb;\n\
|
||||
float tot = 1.0;\n\
|
||||
\n\
|
||||
float radius = RAD_SCALE;\n\
|
||||
for (float ang = 0.0; ang < 100.0; ang += GOLDEN_ANGLE)\n\
|
||||
{\n\
|
||||
vec2 tc = texCoord + vec2(cos(ang), sin(ang)) * u_iresolution * radius;\n\
|
||||
\n\
|
||||
vec3 sampleColor = texture2D(u_texture, tc).rgb;\n\
|
||||
float sampleDepth = texture2D(u_depth_texture, tc).r * u_far;\n\
|
||||
float sampleSize = getBlurSize( sampleDepth, focusPoint, focusScale );\n\
|
||||
if (sampleDepth > centerDepth)\n\
|
||||
sampleSize = clamp(sampleSize, 0.0, centerSize*2.0);\n\
|
||||
\n\
|
||||
float m = smoothstep(radius-0.5, radius+0.5, sampleSize);\n\
|
||||
color += mix(color/tot, sampleColor, m);\n\
|
||||
tot += 1.0;\n\
|
||||
radius += RAD_SCALE/radius;\n\
|
||||
if(radius>=MAX_BLUR_SIZE)\n\
|
||||
return color / tot;\n\
|
||||
}\n\
|
||||
return color / tot;\n\
|
||||
}\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
gl_FragColor = vec4( depthOfField( v_coord, u_focus_point, u_focus_scale ), 1.0 );\n\
|
||||
//gl_FragColor = vec4( texture2D(u_depth_texture, v_coord).r );\n\
|
||||
}\n\
|
||||
";
|
||||
|
||||
LiteGraph.registerNodeType("fx/DOF", LGraphDepthOfField );
|
||||
global.LGraphDepthOfField = LGraphDepthOfField;
|
||||
*/
|
||||
|
||||
//*******************************************************
|
||||
|
||||
@@ -311,7 +424,7 @@ if(typeof(GL) != "undefined")
|
||||
|
||||
|
||||
LiteGraph.registerNodeType("fx/bokeh", LGraphFXBokeh );
|
||||
window.LGraphFXBokeh = LGraphFXBokeh;
|
||||
global.LGraphFXBokeh = LGraphFXBokeh;
|
||||
|
||||
//************************************************
|
||||
|
||||
@@ -380,7 +493,7 @@ if(typeof(GL) != "undefined")
|
||||
gl.disable( gl.BLEND );
|
||||
gl.disable( gl.DEPTH_TEST );
|
||||
var mesh = Mesh.getScreenQuad();
|
||||
var camera = window.LS ? LS.Renderer._current_camera : null;
|
||||
var camera = global.LS ? LS.Renderer._current_camera : null;
|
||||
if(camera)
|
||||
camera_planes = [LS.Renderer._current_camera.near, LS.Renderer._current_camera.far];
|
||||
else
|
||||
@@ -480,7 +593,7 @@ if(typeof(GL) != "undefined")
|
||||
|
||||
|
||||
LiteGraph.registerNodeType("fx/generic", LGraphFXGeneric );
|
||||
window.LGraphFXGeneric = LGraphFXGeneric;
|
||||
global.LGraphFXGeneric = LGraphFXGeneric;
|
||||
|
||||
|
||||
// Vigneting ************************************
|
||||
|
||||
@@ -99,6 +99,18 @@ if(typeof(GL) != "undefined")
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
LGraphTexture.getTextureType = function( precision, ref_texture )
|
||||
{
|
||||
var type = ref_texture ? ref_texture.type : gl.UNSIGNED_BYTE;
|
||||
switch( precision )
|
||||
{
|
||||
case LGraphTexture.LOW: type = gl.UNSIGNED_BYTE; break;
|
||||
case LGraphTexture.HIGH: type = gl.HIGH_PRECISION_FORMAT; break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
LGraphTexture.getNoiseTexture = function()
|
||||
{
|
||||
if(this._noise_texture)
|
||||
@@ -455,33 +467,24 @@ if(typeof(GL) != "undefined")
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
var type = LGraphTexture.getTextureType( this.properties.precision, tex );
|
||||
|
||||
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 });
|
||||
this._tex = new GL.Texture( width, height, { type: type, format: gl.RGBA, filter: gl.LINEAR });
|
||||
else
|
||||
this._tex = LGraphTexture.getTargetTexture( tex || this._tex, this._tex, this.properties.precision );
|
||||
|
||||
/*
|
||||
if(this.properties.low_precision)
|
||||
type = gl.UNSIGNED_BYTE;
|
||||
|
||||
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 uvcode = "";
|
||||
if(this.properties.uvcode)
|
||||
{
|
||||
@@ -578,9 +581,10 @@ if(typeof(GL) != "undefined")
|
||||
function LGraphTextureShader()
|
||||
{
|
||||
this.addOutput("Texture","Texture");
|
||||
this.properties = {code:"", width: 512, height: 512};
|
||||
this.properties = {code:"", width: 512, height: 512, precision: LGraphTexture.DEFAULT };
|
||||
|
||||
this.properties.code = "\nvoid main() {\n vec2 uv = v_coord;\n vec3 color = vec3(0.0);\n//your code here\n\ngl_FragColor = vec4(color, 1.0);\n}\n";
|
||||
this._uniforms = { texSize: vec2.create(), time: time };
|
||||
}
|
||||
|
||||
LGraphTextureShader.title = "Shader";
|
||||
@@ -713,16 +717,25 @@ if(typeof(GL) != "undefined")
|
||||
shader.setUniform( info.name, data );
|
||||
}
|
||||
|
||||
var uniforms = this._uniforms;
|
||||
|
||||
var type = LGraphTexture.getTextureType( this.properties.precision );
|
||||
|
||||
//render to texture
|
||||
if(!this._tex || this._tex.width != this.properties.width || this._tex.height != this.properties.height )
|
||||
this._tex = new GL.Texture( this.properties.width, this.properties.height, { format: gl.RGBA, filter: gl.LINEAR });
|
||||
var w = this.properties.width|0;
|
||||
var h = this.properties.height|0;
|
||||
uniforms.texSize[0] = w;
|
||||
uniforms.texSize[1] = h;
|
||||
|
||||
if(!this._tex || this._tex.type != type || this._tex.width != w || this._tex.height != h )
|
||||
this._tex = new GL.Texture( w, h, { type: type, format: gl.RGBA, filter: gl.LINEAR });
|
||||
var tex = this._tex;
|
||||
var time = this.graph.getTime();
|
||||
tex.drawTo(function() {
|
||||
shader.uniforms({texSize: [tex.width, tex.height], time: time}).draw( Mesh.getScreenQuad() );
|
||||
tex.drawTo(function() {
|
||||
shader.uniforms( uniforms ).draw( GL.Mesh.getScreenQuad() );
|
||||
});
|
||||
|
||||
this.setOutputData(0, this._tex);
|
||||
this.setOutputData( 0, this._tex );
|
||||
}
|
||||
|
||||
LGraphTextureShader.pixel_shader = "precision highp float;\n\
|
||||
@@ -1243,10 +1256,13 @@ if(typeof(GL) != "undefined")
|
||||
function LGraphTextureAverage()
|
||||
{
|
||||
this.addInput("Texture","Texture");
|
||||
this.addOutput("","Texture");
|
||||
this.addOutput("tex","Texture");
|
||||
this.addOutput("avg","vec4");
|
||||
this.addOutput("lum","number");
|
||||
this.properties = { mipmap_offset: 0, low_precision: false };
|
||||
|
||||
this._uniforms = { u_texture: 0, u_mipmap_offset: this.properties.mipmap_offset };
|
||||
this._luminance = new Float32Array(4);
|
||||
}
|
||||
|
||||
LGraphTextureAverage.title = "Average";
|
||||
@@ -1258,7 +1274,7 @@ if(typeof(GL) != "undefined")
|
||||
if(!tex)
|
||||
return;
|
||||
|
||||
if(!this.isOutputConnected(0))
|
||||
if(!this.isOutputConnected(0) && !this.isOutputConnected(1) && !this.isOutputConnected(2))
|
||||
return; //saves work
|
||||
|
||||
if(!LGraphTextureAverage._shader)
|
||||
@@ -1272,7 +1288,10 @@ if(typeof(GL) != "undefined")
|
||||
}
|
||||
|
||||
var temp = this._temp_texture;
|
||||
var type = this.properties.low_precision ? gl.UNSIGNED_BYTE : tex.type;
|
||||
var type = gl.UNSIGNED_BYTE;
|
||||
if(tex.type != type) //force floats, half floats cannot be read with gl.readPixels
|
||||
type = gl.FLOAT;
|
||||
|
||||
if(!temp || temp.type != type )
|
||||
this._temp_texture = new GL.Texture( 1, 1, { type: type, format: gl.RGBA, filter: gl.NEAREST });
|
||||
|
||||
@@ -1284,6 +1303,24 @@ if(typeof(GL) != "undefined")
|
||||
});
|
||||
|
||||
this.setOutputData(0,this._temp_texture);
|
||||
|
||||
if(this.isOutputConnected(1) || this.isOutputConnected(2))
|
||||
{
|
||||
var pixel = this._temp_texture.getPixels();
|
||||
if(pixel)
|
||||
{
|
||||
var v = this._luminance;
|
||||
var type = this._temp_texture.type;
|
||||
v.set( pixel );
|
||||
if(type == gl.UNSIGNED_BYTE)
|
||||
vec4.scale( v,v, 1/255 );
|
||||
else if(type == GL.HALF_FLOAT || type == GL.HALF_FLOAT_OES)
|
||||
vec4.scale( v,v, 1/(255*255) ); //is this correct?
|
||||
this.setOutputData(1,v);
|
||||
this.setOutputData(2,(v[0] + v[1] + v[2]) / 3);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
LGraphTextureAverage.pixel_shader = "precision highp float;\n\
|
||||
@@ -1371,12 +1408,12 @@ if(typeof(GL) != "undefined")
|
||||
}
|
||||
|
||||
LGraphTextureLUT.widgets_info = {
|
||||
"texture": { widget:"texture"},
|
||||
"precision": { widget:"combo", values: LGraphTexture.MODE_VALUES }
|
||||
};
|
||||
|
||||
LGraphTextureLUT.title = "LUT";
|
||||
LGraphTextureLUT.desc = "Apply LUT to Texture";
|
||||
LGraphTextureLUT.widgets_info = {"texture": { widget:"texture"} };
|
||||
|
||||
LGraphTextureLUT.prototype.onExecute = function()
|
||||
{
|
||||
@@ -1391,7 +1428,8 @@ if(typeof(GL) != "undefined")
|
||||
return;
|
||||
}
|
||||
|
||||
if(!tex) return;
|
||||
if(!tex)
|
||||
return;
|
||||
|
||||
var lut_tex = this.getInputData(1);
|
||||
|
||||
@@ -1766,7 +1804,7 @@ if(typeof(GL) != "undefined")
|
||||
this.addInput("Tex.","Texture");
|
||||
|
||||
this.addOutput("Edges","Texture");
|
||||
this.properties = { invert: true, factor: 1, precision: LGraphTexture.DEFAULT };
|
||||
this.properties = { invert: true, threshold: false, factor: 1, precision: LGraphTexture.DEFAULT };
|
||||
|
||||
if(!LGraphTextureEdges._shader)
|
||||
LGraphTextureEdges._shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER, LGraphTextureEdges.pixel_shader );
|
||||
@@ -1803,10 +1841,11 @@ if(typeof(GL) != "undefined")
|
||||
var shader = LGraphTextureEdges._shader;
|
||||
var invert = this.properties.invert;
|
||||
var factor = this.properties.factor;
|
||||
var threshold = this.properties.threshold ? 1 : 0;
|
||||
|
||||
this._tex.drawTo( function() {
|
||||
tex.bind(0);
|
||||
shader.uniforms({u_texture:0, u_isize:[1/tex.width,1/tex.height], u_factor: factor, u_invert: invert ? 1 : 0}).draw(mesh);
|
||||
shader.uniforms({u_texture:0, u_isize:[1/tex.width,1/tex.height], u_factor: factor, u_threshold: threshold, u_invert: invert ? 1 : 0}).draw(mesh);
|
||||
});
|
||||
|
||||
this.setOutputData(0, this._tex);
|
||||
@@ -1819,6 +1858,7 @@ if(typeof(GL) != "undefined")
|
||||
uniform vec2 u_isize;\n\
|
||||
uniform int u_invert;\n\
|
||||
uniform float u_factor;\n\
|
||||
uniform float u_threshold;\n\
|
||||
\n\
|
||||
void main() {\n\
|
||||
vec4 center = texture2D(u_texture, v_coord);\n\
|
||||
@@ -1830,7 +1870,10 @@ if(typeof(GL) != "undefined")
|
||||
diff *= u_factor;\n\
|
||||
if(u_invert == 1)\n\
|
||||
diff.xyz = vec3(1.0) - diff.xyz;\n\
|
||||
gl_FragColor = vec4( diff.xyz, center.a );\n\
|
||||
if( u_threshold == 0.0 )\n\
|
||||
gl_FragColor = vec4( diff.xyz, center.a );\n\
|
||||
else\n\
|
||||
gl_FragColor = vec4( diff.x > 0.5 ? 1.0 : 0.0, diff.y > 0.5 ? 1.0 : 0.0, diff.z > 0.5 ? 1.0 : 0.0, center.a );\n\
|
||||
}\n\
|
||||
";
|
||||
|
||||
@@ -1912,7 +1955,8 @@ if(typeof(GL) != "undefined")
|
||||
shader.uniforms( uniforms ).draw(mesh);
|
||||
});
|
||||
|
||||
this.setOutputData(0, this._temp_texture);
|
||||
this._temp_texture.near_far_planes = planes;
|
||||
this.setOutputData(0, this._temp_texture );
|
||||
}
|
||||
|
||||
LGraphTextureDepthRange.pixel_shader = "precision highp float;\n\
|
||||
@@ -1955,12 +1999,16 @@ if(typeof(GL) != "undefined")
|
||||
this.addInput("Iterations","number");
|
||||
this.addInput("Intensity","number");
|
||||
this.addOutput("Blurred","Texture");
|
||||
this.properties = { intensity: 1, iterations: 1, preserve_aspect: false, scale:[1,1] };
|
||||
this.properties = { intensity: 1, iterations: 1, preserve_aspect: false, scale:[1,1], precision: LGraphTexture.DEFAULT };
|
||||
}
|
||||
|
||||
LGraphTextureBlur.title = "Blur";
|
||||
LGraphTextureBlur.desc = "Blur a texture";
|
||||
|
||||
LGraphTextureBlur.widgets_info = {
|
||||
precision: { widget:"combo", values: LGraphTexture.MODE_VALUES }
|
||||
};
|
||||
|
||||
LGraphTextureBlur.max_iterations = 20;
|
||||
|
||||
LGraphTextureBlur.prototype.onExecute = function()
|
||||
@@ -1972,13 +2020,13 @@ if(typeof(GL) != "undefined")
|
||||
if(!this.isOutputConnected(0))
|
||||
return; //saves work
|
||||
|
||||
var temp = this._temp_texture;
|
||||
var temp = this._final_texture;
|
||||
|
||||
if(!temp || temp.width != tex.width || temp.height != tex.height || temp.type != tex.type )
|
||||
{
|
||||
//we need two textures to do the blurring
|
||||
this._temp_texture = new GL.Texture( tex.width, tex.height, { type: tex.type, format: gl.RGBA, filter: gl.LINEAR });
|
||||
this._final_texture = new GL.Texture( tex.width, tex.height, { type: tex.type, format: gl.RGBA, filter: gl.LINEAR });
|
||||
//this._temp_texture = new GL.Texture( tex.width, tex.height, { type: tex.type, format: gl.RGBA, filter: gl.LINEAR });
|
||||
temp = this._final_texture = new GL.Texture( tex.width, tex.height, { type: tex.type, format: gl.RGBA, filter: gl.LINEAR });
|
||||
}
|
||||
|
||||
//iterations
|
||||
@@ -2010,18 +2058,15 @@ if(typeof(GL) != "undefined")
|
||||
aspect = 1;
|
||||
aspect = this.properties.preserve_aspect ? aspect : 1;
|
||||
|
||||
var start_texture = tex;
|
||||
var scale = this.properties.scale || [1,1];
|
||||
var origin = start_texture;
|
||||
for(var i = 0; i < iterations; ++i)
|
||||
{
|
||||
origin.applyBlur( aspect * scale[0] * i, scale[1] * i, intensity, this._temp_texture, this._final_texture );
|
||||
origin = this._final_texture;
|
||||
}
|
||||
tex.applyBlur( aspect * scale[0], scale[1], intensity, temp );
|
||||
for(var i = 1; i < iterations; ++i)
|
||||
temp.applyBlur( aspect * scale[0] * (i+1), scale[1] * (i+1), intensity );
|
||||
|
||||
this.setOutputData(0, this._final_texture);
|
||||
this.setOutputData(0, temp );
|
||||
}
|
||||
|
||||
/*
|
||||
LGraphTextureBlur.pixel_shader = "precision highp float;\n\
|
||||
precision highp float;\n\
|
||||
varying vec2 v_coord;\n\
|
||||
@@ -2041,12 +2086,237 @@ if(typeof(GL) != "undefined")
|
||||
sum += texture2D(u_texture, v_coord + u_offset * 2.0) * 0.12/0.98;\n\
|
||||
sum += texture2D(u_texture, v_coord + u_offset * 1.0) * 0.15/0.98;\n\
|
||||
gl_FragColor = u_intensity * sum;\n\
|
||||
/*gl_FragColor.a = center.a*/;\n\
|
||||
}\n\
|
||||
";
|
||||
*/
|
||||
|
||||
LiteGraph.registerNodeType("texture/blur", LGraphTextureBlur );
|
||||
|
||||
|
||||
// Texture Glow *****************************************
|
||||
//based in https://catlikecoding.com/unity/tutorials/advanced-rendering/bloom/
|
||||
function LGraphTextureGlow()
|
||||
{
|
||||
this.addInput("in","Texture");
|
||||
this.addInput("dirt","Texture");
|
||||
this.addOutput("out","Texture");
|
||||
this.addOutput("glow","Texture");
|
||||
this.properties = { intensity: 1, persistence: 0.99, iterations:16, threshold:0, scale: 1, dirt_factor: 0.5, precision: LGraphTexture.DEFAULT };
|
||||
this._textures = [];
|
||||
this._uniforms = { u_intensity: 1, u_texture: 0, u_glow_texture: 1, u_threshold: 0, u_texel_size: vec2.create() };
|
||||
}
|
||||
|
||||
LGraphTextureGlow.title = "Glow";
|
||||
LGraphTextureGlow.desc = "Filters a texture giving it a glow effect";
|
||||
LGraphTextureGlow.weights = new Float32Array( [0.5,0.4,0.3,0.2] );
|
||||
|
||||
LGraphTextureGlow.widgets_info = {
|
||||
"iterations": { type:"number", min: 0, max: 16, step: 1, precision: 0 },
|
||||
"threshold": { type:"number", min: 0, max: 10, step: 0.01, precision: 2 },
|
||||
"precision": { widget:"combo", values: LGraphTexture.MODE_VALUES }
|
||||
};
|
||||
|
||||
LGraphTextureGlow.prototype.onGetInputs = function(){
|
||||
return [["enabled","boolean"],["threshold","number"],["intensity","number"],["persistence","number"],["iterations","number"],["dirt_factor","number"]];
|
||||
}
|
||||
|
||||
LGraphTextureGlow.prototype.onGetOutputs = function(){
|
||||
return [["average","Texture"]];
|
||||
}
|
||||
|
||||
LGraphTextureGlow.prototype.onExecute = function()
|
||||
{
|
||||
var tex = this.getInputData(0);
|
||||
if(!tex)
|
||||
return;
|
||||
|
||||
if(!this.isAnyOutputConnected())
|
||||
return; //saves work
|
||||
|
||||
if(this.properties.precision === LGraphTexture.PASS_THROUGH || this.getInputDataByName("enabled" ) === false )
|
||||
{
|
||||
this.setOutputData(0,tex);
|
||||
return;
|
||||
}
|
||||
|
||||
var width = tex.width;
|
||||
var height = tex.height;
|
||||
|
||||
var texture_info = { format: tex.format, type: tex.type, minFilter: GL.LINEAR, magFilter: GL.LINEAR, wrap: gl.CLAMP_TO_EDGE };
|
||||
var type = LGraphTexture.getTextureType( this.properties.precision, tex );
|
||||
|
||||
var uniforms = this._uniforms;
|
||||
var textures = this._textures;
|
||||
|
||||
//cut
|
||||
var shader = LGraphTextureGlow._cut_shader;
|
||||
if(!shader)
|
||||
shader = LGraphTextureGlow._cut_shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureGlow.cut_pixel_shader );
|
||||
|
||||
gl.disable( gl.DEPTH_TEST );
|
||||
gl.disable( gl.BLEND );
|
||||
|
||||
uniforms.u_threshold = this.getInputOrProperty("threshold");
|
||||
var currentDestination = textures[0] = GL.Texture.getTemporary( width, height, texture_info );
|
||||
tex.blit( currentDestination, shader.uniforms(uniforms) );
|
||||
var currentSource = currentDestination;
|
||||
|
||||
var iterations = this.getInputOrProperty("iterations");
|
||||
iterations = Math.clamp( iterations, 1, 16) | 0;
|
||||
var texel_size = uniforms.u_texel_size;
|
||||
var intensity = this.getInputOrProperty("intensity");
|
||||
|
||||
uniforms.u_intensity = 1;
|
||||
uniforms.u_delta = this.properties.scale; //1
|
||||
|
||||
//downscale upscale shader
|
||||
var shader = LGraphTextureGlow._shader;
|
||||
if(!shader)
|
||||
shader = LGraphTextureGlow._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureGlow.scale_pixel_shader );
|
||||
|
||||
var i = 1;
|
||||
//downscale
|
||||
for (;i < iterations; i++) {
|
||||
width = width>>1;
|
||||
if( (height|0) > 1 )
|
||||
height = height>>1;
|
||||
if( width < 2 )
|
||||
break;
|
||||
currentDestination = textures[i] = GL.Texture.getTemporary( width, height, texture_info );
|
||||
texel_size[0] = 1 / currentSource.width; texel_size[1] = 1 / currentSource.height;
|
||||
currentSource.blit( currentDestination, shader.uniforms(uniforms) );
|
||||
currentSource = currentDestination;
|
||||
}
|
||||
|
||||
//average
|
||||
if(this.isOutputConnected(2))
|
||||
{
|
||||
var average_texture = this._average_texture;
|
||||
if(!average_texture || average_texture.type != tex.type || average_texture.format != tex.format )
|
||||
average_texture = this._average_texture = new GL.Texture( 1, 1, { type: tex.type, format: tex.format, filter: gl.LINEAR });
|
||||
texel_size[0] = 1 / currentSource.width; texel_size[1] = 1 / currentSource.height;
|
||||
uniforms.u_intensity = intensity;
|
||||
uniforms.u_delta = 1;
|
||||
currentSource.blit( average_texture, shader.uniforms(uniforms) );
|
||||
this.setOutputData( 2, average_texture );
|
||||
}
|
||||
|
||||
//upscale and blend
|
||||
gl.enable( gl.BLEND );
|
||||
gl.blendFunc( gl.ONE, gl.ONE );
|
||||
uniforms.u_intensity = this.getInputOrProperty("persistence");
|
||||
uniforms.u_delta = 0.5;
|
||||
|
||||
for (i -= 2; i >= 0; i--) // i-=2 => -1 to point to last element in array, -1 to go to texture above
|
||||
{
|
||||
currentDestination = textures[i];
|
||||
textures[i] = null;
|
||||
texel_size[0] = 1 / currentSource.width; texel_size[1] = 1 / currentSource.height;
|
||||
currentSource.blit( currentDestination, shader.uniforms(uniforms) );
|
||||
GL.Texture.releaseTemporary( currentSource );
|
||||
currentSource = currentDestination;
|
||||
}
|
||||
gl.disable( gl.BLEND );
|
||||
|
||||
//glow
|
||||
if(this.isOutputConnected(1))
|
||||
{
|
||||
var glow_texture = this._glow_texture;
|
||||
if(!glow_texture || glow_texture.width != tex.width || glow_texture.height != tex.height || glow_texture.type != type || glow_texture.format != tex.format )
|
||||
glow_texture = this._glow_texture = new GL.Texture( tex.width, tex.height, { type: type, format: tex.format, filter: gl.LINEAR });
|
||||
currentSource.blit( glow_texture );
|
||||
this.setOutputData( 1, glow_texture);
|
||||
}
|
||||
|
||||
//final composition
|
||||
if(this.isOutputConnected(0))
|
||||
{
|
||||
var final_texture = this._final_texture;
|
||||
if(!final_texture || final_texture.width != tex.width || final_texture.height != tex.height || final_texture.type != type || final_texture.format != tex.format )
|
||||
final_texture = this._final_texture = new GL.Texture( tex.width, tex.height, { type: type, format: tex.format, filter: gl.LINEAR });
|
||||
|
||||
var dirt_texture = this.getInputData(1);
|
||||
var dirt_factor = this.getInputOrProperty("dirt_factor");
|
||||
|
||||
uniforms.u_intensity = intensity;
|
||||
|
||||
shader = dirt_texture ? LGraphTextureGlow._dirt_final_shader : LGraphTextureGlow._final_shader;
|
||||
if(!shader)
|
||||
{
|
||||
if(dirt_texture)
|
||||
shader = LGraphTextureGlow._dirt_final_shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureGlow.final_pixel_shader, { USE_DIRT: "" } );
|
||||
else
|
||||
shader = LGraphTextureGlow._final_shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureGlow.final_pixel_shader );
|
||||
}
|
||||
|
||||
final_texture.drawTo( function(){
|
||||
tex.bind(0);
|
||||
currentSource.bind(1);
|
||||
if(dirt_texture)
|
||||
{
|
||||
shader.setUniform( "u_dirt_factor", dirt_factor );
|
||||
shader.setUniform( "u_dirt_texture", dirt_texture.bind(2) );
|
||||
}
|
||||
shader.toViewport( uniforms );
|
||||
});
|
||||
this.setOutputData( 0, final_texture );
|
||||
}
|
||||
|
||||
GL.Texture.releaseTemporary( currentSource );
|
||||
}
|
||||
|
||||
LGraphTextureGlow.cut_pixel_shader = "precision highp float;\n\
|
||||
varying vec2 v_coord;\n\
|
||||
uniform sampler2D u_texture;\n\
|
||||
uniform float u_threshold;\n\
|
||||
void main() {\n\
|
||||
gl_FragColor = max( texture2D( u_texture, v_coord ) - vec4( u_threshold ), vec4(0.0) );\n\
|
||||
}"
|
||||
|
||||
LGraphTextureGlow.scale_pixel_shader = "precision highp float;\n\
|
||||
varying vec2 v_coord;\n\
|
||||
uniform sampler2D u_texture;\n\
|
||||
uniform vec2 u_texel_size;\n\
|
||||
uniform float u_delta;\n\
|
||||
uniform float u_intensity;\n\
|
||||
\n\
|
||||
vec4 sampleBox(vec2 uv) {\n\
|
||||
vec4 o = u_texel_size.xyxy * vec2(-u_delta, u_delta).xxyy;\n\
|
||||
vec4 s = texture2D( u_texture, uv + o.xy ) + texture2D( u_texture, uv + o.zy) + texture2D( u_texture, uv + o.xw) + texture2D( u_texture, uv + o.zw);\n\
|
||||
return s * 0.25;\n\
|
||||
}\n\
|
||||
void main() {\n\
|
||||
gl_FragColor = u_intensity * sampleBox( v_coord );\n\
|
||||
}"
|
||||
|
||||
LGraphTextureGlow.final_pixel_shader = "precision highp float;\n\
|
||||
varying vec2 v_coord;\n\
|
||||
uniform sampler2D u_texture;\n\
|
||||
uniform sampler2D u_glow_texture;\n\
|
||||
#ifdef USE_DIRT\n\
|
||||
uniform sampler2D u_dirt_texture;\n\
|
||||
#endif\n\
|
||||
uniform vec2 u_texel_size;\n\
|
||||
uniform float u_delta;\n\
|
||||
uniform float u_intensity;\n\
|
||||
uniform float u_dirt_factor;\n\
|
||||
\n\
|
||||
vec4 sampleBox(vec2 uv) {\n\
|
||||
vec4 o = u_texel_size.xyxy * vec2(-u_delta, u_delta).xxyy;\n\
|
||||
vec4 s = texture2D( u_glow_texture, uv + o.xy ) + texture2D( u_glow_texture, uv + o.zy) + texture2D( u_glow_texture, uv + o.xw) + texture2D( u_glow_texture, uv + o.zw);\n\
|
||||
return s * 0.25;\n\
|
||||
}\n\
|
||||
void main() {\n\
|
||||
vec4 glow = sampleBox( v_coord );\n\
|
||||
#ifdef USE_DIRT\n\
|
||||
glow = mix( glow, glow * texture2D( u_dirt_texture, v_coord ), u_dirt_factor );\n\
|
||||
#endif\n\
|
||||
gl_FragColor = texture2D( u_texture, v_coord ) + u_intensity * glow;\n\
|
||||
}"
|
||||
|
||||
LiteGraph.registerNodeType("texture/glow", LGraphTextureGlow );
|
||||
|
||||
|
||||
// Texture Blur *****************************************
|
||||
function LGraphTextureKuwaharaFilter()
|
||||
{
|
||||
@@ -2268,12 +2538,18 @@ LGraphTextureKuwaharaFilter.pixel_shader = "\n\
|
||||
|
||||
LGraphTextureWebcam.prototype.onRemoved = function()
|
||||
{
|
||||
if(this._webcam_stream)
|
||||
if(!this._webcam_stream)
|
||||
return;
|
||||
|
||||
var video_streams = this._webcam_stream.getVideoTracks();
|
||||
if(video_streams.length)
|
||||
{
|
||||
this._webcam_stream.stop();
|
||||
this._webcam_stream = null;
|
||||
this._video = null;
|
||||
var webcam = video_streams[0];
|
||||
webcam.stop();
|
||||
}
|
||||
|
||||
this._webcam_stream = null;
|
||||
this._video = null;
|
||||
}
|
||||
|
||||
LGraphTextureWebcam.prototype.onDrawBackground = function(ctx)
|
||||
@@ -2329,15 +2605,424 @@ LGraphTextureKuwaharaFilter.pixel_shader = "\n\
|
||||
LiteGraph.registerNodeType("texture/webcam", LGraphTextureWebcam );
|
||||
|
||||
|
||||
|
||||
//from https://github.com/spite/Wagner
|
||||
function LGraphLensFX()
|
||||
{
|
||||
this.addInput("in","Texture");
|
||||
this.addInput("f","number");
|
||||
this.addOutput("out","Texture");
|
||||
this.properties = { factor: 1, precision: LGraphTexture.LOW };
|
||||
|
||||
this._uniforms = { u_texture: 0, u_factor: 1 };
|
||||
}
|
||||
|
||||
LGraphLensFX.title = "Lens FX";
|
||||
LGraphLensFX.desc = "distortion and chromatic aberration";
|
||||
|
||||
LGraphLensFX.widgets_info = {
|
||||
"precision": { widget:"combo", values: LGraphTexture.MODE_VALUES }
|
||||
};
|
||||
|
||||
LGraphLensFX.prototype.onExecute = function()
|
||||
{
|
||||
var tex = this.getInputData(0);
|
||||
if(!tex)
|
||||
return;
|
||||
|
||||
if(!this.isOutputConnected(0))
|
||||
return; //saves work
|
||||
|
||||
var temp = this._temp_texture;
|
||||
if(!temp || temp.width != tex.width || temp.height != tex.height || temp.type != tex.type )
|
||||
temp = this._temp_texture = new GL.Texture( tex.width, tex.height, { type: tex.type, format: gl.RGBA, filter: gl.LINEAR });
|
||||
|
||||
var shader = LGraphLensFX._shader;
|
||||
if(!shader)
|
||||
shader = LGraphLensFX._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphLensFX.pixel_shader );
|
||||
|
||||
var factor = this.getInputData(1);
|
||||
if(factor == null)
|
||||
factor = this.properties.factor;
|
||||
|
||||
var uniforms = this._uniforms;
|
||||
uniforms.u_factor = factor;
|
||||
|
||||
//apply shader
|
||||
gl.disable( gl.DEPTH_TEST );
|
||||
temp.drawTo(function(){
|
||||
tex.bind(0);
|
||||
shader.uniforms(uniforms).draw( GL.Mesh.getScreenQuad() );
|
||||
});
|
||||
|
||||
this.setOutputData(0,temp);
|
||||
}
|
||||
|
||||
LGraphLensFX.pixel_shader = "precision highp float;\n\
|
||||
varying vec2 v_coord;\n\
|
||||
uniform sampler2D u_texture;\n\
|
||||
uniform float u_factor;\n\
|
||||
vec2 barrelDistortion(vec2 coord, float amt) {\n\
|
||||
vec2 cc = coord - 0.5;\n\
|
||||
float dist = dot(cc, cc);\n\
|
||||
return coord + cc * dist * amt;\n\
|
||||
}\n\
|
||||
\n\
|
||||
float sat( float t )\n\
|
||||
{\n\
|
||||
return clamp( t, 0.0, 1.0 );\n\
|
||||
}\n\
|
||||
\n\
|
||||
float linterp( float t ) {\n\
|
||||
return sat( 1.0 - abs( 2.0*t - 1.0 ) );\n\
|
||||
}\n\
|
||||
\n\
|
||||
float remap( float t, float a, float b ) {\n\
|
||||
return sat( (t - a) / (b - a) );\n\
|
||||
}\n\
|
||||
\n\
|
||||
vec4 spectrum_offset( float t ) {\n\
|
||||
vec4 ret;\n\
|
||||
float lo = step(t,0.5);\n\
|
||||
float hi = 1.0-lo;\n\
|
||||
float w = linterp( remap( t, 1.0/6.0, 5.0/6.0 ) );\n\
|
||||
ret = vec4(lo,1.0,hi, 1.) * vec4(1.0-w, w, 1.0-w, 1.);\n\
|
||||
\n\
|
||||
return pow( ret, vec4(1.0/2.2) );\n\
|
||||
}\n\
|
||||
\n\
|
||||
const float max_distort = 2.2;\n\
|
||||
const int num_iter = 12;\n\
|
||||
const float reci_num_iter_f = 1.0 / float(num_iter);\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{ \n\
|
||||
vec2 uv=v_coord;\n\
|
||||
vec4 sumcol = vec4(0.0);\n\
|
||||
vec4 sumw = vec4(0.0); \n\
|
||||
for ( int i=0; i<num_iter;++i )\n\
|
||||
{\n\
|
||||
float t = float(i) * reci_num_iter_f;\n\
|
||||
vec4 w = spectrum_offset( t );\n\
|
||||
sumw += w;\n\
|
||||
sumcol += w * texture2D( u_texture, barrelDistortion(uv, .6 * max_distort*t * u_factor ) );\n\
|
||||
}\n\
|
||||
gl_FragColor = sumcol / sumw;\n\
|
||||
}";
|
||||
|
||||
LiteGraph.registerNodeType("texture/lensfx", LGraphLensFX );
|
||||
|
||||
|
||||
//simple exposition, but plan to expand it to support different gamma curves
|
||||
function LGraphExposition()
|
||||
{
|
||||
this.addInput("in","Texture");
|
||||
this.addInput("exp","number");
|
||||
this.addOutput("out","Texture");
|
||||
this.properties = { exposition: 1, precision: LGraphTexture.LOW };
|
||||
this._uniforms = { u_texture: 0, u_exposition: exp };
|
||||
}
|
||||
|
||||
LGraphExposition.title = "Exposition";
|
||||
LGraphExposition.desc = "Controls texture exposition";
|
||||
|
||||
LGraphExposition.widgets_info = {
|
||||
"exposition": { widget:"slider", min:0,max:3 },
|
||||
"precision": { widget:"combo", values: LGraphTexture.MODE_VALUES }
|
||||
};
|
||||
|
||||
LGraphExposition.prototype.onExecute = function()
|
||||
{
|
||||
var tex = this.getInputData(0);
|
||||
if(!tex)
|
||||
return;
|
||||
|
||||
if(!this.isOutputConnected(0))
|
||||
return; //saves work
|
||||
|
||||
var temp = this._temp_texture;
|
||||
if(!temp || temp.width != tex.width || temp.height != tex.height || temp.type != tex.type )
|
||||
temp = this._temp_texture = new GL.Texture( tex.width, tex.height, { type: tex.type, format: gl.RGBA, filter: gl.LINEAR });
|
||||
|
||||
var shader = LGraphExposition._shader;
|
||||
if(!shader)
|
||||
shader = LGraphExposition._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphExposition.pixel_shader );
|
||||
|
||||
var exp = this.properties.exposition;
|
||||
var exp_input = this.getInputData(1);
|
||||
if(exp_input != null)
|
||||
exp = this.properties.exposition = exp_input;
|
||||
var uniforms = this._uniforms;
|
||||
|
||||
//apply shader
|
||||
temp.drawTo(function(){
|
||||
gl.disable( gl.DEPTH_TEST );
|
||||
tex.bind(0);
|
||||
shader.uniforms(uniforms).draw(GL.Mesh.getScreenQuad());
|
||||
});
|
||||
|
||||
this.setOutputData(0,temp);
|
||||
}
|
||||
|
||||
LGraphExposition.pixel_shader = "precision highp float;\n\
|
||||
varying vec2 v_coord;\n\
|
||||
uniform sampler2D u_texture;\n\
|
||||
uniform float u_exposition;\n\
|
||||
\n\
|
||||
void main() {\n\
|
||||
vec4 color = texture2D( u_texture, v_coord );\n\
|
||||
gl_FragColor = vec4( color.xyz * u_exposition, color.a );\n\
|
||||
}";
|
||||
|
||||
LiteGraph.registerNodeType("texture/exposition", LGraphExposition );
|
||||
|
||||
|
||||
|
||||
function LGraphToneMapping()
|
||||
{
|
||||
this.addInput("in","Texture");
|
||||
this.addInput("avg","number");
|
||||
this.addOutput("out","Texture");
|
||||
this.properties = { scale:1, gamma: 1, average_lum: 1, lum_white: 1, precision: LGraphTexture.LOW };
|
||||
|
||||
this._uniforms = {
|
||||
u_texture: 0,
|
||||
u_lumwhite2: 1,
|
||||
u_igamma: 1,
|
||||
u_scale: 1,
|
||||
u_average_lum: 1
|
||||
};
|
||||
}
|
||||
|
||||
LGraphToneMapping.title = "Tone Mapping";
|
||||
LGraphToneMapping.desc = "Applies Tone Mapping to convert from high to low";
|
||||
|
||||
LGraphToneMapping.widgets_info = {
|
||||
"precision": { widget:"combo", values: LGraphTexture.MODE_VALUES }
|
||||
};
|
||||
|
||||
LGraphToneMapping.prototype.onGetInputs = function() {
|
||||
return [["enabled","boolean"]];
|
||||
}
|
||||
|
||||
LGraphToneMapping.prototype.onExecute = function()
|
||||
{
|
||||
var tex = this.getInputData(0);
|
||||
if(!tex)
|
||||
return;
|
||||
|
||||
if(!this.isOutputConnected(0))
|
||||
return; //saves work
|
||||
|
||||
if(this.properties.precision === LGraphTexture.PASS_THROUGH || this.getInputDataByName("enabled" ) === false )
|
||||
{
|
||||
this.setOutputData(0, tex );
|
||||
return;
|
||||
}
|
||||
|
||||
var temp = this._temp_texture;
|
||||
|
||||
if(!temp || temp.width != tex.width || temp.height != tex.height || temp.type != tex.type )
|
||||
temp = this._temp_texture = new GL.Texture( tex.width, tex.height, { type: tex.type, format: gl.RGBA, filter: gl.LINEAR });
|
||||
|
||||
//apply shader
|
||||
var shader = LGraphToneMapping._shader;
|
||||
if(!shader)
|
||||
shader = LGraphToneMapping._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphToneMapping.pixel_shader );
|
||||
|
||||
var avg = this.getInputData(1);
|
||||
if(avg != null)
|
||||
this.properties.average_lum = avg;
|
||||
|
||||
var uniforms = this._uniforms;
|
||||
uniforms.u_lumwhite2 = this.properties.lum_white * this.properties.lum_white;
|
||||
uniforms.u_scale = this.properties.scale;
|
||||
uniforms.u_average_lum = this.properties.average_lum;
|
||||
uniforms.u_igamma = 1/this.properties.gamma;
|
||||
|
||||
//apply shader
|
||||
gl.disable( gl.DEPTH_TEST );
|
||||
temp.drawTo(function(){
|
||||
tex.bind(0);
|
||||
shader.uniforms(uniforms).draw( GL.Mesh.getScreenQuad() );
|
||||
});
|
||||
|
||||
this.setOutputData(0,this._temp_texture);
|
||||
}
|
||||
|
||||
LGraphToneMapping.pixel_shader = "precision highp float;\n\
|
||||
varying vec2 v_coord;\n\
|
||||
uniform sampler2D u_texture;\n\
|
||||
uniform float u_scale;\n\
|
||||
uniform float u_average_lum;\n\
|
||||
uniform float u_lumwhite2;\n\
|
||||
uniform float u_igamma;\n\
|
||||
vec3 RGB2xyY (vec3 rgb)\n\
|
||||
{\n\
|
||||
const mat3 RGB2XYZ = mat3(0.4124, 0.3576, 0.1805,\n\
|
||||
0.2126, 0.7152, 0.0722,\n\
|
||||
0.0193, 0.1192, 0.9505);\n\
|
||||
vec3 XYZ = RGB2XYZ * rgb;\n\
|
||||
\n\
|
||||
float f = (XYZ.x + XYZ.y + XYZ.z);\n\
|
||||
return vec3(XYZ.x / f,\n\
|
||||
XYZ.y / f,\n\
|
||||
XYZ.y);\n\
|
||||
}\n\
|
||||
\n\
|
||||
void main() {\n\
|
||||
vec4 color = texture2D( u_texture, v_coord );\n\
|
||||
vec3 rgb = color.xyz;\n\
|
||||
//Ld - this part of the code is the same for both versions\n\
|
||||
float lum = dot(rgb, vec3(0.2126, 0.7152, 0.0722));\n\
|
||||
float L = (u_scale / u_average_lum) * lum;\n\
|
||||
float Ld = (L * (1.0 + L / u_lumwhite2)) / (1.0 + L);\n\
|
||||
//first\n\
|
||||
//vec3 xyY = RGB2xyY(rgb);\n\
|
||||
//xyY.z *= Ld;\n\
|
||||
//rgb = xyYtoRGB(xyY);\n\
|
||||
//second\n\
|
||||
rgb = (rgb / lum) * Ld;\n\
|
||||
rgb = pow( rgb, vec3( u_igamma ) );\n\
|
||||
gl_FragColor = vec4( rgb, color.a );\n\
|
||||
}";
|
||||
|
||||
|
||||
LiteGraph.registerNodeType("texture/tonemapping", LGraphToneMapping );
|
||||
|
||||
|
||||
function LGraphTexturePerlin()
|
||||
{
|
||||
this.addOutput("out","Texture");
|
||||
this.properties = { width: 512, height: 512, seed:0, persistence: 0.1, octaves: 8, scale: 1, offset: [0,0], amplitude: 1, precision: LGraphTexture.DEFAULT };
|
||||
this._key = 0;
|
||||
this._uniforms = { u_persistence: 0.1, u_seed: 0, u_offset: vec2.create(), u_scale: 1, u_viewport: vec2.create() };
|
||||
}
|
||||
|
||||
LGraphTexturePerlin.title = "Perlin";
|
||||
LGraphTexturePerlin.desc = "Generates a perlin noise texture";
|
||||
|
||||
LGraphTexturePerlin.widgets_info = {
|
||||
precision: { widget:"combo", values: LGraphTexture.MODE_VALUES },
|
||||
width: { type: "Number", precision: 0, step: 1 },
|
||||
height: { type: "Number", precision: 0, step: 1 },
|
||||
octaves: { type: "Number", precision: 0, step: 1, min: 1, max: 50 }
|
||||
};
|
||||
|
||||
LGraphTexturePerlin.prototype.onExecute = function()
|
||||
{
|
||||
if(!this.isOutputConnected(0))
|
||||
return; //saves work
|
||||
|
||||
var w = this.properties.width|0;
|
||||
var h = this.properties.height|0;
|
||||
if(w == 0) w = gl.viewport_data[2]; //0 means default
|
||||
if(h == 0) h = gl.viewport_data[3]; //0 means default
|
||||
var type = LGraphTexture.getTextureType( this.properties.precision );
|
||||
|
||||
var temp = this._temp_texture;
|
||||
if(!temp || temp.width != w || temp.height != h || temp.type != type )
|
||||
temp = this._temp_texture = new GL.Texture( w, h, { type: type, format: gl.RGB, filter: gl.LINEAR });
|
||||
|
||||
//reusing old
|
||||
var key = w + h + type + this.properties.persistence + this.properties.octaves + this.properties.scale + this.properties.seed + this.properties.offset[0] + this.properties.offset[1] + this.properties.amplitude;
|
||||
if(key == this._key)
|
||||
{
|
||||
this.setOutputData( 0, temp );
|
||||
return;
|
||||
}
|
||||
this._key = key;
|
||||
|
||||
//gather uniforms
|
||||
var uniforms = this._uniforms;
|
||||
uniforms.u_persistence = this.properties.persistence;
|
||||
uniforms.u_octaves = this.properties.octaves;
|
||||
uniforms.u_offset[0] = this.properties.offset[0];
|
||||
uniforms.u_offset[1] = this.properties.offset[1];
|
||||
uniforms.u_scale = this.properties.scale;
|
||||
uniforms.u_amplitude = this.properties.amplitude;
|
||||
uniforms.u_viewport[0] = w;
|
||||
uniforms.u_viewport[1] = h;
|
||||
uniforms.u_seed = this.properties.seed * 128;
|
||||
|
||||
//render
|
||||
var shader = LGraphTexturePerlin._shader;
|
||||
if(!shader)
|
||||
shader = LGraphTexturePerlin._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTexturePerlin.pixel_shader );
|
||||
|
||||
gl.disable( gl.BLEND );
|
||||
gl.disable( gl.DEPTH_TEST );
|
||||
|
||||
temp.drawTo( function() {
|
||||
shader.uniforms( uniforms ).draw( GL.Mesh.getScreenQuad() );
|
||||
});
|
||||
|
||||
this.setOutputData( 0, temp );
|
||||
}
|
||||
|
||||
LGraphTexturePerlin.pixel_shader = "precision highp float;\n\
|
||||
varying vec2 v_coord;\n\
|
||||
uniform vec2 u_offset;\n\
|
||||
uniform float u_scale;\n\
|
||||
uniform float u_persistence;\n\
|
||||
uniform int u_octaves;\n\
|
||||
uniform float u_amplitude;\n\
|
||||
uniform vec2 u_viewport;\n\
|
||||
uniform float u_seed;\n\
|
||||
#define M_PI 3.14159265358979323846\n\
|
||||
\n\
|
||||
float rand(vec2 c){ return fract(sin(dot(c.xy ,vec2( 12.9898 + u_seed,78.233 + u_seed))) * 43758.5453); }\n\
|
||||
\n\
|
||||
float noise(vec2 p, float freq ){\n\
|
||||
float unit = u_viewport.x/freq;\n\
|
||||
vec2 ij = floor(p/unit);\n\
|
||||
vec2 xy = mod(p,unit)/unit;\n\
|
||||
//xy = 3.*xy*xy-2.*xy*xy*xy;\n\
|
||||
xy = .5*(1.-cos(M_PI*xy));\n\
|
||||
float a = rand((ij+vec2(0.,0.)));\n\
|
||||
float b = rand((ij+vec2(1.,0.)));\n\
|
||||
float c = rand((ij+vec2(0.,1.)));\n\
|
||||
float d = rand((ij+vec2(1.,1.)));\n\
|
||||
float x1 = mix(a, b, xy.x);\n\
|
||||
float x2 = mix(c, d, xy.x);\n\
|
||||
return mix(x1, x2, xy.y);\n\
|
||||
}\n\
|
||||
\n\
|
||||
float pNoise(vec2 p, int res){\n\
|
||||
float persistance = u_persistence;\n\
|
||||
float n = 0.;\n\
|
||||
float normK = 0.;\n\
|
||||
float f = 4.;\n\
|
||||
float amp = 1.0;\n\
|
||||
int iCount = 0;\n\
|
||||
for (int i = 0; i<50; i++){\n\
|
||||
n+=amp*noise(p, f);\n\
|
||||
f*=2.;\n\
|
||||
normK+=amp;\n\
|
||||
amp*=persistance;\n\
|
||||
if (iCount >= res)\n\
|
||||
break;\n\
|
||||
iCount++;\n\
|
||||
}\n\
|
||||
float nf = n/normK;\n\
|
||||
return nf*nf*nf*nf;\n\
|
||||
}\n\
|
||||
void main() {\n\
|
||||
vec2 uv = v_coord * u_scale * u_viewport + u_offset * u_scale;\n\
|
||||
vec4 color = vec4( pNoise( uv, u_octaves ) * u_amplitude );\n\
|
||||
gl_FragColor = color;\n\
|
||||
}";
|
||||
|
||||
LiteGraph.registerNodeType("texture/perlin", LGraphTexturePerlin );
|
||||
|
||||
|
||||
|
||||
function LGraphTextureMatte()
|
||||
{
|
||||
this.addInput("in","Texture");
|
||||
|
||||
this.addOutput("out","Texture");
|
||||
this.properties = { key_color: vec3.fromValues(0.,1.,0.), threshold: 0.8, slope: 0.2, precision: LGraphTexture.DEFAULT };
|
||||
|
||||
if(!LGraphTextureMatte._shader)
|
||||
LGraphTextureMatte._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureMatte.pixel_shader );
|
||||
}
|
||||
|
||||
LGraphTextureMatte.title = "Matte";
|
||||
@@ -2375,6 +3060,8 @@ LGraphTextureKuwaharaFilter.pixel_shader = "\n\
|
||||
|
||||
var mesh = Mesh.getScreenQuad();
|
||||
var shader = LGraphTextureMatte._shader;
|
||||
if(!shader)
|
||||
shader = LGraphTextureMatte._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphTextureMatte.pixel_shader );
|
||||
|
||||
uniforms.u_key_color = this.properties.key_color;
|
||||
uniforms.u_threshold = this.properties.threshold;
|
||||
@@ -2405,6 +3092,7 @@ LGraphTextureKuwaharaFilter.pixel_shader = "\n\
|
||||
|
||||
LiteGraph.registerNodeType("texture/matte", LGraphTextureMatte );
|
||||
|
||||
|
||||
//***********************************
|
||||
//Cubemap reader (to pass a cubemap to a node that requires cubemaps and no images)
|
||||
function LGraphCubemap()
|
||||
|
||||
@@ -1,9 +1,80 @@
|
||||
(function(global){
|
||||
var LiteGraph = global.LiteGraph;
|
||||
|
||||
function GraphicsPlot()
|
||||
{
|
||||
this.addInput("A","Number");
|
||||
this.addInput("B","Number");
|
||||
this.addInput("C","Number");
|
||||
this.addInput("D","Number");
|
||||
|
||||
this.values = [[],[],[],[]];
|
||||
this.properties = { scale: 2 };
|
||||
}
|
||||
|
||||
GraphicsPlot.title = "Plot";
|
||||
GraphicsPlot.desc = "Plots data over time";
|
||||
GraphicsPlot.colors = ["#FFF","#F99","#9F9","#99F"];
|
||||
|
||||
GraphicsPlot.prototype.onExecute = function(ctx)
|
||||
{
|
||||
if(this.flags.collapsed)
|
||||
return;
|
||||
|
||||
var size = this.size;
|
||||
|
||||
for(var i = 0; i < 4; ++i)
|
||||
{
|
||||
var v = this.getInputData(i);
|
||||
if(v == null)
|
||||
continue;
|
||||
var values = this.values[i];
|
||||
values.push(v);
|
||||
if(values.length > size[0])
|
||||
values.shift();
|
||||
}
|
||||
}
|
||||
|
||||
GraphicsPlot.prototype.onDrawBackground = function(ctx)
|
||||
{
|
||||
if(this.flags.collapsed)
|
||||
return;
|
||||
|
||||
var size = this.size;
|
||||
|
||||
var scale = 0.5 * size[1] / this.properties.scale;
|
||||
var colors = GraphicsPlot.colors;
|
||||
var offset = size[1] * 0.5;
|
||||
|
||||
ctx.fillStyle = "#000";
|
||||
ctx.fillRect(0,0, size[0],size[1]);
|
||||
ctx.strokeStyle = "#555";
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, offset);
|
||||
ctx.lineTo(size[0], offset);
|
||||
ctx.stroke();
|
||||
|
||||
for(var i = 0; i < 4; ++i)
|
||||
{
|
||||
var values = this.values[i];
|
||||
ctx.strokeStyle = colors[i];
|
||||
ctx.beginPath();
|
||||
var v = values[0] * scale * -1 + offset;
|
||||
ctx.moveTo(0, Math.clamp( v, 0, size[1]) );
|
||||
for(var j = 1; j < values.length && j < size[0]; ++j)
|
||||
{
|
||||
var v = values[j] * scale * -1 + offset;
|
||||
ctx.lineTo( j, Math.clamp( v, 0, size[1]) );
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("graphics/plot", GraphicsPlot);
|
||||
|
||||
|
||||
function GraphicsImage()
|
||||
{
|
||||
this.inputs = [];
|
||||
this.addOutput("frame","image");
|
||||
this.properties = {"url":""};
|
||||
}
|
||||
|
||||
@@ -59,6 +59,63 @@ var LiteGraph = global.LiteGraph;
|
||||
|
||||
LiteGraph.registerNodeType("widget/button", WidgetButton );
|
||||
|
||||
|
||||
function WidgetToggle()
|
||||
{
|
||||
this.addInput( "", "boolean" );
|
||||
this.addOutput( "v", "boolean" );
|
||||
this.addOutput( "e", LiteGraph.EVENT );
|
||||
this.properties = { font: "", value: false };
|
||||
this.size = [124,64];
|
||||
}
|
||||
|
||||
WidgetToggle.title = "Toggle";
|
||||
WidgetToggle.desc = "Toggles between true or false";
|
||||
|
||||
WidgetToggle.prototype.onDrawForeground = function(ctx)
|
||||
{
|
||||
if(this.flags.collapsed)
|
||||
return;
|
||||
|
||||
var size = this.size[1] * 0.5;
|
||||
var margin = 0.25;
|
||||
var h = this.size[1] * 0.8;
|
||||
|
||||
ctx.fillStyle = "#AAA";
|
||||
ctx.fillRect(10, h - size,size,size);
|
||||
|
||||
ctx.fillStyle = this.properties.value ? "#AEF" : "#000";
|
||||
ctx.fillRect(10+size*margin,h - size + size*margin,size*(1-margin*2),size*(1-margin*2));
|
||||
|
||||
ctx.textAlign = "left";
|
||||
ctx.font = this.properties.font || ((size * 0.8).toFixed(0) + "px Arial");
|
||||
ctx.fillStyle = "#AAA";
|
||||
ctx.fillText( this.title, size + 20, h * 0.85 );
|
||||
ctx.textAlign = "left";
|
||||
}
|
||||
|
||||
WidgetToggle.prototype.onExecute = function()
|
||||
{
|
||||
var v = this.getInputData(0);
|
||||
if( v != null )
|
||||
this.properties.value = v;
|
||||
this.setOutputData( 0, this.properties.value );
|
||||
}
|
||||
|
||||
WidgetToggle.prototype.onMouseDown = function(e, local_pos)
|
||||
{
|
||||
if(local_pos[0] > 1 && local_pos[1] > 1 && local_pos[0] < (this.size[0] - 2) && local_pos[1] < (this.size[1] - 2) )
|
||||
{
|
||||
this.properties.value = !this.properties.value;
|
||||
this.trigger( "clicked", this.properties.value );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("widget/toggle", WidgetToggle );
|
||||
|
||||
|
||||
|
||||
/* Knob ****************/
|
||||
|
||||
function WidgetKnob()
|
||||
|
||||
@@ -375,7 +375,7 @@ MathScale.prototype.onExecute = function()
|
||||
LiteGraph.registerNodeType("math/scale", MathScale );
|
||||
|
||||
|
||||
//Math clamp
|
||||
//Math Average
|
||||
function MathAverageFilter()
|
||||
{
|
||||
this.addInput("in","number");
|
||||
@@ -426,6 +426,35 @@ MathAverageFilter.prototype.onPropertyChanged = function( name, value )
|
||||
LiteGraph.registerNodeType("math/average", MathAverageFilter );
|
||||
|
||||
|
||||
//Math
|
||||
function MathTendTo()
|
||||
{
|
||||
this.addInput("in","number");
|
||||
this.addOutput("out","number");
|
||||
this.addProperty( "factor", 0.1 );
|
||||
this.size = [60,20];
|
||||
this._value = null;
|
||||
}
|
||||
|
||||
MathTendTo.title = "TendTo";
|
||||
MathTendTo.desc = "moves the output value always closer to the input";
|
||||
|
||||
MathTendTo.prototype.onExecute = function()
|
||||
{
|
||||
var v = this.getInputData(0);
|
||||
if(v == null)
|
||||
v = 0;
|
||||
var f = this.properties.factor;
|
||||
if(this._value == null)
|
||||
this._value = v;
|
||||
else
|
||||
this._value = this._value * (1 - f) + v * f;
|
||||
this.setOutputData( 0, this._value );
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("math/tendTo", MathTendTo );
|
||||
|
||||
|
||||
//Math operation
|
||||
function MathOperation()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user