diff --git a/build/litegraph.js b/build/litegraph.js
index 28ef3f779..73259e77c 100644
--- a/build/litegraph.js
+++ b/build/litegraph.js
@@ -1,3 +1,5 @@
+//packer version
+
(function(global) {
// *************************************************************
// LiteGraph CLASS *******
@@ -1476,14 +1478,7 @@
for (var i in this.links) {
//links is an OBJECT
var link = this.links[i];
- links.push([
- link.id,
- link.origin_id,
- link.origin_slot,
- link.target_id,
- link.target_slot,
- link.type
- ]);
+ links.push(link.serialize());
}
var groups_info = [];
@@ -1636,11 +1631,11 @@
LLink.prototype.serialize = function() {
return [
this.id,
- this.type,
this.origin_id,
this.origin_slot,
this.target_id,
- this.target_slot
+ this.target_slot,
+ this.type
];
};
@@ -8537,7 +8532,7 @@ LGraphNode.prototype.executeAction = function(action)
slot.output.links.length
)
menu_info.push({ content: "Disconnect Links", slot: slot });
- const _slot = slot.input || slot.output;
+ var _slot = slot.input || slot.output;
menu_info.push(
_slot.locked
? "Cannot remove"
@@ -9186,7 +9181,6 @@ LGraphNode.prototype.executeAction = function(action)
})(this);
if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
-
//basic nodes
(function(global) {
var LiteGraph = global.LiteGraph;
@@ -9928,7 +9922,6 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
LiteGraph.registerNodeType("basic/script", NodeScript);
})(this);
-
//event related nodes
(function(global) {
var LiteGraph = global.LiteGraph;
@@ -10171,7 +10164,7 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
LiteGraph.registerNodeType("events/timer", TimerEvent);
})(this);
-
+
//widgets
(function(global) {
var LiteGraph = global.LiteGraph;
@@ -10874,7 +10867,7 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
LiteGraph.registerNodeType("widget/panel", WidgetPanel);
})(this);
-
+
(function(global) {
var LiteGraph = global.LiteGraph;
@@ -11233,7 +11226,7 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
LiteGraph.registerNodeType("input/gamepad", GamepadInput);
})(this);
-
+
(function(global) {
var LiteGraph = global.LiteGraph;
@@ -12419,7 +12412,495 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
LiteGraph.registerNodeType("math3d/quat-slerp", Math3DQuatSlerp);
} //glMatrix
})(this);
+
+(function(global) {
+ var LiteGraph = global.LiteGraph;
+ 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);
+
+ function Math3DVec3Scale() {
+ this.addInput("in", "vec3");
+ this.addInput("f", "number");
+ this.addOutput("out", "vec3");
+ this.properties = { f: 1 };
+ this._data = new Float32Array(3);
+ }
+
+ Math3DVec3Scale.title = "vec3_scale";
+ Math3DVec3Scale.desc = "scales the components of a vec3";
+
+ Math3DVec3Scale.prototype.onExecute = function() {
+ var v = this.getInputData(0);
+ if (v == null) return;
+ var f = this.getInputData(1);
+ if (f == null) f = this.properties.f;
+
+ var data = this._data;
+ data[0] = v[0] * f;
+ data[1] = v[1] * f;
+ data[2] = v[2] * f;
+ this.setOutputData(0, data);
+ };
+
+ LiteGraph.registerNodeType("math3d/vec3-scale", Math3DVec3Scale);
+
+ function Math3DVec3Length() {
+ this.addInput("in", "vec3");
+ this.addOutput("out", "number");
+ }
+
+ Math3DVec3Length.title = "vec3_length";
+ Math3DVec3Length.desc = "returns the module of a vector";
+
+ Math3DVec3Length.prototype.onExecute = function() {
+ var v = this.getInputData(0);
+ if (v == null) return;
+ var dist = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ this.setOutputData(0, dist);
+ };
+
+ LiteGraph.registerNodeType("math3d/vec3-length", Math3DVec3Length);
+
+ function Math3DVec3Normalize() {
+ this.addInput("in", "vec3");
+ this.addOutput("out", "vec3");
+ this._data = new Float32Array(3);
+ }
+
+ Math3DVec3Normalize.title = "vec3_normalize";
+ Math3DVec3Normalize.desc = "returns the vector normalized";
+
+ Math3DVec3Normalize.prototype.onExecute = function() {
+ var v = this.getInputData(0);
+ if (v == null) return;
+ var dist = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ var data = this._data;
+ data[0] = v[0] / dist;
+ data[1] = v[1] / dist;
+ data[2] = v[2] / dist;
+
+ this.setOutputData(0, data);
+ };
+
+ LiteGraph.registerNodeType("math3d/vec3-normalize", Math3DVec3Normalize);
+
+ function Math3DVec3Lerp() {
+ this.addInput("A", "vec3");
+ this.addInput("B", "vec3");
+ this.addInput("f", "vec3");
+ this.addOutput("out", "vec3");
+ this.properties = { f: 0.5 };
+ this._data = new Float32Array(3);
+ }
+
+ Math3DVec3Lerp.title = "vec3_lerp";
+ Math3DVec3Lerp.desc = "returns the interpolated vector";
+
+ Math3DVec3Lerp.prototype.onExecute = function() {
+ var A = this.getInputData(0);
+ if (A == null) return;
+ var B = this.getInputData(1);
+ if (B == null) return;
+ var f = this.getInputOrProperty("f");
+
+ var data = this._data;
+ data[0] = A[0] * (1 - f) + B[0] * f;
+ data[1] = A[1] * (1 - f) + B[1] * f;
+ data[2] = A[2] * (1 - f) + B[2] * f;
+
+ this.setOutputData(0, data);
+ };
+
+ LiteGraph.registerNodeType("math3d/vec3-lerp", Math3DVec3Lerp);
+
+ function Math3DVec3Dot() {
+ this.addInput("A", "vec3");
+ this.addInput("B", "vec3");
+ this.addOutput("out", "number");
+ }
+
+ Math3DVec3Dot.title = "vec3_dot";
+ Math3DVec3Dot.desc = "returns the dot product";
+
+ Math3DVec3Dot.prototype.onExecute = function() {
+ var A = this.getInputData(0);
+ if (A == null) return;
+ var B = this.getInputData(1);
+ if (B == null) return;
+
+ var dot = A[0] * B[0] + A[1] * B[1] + A[2] * B[2];
+ this.setOutputData(0, dot);
+ };
+
+ LiteGraph.registerNodeType("math3d/vec3-dot", Math3DVec3Dot);
+
+ //if glMatrix is installed...
+ if (global.glMatrix) {
+ function Math3DQuaternion() {
+ this.addOutput("quat", "quat");
+ this.properties = { x: 0, y: 0, z: 0, w: 1, normalize: false };
+ this._value = quat.create();
+ }
+
+ Math3DQuaternion.title = "Quaternion";
+ Math3DQuaternion.desc = "quaternion";
+
+ Math3DQuaternion.prototype.onExecute = function() {
+ this._value[0] = this.getInputOrProperty("x");
+ this._value[1] = this.getInputOrProperty("y");
+ this._value[2] = this.getInputOrProperty("z");
+ this._value[3] = this.getInputOrProperty("w");
+ if (this.properties.normalize)
+ quat.normalize(this._value, this._value);
+ this.setOutputData(0, this._value);
+ };
+
+ Math3DQuaternion.prototype.onGetInputs = function() {
+ return [
+ ["x", "number"],
+ ["y", "number"],
+ ["z", "number"],
+ ["w", "number"]
+ ];
+ };
+
+ LiteGraph.registerNodeType("math3d/quaternion", Math3DQuaternion);
+
+ function Math3DRotation() {
+ this.addInputs([["degrees", "number"], ["axis", "vec3"]]);
+ this.addOutput("quat", "quat");
+ this.properties = { angle: 90.0, axis: vec3.fromValues(0, 1, 0) };
+
+ this._value = quat.create();
+ }
+
+ Math3DRotation.title = "Rotation";
+ Math3DRotation.desc = "quaternion rotation";
+
+ Math3DRotation.prototype.onExecute = function() {
+ var angle = this.getInputData(0);
+ if (angle == null) angle = this.properties.angle;
+ var axis = this.getInputData(1);
+ if (axis == null) axis = this.properties.axis;
+
+ var R = quat.setAxisAngle(this._value, axis, angle * 0.0174532925);
+ this.setOutputData(0, R);
+ };
+
+ LiteGraph.registerNodeType("math3d/rotation", Math3DRotation);
+
+ //Math3D rotate vec3
+ function Math3DRotateVec3() {
+ this.addInputs([["vec3", "vec3"], ["quat", "quat"]]);
+ this.addOutput("result", "vec3");
+ this.properties = { vec: [0, 0, 1] };
+ }
+
+ Math3DRotateVec3.title = "Rot. Vec3";
+ Math3DRotateVec3.desc = "rotate a point";
+
+ Math3DRotateVec3.prototype.onExecute = function() {
+ var vec = this.getInputData(0);
+ if (vec == null) vec = this.properties.vec;
+ var quat = this.getInputData(1);
+ if (quat == null) this.setOutputData(vec);
+ else
+ this.setOutputData(
+ 0,
+ vec3.transformQuat(vec3.create(), vec, quat)
+ );
+ };
+
+ LiteGraph.registerNodeType("math3d/rotate_vec3", Math3DRotateVec3);
+
+ function Math3DMultQuat() {
+ this.addInputs([["A", "quat"], ["B", "quat"]]);
+ this.addOutput("A*B", "quat");
+
+ this._value = quat.create();
+ }
+
+ Math3DMultQuat.title = "Mult. Quat";
+ Math3DMultQuat.desc = "rotate quaternion";
+
+ Math3DMultQuat.prototype.onExecute = function() {
+ var A = this.getInputData(0);
+ if (A == null) return;
+ var B = this.getInputData(1);
+ if (B == null) return;
+
+ var R = quat.multiply(this._value, A, B);
+ this.setOutputData(0, R);
+ };
+
+ LiteGraph.registerNodeType("math3d/mult-quat", Math3DMultQuat);
+
+ function Math3DQuatSlerp() {
+ this.addInputs([
+ ["A", "quat"],
+ ["B", "quat"],
+ ["factor", "number"]
+ ]);
+ this.addOutput("slerp", "quat");
+ this.addProperty("factor", 0.5);
+
+ this._value = quat.create();
+ }
+
+ Math3DQuatSlerp.title = "Quat Slerp";
+ Math3DQuatSlerp.desc = "quaternion spherical interpolation";
+
+ Math3DQuatSlerp.prototype.onExecute = function() {
+ var A = this.getInputData(0);
+ if (A == null) return;
+ var B = this.getInputData(1);
+ if (B == null) return;
+ var factor = this.properties.factor;
+ if (this.getInputData(2) != null) factor = this.getInputData(2);
+
+ var R = quat.slerp(this._value, A, B, factor);
+ this.setOutputData(0, R);
+ };
+
+ LiteGraph.registerNodeType("math3d/quat-slerp", Math3DQuatSlerp);
+ } //glMatrix
+})(this);
+
+//basic nodes
+(function(global) {
+ var LiteGraph = global.LiteGraph;
+
+ function toString(a) {
+ return String(a);
+ }
+
+ LiteGraph.wrapFunctionAsNode("string/toString", compare, ["*"], "String");
+
+ function compare(a, b) {
+ return a == b;
+ }
+
+ LiteGraph.wrapFunctionAsNode(
+ "string/compare",
+ compare,
+ ["String", "String"],
+ "Boolean"
+ );
+
+ function concatenate(a, b) {
+ if (a === undefined) return b;
+ if (b === undefined) return a;
+ return a + b;
+ }
+
+ LiteGraph.wrapFunctionAsNode(
+ "string/concatenate",
+ concatenate,
+ ["String", "String"],
+ "String"
+ );
+
+ function contains(a, b) {
+ if (a === undefined || b === undefined) return false;
+ return a.indexOf(b) != -1;
+ }
+
+ LiteGraph.wrapFunctionAsNode(
+ "string/contains",
+ contains,
+ ["String", "String"],
+ "Boolean"
+ );
+
+ function toUpperCase(a) {
+ if (a != null && a.constructor === String) return a.toUpperCase();
+ return a;
+ }
+
+ LiteGraph.wrapFunctionAsNode(
+ "string/toUpperCase",
+ toUpperCase,
+ ["String"],
+ "String"
+ );
+
+ function split(a, b) {
+ if (a != null && a.constructor === String) return a.split(b || " ");
+ return [a];
+ }
+
+ LiteGraph.wrapFunctionAsNode(
+ "string/split",
+ toUpperCase,
+ ["String", "String"],
+ "Array"
+ );
+
+ function toFixed(a) {
+ if (a != null && a.constructor === Number)
+ return a.toFixed(this.properties.precision);
+ return a;
+ }
+
+ LiteGraph.wrapFunctionAsNode(
+ "string/toFixed",
+ toFixed,
+ ["Number"],
+ "String",
+ { precision: 0 }
+ );
+})(this);
+
(function(global) {
var LiteGraph = global.LiteGraph;
@@ -12498,7 +12979,786 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
LiteGraph.registerNodeType("logic/sequence", Sequence);
})(this);
-
+
+(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();
+
+ if (this.inputs)
+ for (var i = 0; i < 4; ++i) {
+ var values = this.values[i];
+ if (!this.inputs[i] || !this.inputs[i].link) continue;
+ 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.addOutput("frame", "image");
+ this.properties = { url: "" };
+ }
+
+ GraphicsImage.title = "Image";
+ GraphicsImage.desc = "Image loader";
+ GraphicsImage.widgets = [{ name: "load", text: "Load", type: "button" }];
+
+ GraphicsImage.supported_extensions = ["jpg", "jpeg", "png", "gif"];
+
+ GraphicsImage.prototype.onAdded = function() {
+ if (this.properties["url"] != "" && this.img == null) {
+ this.loadImage(this.properties["url"]);
+ }
+ };
+
+ GraphicsImage.prototype.onDrawBackground = function(ctx) {
+ if (this.flags.collapsed) return;
+ if (this.img && this.size[0] > 5 && this.size[1] > 5)
+ ctx.drawImage(this.img, 0, 0, this.size[0], this.size[1]);
+ };
+
+ GraphicsImage.prototype.onExecute = function() {
+ if (!this.img) this.boxcolor = "#000";
+ if (this.img && this.img.width) this.setOutputData(0, this.img);
+ else this.setOutputData(0, null);
+ if (this.img && this.img.dirty) this.img.dirty = false;
+ };
+
+ GraphicsImage.prototype.onPropertyChanged = function(name, value) {
+ this.properties[name] = value;
+ if (name == "url" && value != "") this.loadImage(value);
+
+ return true;
+ };
+
+ GraphicsImage.prototype.loadImage = function(url, callback) {
+ if (url == "") {
+ this.img = null;
+ return;
+ }
+
+ this.img = document.createElement("img");
+
+ if (url.substr(0, 4) == "http" && LiteGraph.proxy)
+ url = LiteGraph.proxy + url.substr(url.indexOf(":") + 3);
+
+ this.img.src = url;
+ this.boxcolor = "#F95";
+ var that = this;
+ this.img.onload = function() {
+ if (callback) callback(this);
+ that.trace(
+ "Image loaded, size: " + that.img.width + "x" + that.img.height
+ );
+ this.dirty = true;
+ that.boxcolor = "#9F9";
+ that.setDirtyCanvas(true);
+ };
+ };
+
+ GraphicsImage.prototype.onWidget = function(e, widget) {
+ if (widget.name == "load") {
+ this.loadImage(this.properties["url"]);
+ }
+ };
+
+ GraphicsImage.prototype.onDropFile = function(file) {
+ var that = this;
+ if (this._url) URL.revokeObjectURL(this._url);
+ this._url = URL.createObjectURL(file);
+ this.properties.url = this._url;
+ this.loadImage(this._url, function(img) {
+ that.size[1] = (img.height / img.width) * that.size[0];
+ });
+ };
+
+ LiteGraph.registerNodeType("graphics/image", GraphicsImage);
+
+ function ColorPalette() {
+ this.addInput("f", "number");
+ this.addOutput("Color", "color");
+ this.properties = {
+ colorA: "#444444",
+ colorB: "#44AAFF",
+ colorC: "#44FFAA",
+ colorD: "#FFFFFF"
+ };
+ }
+
+ ColorPalette.title = "Palette";
+ ColorPalette.desc = "Generates a color";
+
+ ColorPalette.prototype.onExecute = function() {
+ var c = [];
+
+ if (this.properties.colorA != null)
+ c.push(hex2num(this.properties.colorA));
+ if (this.properties.colorB != null)
+ c.push(hex2num(this.properties.colorB));
+ if (this.properties.colorC != null)
+ c.push(hex2num(this.properties.colorC));
+ if (this.properties.colorD != null)
+ c.push(hex2num(this.properties.colorD));
+
+ var f = this.getInputData(0);
+ if (f == null) f = 0.5;
+ if (f > 1.0) f = 1.0;
+ else if (f < 0.0) f = 0.0;
+
+ if (c.length == 0) return;
+
+ var result = [0, 0, 0];
+ if (f == 0) result = c[0];
+ else if (f == 1) result = c[c.length - 1];
+ else {
+ var pos = (c.length - 1) * f;
+ var c1 = c[Math.floor(pos)];
+ var c2 = c[Math.floor(pos) + 1];
+ var t = pos - Math.floor(pos);
+ result[0] = c1[0] * (1 - t) + c2[0] * t;
+ result[1] = c1[1] * (1 - t) + c2[1] * t;
+ result[2] = c1[2] * (1 - t) + c2[2] * t;
+ }
+
+ /*
+ c[0] = 1.0 - Math.abs( Math.sin( 0.1 * reModular.getTime() * Math.PI) );
+ c[1] = Math.abs( Math.sin( 0.07 * reModular.getTime() * Math.PI) );
+ c[2] = Math.abs( Math.sin( 0.01 * reModular.getTime() * Math.PI) );
+ */
+
+ for (var i in result) result[i] /= 255;
+
+ this.boxcolor = colorToString(result);
+ this.setOutputData(0, result);
+ };
+
+ LiteGraph.registerNodeType("color/palette", ColorPalette);
+
+ function ImageFrame() {
+ this.addInput("", "image,canvas");
+ this.size = [200, 200];
+ }
+
+ ImageFrame.title = "Frame";
+ ImageFrame.desc = "Frame viewerew";
+ ImageFrame.widgets = [
+ { name: "resize", text: "Resize box", type: "button" },
+ { name: "view", text: "View Image", type: "button" }
+ ];
+
+ ImageFrame.prototype.onDrawBackground = function(ctx) {
+ if (this.frame && !this.flags.collapsed)
+ ctx.drawImage(this.frame, 0, 0, this.size[0], this.size[1]);
+ };
+
+ ImageFrame.prototype.onExecute = function() {
+ this.frame = this.getInputData(0);
+ this.setDirtyCanvas(true);
+ };
+
+ ImageFrame.prototype.onWidget = function(e, widget) {
+ if (widget.name == "resize" && this.frame) {
+ var width = this.frame.width;
+ var height = this.frame.height;
+
+ if (!width && this.frame.videoWidth != null) {
+ width = this.frame.videoWidth;
+ height = this.frame.videoHeight;
+ }
+
+ if (width && height) this.size = [width, height];
+ this.setDirtyCanvas(true, true);
+ } else if (widget.name == "view") this.show();
+ };
+
+ ImageFrame.prototype.show = function() {
+ //var str = this.canvas.toDataURL("image/png");
+ if (showElement && this.frame) showElement(this.frame);
+ };
+
+ LiteGraph.registerNodeType("graphics/frame", ImageFrame);
+
+ function ImageFade() {
+ this.addInputs([
+ ["img1", "image"],
+ ["img2", "image"],
+ ["fade", "number"]
+ ]);
+ this.addOutput("", "image");
+ this.properties = { fade: 0.5, width: 512, height: 512 };
+ }
+
+ ImageFade.title = "Image fade";
+ ImageFade.desc = "Fades between images";
+ ImageFade.widgets = [
+ { name: "resizeA", text: "Resize to A", type: "button" },
+ { name: "resizeB", text: "Resize to B", type: "button" }
+ ];
+
+ ImageFade.prototype.onAdded = function() {
+ this.createCanvas();
+ var ctx = this.canvas.getContext("2d");
+ ctx.fillStyle = "#000";
+ ctx.fillRect(0, 0, this.properties["width"], this.properties["height"]);
+ };
+
+ ImageFade.prototype.createCanvas = function() {
+ this.canvas = document.createElement("canvas");
+ this.canvas.width = this.properties["width"];
+ this.canvas.height = this.properties["height"];
+ };
+
+ ImageFade.prototype.onExecute = function() {
+ var ctx = this.canvas.getContext("2d");
+ this.canvas.width = this.canvas.width;
+
+ var A = this.getInputData(0);
+ if (A != null) {
+ ctx.drawImage(A, 0, 0, this.canvas.width, this.canvas.height);
+ }
+
+ var fade = this.getInputData(2);
+ if (fade == null) fade = this.properties["fade"];
+ else this.properties["fade"] = fade;
+
+ ctx.globalAlpha = fade;
+ var B = this.getInputData(1);
+ if (B != null) {
+ ctx.drawImage(B, 0, 0, this.canvas.width, this.canvas.height);
+ }
+ ctx.globalAlpha = 1.0;
+
+ this.setOutputData(0, this.canvas);
+ this.setDirtyCanvas(true);
+ };
+
+ LiteGraph.registerNodeType("graphics/imagefade", ImageFade);
+
+ function ImageCrop() {
+ this.addInput("", "image");
+ this.addOutput("", "image");
+ this.properties = { width: 256, height: 256, x: 0, y: 0, scale: 1.0 };
+ this.size = [50, 20];
+ }
+
+ ImageCrop.title = "Crop";
+ ImageCrop.desc = "Crop Image";
+
+ ImageCrop.prototype.onAdded = function() {
+ this.createCanvas();
+ };
+
+ ImageCrop.prototype.createCanvas = function() {
+ this.canvas = document.createElement("canvas");
+ this.canvas.width = this.properties["width"];
+ this.canvas.height = this.properties["height"];
+ };
+
+ ImageCrop.prototype.onExecute = function() {
+ var input = this.getInputData(0);
+ if (!input) return;
+
+ if (input.width) {
+ var ctx = this.canvas.getContext("2d");
+
+ ctx.drawImage(
+ input,
+ -this.properties["x"],
+ -this.properties["y"],
+ input.width * this.properties["scale"],
+ input.height * this.properties["scale"]
+ );
+ this.setOutputData(0, this.canvas);
+ } else this.setOutputData(0, null);
+ };
+
+ ImageCrop.prototype.onDrawBackground = function(ctx) {
+ if (this.flags.collapsed) return;
+ if (this.canvas)
+ ctx.drawImage(
+ this.canvas,
+ 0,
+ 0,
+ this.canvas.width,
+ this.canvas.height,
+ 0,
+ 0,
+ this.size[0],
+ this.size[1]
+ );
+ };
+
+ ImageCrop.prototype.onPropertyChanged = function(name, value) {
+ this.properties[name] = value;
+
+ if (name == "scale") {
+ this.properties[name] = parseFloat(value);
+ if (this.properties[name] == 0) {
+ this.trace("Error in scale");
+ this.properties[name] = 1.0;
+ }
+ } else this.properties[name] = parseInt(value);
+
+ this.createCanvas();
+
+ return true;
+ };
+
+ LiteGraph.registerNodeType("graphics/cropImage", ImageCrop);
+
+ //CANVAS stuff
+
+ function CanvasNode() {
+ this.addInput("clear", LiteGraph.ACTION);
+ this.addOutput("", "canvas");
+ this.properties = { width: 512, height: 512, autoclear: true };
+
+ this.canvas = document.createElement("canvas");
+ this.ctx = this.canvas.getContext("2d");
+ }
+
+ CanvasNode.title = "Canvas";
+ CanvasNode.desc = "Canvas to render stuff";
+
+ CanvasNode.prototype.onExecute = function() {
+ var canvas = this.canvas;
+ var w = this.properties.width | 0;
+ var h = this.properties.height | 0;
+ if (canvas.width != w) canvas.width = w;
+ if (canvas.height != h) canvas.height = h;
+
+ if (this.properties.autoclear)
+ this.ctx.clearRect(0, 0, canvas.width, canvas.height);
+ this.setOutputData(0, canvas);
+ };
+
+ CanvasNode.prototype.onAction = function(action, param) {
+ if (action == "clear")
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+ };
+
+ LiteGraph.registerNodeType("graphics/canvas", CanvasNode);
+
+ function DrawImageNode() {
+ this.addInput("canvas", "canvas");
+ this.addInput("img", "image,canvas");
+ this.addInput("x", "number");
+ this.addInput("y", "number");
+ this.properties = { x: 0, y: 0, opacity: 1 };
+ }
+
+ DrawImageNode.title = "DrawImage";
+ DrawImageNode.desc = "Draws image into a canvas";
+
+ DrawImageNode.prototype.onExecute = function() {
+ var canvas = this.getInputData(0);
+ if (!canvas) return;
+
+ var img = this.getInputOrProperty("img");
+ if (!img) return;
+
+ var x = this.getInputOrProperty("x");
+ var y = this.getInputOrProperty("y");
+ var ctx = canvas.getContext("2d");
+ ctx.drawImage(img, x, y);
+ };
+
+ LiteGraph.registerNodeType("graphics/drawImage", DrawImageNode);
+
+ function DrawRectangleNode() {
+ this.addInput("canvas", "canvas");
+ this.addInput("x", "number");
+ this.addInput("y", "number");
+ this.addInput("w", "number");
+ this.addInput("h", "number");
+ this.properties = {
+ x: 0,
+ y: 0,
+ w: 10,
+ h: 10,
+ color: "white",
+ opacity: 1
+ };
+ }
+
+ DrawRectangleNode.title = "DrawRectangle";
+ DrawRectangleNode.desc = "Draws rectangle in canvas";
+
+ DrawRectangleNode.prototype.onExecute = function() {
+ var canvas = this.getInputData(0);
+ if (!canvas) return;
+
+ var x = this.getInputOrProperty("x");
+ var y = this.getInputOrProperty("y");
+ var w = this.getInputOrProperty("w");
+ var h = this.getInputOrProperty("h");
+ var ctx = canvas.getContext("2d");
+ ctx.fillRect(x, y, w, h);
+ };
+
+ LiteGraph.registerNodeType("graphics/drawRectangle", DrawRectangleNode);
+
+ function ImageVideo() {
+ this.addInput("t", "number");
+ this.addOutputs([["frame", "image"], ["t", "number"], ["d", "number"]]);
+ this.properties = { url: "", use_proxy: true };
+ }
+
+ ImageVideo.title = "Video";
+ ImageVideo.desc = "Video playback";
+ ImageVideo.widgets = [
+ { name: "play", text: "PLAY", type: "minibutton" },
+ { name: "stop", text: "STOP", type: "minibutton" },
+ { name: "demo", text: "Demo video", type: "button" },
+ { name: "mute", text: "Mute video", type: "button" }
+ ];
+
+ ImageVideo.prototype.onExecute = function() {
+ if (!this.properties.url) return;
+
+ if (this.properties.url != this._video_url)
+ this.loadVideo(this.properties.url);
+
+ if (!this._video || this._video.width == 0) return;
+
+ var t = this.getInputData(0);
+ if (t && t >= 0 && t <= 1.0) {
+ this._video.currentTime = t * this._video.duration;
+ this._video.pause();
+ }
+
+ this._video.dirty = true;
+ this.setOutputData(0, this._video);
+ this.setOutputData(1, this._video.currentTime);
+ this.setOutputData(2, this._video.duration);
+ this.setDirtyCanvas(true);
+ };
+
+ ImageVideo.prototype.onStart = function() {
+ this.play();
+ };
+
+ ImageVideo.prototype.onStop = function() {
+ this.stop();
+ };
+
+ ImageVideo.prototype.loadVideo = function(url) {
+ this._video_url = url;
+
+ if (
+ this.properties.use_proxy &&
+ url.substr(0, 4) == "http" &&
+ LiteGraph.proxy
+ )
+ url = LiteGraph.proxy + url.substr(url.indexOf(":") + 3);
+
+ this._video = document.createElement("video");
+ this._video.src = url;
+ this._video.type = "type=video/mp4";
+
+ this._video.muted = true;
+ this._video.autoplay = true;
+
+ var that = this;
+ this._video.addEventListener("loadedmetadata", function(e) {
+ //onload
+ that.trace("Duration: " + this.duration + " seconds");
+ that.trace("Size: " + this.videoWidth + "," + this.videoHeight);
+ that.setDirtyCanvas(true);
+ this.width = this.videoWidth;
+ this.height = this.videoHeight;
+ });
+ this._video.addEventListener("progress", function(e) {
+ //onload
+ //that.trace("loading...");
+ });
+ this._video.addEventListener("error", function(e) {
+ console.log("Error loading video: " + this.src);
+ that.trace("Error loading video: " + this.src);
+ if (this.error) {
+ switch (this.error.code) {
+ case this.error.MEDIA_ERR_ABORTED:
+ that.trace("You stopped the video.");
+ break;
+ case this.error.MEDIA_ERR_NETWORK:
+ that.trace("Network error - please try again later.");
+ break;
+ case this.error.MEDIA_ERR_DECODE:
+ that.trace("Video is broken..");
+ break;
+ case this.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
+ that.trace(
+ "Sorry, your browser can't play this video."
+ );
+ break;
+ }
+ }
+ });
+
+ this._video.addEventListener("ended", function(e) {
+ that.trace("Ended.");
+ this.play(); //loop
+ });
+
+ //document.body.appendChild(this.video);
+ };
+
+ ImageVideo.prototype.onPropertyChanged = function(name, value) {
+ this.properties[name] = value;
+ if (name == "url" && value != "") this.loadVideo(value);
+
+ return true;
+ };
+
+ ImageVideo.prototype.play = function() {
+ if (this._video) this._video.play();
+ };
+
+ ImageVideo.prototype.playPause = function() {
+ if (!this._video) return;
+ if (this._video.paused) this.play();
+ else this.pause();
+ };
+
+ ImageVideo.prototype.stop = function() {
+ if (!this._video) return;
+ this._video.pause();
+ this._video.currentTime = 0;
+ };
+
+ ImageVideo.prototype.pause = function() {
+ if (!this._video) return;
+ this.trace("Video paused");
+ this._video.pause();
+ };
+
+ ImageVideo.prototype.onWidget = function(e, widget) {
+ /*
+ if(widget.name == "demo")
+ {
+ this.loadVideo();
+ }
+ else if(widget.name == "play")
+ {
+ if(this._video)
+ this.playPause();
+ }
+ if(widget.name == "stop")
+ {
+ this.stop();
+ }
+ else if(widget.name == "mute")
+ {
+ if(this._video)
+ this._video.muted = !this._video.muted;
+ }
+ */
+ };
+
+ LiteGraph.registerNodeType("graphics/video", ImageVideo);
+
+ // Texture Webcam *****************************************
+ function ImageWebcam() {
+ this.addOutput("Webcam", "image");
+ this.properties = { facingMode: "user" };
+ this.boxcolor = "black";
+ this.frame = 0;
+ }
+
+ ImageWebcam.title = "Webcam";
+ ImageWebcam.desc = "Webcam image";
+ ImageWebcam.is_webcam_open = false;
+
+ ImageWebcam.prototype.openStream = function() {
+ if (!navigator.getUserMedia) {
+ //console.log('getUserMedia() is not supported in your browser, use chrome and enable WebRTC from about://flags');
+ return;
+ }
+
+ this._waiting_confirmation = true;
+
+ // Not showing vendor prefixes.
+ var constraints = {
+ audio: false,
+ video: { facingMode: this.properties.facingMode }
+ };
+ navigator.mediaDevices
+ .getUserMedia(constraints)
+ .then(this.streamReady.bind(this))
+ .catch(onFailSoHard);
+
+ var that = this;
+ function onFailSoHard(e) {
+ console.log("Webcam rejected", e);
+ that._webcam_stream = false;
+ ImageWebcam.is_webcam_open = false;
+ that.boxcolor = "red";
+ that.trigger("stream_error");
+ }
+ };
+
+ ImageWebcam.prototype.closeStream = function() {
+ if (this._webcam_stream) {
+ var tracks = this._webcam_stream.getTracks();
+ if (tracks.length) {
+ for (var i = 0; i < tracks.length; ++i) tracks[i].stop();
+ }
+ ImageWebcam.is_webcam_open = false;
+ this._webcam_stream = null;
+ this._video = null;
+ this.boxcolor = "black";
+ this.trigger("stream_closed");
+ }
+ };
+
+ ImageWebcam.prototype.onPropertyChanged = function(name, value) {
+ if (name == "facingMode") {
+ this.properties.facingMode = value;
+ this.closeStream();
+ this.openStream();
+ }
+ };
+
+ ImageWebcam.prototype.onRemoved = function() {
+ this.closeStream();
+ };
+
+ ImageWebcam.prototype.streamReady = function(localMediaStream) {
+ this._webcam_stream = localMediaStream;
+ //this._waiting_confirmation = false;
+ this.boxcolor = "green";
+
+ var video = this._video;
+ if (!video) {
+ video = document.createElement("video");
+ video.autoplay = true;
+ video.srcObject = localMediaStream;
+ this._video = video;
+ //document.body.appendChild( video ); //debug
+ //when video info is loaded (size and so)
+ video.onloadedmetadata = function(e) {
+ // Ready to go. Do some stuff.
+ console.log(e);
+ ImageWebcam.is_webcam_open = true;
+ };
+ }
+
+ this.trigger("stream_ready", video);
+ };
+
+ ImageWebcam.prototype.onExecute = function() {
+ if (this._webcam_stream == null && !this._waiting_confirmation)
+ this.openStream();
+
+ if (!this._video || !this._video.videoWidth) return;
+
+ this._video.frame = ++this.frame;
+ this._video.width = this._video.videoWidth;
+ this._video.height = this._video.videoHeight;
+ this.setOutputData(0, this._video);
+ for (var i = 1; i < this.outputs.length; ++i) {
+ if (!this.outputs[i]) continue;
+ switch (this.outputs[i].name) {
+ case "width":
+ this.setOutputData(i, this._video.videoWidth);
+ break;
+ case "height":
+ this.setOutputData(i, this._video.videoHeight);
+ break;
+ }
+ }
+ };
+
+ ImageWebcam.prototype.getExtraMenuOptions = function(graphcanvas) {
+ var that = this;
+ var txt = !that.properties.show ? "Show Frame" : "Hide Frame";
+ return [
+ {
+ content: txt,
+ callback: function() {
+ that.properties.show = !that.properties.show;
+ }
+ }
+ ];
+ };
+
+ ImageWebcam.prototype.onDrawBackground = function(ctx) {
+ if (this.flags.collapsed || this.size[1] <= 20 || !this.properties.show)
+ return;
+
+ if (!this._video) return;
+
+ //render to graph canvas
+ ctx.save();
+ ctx.drawImage(this._video, 0, 0, this.size[0], this.size[1]);
+ ctx.restore();
+ };
+
+ ImageWebcam.prototype.onGetOutputs = function() {
+ return [
+ ["width", "number"],
+ ["height", "number"],
+ ["stream_ready", LiteGraph.EVENT],
+ ["stream_closed", LiteGraph.EVENT],
+ ["stream_error", LiteGraph.EVENT]
+ ];
+ };
+
+ LiteGraph.registerNodeType("graphics/webcam", ImageWebcam);
+})(this);
+
(function(global) {
var LiteGraph = global.LiteGraph;
@@ -12544,7 +13804,7 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
low: LGraphTexture.LOW,
high: LGraphTexture.HIGH,
reuse: LGraphTexture.REUSE,
- default: LGraphTexture.DEFAULT
+ "default": LGraphTexture.DEFAULT
};
//returns the container where all the loaded textures are stored (overwrite if you have a Resources Manager)
@@ -12594,2741 +13854,2741 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
tex_type = gl.HIGH_PRECISION_FORMAT;
break;
case LGraphTexture.REUSE:
- return origin;
- break;
- case LGraphTexture.COPY:
- default:
- tex_type = origin ? origin.type : gl.UNSIGNED_BYTE;
- break;
- }
-
- if (
- !target ||
- target.width != origin.width ||
- target.height != origin.height ||
- target.type != tex_type
- )
- target = new GL.Texture(origin.width, origin.height, {
- type: tex_type,
- format: gl.RGBA,
- filter: gl.LINEAR
- });
-
- return target;
- };
-
- LGraphTexture.getTextureType = function(precision, ref_texture) {
- var type = ref_texture ? ref_texture.type : gl.UNSIGNED_BYTE;
- switch (precision) {
- case LGraphTexture.HIGH:
- type = gl.HIGH_PRECISION_FORMAT;
- break;
- case LGraphTexture.LOW:
- type = gl.UNSIGNED_BYTE;
- break;
- //no default
- }
- return type;
- };
-
- LGraphTexture.getWhiteTexture = function() {
- if (this._white_texture) return this._white_texture;
- var texture = (this._white_texture = GL.Texture.fromMemory(
- 1,
- 1,
- [255, 255, 255, 255],
- { format: gl.RGBA, wrap: gl.REPEAT, filter: gl.NEAREST }
- ));
- return texture;
- };
-
- LGraphTexture.getNoiseTexture = function() {
- if (this._noise_texture) return this._noise_texture;
-
- var noise = new Uint8Array(512 * 512 * 4);
- for (var i = 0; i < 512 * 512 * 4; ++i)
- noise[i] = Math.random() * 255;
-
- var texture = GL.Texture.fromMemory(512, 512, noise, {
- format: gl.RGBA,
- wrap: gl.REPEAT,
- filter: gl.NEAREST
- });
- this._noise_texture = texture;
- return texture;
- };
-
- LGraphTexture.prototype.onDropFile = function(data, filename, file) {
- if (!data) {
- this._drop_texture = null;
- this.properties.name = "";
- } else {
- var texture = null;
- if (typeof data == "string") texture = GL.Texture.fromURL(data);
- else if (filename.toLowerCase().indexOf(".dds") != -1)
- texture = GL.Texture.fromDDSInMemory(data);
- else {
- var blob = new Blob([file]);
- var url = URL.createObjectURL(blob);
- texture = GL.Texture.fromURL(url);
- }
-
- this._drop_texture = texture;
- this.properties.name = filename;
- }
- };
-
- LGraphTexture.prototype.getExtraMenuOptions = function(graphcanvas) {
- var that = this;
- if (!this._drop_texture) return;
- return [
- {
- content: "Clear",
- callback: function() {
- that._drop_texture = null;
- that.properties.name = "";
- }
- }
- ];
- };
-
- LGraphTexture.prototype.onExecute = function() {
- var tex = null;
- if (this.isOutputConnected(1)) tex = this.getInputData(0);
-
- if (!tex && this._drop_texture) tex = this._drop_texture;
-
- if (!tex && this.properties.name)
- tex = LGraphTexture.getTexture(this.properties.name);
-
- if (!tex) return;
-
- this._last_tex = tex;
-
- if (this.properties.filter === false)
- tex.setParameter(gl.TEXTURE_MAG_FILTER, gl.NEAREST);
- else tex.setParameter(gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-
- 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
- ) {
- if (this.properties.name == old_name)
- this.properties.name = new_name;
- };
-
- LGraphTexture.prototype.onDrawBackground = function(ctx) {
- if (this.flags.collapsed || this.size[1] <= 20) return;
-
- if (this._drop_texture && ctx.webgl) {
- ctx.drawImage(
- this._drop_texture,
- 0,
- 0,
- this.size[0],
- this.size[1]
- );
- //this._drop_texture.renderQuad(this.pos[0],this.pos[1],this.size[0],this.size[1]);
- return;
- }
-
- //Different texture? then get it from the GPU
- if (this._last_preview_tex != this._last_tex) {
- if (ctx.webgl) {
- this._canvas = this._last_tex;
- } else {
- var tex_canvas = LGraphTexture.generateLowResTexturePreview(
- this._last_tex
- );
- if (!tex_canvas) return;
-
- this._last_preview_tex = this._last_tex;
- this._canvas = cloneCanvas(tex_canvas);
- }
- }
-
- if (!this._canvas) return;
-
- //render to graph canvas
- ctx.save();
- if (!ctx.webgl) {
- //reverse image
- ctx.translate(0, this.size[1]);
- ctx.scale(1, -1);
- }
- ctx.drawImage(this._canvas, 0, 0, this.size[0], this.size[1]);
- ctx.restore();
- };
-
- //very slow, used at your own risk
- LGraphTexture.generateLowResTexturePreview = function(tex) {
- if (!tex) return null;
-
- var size = LGraphTexture.image_preview_size;
- var temp_tex = tex;
-
- if (tex.format == gl.DEPTH_COMPONENT) return null; //cannot generate from depth
-
- //Generate low-level version in the GPU to speed up
- if (tex.width > size || tex.height > size) {
- temp_tex = this._preview_temp_tex;
- if (!this._preview_temp_tex) {
- temp_tex = new GL.Texture(size, size, {
- minFilter: gl.NEAREST
- });
- this._preview_temp_tex = temp_tex;
- }
-
- //copy
- tex.copyTo(temp_tex);
- tex = temp_tex;
- }
-
- //create intermediate canvas with lowquality version
- var tex_canvas = this._preview_canvas;
- if (!tex_canvas) {
- tex_canvas = createCanvas(size, size);
- this._preview_canvas = tex_canvas;
- }
-
- if (temp_tex) temp_tex.toCanvas(tex_canvas);
- return tex_canvas;
- };
-
- LGraphTexture.prototype.getResources = function(res) {
- res[this.properties.name] = GL.Texture;
- return res;
- };
-
- LGraphTexture.prototype.onGetInputs = function() {
- return [["in", "Texture"]];
- };
-
- LGraphTexture.prototype.onGetOutputs = function() {
- return [
- ["width", "number"],
- ["height", "number"],
- ["aspect", "number"]
- ];
- };
-
- LiteGraph.registerNodeType("texture/texture", LGraphTexture);
-
- //**************************
- function LGraphTexturePreview() {
- this.addInput("Texture", "Texture");
- this.properties = { flipY: false };
- this.size = [
- LGraphTexture.image_preview_size,
- LGraphTexture.image_preview_size
- ];
- }
-
- LGraphTexturePreview.title = "Preview";
- LGraphTexturePreview.desc = "Show a texture in the graph canvas";
- LGraphTexturePreview.allow_preview = false;
-
- LGraphTexturePreview.prototype.onDrawBackground = function(ctx) {
- if (this.flags.collapsed) return;
-
- if (!ctx.webgl && !LGraphTexturePreview.allow_preview) return; //not working well
-
- var tex = this.getInputData(0);
- if (!tex) return;
-
- var tex_canvas = null;
-
- if (!tex.handle && ctx.webgl) tex_canvas = tex;
- else tex_canvas = LGraphTexture.generateLowResTexturePreview(tex);
-
- //render to graph canvas
- ctx.save();
- if (this.properties.flipY) {
- ctx.translate(0, this.size[1]);
- ctx.scale(1, -1);
- }
- ctx.drawImage(tex_canvas, 0, 0, this.size[0], this.size[1]);
- ctx.restore();
- };
-
- LiteGraph.registerNodeType("texture/preview", LGraphTexturePreview);
-
- //**************************************
-
- function LGraphTextureSave() {
- this.addInput("Texture", "Texture");
- this.addOutput("", "Texture");
- this.properties = { name: "" };
- }
-
- LGraphTextureSave.title = "Save";
- LGraphTextureSave.desc = "Save a texture in the repository";
-
- LGraphTextureSave.prototype.onExecute = function() {
- var tex = this.getInputData(0);
- if (!tex) return;
-
- if (this.properties.name) {
- //for cases where we want to perform something when storing it
- if (LGraphTexture.storeTexture)
- LGraphTexture.storeTexture(this.properties.name, tex);
- else {
- var container = LGraphTexture.getTexturesContainer();
- container[this.properties.name] = tex;
- }
- }
-
- this.setOutputData(0, tex);
- };
-
- LiteGraph.registerNodeType("texture/save", LGraphTextureSave);
-
- //****************************************************
-
- function LGraphTextureOperation() {
- this.addInput("Texture", "Texture");
- this.addInput("TextureB", "Texture");
- this.addInput("value", "number");
- this.addOutput("Texture", "Texture");
- this.help =
- "
pixelcode must be vec3
\
- uvcode must be vec2, is optional
\
- uv: tex. coords
color: texture
colorB: textureB
time: scene time
value: input value
";
-
- this.properties = {
- value: 1,
- uvcode: "",
- pixelcode: "color + colorB * value",
- precision: LGraphTexture.DEFAULT
- };
- }
-
- LGraphTextureOperation.widgets_info = {
- uvcode: { widget: "textarea", height: 100 },
- pixelcode: { widget: "textarea", height: 100 },
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
- };
-
- LGraphTextureOperation.title = "Operation";
- LGraphTextureOperation.desc = "Texture shader operation";
-
- LGraphTextureOperation.prototype.getExtraMenuOptions = function(
- graphcanvas
- ) {
- var that = this;
- var txt = !that.properties.show ? "Show Texture" : "Hide Texture";
- return [
- {
- content: txt,
- callback: function() {
- that.properties.show = !that.properties.show;
- }
- }
- ];
- };
-
- LGraphTextureOperation.prototype.onDrawBackground = function(ctx) {
- if (
- this.flags.collapsed ||
- this.size[1] <= 20 ||
- !this.properties.show
- )
- return;
-
- if (!this._tex) return;
-
- //only works if using a webgl renderer
- if (this._tex.gl != ctx) return;
-
- //render to graph canvas
- ctx.save();
- ctx.drawImage(this._tex, 0, 0, this.size[0], this.size[1]);
- ctx.restore();
- };
-
- LGraphTextureOperation.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);
-
- if (!this.properties.uvcode && !this.properties.pixelcode) return;
-
- var width = 512;
- var height = 512;
- if (tex) {
- width = tex.width;
- height = tex.height;
- } else if (texB) {
- width = texB.width;
- height = texB.height;
- }
-
- var type = LGraphTexture.getTextureType(
- this.properties.precision,
- tex
- );
-
- if (!tex && !this._tex)
- 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
- );
-
- var uvcode = "";
- if (this.properties.uvcode) {
- uvcode = "uv = " + this.properties.uvcode;
- if (this.properties.uvcode.indexOf(";") != -1)
- //there are line breaks, means multiline code
- uvcode = this.properties.uvcode;
- }
-
- var pixelcode = "";
- if (this.properties.pixelcode) {
- pixelcode = "result = " + this.properties.pixelcode;
- if (this.properties.pixelcode.indexOf(";") != -1)
- //there are line breaks, means multiline code
- pixelcode = this.properties.pixelcode;
- }
-
- var shader = this._shader;
-
- if (!shader || this._shader_code != uvcode + "|" + pixelcode) {
- try {
- this._shader = new GL.Shader(
- Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureOperation.pixel_shader,
- { UV_CODE: uvcode, PIXEL_CODE: pixelcode }
- );
- this.boxcolor = "#00FF00";
- } catch (err) {
- console.log("Error compiling shader: ", err);
- this.boxcolor = "#FF0000";
- return;
- }
- this.boxcolor = "#FF0000";
-
- this._shader_code = uvcode + "|" + pixelcode;
- shader = this._shader;
- }
-
- if (!shader) {
- this.boxcolor = "red";
- return;
- } else this.boxcolor = "green";
-
- var value = this.getInputData(2);
- if (value != null) this.properties.value = value;
- else value = parseFloat(this.properties.value);
-
- var time = this.graph.getTime();
-
- 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,
- value: value,
- texSize: [width, height],
- time: time
- })
- .draw(mesh);
- });
-
- this.setOutputData(0, this._tex);
- };
-
- LGraphTextureOperation.pixel_shader =
- "precision highp float;\n\
- \n\
- uniform sampler2D u_texture;\n\
- uniform sampler2D u_textureB;\n\
- varying vec2 v_coord;\n\
- uniform vec2 texSize;\n\
- uniform float time;\n\
- uniform float value;\n\
- \n\
- void main() {\n\
- vec2 uv = v_coord;\n\
- UV_CODE;\n\
- vec4 color4 = texture2D(u_texture, uv);\n\
- vec3 color = color4.rgb;\n\
- vec4 color4B = texture2D(u_textureB, uv);\n\
- vec3 colorB = color4B.rgb;\n\
- vec3 result = color;\n\
- float alpha = 1.0;\n\
- PIXEL_CODE;\n\
- gl_FragColor = vec4(result, alpha);\n\
- }\n\
- ";
-
- LiteGraph.registerNodeType("texture/operation", LGraphTextureOperation);
-
- //****************************************************
-
- function LGraphTextureShader() {
- this.addOutput("out", "Texture");
- 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 = { in_texture: 0, texSize: vec2.create(), time: 0 };
- }
-
- LGraphTextureShader.title = "Shader";
- LGraphTextureShader.desc = "Texture shader";
- LGraphTextureShader.widgets_info = {
- code: { type: "code" },
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
- };
-
- LGraphTextureShader.prototype.onPropertyChanged = function(
- name,
- value
- ) {
- if (name != "code") return;
-
- var shader = this.getShader();
- if (!shader) return;
-
- //update connections
- var uniforms = shader.uniformInfo;
-
- //remove deprecated slots
- if (this.inputs) {
- var already = {};
- for (var i = 0; i < this.inputs.length; ++i) {
- var info = this.getInputInfo(i);
- if (!info) continue;
-
- if (uniforms[info.name] && !already[info.name]) {
- already[info.name] = true;
- continue;
- }
- this.removeInput(i);
- i--;
- }
- }
-
- //update existing ones
- for (var i in uniforms) {
- var info = shader.uniformInfo[i];
- if (info.loc === null) continue; //is an attribute, not a uniform
- if (i == "time")
- //default one
- continue;
-
- var type = "number";
- if (this._shader.samplers[i]) type = "texture";
- else {
- switch (info.size) {
- case 1:
- type = "number";
- break;
- case 2:
- type = "vec2";
- break;
- case 3:
- type = "vec3";
- break;
- case 4:
- type = "vec4";
- break;
- case 9:
- type = "mat3";
- break;
- case 16:
- type = "mat4";
- break;
- default:
- continue;
- }
- }
-
- var slot = this.findInputSlot(i);
- if (slot == -1) {
- this.addInput(i, type);
- continue;
- }
-
- var input_info = this.getInputInfo(slot);
- if (!input_info) this.addInput(i, type);
- else {
- if (input_info.type == type) continue;
- this.removeInput(slot, type);
- this.addInput(i, type);
- }
- }
- };
-
- LGraphTextureShader.prototype.getShader = function() {
- //replug
- if (this._shader && this._shader_code == this.properties.code)
- return this._shader;
-
- this._shader_code = this.properties.code;
- this._shader = new GL.Shader(
- Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureShader.pixel_shader + this.properties.code
- );
- if (!this._shader) {
- this.boxcolor = "red";
- return null;
- } else this.boxcolor = "green";
- return this._shader;
- };
-
- LGraphTextureShader.prototype.onExecute = function() {
- if (!this.isOutputConnected(0)) return; //saves work
-
- var shader = this.getShader();
- if (!shader) return;
-
- var tex_slot = 0;
- var in_tex = null;
-
- //set uniforms
- for (var i = 0; i < this.inputs.length; ++i) {
- var info = this.getInputInfo(i);
- var data = this.getInputData(i);
- if (data == null) continue;
-
- if (data.constructor === GL.Texture) {
- data.bind(tex_slot);
- if (!in_tex) in_tex = data;
- data = tex_slot;
- tex_slot++;
- }
- shader.setUniform(info.name, data); //data is tex_slot
- }
-
- var uniforms = this._uniforms;
- var type = LGraphTexture.getTextureType(
- this.properties.precision,
- in_tex
- );
-
- //render to texture
- var w = this.properties.width | 0;
- var h = this.properties.height | 0;
- if (w == 0) w = in_tex ? in_tex.width : gl.canvas.width;
- if (h == 0) h = in_tex ? in_tex.height : gl.canvas.height;
- uniforms.texSize[0] = w;
- uniforms.texSize[1] = h;
- uniforms.time = this.graph.getTime();
-
- 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;
- tex.drawTo(function() {
- shader.uniforms(uniforms).draw(GL.Mesh.getScreenQuad());
- });
-
- this.setOutputData(0, this._tex);
- };
-
- LGraphTextureShader.pixel_shader =
- "precision highp float;\n\
- \n\
- varying vec2 v_coord;\n\
- uniform float time;\n\
- ";
-
- 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 - vec2(0.5)) * 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,
- filter: true,
- disable_alpha: false,
- gamma: 1.0
- };
- this.size[0] = 130;
- }
-
- LGraphTextureToViewport.title = "to Viewport";
- LGraphTextureToViewport.desc = "Texture to viewport";
-
- LGraphTextureToViewport.prototype.onExecute = function() {
- var tex = this.getInputData(0);
- if (!tex) return;
-
- if (this.properties.disable_alpha) gl.disable(gl.BLEND);
- else {
- gl.enable(gl.BLEND);
- if (this.properties.additive)
- gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
- else gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
- }
-
- gl.disable(gl.DEPTH_TEST);
- var gamma = this.properties.gamma || 1.0;
- if (this.isInputConnected(1)) gamma = this.getInputData(1);
-
- tex.setParameter(
- gl.TEXTURE_MAG_FILTER,
- this.properties.filter ? gl.LINEAR : gl.NEAREST
- );
-
- 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],
- u_igamma: 1 / gamma,
- inverseVP: [1 / tex.width, 1 / tex.height]
- })
- .draw(mesh);
- } else {
- 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.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\
- \n\
- /* from mitsuhiko/webgl-meincraft based on the code on geeks3d.com */\n\
- vec4 applyFXAA(sampler2D tex, vec2 fragCoord)\n\
- {\n\
- vec4 color = vec4(0.0);\n\
- /*vec2 inverseVP = vec2(1.0 / uViewportSize.x, 1.0 / uViewportSize.y);*/\n\
- vec3 rgbNW = texture2D(tex, (fragCoord + vec2(-1.0, -1.0)) * inverseVP).xyz;\n\
- vec3 rgbNE = texture2D(tex, (fragCoord + vec2(1.0, -1.0)) * inverseVP).xyz;\n\
- vec3 rgbSW = texture2D(tex, (fragCoord + vec2(-1.0, 1.0)) * inverseVP).xyz;\n\
- vec3 rgbSE = texture2D(tex, (fragCoord + vec2(1.0, 1.0)) * inverseVP).xyz;\n\
- vec3 rgbM = texture2D(tex, fragCoord * inverseVP).xyz;\n\
- vec3 luma = vec3(0.299, 0.587, 0.114);\n\
- float lumaNW = dot(rgbNW, luma);\n\
- float lumaNE = dot(rgbNE, luma);\n\
- float lumaSW = dot(rgbSW, luma);\n\
- float lumaSE = dot(rgbSE, luma);\n\
- float lumaM = dot(rgbM, luma);\n\
- float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));\n\
- float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));\n\
- \n\
- vec2 dir;\n\
- dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n\
- dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n\
- \n\
- float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);\n\
- \n\
- float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);\n\
- dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * inverseVP;\n\
- \n\
- vec3 rgbA = 0.5 * (texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + \n\
- texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);\n\
- 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\
- 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\
- void main() {\n\
- gl_FragColor = applyFXAA( u_texture, v_coord * uViewportSize) ;\n\
- }\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
- );
-
- // Texture Copy *****************************************
- function LGraphTextureCopy() {
- this.addInput("Texture", "Texture");
- this.addOutput("", "Texture");
- this.properties = {
- size: 0,
- generate_mipmaps: false,
- precision: LGraphTexture.DEFAULT
- };
- }
-
- LGraphTextureCopy.title = "Copy";
- LGraphTextureCopy.desc = "Copy Texture";
- LGraphTextureCopy.widgets_info = {
- size: {
- widget: "combo",
- values: [0, 32, 64, 128, 256, 512, 1024, 2048]
- },
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
- };
-
- LGraphTextureCopy.prototype.onExecute = function() {
- var tex = this.getInputData(0);
- if (!tex && !this._temp_texture) return;
-
- if (!this.isOutputConnected(0)) return; //saves work
-
- //copy the texture
- if (tex) {
- var width = tex.width;
- var height = tex.height;
-
- if (this.properties.size != 0) {
- width = this.properties.size;
- height = this.properties.size;
- }
-
- var temp = this._temp_texture;
-
- var type = tex.type;
- if (this.properties.precision === LGraphTexture.LOW)
- type = gl.UNSIGNED_BYTE;
- else if (this.properties.precision === LGraphTexture.HIGH)
- type = gl.HIGH_PRECISION_FORMAT;
-
- if (
- !temp ||
- temp.width != width ||
- temp.height != height ||
- temp.type != type
- ) {
- var minFilter = gl.LINEAR;
- if (
- this.properties.generate_mipmaps &&
- isPowerOfTwo(width) &&
- isPowerOfTwo(height)
- )
- minFilter = gl.LINEAR_MIPMAP_LINEAR;
- this._temp_texture = new GL.Texture(width, height, {
- type: type,
- format: gl.RGBA,
- minFilter: minFilter,
- magFilter: gl.LINEAR
- });
- }
- tex.copyTo(this._temp_texture);
-
- if (this.properties.generate_mipmaps) {
- this._temp_texture.bind(0);
- gl.generateMipmap(this._temp_texture.texture_type);
- this._temp_texture.unbind(0);
- }
- }
-
- this.setOutputData(0, this._temp_texture);
- };
-
- LiteGraph.registerNodeType("texture/copy", LGraphTextureCopy);
-
- // Texture Downsample *****************************************
- function LGraphTextureDownsample() {
- this.addInput("Texture", "Texture");
- this.addOutput("", "Texture");
- this.properties = {
- iterations: 1,
- generate_mipmaps: false,
- precision: LGraphTexture.DEFAULT
- };
- }
-
- LGraphTextureDownsample.title = "Downsample";
- LGraphTextureDownsample.desc = "Downsample Texture";
- LGraphTextureDownsample.widgets_info = {
- iterations: { type: "number", step: 1, precision: 0, min: 0 },
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
- };
-
- LGraphTextureDownsample.prototype.onExecute = function() {
- var tex = this.getInputData(0);
- if (!tex && !this._temp_texture) return;
-
- if (!this.isOutputConnected(0)) return; //saves work
-
- //we do not allow any texture different than texture 2D
- if (!tex || tex.texture_type !== GL.TEXTURE_2D) return;
-
- if (this.properties.iterations < 1) {
- this.setOutputData(0, tex);
- return;
- }
-
- var shader = LGraphTextureDownsample._shader;
- if (!shader)
- LGraphTextureDownsample._shader = shader = new GL.Shader(
- GL.Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureDownsample.pixel_shader
- );
-
- var width = tex.width | 0;
- var height = tex.height | 0;
- var type = tex.type;
- if (this.properties.precision === LGraphTexture.LOW)
- type = gl.UNSIGNED_BYTE;
- else if (this.properties.precision === LGraphTexture.HIGH)
- type = gl.HIGH_PRECISION_FORMAT;
- var iterations = this.properties.iterations || 1;
-
- var origin = tex;
- var target = null;
-
- var temp = [];
- var options = {
- type: type,
- format: tex.format
- };
-
- var offset = vec2.create();
- var uniforms = {
- u_offset: offset
- };
-
- if (this._texture) GL.Texture.releaseTemporary(this._texture);
-
- for (var i = 0; i < iterations; ++i) {
- offset[0] = 1 / width;
- offset[1] = 1 / height;
- width = width >> 1 || 0;
- height = height >> 1 || 0;
- target = GL.Texture.getTemporary(width, height, options);
- temp.push(target);
- origin.setParameter(GL.TEXTURE_MAG_FILTER, GL.NEAREST);
- origin.copyTo(target, shader, uniforms);
- if (width == 1 && height == 1) break; //nothing else to do
- origin = target;
- }
-
- //keep the last texture used
- this._texture = temp.pop();
-
- //free the rest
- for (var i = 0; i < temp.length; ++i)
- GL.Texture.releaseTemporary(temp[i]);
-
- if (this.properties.generate_mipmaps) {
- this._texture.bind(0);
- gl.generateMipmap(this._texture.texture_type);
- this._texture.unbind(0);
- }
-
- this.setOutputData(0, this._texture);
- };
-
- LGraphTextureDownsample.pixel_shader =
- "precision highp float;\n\
- precision highp float;\n\
- uniform sampler2D u_texture;\n\
- uniform vec2 u_offset;\n\
- varying vec2 v_coord;\n\
- \n\
- void main() {\n\
- vec4 color = texture2D(u_texture, v_coord );\n\
- color += texture2D(u_texture, v_coord + vec2( u_offset.x, 0.0 ) );\n\
- color += texture2D(u_texture, v_coord + vec2( 0.0, u_offset.y ) );\n\
- color += texture2D(u_texture, v_coord + vec2( u_offset.x, u_offset.y ) );\n\
- gl_FragColor = color * 0.25;\n\
- }\n\
- ";
-
- LiteGraph.registerNodeType(
- "texture/downsample",
- LGraphTextureDownsample
- );
-
- // Texture Average *****************************************
- function LGraphTextureAverage() {
- this.addInput("Texture", "Texture");
- this.addOutput("tex", "Texture");
- this.addOutput("avg", "vec4");
- this.addOutput("lum", "number");
- this.properties = {
- use_previous_frame: true,
- 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";
- LGraphTextureAverage.desc =
- "Compute a partial average (32 random samples) of a texture and stores it as a 1x1 pixel texture";
-
- LGraphTextureAverage.prototype.onExecute = function() {
- if (!this.properties.use_previous_frame) this.updateAverage();
-
- var v = this._luminance;
- this.setOutputData(0, this._temp_texture);
- this.setOutputData(1, v);
- this.setOutputData(2, (v[0] + v[1] + v[2]) / 3);
- };
-
- //executed before rendering the frame
- LGraphTextureAverage.prototype.onPreRenderExecute = function() {
- this.updateAverage();
- };
-
- LGraphTextureAverage.prototype.updateAverage = function() {
- var tex = this.getInputData(0);
- if (!tex) return;
-
- if (
- !this.isOutputConnected(0) &&
- !this.isOutputConnected(1) &&
- !this.isOutputConnected(2)
- )
- return; //saves work
-
- if (!LGraphTextureAverage._shader) {
- LGraphTextureAverage._shader = new GL.Shader(
- GL.Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureAverage.pixel_shader
- );
- //creates 32 random numbers and stores the, in two mat4
- var samples = new Float32Array(32);
- for (var i = 0; i < 32; ++i) samples[i] = Math.random();
- LGraphTextureAverage._shader.uniforms({
- u_samples_a: samples.subarray(0, 16),
- u_samples_b: samples.subarray(16, 32)
- });
- }
-
- var temp = this._temp_texture;
- 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
- });
-
- var shader = LGraphTextureAverage._shader;
- var uniforms = this._uniforms;
- uniforms.u_mipmap_offset = this.properties.mipmap_offset;
- gl.disable(gl.DEPTH_TEST);
- gl.disable(gl.BLEND);
- this._temp_texture.drawTo(function() {
- tex.toViewport(shader, uniforms);
- });
-
- 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
- ) {
- //no half floats possible, hard to read back unless copyed to a FLOAT texture, so temp_texture is always forced to FLOAT
- }
- }
- }
- };
-
- LGraphTextureAverage.pixel_shader =
- "precision highp float;\n\
- precision highp float;\n\
- uniform mat4 u_samples_a;\n\
- uniform mat4 u_samples_b;\n\
- uniform sampler2D u_texture;\n\
- uniform float u_mipmap_offset;\n\
- varying vec2 v_coord;\n\
- \n\
- void main() {\n\
- vec4 color = vec4(0.0);\n\
- for(int i = 0; i < 4; ++i)\n\
- for(int j = 0; j < 4; ++j)\n\
- {\n\
- color += texture2D(u_texture, vec2( u_samples_a[i][j], u_samples_b[i][j] ), u_mipmap_offset );\n\
- color += texture2D(u_texture, vec2( 1.0 - u_samples_a[i][j], 1.0 - u_samples_b[i][j] ), u_mipmap_offset );\n\
- }\n\
- gl_FragColor = color * 0.03125;\n\
- }\n\
- ";
-
- LiteGraph.registerNodeType("texture/average", LGraphTextureAverage);
-
- function LGraphTextureTemporalSmooth() {
- this.addInput("in", "Texture");
- this.addInput("factor", "Number");
- this.addOutput("out", "Texture");
- this.properties = { factor: 0.5 };
- this._uniforms = {
- u_texture: 0,
- u_textureB: 1,
- u_factor: this.properties.factor
- };
- }
-
- LGraphTextureTemporalSmooth.title = "Smooth";
- LGraphTextureTemporalSmooth.desc = "Smooth texture over time";
-
- LGraphTextureTemporalSmooth.prototype.onExecute = function() {
- var tex = this.getInputData(0);
- if (!tex || !this.isOutputConnected(0)) return;
-
- if (!LGraphTextureTemporalSmooth._shader)
- LGraphTextureTemporalSmooth._shader = new GL.Shader(
- GL.Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureTemporalSmooth.pixel_shader
- );
-
- var temp = this._temp_texture;
- if (
- !temp ||
- temp.type != tex.type ||
- temp.width != tex.width ||
- temp.height != tex.height
- ) {
- this._temp_texture = new GL.Texture(tex.width, tex.height, {
- type: tex.type,
- format: gl.RGBA,
- filter: gl.NEAREST
- });
- this._temp_texture2 = new GL.Texture(tex.width, tex.height, {
- type: tex.type,
- format: gl.RGBA,
- filter: gl.NEAREST
- });
- tex.copyTo(this._temp_texture2);
- }
-
- var tempA = this._temp_texture;
- var tempB = this._temp_texture2;
-
- var shader = LGraphTextureTemporalSmooth._shader;
- var uniforms = this._uniforms;
- uniforms.u_factor = 1.0 - this.getInputOrProperty("factor");
-
- gl.disable(gl.BLEND);
- gl.disable(gl.DEPTH_TEST);
- tempA.drawTo(function() {
- tempB.bind(1);
- tex.toViewport(shader, uniforms);
- });
-
- this.setOutputData(0, tempA);
-
- //swap
- this._temp_texture = tempB;
- this._temp_texture2 = tempA;
- };
-
- LGraphTextureTemporalSmooth.pixel_shader =
- "precision highp float;\n\
- precision highp float;\n\
- uniform sampler2D u_texture;\n\
- uniform sampler2D u_textureB;\n\
- uniform float u_factor;\n\
- varying vec2 v_coord;\n\
- \n\
- void main() {\n\
- gl_FragColor = mix( texture2D( u_texture, v_coord ), texture2D( u_textureB, v_coord ), u_factor );\n\
- }\n\
- ";
-
- LiteGraph.registerNodeType(
- "texture/temporal_smooth",
- LGraphTextureTemporalSmooth
- );
-
- // Image To Texture *****************************************
- function LGraphImageToTexture() {
- this.addInput("Image", "image");
- this.addOutput("", "Texture");
- this.properties = {};
- }
-
- LGraphImageToTexture.title = "Image to Texture";
- LGraphImageToTexture.desc = "Uploads an image to the GPU";
- //LGraphImageToTexture.widgets_info = { size: { widget:"combo", values:[0,32,64,128,256,512,1024,2048]} };
-
- LGraphImageToTexture.prototype.onExecute = function() {
- var img = this.getInputData(0);
- if (!img) return;
-
- var width = img.videoWidth || img.width;
- var height = img.videoHeight || img.height;
-
- //this is in case we are using a webgl canvas already, no need to reupload it
- if (img.gltexture) {
- this.setOutputData(0, img.gltexture);
- return;
- }
-
- var temp = this._temp_texture;
- if (!temp || temp.width != width || temp.height != height)
- this._temp_texture = new GL.Texture(width, height, {
- format: gl.RGBA,
- filter: gl.LINEAR
- });
-
- try {
- this._temp_texture.uploadImage(img);
- } catch (err) {
- console.error(
- "image comes from an unsafe location, cannot be uploaded to webgl: " +
- err
- );
- return;
- }
-
- this.setOutputData(0, this._temp_texture);
- };
-
- LiteGraph.registerNodeType(
- "texture/imageToTexture",
- LGraphImageToTexture
- );
-
- // Texture LUT *****************************************
- function LGraphTextureLUT() {
- this.addInput("Texture", "Texture");
- this.addInput("LUT", "Texture");
- this.addInput("Intensity", "number");
- this.addOutput("", "Texture");
- this.properties = {
- intensity: 1,
- precision: LGraphTexture.DEFAULT,
- texture: null
- };
-
- if (!LGraphTextureLUT._shader)
- LGraphTextureLUT._shader = new GL.Shader(
- Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureLUT.pixel_shader
- );
- }
-
- LGraphTextureLUT.widgets_info = {
- texture: { widget: "texture" },
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
- };
-
- LGraphTextureLUT.title = "LUT";
- LGraphTextureLUT.desc = "Apply LUT to Texture";
-
- LGraphTextureLUT.prototype.onExecute = function() {
- if (!this.isOutputConnected(0)) return; //saves work
-
- var tex = this.getInputData(0);
-
- if (this.properties.precision === LGraphTexture.PASS_THROUGH) {
- this.setOutputData(0, tex);
- return;
- }
-
- if (!tex) return;
-
- var lut_tex = this.getInputData(1);
-
- if (!lut_tex)
- lut_tex = LGraphTexture.getTexture(this.properties.texture);
-
- if (!lut_tex) {
- this.setOutputData(0, tex);
- return;
- }
-
- lut_tex.bind(0);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
- gl.texParameteri(
- gl.TEXTURE_2D,
- gl.TEXTURE_WRAP_S,
- gl.CLAMP_TO_EDGE
- );
- gl.texParameteri(
- gl.TEXTURE_2D,
- gl.TEXTURE_WRAP_T,
- gl.CLAMP_TO_EDGE
- );
- gl.bindTexture(gl.TEXTURE_2D, null);
-
- var intensity = this.properties.intensity;
- if (this.isInputConnected(2))
- this.properties.intensity = intensity = this.getInputData(2);
-
- this._tex = LGraphTexture.getTargetTexture(
- tex,
- this._tex,
- this.properties.precision
- );
-
- //var mesh = Mesh.getScreenQuad();
-
- this._tex.drawTo(function() {
- lut_tex.bind(1);
- tex.toViewport(LGraphTextureLUT._shader, {
- u_texture: 0,
- u_textureB: 1,
- u_amount: intensity
- });
- });
-
- this.setOutputData(0, this._tex);
- };
-
- LGraphTextureLUT.pixel_shader =
- "precision highp float;\n\
- precision highp float;\n\
- varying vec2 v_coord;\n\
- uniform sampler2D u_texture;\n\
- uniform sampler2D u_textureB;\n\
- uniform float u_amount;\n\
- \n\
- void main() {\n\
- lowp vec4 textureColor = clamp( texture2D(u_texture, v_coord), vec4(0.0), vec4(1.0) );\n\
- mediump float blueColor = textureColor.b * 63.0;\n\
- mediump vec2 quad1;\n\
- quad1.y = floor(floor(blueColor) / 8.0);\n\
- quad1.x = floor(blueColor) - (quad1.y * 8.0);\n\
- mediump vec2 quad2;\n\
- quad2.y = floor(ceil(blueColor) / 8.0);\n\
- quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n\
- highp vec2 texPos1;\n\
- texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n\
- texPos1.y = 1.0 - ((quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g));\n\
- highp vec2 texPos2;\n\
- texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n\
- texPos2.y = 1.0 - ((quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g));\n\
- lowp vec4 newColor1 = texture2D(u_textureB, texPos1);\n\
- lowp vec4 newColor2 = texture2D(u_textureB, texPos2);\n\
- lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n\
- gl_FragColor = vec4( mix( textureColor.rgb, newColor.rgb, u_amount), textureColor.w);\n\
- }\n\
- ";
-
- LiteGraph.registerNodeType("texture/LUT", LGraphTextureLUT);
-
- // Texture Channels *****************************************
- function LGraphTextureChannels() {
- this.addInput("Texture", "Texture");
-
- this.addOutput("R", "Texture");
- this.addOutput("G", "Texture");
- this.addOutput("B", "Texture");
- this.addOutput("A", "Texture");
-
- this.properties = { use_luminance: true };
- if (!LGraphTextureChannels._shader)
- LGraphTextureChannels._shader = new GL.Shader(
- Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureChannels.pixel_shader
- );
- }
-
- LGraphTextureChannels.title = "Texture to Channels";
- LGraphTextureChannels.desc = "Split texture channels";
-
- LGraphTextureChannels.prototype.onExecute = function() {
- var texA = this.getInputData(0);
- if (!texA) return;
-
- if (!this._channels) this._channels = Array(4);
-
- var format = this.properties.use_luminance ? gl.LUMINANCE : gl.RGBA;
- var connections = 0;
- for (var i = 0; i < 4; i++) {
- if (this.isOutputConnected(i)) {
- if (
- !this._channels[i] ||
- this._channels[i].width != texA.width ||
- this._channels[i].height != texA.height ||
- this._channels[i].type != texA.type ||
- this._channels[i].format != format
- )
- this._channels[i] = new GL.Texture(
- texA.width,
- texA.height,
- {
- type: texA.type,
- format: format,
- filter: gl.LINEAR
- }
- );
- connections++;
- } else this._channels[i] = null;
- }
-
- if (!connections) return;
-
- gl.disable(gl.BLEND);
- gl.disable(gl.DEPTH_TEST);
-
- var mesh = Mesh.getScreenQuad();
- var shader = LGraphTextureChannels._shader;
- var masks = [
- [1, 0, 0, 0],
- [0, 1, 0, 0],
- [0, 0, 1, 0],
- [0, 0, 0, 1]
- ];
-
- for (var i = 0; i < 4; i++) {
- if (!this._channels[i]) continue;
-
- this._channels[i].drawTo(function() {
- texA.bind(0);
- shader
- .uniforms({ u_texture: 0, u_mask: masks[i] })
- .draw(mesh);
- });
- this.setOutputData(i, this._channels[i]);
- }
- };
-
- LGraphTextureChannels.pixel_shader =
- "precision highp float;\n\
- precision highp float;\n\
- varying vec2 v_coord;\n\
- uniform sampler2D u_texture;\n\
- uniform vec4 u_mask;\n\
- \n\
- void main() {\n\
- gl_FragColor = vec4( vec3( length( texture2D(u_texture, v_coord) * u_mask )), 1.0 );\n\
- }\n\
- ";
-
- LiteGraph.registerNodeType(
- "texture/textureChannels",
- LGraphTextureChannels
- );
-
- // Texture Channels to Texture *****************************************
- function LGraphChannelsTexture() {
- this.addInput("R", "Texture");
- this.addInput("G", "Texture");
- this.addInput("B", "Texture");
- this.addInput("A", "Texture");
-
- this.addOutput("Texture", "Texture");
-
- this.properties = {
- precision: LGraphTexture.DEFAULT,
- R: 1,
- G: 1,
- B: 1,
- A: 1
- };
- this._color = vec4.create();
- this._uniforms = {
- u_textureR: 0,
- u_textureG: 1,
- u_textureB: 2,
- u_textureA: 3,
- u_color: this._color
- };
- }
-
- LGraphChannelsTexture.title = "Channels to Texture";
- LGraphChannelsTexture.desc = "Split texture channels";
- LGraphChannelsTexture.widgets_info = {
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
- };
-
- LGraphChannelsTexture.prototype.onExecute = function() {
- var white = LGraphTexture.getWhiteTexture();
- var texR = this.getInputData(0) || white;
- var texG = this.getInputData(1) || white;
- var texB = this.getInputData(2) || white;
- var texA = this.getInputData(3) || white;
-
- gl.disable(gl.BLEND);
- gl.disable(gl.DEPTH_TEST);
-
- var mesh = Mesh.getScreenQuad();
- if (!LGraphChannelsTexture._shader)
- LGraphChannelsTexture._shader = new GL.Shader(
- Shader.SCREEN_VERTEX_SHADER,
- LGraphChannelsTexture.pixel_shader
- );
- var shader = LGraphChannelsTexture._shader;
-
- var w = Math.max(texR.width, texG.width, texB.width, texA.width);
- var h = Math.max(
- texR.height,
- texG.height,
- texB.height,
- texA.height
- );
- var type =
- this.properties.precision == LGraphTexture.HIGH
- ? LGraphTexture.HIGH_PRECISION_FORMAT
- : gl.UNSIGNED_BYTE;
-
- if (
- !this._texture ||
- this._texture.width != w ||
- this._texture.height != h ||
- this._texture.type != type
- )
- this._texture = new GL.Texture(w, h, {
- type: type,
- format: gl.RGBA,
- filter: gl.LINEAR
- });
-
- var color = this._color;
- color[0] = this.properties.R;
- color[1] = this.properties.G;
- color[2] = this.properties.B;
- color[3] = this.properties.A;
- var uniforms = this._uniforms;
-
- this._texture.drawTo(function() {
- texR.bind(0);
- texG.bind(1);
- texB.bind(2);
- texA.bind(3);
- shader.uniforms(uniforms).draw(mesh);
- });
- this.setOutputData(0, this._texture);
- };
-
- LGraphChannelsTexture.pixel_shader =
- "precision highp float;\n\
- precision highp float;\n\
- varying vec2 v_coord;\n\
- uniform sampler2D u_textureR;\n\
- uniform sampler2D u_textureG;\n\
- uniform sampler2D u_textureB;\n\
- uniform sampler2D u_textureA;\n\
- uniform vec4 u_color;\n\
- \n\
- void main() {\n\
- gl_FragColor = u_color * vec4( \
- texture2D(u_textureR, v_coord).r,\
- texture2D(u_textureG, v_coord).r,\
- texture2D(u_textureB, v_coord).r,\
- texture2D(u_textureA, v_coord).r);\n\
- }\n\
- ";
-
- LiteGraph.registerNodeType(
- "texture/channelsTexture",
- LGraphChannelsTexture
- );
-
- // Texture Color *****************************************
- function LGraphTextureColor() {
- this.addOutput("Texture", "Texture");
-
- this._tex_color = vec4.create();
- this.properties = {
- color: vec4.create(),
- precision: LGraphTexture.DEFAULT
- };
- }
-
- LGraphTextureColor.title = "Color";
- LGraphTextureColor.desc =
- "Generates a 1x1 texture with a constant color";
-
- LGraphTextureColor.widgets_info = {
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
- };
-
- LGraphTextureColor.prototype.onDrawBackground = function(ctx) {
- var c = this.properties.color;
- ctx.fillStyle =
- "rgb(" +
- Math.floor(Math.clamp(c[0], 0, 1) * 255) +
- "," +
- Math.floor(Math.clamp(c[1], 0, 1) * 255) +
- "," +
- Math.floor(Math.clamp(c[2], 0, 1) * 255) +
- ")";
- if (this.flags.collapsed) this.boxcolor = ctx.fillStyle;
- else ctx.fillRect(0, 0, this.size[0], this.size[1]);
- };
-
- LGraphTextureColor.prototype.onExecute = function() {
- var type =
- this.properties.precision == LGraphTexture.HIGH
- ? LGraphTexture.HIGH_PRECISION_FORMAT
- : gl.UNSIGNED_BYTE;
-
- if (!this._tex || this._tex.type != type)
- this._tex = new GL.Texture(1, 1, {
- format: gl.RGBA,
- type: type,
- minFilter: gl.NEAREST
- });
- var color = this.properties.color;
-
- 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;
- switch (input.name) {
- case "RGB":
- case "RGBA":
- color.set(v);
- break;
- case "R":
- color[0] = v;
- break;
- case "G":
- color[1] = v;
- break;
- case "B":
- color[2] = v;
- break;
- case "A":
- color[3] = v;
- break;
- }
- }
-
- if (vec4.sqrDist(this._tex_color, color) > 0.001) {
- this._tex_color.set(color);
- this._tex.fill(color);
- }
- this.setOutputData(0, this._tex);
- };
-
- LGraphTextureColor.prototype.onGetInputs = function() {
- return [
- ["RGB", "vec3"],
- ["RGBA", "vec4"],
- ["R", "number"],
- ["G", "number"],
- ["B", "number"],
- ["A", "number"]
- ];
- };
-
- LiteGraph.registerNodeType("texture/color", LGraphTextureColor);
-
- // Texture Channels to Texture *****************************************
- function LGraphTextureGradient() {
- this.addInput("A", "color");
- this.addInput("B", "color");
- this.addOutput("Texture", "Texture");
-
- this.properties = {
- angle: 0,
- scale: 1,
- A: [0, 0, 0],
- B: [1, 1, 1],
- texture_size: 32
- };
- if (!LGraphTextureGradient._shader)
- LGraphTextureGradient._shader = new GL.Shader(
- Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureGradient.pixel_shader
- );
-
- this._uniforms = {
- u_angle: 0,
- u_colorA: vec3.create(),
- u_colorB: vec3.create()
- };
- }
-
- LGraphTextureGradient.title = "Gradient";
- LGraphTextureGradient.desc = "Generates a gradient";
- LGraphTextureGradient["@A"] = { type: "color" };
- LGraphTextureGradient["@B"] = { type: "color" };
- LGraphTextureGradient["@texture_size"] = {
- type: "enum",
- values: [32, 64, 128, 256, 512]
- };
-
- LGraphTextureGradient.prototype.onExecute = function() {
- gl.disable(gl.BLEND);
- gl.disable(gl.DEPTH_TEST);
-
- var mesh = GL.Mesh.getScreenQuad();
- var shader = LGraphTextureGradient._shader;
-
- var A = this.getInputData(0);
- if (!A) A = this.properties.A;
- var B = this.getInputData(1);
- if (!B) B = this.properties.B;
-
- //angle and scale
- for (var i = 2; 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 uniforms = this._uniforms;
- this._uniforms.u_angle = this.properties.angle * DEG2RAD;
- this._uniforms.u_scale = this.properties.scale;
- vec3.copy(uniforms.u_colorA, A);
- vec3.copy(uniforms.u_colorB, B);
-
- var size = parseInt(this.properties.texture_size);
- if (!this._tex || this._tex.width != size)
- this._tex = new GL.Texture(size, size, {
- format: gl.RGB,
- filter: gl.LINEAR
- });
-
- this._tex.drawTo(function() {
- shader.uniforms(uniforms).draw(mesh);
- });
- this.setOutputData(0, this._tex);
- };
-
- LGraphTextureGradient.prototype.onGetInputs = function() {
- return [["angle", "number"], ["scale", "number"]];
- };
-
- LGraphTextureGradient.pixel_shader =
- "precision highp float;\n\
- precision highp float;\n\
- varying vec2 v_coord;\n\
- uniform float u_angle;\n\
- uniform float u_scale;\n\
- uniform vec3 u_colorA;\n\
- uniform vec3 u_colorB;\n\
- \n\
- vec2 rotate(vec2 v, float angle)\n\
- {\n\
- vec2 result;\n\
- float _cos = cos(angle);\n\
- float _sin = sin(angle);\n\
- result.x = v.x * _cos - v.y * _sin;\n\
- result.y = v.x * _sin + v.y * _cos;\n\
- return result;\n\
- }\n\
- void main() {\n\
- float f = (rotate(u_scale * (v_coord - vec2(0.5)), u_angle) + vec2(0.5)).x;\n\
- vec3 color = mix(u_colorA,u_colorB,clamp(f,0.0,1.0));\n\
- gl_FragColor = vec4(color,1.0);\n\
- }\n\
- ";
-
- LiteGraph.registerNodeType("texture/gradient", LGraphTextureGradient);
-
- // Texture Mix *****************************************
- function LGraphTextureMix() {
- this.addInput("A", "Texture");
- this.addInput("B", "Texture");
- this.addInput("Mixer", "Texture");
-
- this.addOutput("Texture", "Texture");
- this.properties = { factor: 0.5, precision: LGraphTexture.DEFAULT };
- this._uniforms = {
- u_textureA: 0,
- u_textureB: 1,
- u_textureMix: 2,
- u_mix: vec4.create()
- };
- }
-
- LGraphTextureMix.title = "Mix";
- LGraphTextureMix.desc = "Generates a texture mixing two textures";
-
- LGraphTextureMix.widgets_info = {
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
- };
-
- LGraphTextureMix.prototype.onExecute = function() {
- var texA = this.getInputData(0);
-
- if (!this.isOutputConnected(0)) return; //saves work
-
- if (this.properties.precision === LGraphTexture.PASS_THROUGH) {
- this.setOutputData(0, texA);
- return;
- }
-
- var texB = this.getInputData(1);
- if (!texA || !texB) return;
-
- var texMix = this.getInputData(2);
-
- var factor = this.getInputData(3);
-
- this._tex = LGraphTexture.getTargetTexture(
- texA,
- this._tex,
- this.properties.precision
- );
-
- gl.disable(gl.BLEND);
- gl.disable(gl.DEPTH_TEST);
-
- var mesh = Mesh.getScreenQuad();
- var shader = null;
- var uniforms = this._uniforms;
- if (texMix) {
- shader = LGraphTextureMix._shader_tex;
- if (!shader)
- shader = LGraphTextureMix._shader_tex = new GL.Shader(
- Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureMix.pixel_shader,
- { MIX_TEX: "" }
- );
- } else {
- shader = LGraphTextureMix._shader_factor;
- if (!shader)
- shader = LGraphTextureMix._shader_factor = new GL.Shader(
- Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureMix.pixel_shader
- );
- var f = factor == null ? this.properties.factor : factor;
- uniforms.u_mix.set([f, f, f, f]);
- }
-
- this._tex.drawTo(function() {
- texA.bind(0);
- texB.bind(1);
- if (texMix) texMix.bind(2);
- shader.uniforms(uniforms).draw(mesh);
- });
-
- this.setOutputData(0, this._tex);
- };
-
- LGraphTextureMix.prototype.onGetInputs = function() {
- return [["factor", "number"]];
- };
-
- LGraphTextureMix.pixel_shader =
- "precision highp float;\n\
- precision highp float;\n\
- varying vec2 v_coord;\n\
- uniform sampler2D u_textureA;\n\
- uniform sampler2D u_textureB;\n\
- #ifdef MIX_TEX\n\
- uniform sampler2D u_textureMix;\n\
- #else\n\
- uniform vec4 u_mix;\n\
- #endif\n\
- \n\
- void main() {\n\
- #ifdef MIX_TEX\n\
- vec4 f = texture2D(u_textureMix, v_coord);\n\
- #else\n\
- vec4 f = u_mix;\n\
- #endif\n\
- gl_FragColor = mix( texture2D(u_textureA, v_coord), texture2D(u_textureB, v_coord), f );\n\
- }\n\
- ";
-
- LiteGraph.registerNodeType("texture/mix", LGraphTextureMix);
-
- // Texture Edges detection *****************************************
- function LGraphTextureEdges() {
- this.addInput("Tex.", "Texture");
-
- this.addOutput("Edges", "Texture");
- 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
- );
- }
-
- LGraphTextureEdges.title = "Edges";
- LGraphTextureEdges.desc = "Detects edges";
-
- LGraphTextureEdges.widgets_info = {
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
- };
-
- LGraphTextureEdges.prototype.onExecute = function() {
- if (!this.isOutputConnected(0)) return; //saves work
-
- var tex = this.getInputData(0);
-
- if (this.properties.precision === LGraphTexture.PASS_THROUGH) {
- this.setOutputData(0, tex);
- return;
- }
-
- if (!tex) return;
-
- this._tex = LGraphTexture.getTargetTexture(
- tex,
- this._tex,
- this.properties.precision
- );
-
- gl.disable(gl.BLEND);
- gl.disable(gl.DEPTH_TEST);
-
- var mesh = Mesh.getScreenQuad();
- 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_threshold: threshold,
- u_invert: invert ? 1 : 0
- })
- .draw(mesh);
- });
-
- this.setOutputData(0, this._tex);
- };
-
- LGraphTextureEdges.pixel_shader =
- "precision highp float;\n\
- precision highp float;\n\
- varying vec2 v_coord;\n\
- uniform sampler2D u_texture;\n\
- 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\
- vec4 up = texture2D(u_texture, v_coord + u_isize * vec2(0.0,1.0) );\n\
- vec4 down = texture2D(u_texture, v_coord + u_isize * vec2(0.0,-1.0) );\n\
- vec4 left = texture2D(u_texture, v_coord + u_isize * vec2(1.0,0.0) );\n\
- vec4 right = texture2D(u_texture, v_coord + u_isize * vec2(-1.0,0.0) );\n\
- vec4 diff = abs(center - up) + abs(center - down) + abs(center - left) + abs(center - right);\n\
- diff *= u_factor;\n\
- if(u_invert == 1)\n\
- diff.xyz = vec3(1.0) - diff.xyz;\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\
- ";
-
- LiteGraph.registerNodeType("texture/edges", LGraphTextureEdges);
-
- // Texture Depth *****************************************
- function LGraphTextureDepthRange() {
- this.addInput("Texture", "Texture");
- this.addInput("Distance", "number");
- this.addInput("Range", "number");
- this.addOutput("Texture", "Texture");
- this.properties = {
- distance: 100,
- range: 50,
- only_depth: false,
- high_precision: false
- };
- this._uniforms = {
- u_texture: 0,
- u_distance: 100,
- u_range: 50,
- u_camera_planes: null
- };
- }
-
- LGraphTextureDepthRange.title = "Depth Range";
- LGraphTextureDepthRange.desc = "Generates a texture with a depth range";
-
- LGraphTextureDepthRange.prototype.onExecute = function() {
- if (!this.isOutputConnected(0)) return; //saves work
-
- var tex = this.getInputData(0);
- if (!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 uniforms = this._uniforms;
-
- //iterations
- var distance = this.properties.distance;
- if (this.isInputConnected(1)) {
- distance = this.getInputData(1);
- this.properties.distance = distance;
- }
-
- var range = this.properties.range;
- if (this.isInputConnected(2)) {
- range = this.getInputData(2);
- this.properties.range = range;
- }
-
- uniforms.u_distance = distance;
- uniforms.u_range = range;
-
- gl.disable(gl.BLEND);
- gl.disable(gl.DEPTH_TEST);
- var mesh = Mesh.getScreenQuad();
- if (!LGraphTextureDepthRange._shader) {
- LGraphTextureDepthRange._shader = new GL.Shader(
- Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureDepthRange.pixel_shader
- );
- LGraphTextureDepthRange._shader_onlydepth = new GL.Shader(
- Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureDepthRange.pixel_shader,
- { ONLY_DEPTH: "" }
- );
- }
- var shader = this.properties.only_depth
- ? LGraphTextureDepthRange._shader_onlydepth
- : LGraphTextureDepthRange._shader;
-
- //NEAR AND FAR PLANES
- var planes = null;
- if (tex.near_far_planes) planes = tex.near_far_planes;
- else if (window.LS && LS.Renderer._main_camera)
- planes = LS.Renderer._main_camera._uniforms.u_camera_planes;
- else planes = [0.1, 1000]; //hardcoded
- uniforms.u_camera_planes = planes;
-
- this._temp_texture.drawTo(function() {
- tex.bind(0);
- shader.uniforms(uniforms).draw(mesh);
- });
-
- this._temp_texture.near_far_planes = planes;
- this.setOutputData(0, this._temp_texture);
- };
-
- LGraphTextureDepthRange.pixel_shader =
- "precision highp float;\n\
- precision highp float;\n\
- varying vec2 v_coord;\n\
- uniform sampler2D u_texture;\n\
- uniform vec2 u_camera_planes;\n\
- uniform float u_distance;\n\
- uniform float u_range;\n\
- \n\
- float LinearDepth()\n\
- {\n\
- float zNear = u_camera_planes.x;\n\
- float zFar = u_camera_planes.y;\n\
- float depth = texture2D(u_texture, v_coord).x;\n\
- depth = depth * 2.0 - 1.0;\n\
- return zNear * (depth + 1.0) / (zFar + zNear - depth * (zFar - zNear));\n\
- }\n\
- \n\
- void main() {\n\
- float depth = LinearDepth();\n\
- #ifdef ONLY_DEPTH\n\
- gl_FragColor = vec4(depth);\n\
- #else\n\
- float diff = abs(depth * u_camera_planes.y - u_distance);\n\
- float dof = 1.0;\n\
- if(diff <= u_range)\n\
- dof = diff / u_range;\n\
- gl_FragColor = vec4(dof);\n\
- #endif\n\
- }\n\
- ";
-
- LiteGraph.registerNodeType(
- "texture/depth_range",
- LGraphTextureDepthRange
- );
-
- // Texture Blur *****************************************
- function LGraphTextureBlur() {
- this.addInput("Texture", "Texture");
- this.addInput("Iterations", "number");
- this.addInput("Intensity", "number");
- this.addOutput("Blurred", "Texture");
- 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() {
- var tex = this.getInputData(0);
- if (!tex) return;
-
- if (!this.isOutputConnected(0)) return; //saves work
-
- 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 });
- temp = this._final_texture = new GL.Texture(
- tex.width,
- tex.height,
- { type: tex.type, format: gl.RGBA, filter: gl.LINEAR }
- );
- }
-
- //iterations
- var iterations = this.properties.iterations;
- if (this.isInputConnected(1)) {
- iterations = this.getInputData(1);
- this.properties.iterations = iterations;
- }
- iterations = Math.min(
- Math.floor(iterations),
- LGraphTextureBlur.max_iterations
- );
- if (iterations == 0) {
- //skip blurring
- this.setOutputData(0, tex);
- return;
- }
-
- var intensity = this.properties.intensity;
- if (this.isInputConnected(2)) {
- intensity = this.getInputData(2);
- this.properties.intensity = intensity;
- }
-
- //blur sometimes needs an aspect correction
- var aspect = LiteGraph.camera_aspect;
- if (!aspect && window.gl !== undefined)
- aspect = gl.canvas.height / gl.canvas.width;
- if (!aspect) aspect = 1;
- aspect = this.properties.preserve_aspect ? aspect : 1;
-
- var scale = this.properties.scale || [1, 1];
- 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, temp);
- };
-
- /*
- LGraphTextureBlur.pixel_shader = "precision highp float;\n\
- precision highp float;\n\
- varying vec2 v_coord;\n\
- uniform sampler2D u_texture;\n\
- uniform vec2 u_offset;\n\
- uniform float u_intensity;\n\
- void main() {\n\
- vec4 sum = vec4(0.0);\n\
- vec4 center = texture2D(u_texture, v_coord);\n\
- sum += texture2D(u_texture, v_coord + u_offset * -4.0) * 0.05/0.98;\n\
- sum += texture2D(u_texture, v_coord + u_offset * -3.0) * 0.09/0.98;\n\
- 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\
- sum += center * 0.16/0.98;\n\
- sum += texture2D(u_texture, v_coord + u_offset * 4.0) * 0.05/0.98;\n\
- sum += texture2D(u_texture, v_coord + u_offset * 3.0) * 0.09/0.98;\n\
- 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\
- }\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 = {
- enabled: true,
- 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.getInputOrProperty("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)
+ return origin;
+ break;
+ case LGraphTexture.COPY:
+ default:
+ tex_type = origin ? origin.type : gl.UNSIGNED_BYTE;
+ break;
+ }
+
+ if (
+ !target ||
+ target.width != origin.width ||
+ target.height != origin.height ||
+ target.type != tex_type
+ )
+ target = new GL.Texture(origin.width, origin.height, {
+ type: tex_type,
+ format: gl.RGBA,
+ filter: gl.LINEAR
+ });
+
+ return target;
+ };
+
+ LGraphTexture.getTextureType = function(precision, ref_texture) {
+ var type = ref_texture ? ref_texture.type : gl.UNSIGNED_BYTE;
+ switch (precision) {
+ case LGraphTexture.HIGH:
+ type = gl.HIGH_PRECISION_FORMAT;
+ break;
+ case LGraphTexture.LOW:
+ type = gl.UNSIGNED_BYTE;
+ break;
+ //no default
+ }
+ return type;
+ };
+
+ LGraphTexture.getWhiteTexture = function() {
+ if (this._white_texture) return this._white_texture;
+ var texture = (this._white_texture = GL.Texture.fromMemory(
+ 1,
+ 1,
+ [255, 255, 255, 255],
+ { format: gl.RGBA, wrap: gl.REPEAT, filter: gl.NEAREST }
+ ));
+ return texture;
+ };
+
+ LGraphTexture.getNoiseTexture = function() {
+ if (this._noise_texture) return this._noise_texture;
+
+ var noise = new Uint8Array(512 * 512 * 4);
+ for (var i = 0; i < 512 * 512 * 4; ++i)
+ noise[i] = Math.random() * 255;
+
+ var texture = GL.Texture.fromMemory(512, 512, noise, {
+ format: gl.RGBA,
+ wrap: gl.REPEAT,
+ filter: gl.NEAREST
+ });
+ this._noise_texture = texture;
+ return texture;
+ };
+
+ LGraphTexture.prototype.onDropFile = function(data, filename, file) {
+ if (!data) {
+ this._drop_texture = null;
+ this.properties.name = "";
+ } else {
+ var texture = null;
+ if (typeof data == "string") texture = GL.Texture.fromURL(data);
+ else if (filename.toLowerCase().indexOf(".dds") != -1)
+ texture = GL.Texture.fromDDSInMemory(data);
+ else {
+ var blob = new Blob([file]);
+ var url = URL.createObjectURL(blob);
+ texture = GL.Texture.fromURL(url);
+ }
+
+ this._drop_texture = texture;
+ this.properties.name = filename;
+ }
+ };
+
+ LGraphTexture.prototype.getExtraMenuOptions = function(graphcanvas) {
+ var that = this;
+ if (!this._drop_texture) return;
+ return [
+ {
+ content: "Clear",
+ callback: function() {
+ that._drop_texture = null;
+ that.properties.name = "";
+ }
+ }
+ ];
+ };
+
+ LGraphTexture.prototype.onExecute = function() {
+ var tex = null;
+ if (this.isOutputConnected(1)) tex = this.getInputData(0);
+
+ if (!tex && this._drop_texture) tex = this._drop_texture;
+
+ if (!tex && this.properties.name)
+ tex = LGraphTexture.getTexture(this.properties.name);
+
+ if (!tex) return;
+
+ this._last_tex = tex;
+
+ if (this.properties.filter === false)
+ tex.setParameter(gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ else tex.setParameter(gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+
+ 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
+ ) {
+ if (this.properties.name == old_name)
+ this.properties.name = new_name;
+ };
+
+ LGraphTexture.prototype.onDrawBackground = function(ctx) {
+ if (this.flags.collapsed || this.size[1] <= 20) return;
+
+ if (this._drop_texture && ctx.webgl) {
+ ctx.drawImage(
+ this._drop_texture,
+ 0,
+ 0,
+ this.size[0],
+ this.size[1]
+ );
+ //this._drop_texture.renderQuad(this.pos[0],this.pos[1],this.size[0],this.size[1]);
+ return;
+ }
+
+ //Different texture? then get it from the GPU
+ if (this._last_preview_tex != this._last_tex) {
+ if (ctx.webgl) {
+ this._canvas = this._last_tex;
+ } else {
+ var tex_canvas = LGraphTexture.generateLowResTexturePreview(
+ this._last_tex
+ );
+ if (!tex_canvas) return;
+
+ this._last_preview_tex = this._last_tex;
+ this._canvas = cloneCanvas(tex_canvas);
+ }
+ }
+
+ if (!this._canvas) return;
+
+ //render to graph canvas
+ ctx.save();
+ if (!ctx.webgl) {
+ //reverse image
+ ctx.translate(0, this.size[1]);
+ ctx.scale(1, -1);
+ }
+ ctx.drawImage(this._canvas, 0, 0, this.size[0], this.size[1]);
+ ctx.restore();
+ };
+
+ //very slow, used at your own risk
+ LGraphTexture.generateLowResTexturePreview = function(tex) {
+ if (!tex) return null;
+
+ var size = LGraphTexture.image_preview_size;
+ var temp_tex = tex;
+
+ if (tex.format == gl.DEPTH_COMPONENT) return null; //cannot generate from depth
+
+ //Generate low-level version in the GPU to speed up
+ if (tex.width > size || tex.height > size) {
+ temp_tex = this._preview_temp_tex;
+ if (!this._preview_temp_tex) {
+ temp_tex = new GL.Texture(size, size, {
+ minFilter: gl.NEAREST
+ });
+ this._preview_temp_tex = temp_tex;
+ }
+
+ //copy
+ tex.copyTo(temp_tex);
+ tex = temp_tex;
+ }
+
+ //create intermediate canvas with lowquality version
+ var tex_canvas = this._preview_canvas;
+ if (!tex_canvas) {
+ tex_canvas = createCanvas(size, size);
+ this._preview_canvas = tex_canvas;
+ }
+
+ if (temp_tex) temp_tex.toCanvas(tex_canvas);
+ return tex_canvas;
+ };
+
+ LGraphTexture.prototype.getResources = function(res) {
+ res[this.properties.name] = GL.Texture;
+ return res;
+ };
+
+ LGraphTexture.prototype.onGetInputs = function() {
+ return [["in", "Texture"]];
+ };
+
+ LGraphTexture.prototype.onGetOutputs = function() {
+ return [
+ ["width", "number"],
+ ["height", "number"],
+ ["aspect", "number"]
+ ];
+ };
+
+ LiteGraph.registerNodeType("texture/texture", LGraphTexture);
+
+ //**************************
+ function LGraphTexturePreview() {
+ this.addInput("Texture", "Texture");
+ this.properties = { flipY: false };
+ this.size = [
+ LGraphTexture.image_preview_size,
+ LGraphTexture.image_preview_size
+ ];
+ }
+
+ LGraphTexturePreview.title = "Preview";
+ LGraphTexturePreview.desc = "Show a texture in the graph canvas";
+ LGraphTexturePreview.allow_preview = false;
+
+ LGraphTexturePreview.prototype.onDrawBackground = function(ctx) {
+ if (this.flags.collapsed) return;
+
+ if (!ctx.webgl && !LGraphTexturePreview.allow_preview) return; //not working well
+
+ var tex = this.getInputData(0);
+ if (!tex) return;
+
+ var tex_canvas = null;
+
+ if (!tex.handle && ctx.webgl) tex_canvas = tex;
+ else tex_canvas = LGraphTexture.generateLowResTexturePreview(tex);
+
+ //render to graph canvas
+ ctx.save();
+ if (this.properties.flipY) {
+ ctx.translate(0, this.size[1]);
+ ctx.scale(1, -1);
+ }
+ ctx.drawImage(tex_canvas, 0, 0, this.size[0], this.size[1]);
+ ctx.restore();
+ };
+
+ LiteGraph.registerNodeType("texture/preview", LGraphTexturePreview);
+
+ //**************************************
+
+ function LGraphTextureSave() {
+ this.addInput("Texture", "Texture");
+ this.addOutput("", "Texture");
+ this.properties = { name: "" };
+ }
+
+ LGraphTextureSave.title = "Save";
+ LGraphTextureSave.desc = "Save a texture in the repository";
+
+ LGraphTextureSave.prototype.onExecute = function() {
+ var tex = this.getInputData(0);
+ if (!tex) return;
+
+ if (this.properties.name) {
+ //for cases where we want to perform something when storing it
+ if (LGraphTexture.storeTexture)
+ LGraphTexture.storeTexture(this.properties.name, tex);
+ else {
+ var container = LGraphTexture.getTexturesContainer();
+ container[this.properties.name] = tex;
+ }
+ }
+
+ this.setOutputData(0, tex);
+ };
+
+ LiteGraph.registerNodeType("texture/save", LGraphTextureSave);
+
+ //****************************************************
+
+ function LGraphTextureOperation() {
+ this.addInput("Texture", "Texture");
+ this.addInput("TextureB", "Texture");
+ this.addInput("value", "number");
+ this.addOutput("Texture", "Texture");
+ this.help =
+ "pixelcode must be vec3
\
+ uvcode must be vec2, is optional
\
+ uv: tex. coords
color: texture
colorB: textureB
time: scene time
value: input value
";
+
+ this.properties = {
+ value: 1,
+ uvcode: "",
+ pixelcode: "color + colorB * value",
+ precision: LGraphTexture.DEFAULT
+ };
+ }
+
+ LGraphTextureOperation.widgets_info = {
+ uvcode: { widget: "textarea", height: 100 },
+ pixelcode: { widget: "textarea", height: 100 },
+ precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
+ };
+
+ LGraphTextureOperation.title = "Operation";
+ LGraphTextureOperation.desc = "Texture shader operation";
+
+ LGraphTextureOperation.prototype.getExtraMenuOptions = function(
+ graphcanvas
+ ) {
+ var that = this;
+ var txt = !that.properties.show ? "Show Texture" : "Hide Texture";
+ return [
+ {
+ content: txt,
+ callback: function() {
+ that.properties.show = !that.properties.show;
+ }
+ }
+ ];
+ };
+
+ LGraphTextureOperation.prototype.onDrawBackground = function(ctx) {
+ if (
+ this.flags.collapsed ||
+ this.size[1] <= 20 ||
+ !this.properties.show
+ )
+ return;
+
+ if (!this._tex) return;
+
+ //only works if using a webgl renderer
+ if (this._tex.gl != ctx) return;
+
+ //render to graph canvas
+ ctx.save();
+ ctx.drawImage(this._tex, 0, 0, this.size[0], this.size[1]);
+ ctx.restore();
+ };
+
+ LGraphTextureOperation.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);
+
+ if (!this.properties.uvcode && !this.properties.pixelcode) return;
+
+ var width = 512;
+ var height = 512;
+ if (tex) {
+ width = tex.width;
+ height = tex.height;
+ } else if (texB) {
+ width = texB.width;
+ height = texB.height;
+ }
+
+ var type = LGraphTexture.getTextureType(
+ this.properties.precision,
+ tex
+ );
+
+ if (!tex && !this._tex)
+ 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
+ );
+
+ var uvcode = "";
+ if (this.properties.uvcode) {
+ uvcode = "uv = " + this.properties.uvcode;
+ if (this.properties.uvcode.indexOf(";") != -1)
+ //there are line breaks, means multiline code
+ uvcode = this.properties.uvcode;
+ }
+
+ var pixelcode = "";
+ if (this.properties.pixelcode) {
+ pixelcode = "result = " + this.properties.pixelcode;
+ if (this.properties.pixelcode.indexOf(";") != -1)
+ //there are line breaks, means multiline code
+ pixelcode = this.properties.pixelcode;
+ }
+
+ var shader = this._shader;
+
+ if (!shader || this._shader_code != uvcode + "|" + pixelcode) {
+ try {
+ this._shader = new GL.Shader(
+ Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureOperation.pixel_shader,
+ { UV_CODE: uvcode, PIXEL_CODE: pixelcode }
+ );
+ this.boxcolor = "#00FF00";
+ } catch (err) {
+ console.log("Error compiling shader: ", err);
+ this.boxcolor = "#FF0000";
+ return;
+ }
+ this.boxcolor = "#FF0000";
+
+ this._shader_code = uvcode + "|" + pixelcode;
+ shader = this._shader;
+ }
+
+ if (!shader) {
+ this.boxcolor = "red";
+ return;
+ } else this.boxcolor = "green";
+
+ var value = this.getInputData(2);
+ if (value != null) this.properties.value = value;
+ else value = parseFloat(this.properties.value);
+
+ var time = this.graph.getTime();
+
+ 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,
+ value: value,
+ texSize: [width, height],
+ time: time
+ })
+ .draw(mesh);
+ });
+
+ this.setOutputData(0, this._tex);
+ };
+
+ LGraphTextureOperation.pixel_shader =
+ "precision highp float;\n\
+ \n\
+ uniform sampler2D u_texture;\n\
+ uniform sampler2D u_textureB;\n\
+ varying vec2 v_coord;\n\
+ uniform vec2 texSize;\n\
+ uniform float time;\n\
+ uniform float value;\n\
+ \n\
+ void main() {\n\
+ vec2 uv = v_coord;\n\
+ UV_CODE;\n\
+ vec4 color4 = texture2D(u_texture, uv);\n\
+ vec3 color = color4.rgb;\n\
+ vec4 color4B = texture2D(u_textureB, uv);\n\
+ vec3 colorB = color4B.rgb;\n\
+ vec3 result = color;\n\
+ float alpha = 1.0;\n\
+ PIXEL_CODE;\n\
+ gl_FragColor = vec4(result, alpha);\n\
+ }\n\
+ ";
+
+ LiteGraph.registerNodeType("texture/operation", LGraphTextureOperation);
+
+ //****************************************************
+
+ function LGraphTextureShader() {
+ this.addOutput("out", "Texture");
+ 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 = { in_texture: 0, texSize: vec2.create(), time: 0 };
+ }
+
+ LGraphTextureShader.title = "Shader";
+ LGraphTextureShader.desc = "Texture shader";
+ LGraphTextureShader.widgets_info = {
+ code: { type: "code" },
+ precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
+ };
+
+ LGraphTextureShader.prototype.onPropertyChanged = function(
+ name,
+ value
+ ) {
+ if (name != "code") return;
+
+ var shader = this.getShader();
+ if (!shader) return;
+
+ //update connections
+ var uniforms = shader.uniformInfo;
+
+ //remove deprecated slots
+ if (this.inputs) {
+ var already = {};
+ for (var i = 0; i < this.inputs.length; ++i) {
+ var info = this.getInputInfo(i);
+ if (!info) continue;
+
+ if (uniforms[info.name] && !already[info.name]) {
+ already[info.name] = true;
+ continue;
+ }
+ this.removeInput(i);
+ i--;
+ }
+ }
+
+ //update existing ones
+ for (var i in uniforms) {
+ var info = shader.uniformInfo[i];
+ if (info.loc === null) continue; //is an attribute, not a uniform
+ if (i == "time")
+ //default one
+ continue;
+
+ var type = "number";
+ if (this._shader.samplers[i]) type = "texture";
+ else {
+ switch (info.size) {
+ case 1:
+ type = "number";
+ break;
+ case 2:
+ type = "vec2";
+ break;
+ case 3:
+ type = "vec3";
+ break;
+ case 4:
+ type = "vec4";
+ break;
+ case 9:
+ type = "mat3";
+ break;
+ case 16:
+ type = "mat4";
+ break;
+ default:
+ continue;
+ }
+ }
+
+ var slot = this.findInputSlot(i);
+ if (slot == -1) {
+ this.addInput(i, type);
+ continue;
+ }
+
+ var input_info = this.getInputInfo(slot);
+ if (!input_info) this.addInput(i, type);
+ else {
+ if (input_info.type == type) continue;
+ this.removeInput(slot, type);
+ this.addInput(i, type);
+ }
+ }
+ };
+
+ LGraphTextureShader.prototype.getShader = function() {
+ //replug
+ if (this._shader && this._shader_code == this.properties.code)
+ return this._shader;
+
+ this._shader_code = this.properties.code;
+ this._shader = new GL.Shader(
+ Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureShader.pixel_shader + this.properties.code
+ );
+ if (!this._shader) {
+ this.boxcolor = "red";
+ return null;
+ } else this.boxcolor = "green";
+ return this._shader;
+ };
+
+ LGraphTextureShader.prototype.onExecute = function() {
+ if (!this.isOutputConnected(0)) return; //saves work
+
+ var shader = this.getShader();
+ if (!shader) return;
+
+ var tex_slot = 0;
+ var in_tex = null;
+
+ //set uniforms
+ for (var i = 0; i < this.inputs.length; ++i) {
+ var info = this.getInputInfo(i);
+ var data = this.getInputData(i);
+ if (data == null) continue;
+
+ if (data.constructor === GL.Texture) {
+ data.bind(tex_slot);
+ if (!in_tex) in_tex = data;
+ data = tex_slot;
+ tex_slot++;
+ }
+ shader.setUniform(info.name, data); //data is tex_slot
+ }
+
+ var uniforms = this._uniforms;
+ var type = LGraphTexture.getTextureType(
+ this.properties.precision,
+ in_tex
+ );
+
+ //render to texture
+ var w = this.properties.width | 0;
+ var h = this.properties.height | 0;
+ if (w == 0) w = in_tex ? in_tex.width : gl.canvas.width;
+ if (h == 0) h = in_tex ? in_tex.height : gl.canvas.height;
+ uniforms.texSize[0] = w;
+ uniforms.texSize[1] = h;
+ uniforms.time = this.graph.getTime();
+
+ 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;
+ tex.drawTo(function() {
+ shader.uniforms(uniforms).draw(GL.Mesh.getScreenQuad());
+ });
+
+ this.setOutputData(0, this._tex);
+ };
+
+ LGraphTextureShader.pixel_shader =
+ "precision highp float;\n\
+ \n\
+ varying vec2 v_coord;\n\
+ uniform float time;\n\
+ ";
+
+ 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 - vec2(0.5)) * 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,
+ filter: true,
+ disable_alpha: false,
+ gamma: 1.0
+ };
+ this.size[0] = 130;
+ }
+
+ LGraphTextureToViewport.title = "to Viewport";
+ LGraphTextureToViewport.desc = "Texture to viewport";
+
+ LGraphTextureToViewport.prototype.onExecute = function() {
+ var tex = this.getInputData(0);
+ if (!tex) return;
+
+ if (this.properties.disable_alpha) gl.disable(gl.BLEND);
+ else {
+ gl.enable(gl.BLEND);
+ if (this.properties.additive)
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
+ else gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+ }
+
+ gl.disable(gl.DEPTH_TEST);
+ var gamma = this.properties.gamma || 1.0;
+ if (this.isInputConnected(1)) gamma = this.getInputData(1);
+
+ tex.setParameter(
+ gl.TEXTURE_MAG_FILTER,
+ this.properties.filter ? gl.LINEAR : gl.NEAREST
+ );
+
+ 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],
+ u_igamma: 1 / gamma,
+ inverseVP: [1 / tex.width, 1 / tex.height]
+ })
+ .draw(mesh);
+ } else {
+ 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.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\
+ \n\
+ /* from mitsuhiko/webgl-meincraft based on the code on geeks3d.com */\n\
+ vec4 applyFXAA(sampler2D tex, vec2 fragCoord)\n\
+ {\n\
+ vec4 color = vec4(0.0);\n\
+ /*vec2 inverseVP = vec2(1.0 / uViewportSize.x, 1.0 / uViewportSize.y);*/\n\
+ vec3 rgbNW = texture2D(tex, (fragCoord + vec2(-1.0, -1.0)) * inverseVP).xyz;\n\
+ vec3 rgbNE = texture2D(tex, (fragCoord + vec2(1.0, -1.0)) * inverseVP).xyz;\n\
+ vec3 rgbSW = texture2D(tex, (fragCoord + vec2(-1.0, 1.0)) * inverseVP).xyz;\n\
+ vec3 rgbSE = texture2D(tex, (fragCoord + vec2(1.0, 1.0)) * inverseVP).xyz;\n\
+ vec3 rgbM = texture2D(tex, fragCoord * inverseVP).xyz;\n\
+ vec3 luma = vec3(0.299, 0.587, 0.114);\n\
+ float lumaNW = dot(rgbNW, luma);\n\
+ float lumaNE = dot(rgbNE, luma);\n\
+ float lumaSW = dot(rgbSW, luma);\n\
+ float lumaSE = dot(rgbSE, luma);\n\
+ float lumaM = dot(rgbM, luma);\n\
+ float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));\n\
+ float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));\n\
+ \n\
+ vec2 dir;\n\
+ dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n\
+ dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n\
+ \n\
+ float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);\n\
+ \n\
+ float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);\n\
+ dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * inverseVP;\n\
+ \n\
+ vec3 rgbA = 0.5 * (texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + \n\
+ texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);\n\
+ 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\
+ 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\
+ void main() {\n\
+ gl_FragColor = applyFXAA( u_texture, v_coord * uViewportSize) ;\n\
+ }\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
+ );
+
+ // Texture Copy *****************************************
+ function LGraphTextureCopy() {
+ this.addInput("Texture", "Texture");
+ this.addOutput("", "Texture");
+ this.properties = {
+ size: 0,
+ generate_mipmaps: false,
+ precision: LGraphTexture.DEFAULT
+ };
+ }
+
+ LGraphTextureCopy.title = "Copy";
+ LGraphTextureCopy.desc = "Copy Texture";
+ LGraphTextureCopy.widgets_info = {
+ size: {
+ widget: "combo",
+ values: [0, 32, 64, 128, 256, 512, 1024, 2048]
+ },
+ precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
+ };
+
+ LGraphTextureCopy.prototype.onExecute = function() {
+ var tex = this.getInputData(0);
+ if (!tex && !this._temp_texture) return;
+
+ if (!this.isOutputConnected(0)) return; //saves work
+
+ //copy the texture
+ if (tex) {
+ var width = tex.width;
+ var height = tex.height;
+
+ if (this.properties.size != 0) {
+ width = this.properties.size;
+ height = this.properties.size;
+ }
+
+ var temp = this._temp_texture;
+
+ var type = tex.type;
+ if (this.properties.precision === LGraphTexture.LOW)
+ type = gl.UNSIGNED_BYTE;
+ else if (this.properties.precision === LGraphTexture.HIGH)
+ type = gl.HIGH_PRECISION_FORMAT;
+
+ if (
+ !temp ||
+ temp.width != width ||
+ temp.height != height ||
+ temp.type != type
+ ) {
+ var minFilter = gl.LINEAR;
+ if (
+ this.properties.generate_mipmaps &&
+ isPowerOfTwo(width) &&
+ isPowerOfTwo(height)
+ )
+ minFilter = gl.LINEAR_MIPMAP_LINEAR;
+ this._temp_texture = new GL.Texture(width, height, {
+ type: type,
+ format: gl.RGBA,
+ minFilter: minFilter,
+ magFilter: gl.LINEAR
+ });
+ }
+ tex.copyTo(this._temp_texture);
+
+ if (this.properties.generate_mipmaps) {
+ this._temp_texture.bind(0);
+ gl.generateMipmap(this._temp_texture.texture_type);
+ this._temp_texture.unbind(0);
+ }
+ }
+
+ this.setOutputData(0, this._temp_texture);
+ };
+
+ LiteGraph.registerNodeType("texture/copy", LGraphTextureCopy);
+
+ // Texture Downsample *****************************************
+ function LGraphTextureDownsample() {
+ this.addInput("Texture", "Texture");
+ this.addOutput("", "Texture");
+ this.properties = {
+ iterations: 1,
+ generate_mipmaps: false,
+ precision: LGraphTexture.DEFAULT
+ };
+ }
+
+ LGraphTextureDownsample.title = "Downsample";
+ LGraphTextureDownsample.desc = "Downsample Texture";
+ LGraphTextureDownsample.widgets_info = {
+ iterations: { type: "number", step: 1, precision: 0, min: 0 },
+ precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
+ };
+
+ LGraphTextureDownsample.prototype.onExecute = function() {
+ var tex = this.getInputData(0);
+ if (!tex && !this._temp_texture) return;
+
+ if (!this.isOutputConnected(0)) return; //saves work
+
+ //we do not allow any texture different than texture 2D
+ if (!tex || tex.texture_type !== GL.TEXTURE_2D) return;
+
+ if (this.properties.iterations < 1) {
+ this.setOutputData(0, tex);
+ return;
+ }
+
+ var shader = LGraphTextureDownsample._shader;
+ if (!shader)
+ LGraphTextureDownsample._shader = shader = new GL.Shader(
+ GL.Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureDownsample.pixel_shader
+ );
+
+ var width = tex.width | 0;
+ var height = tex.height | 0;
+ var type = tex.type;
+ if (this.properties.precision === LGraphTexture.LOW)
+ type = gl.UNSIGNED_BYTE;
+ else if (this.properties.precision === LGraphTexture.HIGH)
+ type = gl.HIGH_PRECISION_FORMAT;
+ var iterations = this.properties.iterations || 1;
+
+ var origin = tex;
+ var target = null;
+
+ var temp = [];
+ var options = {
+ type: type,
+ format: tex.format
+ };
+
+ var offset = vec2.create();
+ var uniforms = {
+ u_offset: offset
+ };
+
+ if (this._texture) GL.Texture.releaseTemporary(this._texture);
+
+ for (var i = 0; i < iterations; ++i) {
+ offset[0] = 1 / width;
+ offset[1] = 1 / height;
+ width = width >> 1 || 0;
+ height = height >> 1 || 0;
+ target = GL.Texture.getTemporary(width, height, options);
+ temp.push(target);
+ origin.setParameter(GL.TEXTURE_MAG_FILTER, GL.NEAREST);
+ origin.copyTo(target, shader, uniforms);
+ if (width == 1 && height == 1) break; //nothing else to do
+ origin = target;
+ }
+
+ //keep the last texture used
+ this._texture = temp.pop();
+
+ //free the rest
+ for (var i = 0; i < temp.length; ++i)
+ GL.Texture.releaseTemporary(temp[i]);
+
+ if (this.properties.generate_mipmaps) {
+ this._texture.bind(0);
+ gl.generateMipmap(this._texture.texture_type);
+ this._texture.unbind(0);
+ }
+
+ this.setOutputData(0, this._texture);
+ };
+
+ LGraphTextureDownsample.pixel_shader =
+ "precision highp float;\n\
+ precision highp float;\n\
+ uniform sampler2D u_texture;\n\
+ uniform vec2 u_offset;\n\
+ varying vec2 v_coord;\n\
+ \n\
+ void main() {\n\
+ vec4 color = texture2D(u_texture, v_coord );\n\
+ color += texture2D(u_texture, v_coord + vec2( u_offset.x, 0.0 ) );\n\
+ color += texture2D(u_texture, v_coord + vec2( 0.0, u_offset.y ) );\n\
+ color += texture2D(u_texture, v_coord + vec2( u_offset.x, u_offset.y ) );\n\
+ gl_FragColor = color * 0.25;\n\
+ }\n\
+ ";
+
+ LiteGraph.registerNodeType(
+ "texture/downsample",
+ LGraphTextureDownsample
+ );
+
+ // Texture Average *****************************************
+ function LGraphTextureAverage() {
+ this.addInput("Texture", "Texture");
+ this.addOutput("tex", "Texture");
+ this.addOutput("avg", "vec4");
+ this.addOutput("lum", "number");
+ this.properties = {
+ use_previous_frame: true,
+ 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";
+ LGraphTextureAverage.desc =
+ "Compute a partial average (32 random samples) of a texture and stores it as a 1x1 pixel texture";
+
+ LGraphTextureAverage.prototype.onExecute = function() {
+ if (!this.properties.use_previous_frame) this.updateAverage();
+
+ var v = this._luminance;
+ this.setOutputData(0, this._temp_texture);
+ this.setOutputData(1, v);
+ this.setOutputData(2, (v[0] + v[1] + v[2]) / 3);
+ };
+
+ //executed before rendering the frame
+ LGraphTextureAverage.prototype.onPreRenderExecute = function() {
+ this.updateAverage();
+ };
+
+ LGraphTextureAverage.prototype.updateAverage = function() {
+ var tex = this.getInputData(0);
+ if (!tex) return;
+
+ if (
+ !this.isOutputConnected(0) &&
+ !this.isOutputConnected(1) &&
+ !this.isOutputConnected(2)
+ )
+ return; //saves work
+
+ if (!LGraphTextureAverage._shader) {
+ LGraphTextureAverage._shader = new GL.Shader(
+ GL.Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureAverage.pixel_shader
+ );
+ //creates 32 random numbers and stores the, in two mat4
+ var samples = new Float32Array(32);
+ for (var i = 0; i < 32; ++i) samples[i] = Math.random();
+ LGraphTextureAverage._shader.uniforms({
+ u_samples_a: samples.subarray(0, 16),
+ u_samples_b: samples.subarray(16, 32)
+ });
+ }
+
+ var temp = this._temp_texture;
+ 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
+ });
+
+ var shader = LGraphTextureAverage._shader;
+ var uniforms = this._uniforms;
+ uniforms.u_mipmap_offset = this.properties.mipmap_offset;
+ gl.disable(gl.DEPTH_TEST);
+ gl.disable(gl.BLEND);
+ this._temp_texture.drawTo(function() {
+ tex.toViewport(shader, uniforms);
+ });
+
+ 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
+ ) {
+ //no half floats possible, hard to read back unless copyed to a FLOAT texture, so temp_texture is always forced to FLOAT
+ }
+ }
+ }
+ };
+
+ LGraphTextureAverage.pixel_shader =
+ "precision highp float;\n\
+ precision highp float;\n\
+ uniform mat4 u_samples_a;\n\
+ uniform mat4 u_samples_b;\n\
+ uniform sampler2D u_texture;\n\
+ uniform float u_mipmap_offset;\n\
+ varying vec2 v_coord;\n\
+ \n\
+ void main() {\n\
+ vec4 color = vec4(0.0);\n\
+ for(int i = 0; i < 4; ++i)\n\
+ for(int j = 0; j < 4; ++j)\n\
+ {\n\
+ color += texture2D(u_texture, vec2( u_samples_a[i][j], u_samples_b[i][j] ), u_mipmap_offset );\n\
+ color += texture2D(u_texture, vec2( 1.0 - u_samples_a[i][j], 1.0 - u_samples_b[i][j] ), u_mipmap_offset );\n\
+ }\n\
+ gl_FragColor = color * 0.03125;\n\
+ }\n\
+ ";
+
+ LiteGraph.registerNodeType("texture/average", LGraphTextureAverage);
+
+ function LGraphTextureTemporalSmooth() {
+ this.addInput("in", "Texture");
+ this.addInput("factor", "Number");
+ this.addOutput("out", "Texture");
+ this.properties = { factor: 0.5 };
+ this._uniforms = {
+ u_texture: 0,
+ u_textureB: 1,
+ u_factor: this.properties.factor
+ };
+ }
+
+ LGraphTextureTemporalSmooth.title = "Smooth";
+ LGraphTextureTemporalSmooth.desc = "Smooth texture over time";
+
+ LGraphTextureTemporalSmooth.prototype.onExecute = function() {
+ var tex = this.getInputData(0);
+ if (!tex || !this.isOutputConnected(0)) return;
+
+ if (!LGraphTextureTemporalSmooth._shader)
+ LGraphTextureTemporalSmooth._shader = new GL.Shader(
+ GL.Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureTemporalSmooth.pixel_shader
+ );
+
+ var temp = this._temp_texture;
+ if (
+ !temp ||
+ temp.type != tex.type ||
+ temp.width != tex.width ||
+ temp.height != tex.height
+ ) {
+ this._temp_texture = new GL.Texture(tex.width, tex.height, {
+ type: tex.type,
+ format: gl.RGBA,
+ filter: gl.NEAREST
+ });
+ this._temp_texture2 = new GL.Texture(tex.width, tex.height, {
+ type: tex.type,
+ format: gl.RGBA,
+ filter: gl.NEAREST
+ });
+ tex.copyTo(this._temp_texture2);
+ }
+
+ var tempA = this._temp_texture;
+ var tempB = this._temp_texture2;
+
+ var shader = LGraphTextureTemporalSmooth._shader;
+ var uniforms = this._uniforms;
+ uniforms.u_factor = 1.0 - this.getInputOrProperty("factor");
+
+ gl.disable(gl.BLEND);
+ gl.disable(gl.DEPTH_TEST);
+ tempA.drawTo(function() {
+ tempB.bind(1);
+ tex.toViewport(shader, uniforms);
+ });
+
+ this.setOutputData(0, tempA);
+
+ //swap
+ this._temp_texture = tempB;
+ this._temp_texture2 = tempA;
+ };
+
+ LGraphTextureTemporalSmooth.pixel_shader =
+ "precision highp float;\n\
+ precision highp float;\n\
+ uniform sampler2D u_texture;\n\
+ uniform sampler2D u_textureB;\n\
+ uniform float u_factor;\n\
+ varying vec2 v_coord;\n\
+ \n\
+ void main() {\n\
+ gl_FragColor = mix( texture2D( u_texture, v_coord ), texture2D( u_textureB, v_coord ), u_factor );\n\
+ }\n\
+ ";
+
+ LiteGraph.registerNodeType(
+ "texture/temporal_smooth",
+ LGraphTextureTemporalSmooth
+ );
+
+ // Image To Texture *****************************************
+ function LGraphImageToTexture() {
+ this.addInput("Image", "image");
+ this.addOutput("", "Texture");
+ this.properties = {};
+ }
+
+ LGraphImageToTexture.title = "Image to Texture";
+ LGraphImageToTexture.desc = "Uploads an image to the GPU";
+ //LGraphImageToTexture.widgets_info = { size: { widget:"combo", values:[0,32,64,128,256,512,1024,2048]} };
+
+ LGraphImageToTexture.prototype.onExecute = function() {
+ var img = this.getInputData(0);
+ if (!img) return;
+
+ var width = img.videoWidth || img.width;
+ var height = img.videoHeight || img.height;
+
+ //this is in case we are using a webgl canvas already, no need to reupload it
+ if (img.gltexture) {
+ this.setOutputData(0, img.gltexture);
+ return;
+ }
+
+ var temp = this._temp_texture;
+ if (!temp || temp.width != width || temp.height != height)
+ this._temp_texture = new GL.Texture(width, height, {
+ format: gl.RGBA,
+ filter: gl.LINEAR
+ });
+
+ try {
+ this._temp_texture.uploadImage(img);
+ } catch (err) {
+ console.error(
+ "image comes from an unsafe location, cannot be uploaded to webgl: " +
+ err
+ );
+ return;
+ }
+
+ this.setOutputData(0, this._temp_texture);
+ };
+
+ LiteGraph.registerNodeType(
+ "texture/imageToTexture",
+ LGraphImageToTexture
+ );
+
+ // Texture LUT *****************************************
+ function LGraphTextureLUT() {
+ this.addInput("Texture", "Texture");
+ this.addInput("LUT", "Texture");
+ this.addInput("Intensity", "number");
+ this.addOutput("", "Texture");
+ this.properties = {
+ intensity: 1,
+ precision: LGraphTexture.DEFAULT,
+ texture: null
+ };
+
+ if (!LGraphTextureLUT._shader)
+ LGraphTextureLUT._shader = new GL.Shader(
+ Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureLUT.pixel_shader
+ );
+ }
+
+ LGraphTextureLUT.widgets_info = {
+ texture: { widget: "texture" },
+ precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
+ };
+
+ LGraphTextureLUT.title = "LUT";
+ LGraphTextureLUT.desc = "Apply LUT to Texture";
+
+ LGraphTextureLUT.prototype.onExecute = function() {
+ if (!this.isOutputConnected(0)) return; //saves work
+
+ var tex = this.getInputData(0);
+
+ if (this.properties.precision === LGraphTexture.PASS_THROUGH) {
+ this.setOutputData(0, tex);
+ return;
+ }
+
+ if (!tex) return;
+
+ var lut_tex = this.getInputData(1);
+
+ if (!lut_tex)
+ lut_tex = LGraphTexture.getTexture(this.properties.texture);
+
+ if (!lut_tex) {
+ this.setOutputData(0, tex);
+ return;
+ }
+
+ lut_tex.bind(0);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(
+ gl.TEXTURE_2D,
+ gl.TEXTURE_WRAP_S,
+ gl.CLAMP_TO_EDGE
+ );
+ gl.texParameteri(
+ gl.TEXTURE_2D,
+ gl.TEXTURE_WRAP_T,
+ gl.CLAMP_TO_EDGE
+ );
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ var intensity = this.properties.intensity;
+ if (this.isInputConnected(2))
+ this.properties.intensity = intensity = this.getInputData(2);
+
+ this._tex = LGraphTexture.getTargetTexture(
+ tex,
+ this._tex,
+ this.properties.precision
+ );
+
+ //var mesh = Mesh.getScreenQuad();
+
+ this._tex.drawTo(function() {
+ lut_tex.bind(1);
+ tex.toViewport(LGraphTextureLUT._shader, {
+ u_texture: 0,
+ u_textureB: 1,
+ u_amount: intensity
+ });
+ });
+
+ this.setOutputData(0, this._tex);
+ };
+
+ LGraphTextureLUT.pixel_shader =
+ "precision highp float;\n\
+ precision highp float;\n\
+ varying vec2 v_coord;\n\
+ uniform sampler2D u_texture;\n\
+ uniform sampler2D u_textureB;\n\
+ uniform float u_amount;\n\
+ \n\
+ void main() {\n\
+ lowp vec4 textureColor = clamp( texture2D(u_texture, v_coord), vec4(0.0), vec4(1.0) );\n\
+ mediump float blueColor = textureColor.b * 63.0;\n\
+ mediump vec2 quad1;\n\
+ quad1.y = floor(floor(blueColor) / 8.0);\n\
+ quad1.x = floor(blueColor) - (quad1.y * 8.0);\n\
+ mediump vec2 quad2;\n\
+ quad2.y = floor(ceil(blueColor) / 8.0);\n\
+ quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n\
+ highp vec2 texPos1;\n\
+ texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n\
+ texPos1.y = 1.0 - ((quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g));\n\
+ highp vec2 texPos2;\n\
+ texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n\
+ texPos2.y = 1.0 - ((quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g));\n\
+ lowp vec4 newColor1 = texture2D(u_textureB, texPos1);\n\
+ lowp vec4 newColor2 = texture2D(u_textureB, texPos2);\n\
+ lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n\
+ gl_FragColor = vec4( mix( textureColor.rgb, newColor.rgb, u_amount), textureColor.w);\n\
+ }\n\
+ ";
+
+ LiteGraph.registerNodeType("texture/LUT", LGraphTextureLUT);
+
+ // Texture Channels *****************************************
+ function LGraphTextureChannels() {
+ this.addInput("Texture", "Texture");
+
+ this.addOutput("R", "Texture");
+ this.addOutput("G", "Texture");
+ this.addOutput("B", "Texture");
+ this.addOutput("A", "Texture");
+
+ this.properties = { use_luminance: true };
+ if (!LGraphTextureChannels._shader)
+ LGraphTextureChannels._shader = new GL.Shader(
+ Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureChannels.pixel_shader
+ );
+ }
+
+ LGraphTextureChannels.title = "Texture to Channels";
+ LGraphTextureChannels.desc = "Split texture channels";
+
+ LGraphTextureChannels.prototype.onExecute = function() {
+ var texA = this.getInputData(0);
+ if (!texA) return;
+
+ if (!this._channels) this._channels = Array(4);
+
+ var format = this.properties.use_luminance ? gl.LUMINANCE : gl.RGBA;
+ var connections = 0;
+ for (var i = 0; i < 4; i++) {
+ if (this.isOutputConnected(i)) {
+ if (
+ !this._channels[i] ||
+ this._channels[i].width != texA.width ||
+ this._channels[i].height != texA.height ||
+ this._channels[i].type != texA.type ||
+ this._channels[i].format != format
+ )
+ this._channels[i] = new GL.Texture(
+ texA.width,
+ texA.height,
+ {
+ type: texA.type,
+ format: format,
+ filter: gl.LINEAR
+ }
+ );
+ connections++;
+ } else this._channels[i] = null;
+ }
+
+ if (!connections) return;
+
+ gl.disable(gl.BLEND);
+ gl.disable(gl.DEPTH_TEST);
+
+ var mesh = Mesh.getScreenQuad();
+ var shader = LGraphTextureChannels._shader;
+ var masks = [
+ [1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0],
+ [0, 0, 0, 1]
+ ];
+
+ for (var i = 0; i < 4; i++) {
+ if (!this._channels[i]) continue;
+
+ this._channels[i].drawTo(function() {
+ texA.bind(0);
+ shader
+ .uniforms({ u_texture: 0, u_mask: masks[i] })
+ .draw(mesh);
+ });
+ this.setOutputData(i, this._channels[i]);
+ }
+ };
+
+ LGraphTextureChannels.pixel_shader =
+ "precision highp float;\n\
+ precision highp float;\n\
+ varying vec2 v_coord;\n\
+ uniform sampler2D u_texture;\n\
+ uniform vec4 u_mask;\n\
+ \n\
+ void main() {\n\
+ gl_FragColor = vec4( vec3( length( texture2D(u_texture, v_coord) * u_mask )), 1.0 );\n\
+ }\n\
+ ";
+
+ LiteGraph.registerNodeType(
+ "texture/textureChannels",
+ LGraphTextureChannels
+ );
+
+ // Texture Channels to Texture *****************************************
+ function LGraphChannelsTexture() {
+ this.addInput("R", "Texture");
+ this.addInput("G", "Texture");
+ this.addInput("B", "Texture");
+ this.addInput("A", "Texture");
+
+ this.addOutput("Texture", "Texture");
+
+ this.properties = {
+ precision: LGraphTexture.DEFAULT,
+ R: 1,
+ G: 1,
+ B: 1,
+ A: 1
+ };
+ this._color = vec4.create();
+ this._uniforms = {
+ u_textureR: 0,
+ u_textureG: 1,
+ u_textureB: 2,
+ u_textureA: 3,
+ u_color: this._color
+ };
+ }
+
+ LGraphChannelsTexture.title = "Channels to Texture";
+ LGraphChannelsTexture.desc = "Split texture channels";
+ LGraphChannelsTexture.widgets_info = {
+ precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
+ };
+
+ LGraphChannelsTexture.prototype.onExecute = function() {
+ var white = LGraphTexture.getWhiteTexture();
+ var texR = this.getInputData(0) || white;
+ var texG = this.getInputData(1) || white;
+ var texB = this.getInputData(2) || white;
+ var texA = this.getInputData(3) || white;
+
+ gl.disable(gl.BLEND);
+ gl.disable(gl.DEPTH_TEST);
+
+ var mesh = Mesh.getScreenQuad();
+ if (!LGraphChannelsTexture._shader)
+ LGraphChannelsTexture._shader = new GL.Shader(
+ Shader.SCREEN_VERTEX_SHADER,
+ LGraphChannelsTexture.pixel_shader
+ );
+ var shader = LGraphChannelsTexture._shader;
+
+ var w = Math.max(texR.width, texG.width, texB.width, texA.width);
+ var h = Math.max(
+ texR.height,
+ texG.height,
+ texB.height,
+ texA.height
+ );
+ var type =
+ this.properties.precision == LGraphTexture.HIGH
+ ? LGraphTexture.HIGH_PRECISION_FORMAT
+ : gl.UNSIGNED_BYTE;
+
+ if (
+ !this._texture ||
+ this._texture.width != w ||
+ this._texture.height != h ||
+ this._texture.type != type
+ )
+ this._texture = new GL.Texture(w, h, {
+ type: type,
+ format: gl.RGBA,
+ filter: gl.LINEAR
+ });
+
+ var color = this._color;
+ color[0] = this.properties.R;
+ color[1] = this.properties.G;
+ color[2] = this.properties.B;
+ color[3] = this.properties.A;
+ var uniforms = this._uniforms;
+
+ this._texture.drawTo(function() {
+ texR.bind(0);
+ texG.bind(1);
+ texB.bind(2);
+ texA.bind(3);
+ shader.uniforms(uniforms).draw(mesh);
+ });
+ this.setOutputData(0, this._texture);
+ };
+
+ LGraphChannelsTexture.pixel_shader =
+ "precision highp float;\n\
+ precision highp float;\n\
+ varying vec2 v_coord;\n\
+ uniform sampler2D u_textureR;\n\
+ uniform sampler2D u_textureG;\n\
+ uniform sampler2D u_textureB;\n\
+ uniform sampler2D u_textureA;\n\
+ uniform vec4 u_color;\n\
+ \n\
+ void main() {\n\
+ gl_FragColor = u_color * vec4( \
+ texture2D(u_textureR, v_coord).r,\
+ texture2D(u_textureG, v_coord).r,\
+ texture2D(u_textureB, v_coord).r,\
+ texture2D(u_textureA, v_coord).r);\n\
+ }\n\
+ ";
+
+ LiteGraph.registerNodeType(
+ "texture/channelsTexture",
+ LGraphChannelsTexture
+ );
+
+ // Texture Color *****************************************
+ function LGraphTextureColor() {
+ this.addOutput("Texture", "Texture");
+
+ this._tex_color = vec4.create();
+ this.properties = {
+ color: vec4.create(),
+ precision: LGraphTexture.DEFAULT
+ };
+ }
+
+ LGraphTextureColor.title = "Color";
+ LGraphTextureColor.desc =
+ "Generates a 1x1 texture with a constant color";
+
+ LGraphTextureColor.widgets_info = {
+ precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
+ };
+
+ LGraphTextureColor.prototype.onDrawBackground = function(ctx) {
+ var c = this.properties.color;
+ ctx.fillStyle =
+ "rgb(" +
+ Math.floor(Math.clamp(c[0], 0, 1) * 255) +
+ "," +
+ Math.floor(Math.clamp(c[1], 0, 1) * 255) +
+ "," +
+ Math.floor(Math.clamp(c[2], 0, 1) * 255) +
+ ")";
+ if (this.flags.collapsed) this.boxcolor = ctx.fillStyle;
+ else ctx.fillRect(0, 0, this.size[0], this.size[1]);
+ };
+
+ LGraphTextureColor.prototype.onExecute = function() {
+ var type =
+ this.properties.precision == LGraphTexture.HIGH
+ ? LGraphTexture.HIGH_PRECISION_FORMAT
+ : gl.UNSIGNED_BYTE;
+
+ if (!this._tex || this._tex.type != type)
+ this._tex = new GL.Texture(1, 1, {
+ format: gl.RGBA,
+ type: type,
+ minFilter: gl.NEAREST
+ });
+ var color = this.properties.color;
+
+ 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;
+ switch (input.name) {
+ case "RGB":
+ case "RGBA":
+ color.set(v);
+ break;
+ case "R":
+ color[0] = v;
+ break;
+ case "G":
+ color[1] = v;
+ break;
+ case "B":
+ color[2] = v;
+ break;
+ case "A":
+ color[3] = v;
+ break;
+ }
+ }
+
+ if (vec4.sqrDist(this._tex_color, color) > 0.001) {
+ this._tex_color.set(color);
+ this._tex.fill(color);
+ }
+ this.setOutputData(0, this._tex);
+ };
+
+ LGraphTextureColor.prototype.onGetInputs = function() {
+ return [
+ ["RGB", "vec3"],
+ ["RGBA", "vec4"],
+ ["R", "number"],
+ ["G", "number"],
+ ["B", "number"],
+ ["A", "number"]
+ ];
+ };
+
+ LiteGraph.registerNodeType("texture/color", LGraphTextureColor);
+
+ // Texture Channels to Texture *****************************************
+ function LGraphTextureGradient() {
+ this.addInput("A", "color");
+ this.addInput("B", "color");
+ this.addOutput("Texture", "Texture");
+
+ this.properties = {
+ angle: 0,
+ scale: 1,
+ A: [0, 0, 0],
+ B: [1, 1, 1],
+ texture_size: 32
+ };
+ if (!LGraphTextureGradient._shader)
+ LGraphTextureGradient._shader = new GL.Shader(
+ Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureGradient.pixel_shader
+ );
+
+ this._uniforms = {
+ u_angle: 0,
+ u_colorA: vec3.create(),
+ u_colorB: vec3.create()
+ };
+ }
+
+ LGraphTextureGradient.title = "Gradient";
+ LGraphTextureGradient.desc = "Generates a gradient";
+ LGraphTextureGradient["@A"] = { type: "color" };
+ LGraphTextureGradient["@B"] = { type: "color" };
+ LGraphTextureGradient["@texture_size"] = {
+ type: "enum",
+ values: [32, 64, 128, 256, 512]
+ };
+
+ LGraphTextureGradient.prototype.onExecute = function() {
+ gl.disable(gl.BLEND);
+ gl.disable(gl.DEPTH_TEST);
+
+ var mesh = GL.Mesh.getScreenQuad();
+ var shader = LGraphTextureGradient._shader;
+
+ var A = this.getInputData(0);
+ if (!A) A = this.properties.A;
+ var B = this.getInputData(1);
+ if (!B) B = this.properties.B;
+
+ //angle and scale
+ for (var i = 2; 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 uniforms = this._uniforms;
+ this._uniforms.u_angle = this.properties.angle * DEG2RAD;
+ this._uniforms.u_scale = this.properties.scale;
+ vec3.copy(uniforms.u_colorA, A);
+ vec3.copy(uniforms.u_colorB, B);
+
+ var size = parseInt(this.properties.texture_size);
+ if (!this._tex || this._tex.width != size)
+ this._tex = new GL.Texture(size, size, {
+ format: gl.RGB,
+ filter: gl.LINEAR
+ });
+
+ this._tex.drawTo(function() {
+ shader.uniforms(uniforms).draw(mesh);
+ });
+ this.setOutputData(0, this._tex);
+ };
+
+ LGraphTextureGradient.prototype.onGetInputs = function() {
+ return [["angle", "number"], ["scale", "number"]];
+ };
+
+ LGraphTextureGradient.pixel_shader =
+ "precision highp float;\n\
+ precision highp float;\n\
+ varying vec2 v_coord;\n\
+ uniform float u_angle;\n\
+ uniform float u_scale;\n\
+ uniform vec3 u_colorA;\n\
+ uniform vec3 u_colorB;\n\
+ \n\
+ vec2 rotate(vec2 v, float angle)\n\
+ {\n\
+ vec2 result;\n\
+ float _cos = cos(angle);\n\
+ float _sin = sin(angle);\n\
+ result.x = v.x * _cos - v.y * _sin;\n\
+ result.y = v.x * _sin + v.y * _cos;\n\
+ return result;\n\
+ }\n\
+ void main() {\n\
+ float f = (rotate(u_scale * (v_coord - vec2(0.5)), u_angle) + vec2(0.5)).x;\n\
+ vec3 color = mix(u_colorA,u_colorB,clamp(f,0.0,1.0));\n\
+ gl_FragColor = vec4(color,1.0);\n\
+ }\n\
+ ";
+
+ LiteGraph.registerNodeType("texture/gradient", LGraphTextureGradient);
+
+ // Texture Mix *****************************************
+ function LGraphTextureMix() {
+ this.addInput("A", "Texture");
+ this.addInput("B", "Texture");
+ this.addInput("Mixer", "Texture");
+
+ this.addOutput("Texture", "Texture");
+ this.properties = { factor: 0.5, precision: LGraphTexture.DEFAULT };
+ this._uniforms = {
+ u_textureA: 0,
+ u_textureB: 1,
+ u_textureMix: 2,
+ u_mix: vec4.create()
+ };
+ }
+
+ LGraphTextureMix.title = "Mix";
+ LGraphTextureMix.desc = "Generates a texture mixing two textures";
+
+ LGraphTextureMix.widgets_info = {
+ precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
+ };
+
+ LGraphTextureMix.prototype.onExecute = function() {
+ var texA = this.getInputData(0);
+
+ if (!this.isOutputConnected(0)) return; //saves work
+
+ if (this.properties.precision === LGraphTexture.PASS_THROUGH) {
+ this.setOutputData(0, texA);
+ return;
+ }
+
+ var texB = this.getInputData(1);
+ if (!texA || !texB) return;
+
+ var texMix = this.getInputData(2);
+
+ var factor = this.getInputData(3);
+
+ this._tex = LGraphTexture.getTargetTexture(
+ texA,
+ this._tex,
+ this.properties.precision
+ );
+
+ gl.disable(gl.BLEND);
+ gl.disable(gl.DEPTH_TEST);
+
+ var mesh = Mesh.getScreenQuad();
+ var shader = null;
+ var uniforms = this._uniforms;
+ if (texMix) {
+ shader = LGraphTextureMix._shader_tex;
+ if (!shader)
+ shader = LGraphTextureMix._shader_tex = new GL.Shader(
+ Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureMix.pixel_shader,
+ { MIX_TEX: "" }
+ );
+ } else {
+ shader = LGraphTextureMix._shader_factor;
+ if (!shader)
+ shader = LGraphTextureMix._shader_factor = new GL.Shader(
+ Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureMix.pixel_shader
+ );
+ var f = factor == null ? this.properties.factor : factor;
+ uniforms.u_mix.set([f, f, f, f]);
+ }
+
+ this._tex.drawTo(function() {
+ texA.bind(0);
+ texB.bind(1);
+ if (texMix) texMix.bind(2);
+ shader.uniforms(uniforms).draw(mesh);
+ });
+
+ this.setOutputData(0, this._tex);
+ };
+
+ LGraphTextureMix.prototype.onGetInputs = function() {
+ return [["factor", "number"]];
+ };
+
+ LGraphTextureMix.pixel_shader =
+ "precision highp float;\n\
+ precision highp float;\n\
+ varying vec2 v_coord;\n\
+ uniform sampler2D u_textureA;\n\
+ uniform sampler2D u_textureB;\n\
+ #ifdef MIX_TEX\n\
+ uniform sampler2D u_textureMix;\n\
+ #else\n\
+ uniform vec4 u_mix;\n\
+ #endif\n\
+ \n\
+ void main() {\n\
+ #ifdef MIX_TEX\n\
+ vec4 f = texture2D(u_textureMix, v_coord);\n\
+ #else\n\
+ vec4 f = u_mix;\n\
+ #endif\n\
+ gl_FragColor = mix( texture2D(u_textureA, v_coord), texture2D(u_textureB, v_coord), f );\n\
+ }\n\
+ ";
+
+ LiteGraph.registerNodeType("texture/mix", LGraphTextureMix);
+
+ // Texture Edges detection *****************************************
+ function LGraphTextureEdges() {
+ this.addInput("Tex.", "Texture");
+
+ this.addOutput("Edges", "Texture");
+ 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
+ );
+ }
+
+ LGraphTextureEdges.title = "Edges";
+ LGraphTextureEdges.desc = "Detects edges";
+
+ LGraphTextureEdges.widgets_info = {
+ precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
+ };
+
+ LGraphTextureEdges.prototype.onExecute = function() {
+ if (!this.isOutputConnected(0)) return; //saves work
+
+ var tex = this.getInputData(0);
+
+ if (this.properties.precision === LGraphTexture.PASS_THROUGH) {
+ this.setOutputData(0, tex);
+ return;
+ }
+
+ if (!tex) return;
+
+ this._tex = LGraphTexture.getTargetTexture(
+ tex,
+ this._tex,
+ this.properties.precision
+ );
+
+ gl.disable(gl.BLEND);
+ gl.disable(gl.DEPTH_TEST);
+
+ var mesh = Mesh.getScreenQuad();
+ 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_threshold: threshold,
+ u_invert: invert ? 1 : 0
+ })
+ .draw(mesh);
+ });
+
+ this.setOutputData(0, this._tex);
+ };
+
+ LGraphTextureEdges.pixel_shader =
+ "precision highp float;\n\
+ precision highp float;\n\
+ varying vec2 v_coord;\n\
+ uniform sampler2D u_texture;\n\
+ 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\
+ vec4 up = texture2D(u_texture, v_coord + u_isize * vec2(0.0,1.0) );\n\
+ vec4 down = texture2D(u_texture, v_coord + u_isize * vec2(0.0,-1.0) );\n\
+ vec4 left = texture2D(u_texture, v_coord + u_isize * vec2(1.0,0.0) );\n\
+ vec4 right = texture2D(u_texture, v_coord + u_isize * vec2(-1.0,0.0) );\n\
+ vec4 diff = abs(center - up) + abs(center - down) + abs(center - left) + abs(center - right);\n\
+ diff *= u_factor;\n\
+ if(u_invert == 1)\n\
+ diff.xyz = vec3(1.0) - diff.xyz;\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\
+ ";
+
+ LiteGraph.registerNodeType("texture/edges", LGraphTextureEdges);
+
+ // Texture Depth *****************************************
+ function LGraphTextureDepthRange() {
+ this.addInput("Texture", "Texture");
+ this.addInput("Distance", "number");
+ this.addInput("Range", "number");
+ this.addOutput("Texture", "Texture");
+ this.properties = {
+ distance: 100,
+ range: 50,
+ only_depth: false,
+ high_precision: false
+ };
+ this._uniforms = {
+ u_texture: 0,
+ u_distance: 100,
+ u_range: 50,
+ u_camera_planes: null
+ };
+ }
+
+ LGraphTextureDepthRange.title = "Depth Range";
+ LGraphTextureDepthRange.desc = "Generates a texture with a depth range";
+
+ LGraphTextureDepthRange.prototype.onExecute = function() {
+ if (!this.isOutputConnected(0)) return; //saves work
+
+ var tex = this.getInputData(0);
+ if (!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 uniforms = this._uniforms;
+
+ //iterations
+ var distance = this.properties.distance;
+ if (this.isInputConnected(1)) {
+ distance = this.getInputData(1);
+ this.properties.distance = distance;
+ }
+
+ var range = this.properties.range;
+ if (this.isInputConnected(2)) {
+ range = this.getInputData(2);
+ this.properties.range = range;
+ }
+
+ uniforms.u_distance = distance;
+ uniforms.u_range = range;
+
+ gl.disable(gl.BLEND);
+ gl.disable(gl.DEPTH_TEST);
+ var mesh = Mesh.getScreenQuad();
+ if (!LGraphTextureDepthRange._shader) {
+ LGraphTextureDepthRange._shader = new GL.Shader(
+ Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureDepthRange.pixel_shader
+ );
+ LGraphTextureDepthRange._shader_onlydepth = new GL.Shader(
+ Shader.SCREEN_VERTEX_SHADER,
+ LGraphTextureDepthRange.pixel_shader,
+ { ONLY_DEPTH: "" }
+ );
+ }
+ var shader = this.properties.only_depth
+ ? LGraphTextureDepthRange._shader_onlydepth
+ : LGraphTextureDepthRange._shader;
+
+ //NEAR AND FAR PLANES
+ var planes = null;
+ if (tex.near_far_planes) planes = tex.near_far_planes;
+ else if (window.LS && LS.Renderer._main_camera)
+ planes = LS.Renderer._main_camera._uniforms.u_camera_planes;
+ else planes = [0.1, 1000]; //hardcoded
+ uniforms.u_camera_planes = planes;
+
+ this._temp_texture.drawTo(function() {
+ tex.bind(0);
+ shader.uniforms(uniforms).draw(mesh);
+ });
+
+ this._temp_texture.near_far_planes = planes;
+ this.setOutputData(0, this._temp_texture);
+ };
+
+ LGraphTextureDepthRange.pixel_shader =
+ "precision highp float;\n\
+ precision highp float;\n\
+ varying vec2 v_coord;\n\
+ uniform sampler2D u_texture;\n\
+ uniform vec2 u_camera_planes;\n\
+ uniform float u_distance;\n\
+ uniform float u_range;\n\
+ \n\
+ float LinearDepth()\n\
+ {\n\
+ float zNear = u_camera_planes.x;\n\
+ float zFar = u_camera_planes.y;\n\
+ float depth = texture2D(u_texture, v_coord).x;\n\
+ depth = depth * 2.0 - 1.0;\n\
+ return zNear * (depth + 1.0) / (zFar + zNear - depth * (zFar - zNear));\n\
+ }\n\
+ \n\
+ void main() {\n\
+ float depth = LinearDepth();\n\
+ #ifdef ONLY_DEPTH\n\
+ gl_FragColor = vec4(depth);\n\
+ #else\n\
+ float diff = abs(depth * u_camera_planes.y - u_distance);\n\
+ float dof = 1.0;\n\
+ if(diff <= u_range)\n\
+ dof = diff / u_range;\n\
+ gl_FragColor = vec4(dof);\n\
+ #endif\n\
+ }\n\
+ ";
+
+ LiteGraph.registerNodeType(
+ "texture/depth_range",
+ LGraphTextureDepthRange
+ );
+
+ // Texture Blur *****************************************
+ function LGraphTextureBlur() {
+ this.addInput("Texture", "Texture");
+ this.addInput("Iterations", "number");
+ this.addInput("Intensity", "number");
+ this.addOutput("Blurred", "Texture");
+ 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() {
+ var tex = this.getInputData(0);
+ if (!tex) return;
+
+ if (!this.isOutputConnected(0)) return; //saves work
+
+ 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 });
+ temp = this._final_texture = new GL.Texture(
+ tex.width,
+ tex.height,
+ { type: tex.type, format: gl.RGBA, filter: gl.LINEAR }
+ );
+ }
+
+ //iterations
+ var iterations = this.properties.iterations;
+ if (this.isInputConnected(1)) {
+ iterations = this.getInputData(1);
+ this.properties.iterations = iterations;
+ }
+ iterations = Math.min(
+ Math.floor(iterations),
+ LGraphTextureBlur.max_iterations
+ );
+ if (iterations == 0) {
+ //skip blurring
+ this.setOutputData(0, tex);
+ return;
+ }
+
+ var intensity = this.properties.intensity;
+ if (this.isInputConnected(2)) {
+ intensity = this.getInputData(2);
+ this.properties.intensity = intensity;
+ }
+
+ //blur sometimes needs an aspect correction
+ var aspect = LiteGraph.camera_aspect;
+ if (!aspect && window.gl !== undefined)
+ aspect = gl.canvas.height / gl.canvas.width;
+ if (!aspect) aspect = 1;
+ aspect = this.properties.preserve_aspect ? aspect : 1;
+
+ var scale = this.properties.scale || [1, 1];
+ 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, temp);
+ };
+
+ /*
+ LGraphTextureBlur.pixel_shader = "precision highp float;\n\
+ precision highp float;\n\
+ varying vec2 v_coord;\n\
+ uniform sampler2D u_texture;\n\
+ uniform vec2 u_offset;\n\
+ uniform float u_intensity;\n\
+ void main() {\n\
+ vec4 sum = vec4(0.0);\n\
+ vec4 center = texture2D(u_texture, v_coord);\n\
+ sum += texture2D(u_texture, v_coord + u_offset * -4.0) * 0.05/0.98;\n\
+ sum += texture2D(u_texture, v_coord + u_offset * -3.0) * 0.09/0.98;\n\
+ 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\
+ sum += center * 0.16/0.98;\n\
+ sum += texture2D(u_texture, v_coord + u_offset * 4.0) * 0.05/0.98;\n\
+ sum += texture2D(u_texture, v_coord + u_offset * 3.0) * 0.09/0.98;\n\
+ 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\
+ }\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 = {
+ enabled: true,
+ 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.getInputOrProperty("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,
@@ -15409,96 +16669,74 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
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);
+ LiteGraph.registerNodeType("texture/glow", LGraphTextureGlow );
- // Texture Blur *****************************************
- function LGraphTextureKuwaharaFilter() {
- this.addInput("Texture", "Texture");
- this.addOutput("Filtered", "Texture");
- this.properties = { intensity: 1, radius: 5 };
- }
- LGraphTextureKuwaharaFilter.title = "Kuwahara Filter";
- LGraphTextureKuwaharaFilter.desc =
- "Filters a texture giving an artistic oil canvas painting";
+ // Texture Filter *****************************************
+ function LGraphTextureKuwaharaFilter()
+ {
+ this.addInput("Texture","Texture");
+ this.addOutput("Filtered","Texture");
+ this.properties = { intensity: 1, radius: 5 };
+ }
- LGraphTextureKuwaharaFilter.max_radius = 10;
- LGraphTextureKuwaharaFilter._shaders = [];
+ LGraphTextureKuwaharaFilter.title = "Kuwahara Filter";
+ LGraphTextureKuwaharaFilter.desc = "Filters a texture giving an artistic oil canvas painting";
- LGraphTextureKuwaharaFilter.prototype.onExecute = function() {
- var tex = this.getInputData(0);
- if (!tex) return;
+ LGraphTextureKuwaharaFilter.max_radius = 10;
+ LGraphTextureKuwaharaFilter._shaders = [];
- if (!this.isOutputConnected(0)) return; //saves work
+ LGraphTextureKuwaharaFilter.prototype.onExecute = function()
+ {
+ var tex = this.getInputData(0);
+ if(!tex)
+ return;
- var temp = this._temp_texture;
+ if(!this.isOutputConnected(0))
+ return; //saves work
- 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 });
- }
+ var temp = this._temp_texture;
- //iterations
- var radius = this.properties.radius;
- radius = Math.min(
- Math.floor(radius),
- LGraphTextureKuwaharaFilter.max_radius
- );
- if (radius == 0) {
- //skip blurring
- this.setOutputData(0, tex);
- return;
- }
+ if(!temp || temp.width != tex.width || temp.height != tex.height || temp.type != tex.type )
+ this._temp_texture = new GL.Texture( tex.width, tex.height, { type: tex.type, format: gl.RGBA, filter: gl.LINEAR });
- var intensity = this.properties.intensity;
+ //iterations
+ var radius = this.properties.radius;
+ radius = Math.min( Math.floor(radius), LGraphTextureKuwaharaFilter.max_radius );
+ if(radius == 0) //skip blurring
+ {
+ this.setOutputData(0, tex);
+ return;
+ }
- //blur sometimes needs an aspect correction
- var aspect = LiteGraph.camera_aspect;
- if (!aspect && window.gl !== undefined)
- aspect = gl.canvas.height / gl.canvas.width;
- if (!aspect) aspect = 1;
- aspect = this.properties.preserve_aspect ? aspect : 1;
+ var intensity = this.properties.intensity;
- if (!LGraphTextureKuwaharaFilter._shaders[radius])
- LGraphTextureKuwaharaFilter._shaders[radius] = new GL.Shader(
- Shader.SCREEN_VERTEX_SHADER,
- LGraphTextureKuwaharaFilter.pixel_shader,
- { RADIUS: radius.toFixed(0) }
- );
+ //blur sometimes needs an aspect correction
+ var aspect = LiteGraph.camera_aspect;
+ if(!aspect && window.gl !== undefined)
+ aspect = gl.canvas.height / gl.canvas.width;
+ if(!aspect)
+ aspect = 1;
+ aspect = this.properties.preserve_aspect ? aspect : 1;
- var shader = LGraphTextureKuwaharaFilter._shaders[radius];
- var mesh = GL.Mesh.getScreenQuad();
- tex.bind(0);
+ if(!LGraphTextureKuwaharaFilter._shaders[ radius ])
+ LGraphTextureKuwaharaFilter._shaders[ radius ] = new GL.Shader( Shader.SCREEN_VERTEX_SHADER, LGraphTextureKuwaharaFilter.pixel_shader, { RADIUS: radius.toFixed(0) });
- this._temp_texture.drawTo(function() {
- shader
- .uniforms({
- u_texture: 0,
- u_intensity: intensity,
- u_resolution: [tex.width, tex.height],
- u_iResolution: [1 / tex.width, 1 / tex.height]
- })
- .draw(mesh);
- });
+ var shader = LGraphTextureKuwaharaFilter._shaders[ radius ];
+ var mesh = GL.Mesh.getScreenQuad();
+ tex.bind(0);
- this.setOutputData(0, this._temp_texture);
- };
+ this._temp_texture.drawTo( function() {
+ shader.uniforms({ u_texture: 0, u_intensity: intensity, u_resolution: [tex.width, tex.height], u_iResolution: [1/tex.width,1/tex.height]}).draw(mesh);
+ });
- //from https://www.shadertoy.com/view/MsXSz4
- LGraphTextureKuwaharaFilter.pixel_shader =
- "\n\
+ this.setOutputData(0, this._temp_texture);
+ }
+
+//from https://www.shadertoy.com/view/MsXSz4
+LGraphTextureKuwaharaFilter.pixel_shader = "\n\
precision highp float;\n\
varying vec2 v_coord;\n\
uniform sampler2D u_texture;\n\
@@ -15592,260 +16830,346 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
}\n\
";
- LiteGraph.registerNodeType(
- "texture/kuwahara",
- LGraphTextureKuwaharaFilter
- );
+ LiteGraph.registerNodeType("texture/kuwahara", LGraphTextureKuwaharaFilter );
- // Texture Webcam *****************************************
- function LGraphTextureWebcam() {
- this.addOutput("Webcam", "Texture");
- this.properties = { texture_name: "", facingMode: "user" };
- this.boxcolor = "black";
- this.version = 0;
- }
+ // Texture *****************************************
+ function LGraphTextureXDoGFilter()
+ {
+ this.addInput("Texture","Texture");
+ this.addOutput("Filtered","Texture");
+ this.properties = { sigma: 1.4, k: 1.6, p:21.7, epsilon:79, phi:0.017 };
+ }
- LGraphTextureWebcam.title = "Webcam";
- LGraphTextureWebcam.desc = "Webcam texture";
+ LGraphTextureXDoGFilter.title = "XDoG Filter";
+ LGraphTextureXDoGFilter.desc = "Filters a texture giving an artistic ink style";
- LGraphTextureWebcam.is_webcam_open = false;
+ LGraphTextureXDoGFilter.max_radius = 10;
+ LGraphTextureXDoGFilter._shaders = [];
- LGraphTextureWebcam.prototype.openStream = function() {
- if (!navigator.getUserMedia) {
- //console.log('getUserMedia() is not supported in your browser, use chrome and enable WebRTC from about://flags');
- return;
- }
+ LGraphTextureXDoGFilter.prototype.onExecute = function()
+ {
+ var tex = this.getInputData(0);
+ if(!tex)
+ return;
- this._waiting_confirmation = true;
+ if(!this.isOutputConnected(0))
+ return; //saves work
- // Not showing vendor prefixes.
- var constraints = {
- audio: false,
- video: { facingMode: this.properties.facingMode }
- };
- navigator.mediaDevices
- .getUserMedia(constraints)
- .then(this.streamReady.bind(this))
- .catch(onFailSoHard);
+ var temp = this._temp_texture;
+ if(!temp || temp.width != tex.width || temp.height != tex.height || temp.type != tex.type )
+ this._temp_texture = new GL.Texture( tex.width, tex.height, { type: tex.type, format: gl.RGBA, filter: gl.LINEAR });
- var that = this;
- function onFailSoHard(e) {
- LGraphTextureWebcam.is_webcam_open = false;
- console.log("Webcam rejected", e);
- that._webcam_stream = false;
- that.boxcolor = "red";
- that.trigger("stream_error");
- }
- };
+ if(!LGraphTextureXDoGFilter._xdog_shader)
+ LGraphTextureXDoGFilter._xdog_shader = new GL.Shader( Shader.SCREEN_VERTEX_SHADER, LGraphTextureXDoGFilter.xdog_pixel_shader );
+ var shader = LGraphTextureXDoGFilter._xdog_shader;
+ var mesh = GL.Mesh.getScreenQuad();
- LGraphTextureWebcam.prototype.closeStream = function() {
- if (this._webcam_stream) {
- var tracks = this._webcam_stream.getTracks();
- if (tracks.length) {
- for (var i = 0; i < tracks.length; ++i) tracks[i].stop();
- }
- LGraphTextureWebcam.is_webcam_open = false;
- this._webcam_stream = null;
- this._video = null;
- this.boxcolor = "black";
- this.trigger("stream_closed");
- }
- };
+ var sigma = this.properties.sigma;
+ var k = this.properties.k;
+ var p = this.properties.p;
+ var epsilon = this.properties.epsilon;
+ var phi = this.properties.phi;
+ tex.bind(0);
+ this._temp_texture.drawTo( function() {
+ shader.uniforms({ src:0, sigma: sigma, k:k, p:p, epsilon:epsilon, phi:phi, cvsWidth: tex.width, cvsHeight: tex.height }).draw(mesh);
+ });
- LGraphTextureWebcam.prototype.streamReady = function(localMediaStream) {
- this._webcam_stream = localMediaStream;
- //this._waiting_confirmation = false;
- this.boxcolor = "green";
- var video = this._video;
- if (!video) {
- video = document.createElement("video");
- video.autoplay = true;
- video.srcObject = localMediaStream;
- this._video = video;
- //document.body.appendChild( video ); //debug
- //when video info is loaded (size and so)
- video.onloadedmetadata = function(e) {
- // Ready to go. Do some stuff.
- LGraphTextureWebcam.is_webcam_open = true;
- console.log(e);
- };
- }
- this.trigger("stream_ready", video);
- };
+ this.setOutputData(0, this._temp_texture );
+ }
- LGraphTextureWebcam.prototype.onPropertyChanged = function(
- name,
- value
- ) {
- if (name == "facingMode") {
- this.properties.facingMode = value;
- this.closeStream();
- this.openStream();
- }
- };
+ //from https://github.com/RaymondMcGuire/GPU-Based-Image-Processing-Tools/blob/master/lib_webgl/scripts/main.js
+ LGraphTextureXDoGFilter.xdog_pixel_shader = "\n\
+ precision highp float;\n\
+ uniform sampler2D src;\n\n\
+ uniform float cvsHeight;\n\
+ uniform float cvsWidth;\n\n\
+ uniform float sigma;\n\
+ uniform float k;\n\
+ uniform float p;\n\
+ uniform float epsilon;\n\
+ uniform float phi;\n\
+ varying vec2 v_coord;\n\n\
+ float cosh(float val)\n\
+ {\n\
+ float tmp = exp(val);\n\
+ float cosH = (tmp + 1.0 / tmp) / 2.0;\n\
+ return cosH;\n\
+ }\n\n\
+ float tanh(float val)\n\
+ {\n\
+ float tmp = exp(val);\n\
+ float tanH = (tmp - 1.0 / tmp) / (tmp + 1.0 / tmp);\n\
+ return tanH;\n\
+ }\n\n\
+ float sinh(float val)\n\
+ {\n\
+ float tmp = exp(val);\n\
+ float sinH = (tmp - 1.0 / tmp) / 2.0;\n\
+ return sinH;\n\
+ }\n\n\
+ void main(void){\n\
+ vec3 destColor = vec3(0.0);\n\
+ float tFrag = 1.0 / cvsHeight;\n\
+ float sFrag = 1.0 / cvsWidth;\n\
+ vec2 Frag = vec2(sFrag,tFrag);\n\
+ vec2 uv = gl_FragCoord.st;\n\
+ float twoSigmaESquared = 2.0 * sigma * sigma;\n\
+ float twoSigmaRSquared = twoSigmaESquared * k * k;\n\
+ int halfWidth = int(ceil( 1.0 * sigma * k ));\n\n\
+ const int MAX_NUM_ITERATION = 99999;\n\
+ vec2 sum = vec2(0.0);\n\
+ vec2 norm = vec2(0.0);\n\n\
+ for(int cnt=0;cnt (2*halfWidth+1)*(2*halfWidth+1)){break;}\n\
+ int i = int(cnt / (2*halfWidth+1)) - halfWidth;\n\
+ int j = cnt - halfWidth - int(cnt / (2*halfWidth+1)) * (2*halfWidth+1);\n\n\
+ float d = length(vec2(i,j));\n\
+ vec2 kernel = vec2( exp( -d * d / twoSigmaESquared ), \n\
+ exp( -d * d / twoSigmaRSquared ));\n\n\
+ vec2 L = texture2D(src, (uv + vec2(i,j)) * Frag).xx;\n\n\
+ norm += kernel;\n\
+ sum += kernel * L;\n\
+ }\n\n\
+ sum /= norm;\n\n\
+ float H = 100.0 * ((1.0 + p) * sum.x - p * sum.y);\n\
+ float edge = ( H > epsilon )? 1.0 : 1.0 + tanh( phi * (H - epsilon));\n\
+ destColor = vec3(edge);\n\
+ gl_FragColor = vec4(destColor, 1.0);\n\
+ }";
+
+ LiteGraph.registerNodeType("texture/xDoG", LGraphTextureXDoGFilter );
+
+ // Texture Webcam *****************************************
+ function LGraphTextureWebcam()
+ {
+ this.addOutput("Webcam","Texture");
+ this.properties = { texture_name: "", facingMode: "user" };
+ this.boxcolor = "black";
+ this.version = 0;
+ }
+
+ LGraphTextureWebcam.title = "Webcam";
+ LGraphTextureWebcam.desc = "Webcam texture";
+
+ LGraphTextureWebcam.is_webcam_open = false;
+
+ LGraphTextureWebcam.prototype.openStream = function()
+ {
+ if (!navigator.getUserMedia) {
+ //console.log('getUserMedia() is not supported in your browser, use chrome and enable WebRTC from about://flags');
+ return;
+ }
+
+ this._waiting_confirmation = true;
+
+ // Not showing vendor prefixes.
+ var constraints = { audio: false, video: { facingMode: this.properties.facingMode } };
+ navigator.mediaDevices.getUserMedia( constraints ).then( this.streamReady.bind(this) ).catch( onFailSoHard );
+
+ var that = this;
+ function onFailSoHard(e) {
+ LGraphTextureWebcam.is_webcam_open = false;
+ console.log('Webcam rejected', e);
+ that._webcam_stream = false;
+ that.boxcolor = "red";
+ that.trigger("stream_error");
+ };
+ }
+
+ LGraphTextureWebcam.prototype.closeStream = function()
+ {
+ if(this._webcam_stream)
+ {
+ var tracks = this._webcam_stream.getTracks();
+ if(tracks.length)
+ {
+ for(var i = 0;i < tracks.length; ++i)
+ tracks[i].stop();
+ }
+ LGraphTextureWebcam.is_webcam_open = false;
+ this._webcam_stream = null;
+ this._video = null;
+ this.boxcolor = "black";
+ this.trigger("stream_closed");
+ }
+ }
+
+ LGraphTextureWebcam.prototype.streamReady = function(localMediaStream)
+ {
+ this._webcam_stream = localMediaStream;
+ //this._waiting_confirmation = false;
+ this.boxcolor = "green";
+ var video = this._video;
+ if(!video)
+ {
+ video = document.createElement("video");
+ video.autoplay = true;
+ video.srcObject = localMediaStream;
+ this._video = video;
+ //document.body.appendChild( video ); //debug
+ //when video info is loaded (size and so)
+ video.onloadedmetadata = function(e) {
+ // Ready to go. Do some stuff.
+ LGraphTextureWebcam.is_webcam_open = true;
+ console.log(e);
+ };
+ }
+ this.trigger("stream_ready",video);
+ }
+
+ LGraphTextureWebcam.prototype.onPropertyChanged = function(name,value)
+ {
+ if(name == "facingMode")
+ {
+ this.properties.facingMode = value;
+ this.closeStream();
+ this.openStream();
+ }
+ }
+
+ LGraphTextureWebcam.prototype.onRemoved = function()
+ {
+ if(!this._webcam_stream)
+ return;
+
+ var tracks = this._webcam_stream.getTracks();
+ if(tracks.length)
+ {
+ for(var i = 0;i < tracks.length; ++i)
+ tracks[i].stop();
+ }
+
+ this._webcam_stream = null;
+ this._video = null;
+ }
+
+ LGraphTextureWebcam.prototype.onDrawBackground = function(ctx)
+ {
+ if(this.flags.collapsed || this.size[1] <= 20)
+ return;
+
+ if(!this._video)
+ return;
- LGraphTextureWebcam.prototype.onRemoved = function() {
- if (!this._webcam_stream) return;
+ //render to graph canvas
+ ctx.save();
+ if(!ctx.webgl) //reverse image
+ ctx.drawImage(this._video, 0, 0, this.size[0], this.size[1]);
+ else
+ {
+ if(this._video_texture)
+ ctx.drawImage(this._video_texture, 0, 0, this.size[0], this.size[1]);
+ }
+ ctx.restore();
+ }
- var tracks = this._webcam_stream.getTracks();
- if (tracks.length) {
- for (var i = 0; i < tracks.length; ++i) tracks[i].stop();
- }
+ LGraphTextureWebcam.prototype.onExecute = function()
+ {
+ if(this._webcam_stream == null && !this._waiting_confirmation)
+ this.openStream();
- this._webcam_stream = null;
- this._video = null;
- };
+ if(!this._video || !this._video.videoWidth)
+ return;
- LGraphTextureWebcam.prototype.onDrawBackground = function(ctx) {
- if (this.flags.collapsed || this.size[1] <= 20) return;
+ var width = this._video.videoWidth;
+ var height = this._video.videoHeight;
- if (!this._video) return;
+ var temp = this._video_texture;
+ if(!temp || temp.width != width || temp.height != height )
+ this._video_texture = new GL.Texture( width, height, { format: gl.RGB, filter: gl.LINEAR });
- //render to graph canvas
- ctx.save();
- if (!ctx.webgl)
- //reverse image
- ctx.drawImage(this._video, 0, 0, this.size[0], this.size[1]);
- else {
- if (this._video_texture)
- ctx.drawImage(
- this._video_texture,
- 0,
- 0,
- this.size[0],
- this.size[1]
- );
- }
- ctx.restore();
- };
+ this._video_texture.uploadImage( this._video );
+ this._video_texture.version = ++this.version;
+
+ if(this.properties.texture_name)
+ {
+ var container = LGraphTexture.getTexturesContainer();
+ container[ this.properties.texture_name ] = this._video_texture;
+ }
- LGraphTextureWebcam.prototype.onExecute = function() {
- if (this._webcam_stream == null && !this._waiting_confirmation)
- this.openStream();
+ this.setOutputData(0,this._video_texture);
+ for(var i = 1; i < this.outputs.length; ++i)
+ {
+ if(!this.outputs[i])
+ continue;
+ switch( this.outputs[i].name )
+ {
+ case "width": this.setOutputData(i,this._video.videoWidth);break;
+ case "height": this.setOutputData(i,this._video.videoHeight);break;
+ }
+ }
+ }
- if (!this._video || !this._video.videoWidth) return;
+ LGraphTextureWebcam.prototype.onGetOutputs = function()
+ {
+ return [["width","number"],["height","number"],["stream_ready",LiteGraph.EVENT],["stream_closed",LiteGraph.EVENT],["stream_error",LiteGraph.EVENT]];
+ }
- var width = this._video.videoWidth;
- var height = this._video.videoHeight;
+ LiteGraph.registerNodeType("texture/webcam", LGraphTextureWebcam );
- var temp = this._video_texture;
- if (!temp || temp.width != width || temp.height != height)
- this._video_texture = new GL.Texture(width, height, {
- format: gl.RGB,
- filter: gl.LINEAR
- });
- this._video_texture.uploadImage(this._video);
- this._video_texture.version = ++this.version;
- if (this.properties.texture_name) {
- var container = LGraphTexture.getTexturesContainer();
- container[this.properties.texture_name] = this._video_texture;
- }
+ //from https://github.com/spite/Wagner
+ function LGraphLensFX()
+ {
+ this.addInput("in","Texture");
+ this.addInput("f","number");
+ this.addOutput("out","Texture");
+ this.properties = { enabled: true, factor: 1, precision: LGraphTexture.LOW };
- this.setOutputData(0, this._video_texture);
- for (var i = 1; i < this.outputs.length; ++i) {
- if (!this.outputs[i]) continue;
- switch (this.outputs[i].name) {
- case "width":
- this.setOutputData(i, this._video.videoWidth);
- break;
- case "height":
- this.setOutputData(i, this._video.videoHeight);
- break;
- }
- }
- };
+ this._uniforms = { u_texture: 0, u_factor: 1 };
+ }
- LGraphTextureWebcam.prototype.onGetOutputs = function() {
- return [
- ["width", "number"],
- ["height", "number"],
- ["stream_ready", LiteGraph.EVENT],
- ["stream_closed", LiteGraph.EVENT],
- ["stream_error", LiteGraph.EVENT]
- ];
- };
+ LGraphLensFX.title = "Lens FX";
+ LGraphLensFX.desc = "distortion and chromatic aberration";
- LiteGraph.registerNodeType("texture/webcam", LGraphTextureWebcam);
+ LGraphLensFX.widgets_info = {
+ "precision": { widget:"combo", values: LGraphTexture.MODE_VALUES }
+ };
- //from https://github.com/spite/Wagner
- function LGraphLensFX() {
- this.addInput("in", "Texture");
- this.addInput("f", "number");
- this.addOutput("out", "Texture");
- this.properties = {
- enabled: true,
- factor: 1,
- precision: LGraphTexture.LOW
- };
+ LGraphLensFX.prototype.onGetInputs = function() { return [["enabled","boolean"]]; }
- this._uniforms = { u_texture: 0, u_factor: 1 };
- }
+ LGraphLensFX.prototype.onExecute = function()
+ {
+ var tex = this.getInputData(0);
+ if(!tex)
+ return;
- LGraphLensFX.title = "Lens FX";
- LGraphLensFX.desc = "distortion and chromatic aberration";
+ if(!this.isOutputConnected(0))
+ return; //saves work
- LGraphLensFX.widgets_info = {
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
- };
+ if(this.properties.precision === LGraphTexture.PASS_THROUGH || this.getInputOrProperty("enabled" ) === false )
+ {
+ this.setOutputData(0, tex );
+ return;
+ }
- LGraphLensFX.prototype.onGetInputs = function() {
- return [["enabled", "boolean"]];
- };
+ 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 });
- LGraphLensFX.prototype.onExecute = function() {
- var tex = this.getInputData(0);
- if (!tex) return;
+ var shader = LGraphLensFX._shader;
+ if(!shader)
+ shader = LGraphLensFX._shader = new GL.Shader( GL.Shader.SCREEN_VERTEX_SHADER, LGraphLensFX.pixel_shader );
- if (!this.isOutputConnected(0)) return; //saves work
+ var factor = this.getInputData(1);
+ if(factor == null)
+ factor = this.properties.factor;
- if (
- this.properties.precision === LGraphTexture.PASS_THROUGH ||
- this.getInputOrProperty("enabled") === false
- ) {
- this.setOutputData(0, tex);
- return;
- }
+ var uniforms = this._uniforms;
+ uniforms.u_factor = factor;
- 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
+ gl.disable( gl.DEPTH_TEST );
+ temp.drawTo(function(){
+ tex.bind(0);
+ shader.uniforms(uniforms).draw( GL.Mesh.getScreenQuad() );
+ });
- var shader = LGraphLensFX._shader;
- if (!shader)
- shader = LGraphLensFX._shader = new GL.Shader(
- GL.Shader.SCREEN_VERTEX_SHADER,
- LGraphLensFX.pixel_shader
- );
+ this.setOutputData(0,temp);
+ }
- 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\
+ LGraphLensFX.pixel_shader = "precision highp float;\n\
varying vec2 v_coord;\n\
uniform sampler2D u_texture;\n\
uniform float u_factor;\n\
@@ -15903,637 +17227,637 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
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: 1 };
- }
-
- 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,Texture");
- this.addOutput("out", "Texture");
- this.properties = {
- enabled: true,
- 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.getInputOrProperty("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 }
- );
-
- var avg = this.getInputData(1);
- if (avg == null) avg = this.properties.average_lum;
-
- var uniforms = this._uniforms;
- var shader = null;
-
- if (avg.constructor === Number) {
- this.properties.average_lum = avg;
- uniforms.u_average_lum = this.properties.average_lum;
- shader = LGraphToneMapping._shader;
- if (!shader)
- shader = LGraphToneMapping._shader = new GL.Shader(
- GL.Shader.SCREEN_VERTEX_SHADER,
- LGraphToneMapping.pixel_shader
- );
- } else if (avg.constructor === GL.Texture) {
- uniforms.u_average_texture = avg.bind(1);
- shader = LGraphToneMapping._shader_texture;
- if (!shader)
- shader = LGraphToneMapping._shader_texture = new GL.Shader(
- GL.Shader.SCREEN_VERTEX_SHADER,
- LGraphToneMapping.pixel_shader,
- { AVG_TEXTURE: "" }
- );
- }
-
- uniforms.u_lumwhite2 =
- this.properties.lum_white * this.properties.lum_white;
- uniforms.u_scale = this.properties.scale;
- 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\
- #ifdef AVG_TEXTURE\n\
- uniform sampler2D u_average_texture;\n\
- #else\n\
- uniform float u_average_lum;\n\
- #endif\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\
- float average_lum = 0.0;\n\
- #ifdef AVG_TEXTURE\n\
- vec3 pixel = texture2D(u_average_texture,vec2(0.5)).xyz;\n\
- average_lum = (pixel.x + pixel.y + pixel.z) / 3.0;\n\
- #else\n\
- average_lum = u_average_lum;\n\
- #endif\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 / 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._texture = null;
- 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.onGetInputs = function() {
- return [
- ["seed", "Number"],
- ["persistence", "Number"],
- ["octaves", "Number"],
- ["scale", "Number"],
- ["amplitude", "Number"],
- ["offset", "vec2"]
- ];
- };
-
- 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._texture;
- if (
- !temp ||
- temp.width != w ||
- temp.height != h ||
- temp.type != type
- )
- temp = this._texture = new GL.Texture(w, h, {
- type: type,
- format: gl.RGB,
- filter: gl.LINEAR
- });
-
- var persistence = this.getInputOrProperty("persistence");
- var octaves = this.getInputOrProperty("octaves");
- var offset = this.getInputOrProperty("offset");
- var scale = this.getInputOrProperty("scale");
- var amplitude = this.getInputOrProperty("amplitude");
- var seed = this.getInputOrProperty("seed");
-
- //reusing old texture
- var key =
- "" +
- w +
- h +
- type +
- persistence +
- octaves +
- scale +
- seed +
- offset[0] +
- offset[1] +
- amplitude;
- if (key == this._key) {
- this.setOutputData(0, temp);
- return;
- }
- this._key = key;
-
- //gather uniforms
- var uniforms = this._uniforms;
- uniforms.u_persistence = persistence;
- uniforms.u_octaves = octaves;
- uniforms.u_offset.set(offset);
- uniforms.u_scale = scale;
- uniforms.u_amplitude = amplitude;
- uniforms.u_seed = seed * 128;
- uniforms.u_viewport[0] = w;
- uniforms.u_viewport[1] = h;
-
- //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 LGraphTextureCanvas2D() {
- this.addOutput("out", "Texture");
- this.properties = {
- code: "",
- width: 512,
- height: 512,
- precision: LGraphTexture.DEFAULT
- };
- this._func = null;
- this._temp_texture = null;
- }
-
- LGraphTextureCanvas2D.title = "Canvas2D";
- LGraphTextureCanvas2D.desc =
- "Executes Canvas2D code inside a texture or the viewport";
-
- LGraphTextureCanvas2D.widgets_info = {
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES },
- code: { type: "code" },
- width: { type: "Number", precision: 0, step: 1 },
- height: { type: "Number", precision: 0, step: 1 }
- };
-
- LGraphTextureCanvas2D.prototype.onPropertyChanged = function(
- name,
- value
- ) {
- if (name == "code" && LiteGraph.allow_scripts) {
- this._func = null;
- try {
- this._func = new Function(
- "canvas",
- "ctx",
- "time",
- "script",
- value
- );
- this.boxcolor = "#00FF00";
- } catch (err) {
- this.boxcolor = "#FF0000";
- console.error("Error parsing script");
- console.error(err);
- }
- }
- };
-
- LGraphTextureCanvas2D.prototype.onExecute = function() {
- var func = this._func;
- if (!func || !this.isOutputConnected(0)) return;
-
- if (!global.enableWebGLCanvas) {
- console.warn(
- "cannot use LGraphTextureCanvas2D if Canvas2DtoWebGL is not included"
- );
- return;
- }
-
- var width = this.properties.width || gl.canvas.width;
- var height = this.properties.height || gl.canvas.height;
- var temp = this._temp_texture;
- if (!temp || temp.width != width || temp.height != height)
- temp = this._temp_texture = new GL.Texture(width, height, {
- format: gl.RGBA,
- filter: gl.LINEAR
- });
-
- var that = this;
- var time = this.graph.getTime();
- temp.drawTo(function() {
- gl.start2D();
- try {
- if (func.draw)
- func.draw.call(that, gl.canvas, gl, time, func);
- else func.call(that, gl.canvas, gl, time, func);
- that.boxcolor = "#00FF00";
- } catch (err) {
- that.boxcolor = "#FF0000";
- console.error("Error executing script");
- console.error(err);
- }
- gl.finish2D();
- });
-
- this.setOutputData(0, temp);
- };
-
- LiteGraph.registerNodeType("texture/canvas2D", LGraphTextureCanvas2D);
-
- 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
- };
- }
-
- LGraphTextureMatte.title = "Matte";
- LGraphTextureMatte.desc = "Extracts background";
-
- LGraphTextureMatte.widgets_info = {
- key_color: { widget: "color" },
- precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
- };
-
- LGraphTextureMatte.prototype.onExecute = function() {
- if (!this.isOutputConnected(0)) return; //saves work
-
- var tex = this.getInputData(0);
-
- if (this.properties.precision === LGraphTexture.PASS_THROUGH) {
- this.setOutputData(0, tex);
- return;
- }
-
- if (!tex) return;
-
- this._tex = LGraphTexture.getTargetTexture(
- tex,
- this._tex,
- this.properties.precision
- );
-
- gl.disable(gl.BLEND);
- gl.disable(gl.DEPTH_TEST);
-
- if (!this._uniforms)
- this._uniforms = {
- u_texture: 0,
- u_key_color: this.properties.key_color,
- u_threshold: 1,
- u_slope: 1
- };
- var uniforms = this._uniforms;
-
- 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;
- uniforms.u_slope = this.properties.slope;
-
- this._tex.drawTo(function() {
- tex.bind(0);
- shader.uniforms(uniforms).draw(mesh);
- });
-
- this.setOutputData(0, this._tex);
- };
-
- LGraphTextureMatte.pixel_shader =
- "precision highp float;\n\
- varying vec2 v_coord;\n\
- uniform sampler2D u_texture;\n\
- uniform vec3 u_key_color;\n\
- uniform float u_threshold;\n\
- uniform float u_slope;\n\
- \n\
- void main() {\n\
- vec3 color = texture2D( u_texture, v_coord ).xyz;\n\
- float diff = length( normalize(color) - normalize(u_key_color) );\n\
- float edge = u_threshold * (1.0 - u_slope);\n\
- float alpha = smoothstep( edge, u_threshold, diff);\n\
- gl_FragColor = vec4( color, alpha );\n\
- }";
-
- LiteGraph.registerNodeType("texture/matte", LGraphTextureMatte);
-
- //***********************************
- //Cubemap reader (to pass a cubemap to a node that requires cubemaps and no images)
- function LGraphCubemap() {
- this.addOutput("Cubemap", "Cubemap");
- this.properties = { name: "" };
- this.size = [
- LGraphTexture.image_preview_size,
- LGraphTexture.image_preview_size
- ];
- }
-
- LGraphCubemap.title = "Cubemap";
-
- LGraphCubemap.prototype.onDropFile = function(data, filename, file) {
- if (!data) {
- this._drop_texture = null;
- this.properties.name = "";
- } else {
- if (typeof data == "string")
- this._drop_texture = GL.Texture.fromURL(data);
- else this._drop_texture = GL.Texture.fromDDSInMemory(data);
- this.properties.name = filename;
- }
- };
-
- LGraphCubemap.prototype.onExecute = function() {
- if (this._drop_texture) {
- this.setOutputData(0, this._drop_texture);
- return;
- }
-
- if (!this.properties.name) return;
-
- var tex = LGraphTexture.getTexture(this.properties.name);
- if (!tex) return;
-
- this._last_tex = tex;
- this.setOutputData(0, tex);
- };
-
- LGraphCubemap.prototype.onDrawBackground = function(ctx) {
- if (this.flags.collapsed || this.size[1] <= 20) return;
-
- if (!ctx.webgl) return;
-
- var cube_mesh = gl.meshes["cube"];
- if (!cube_mesh)
- cube_mesh = gl.meshes["cube"] = GL.Mesh.cube({ size: 1 });
-
- //var view = mat4.lookAt( mat4.create(), [0,0
- };
-
+ this.addOutput("out", "Texture");
+ this.properties = { exposition: 1, precision: LGraphTexture.LOW };
+ this._uniforms = { u_texture: 0, u_exposition: 1 };
+ }
+
+ 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,Texture");
+ this.addOutput("out", "Texture");
+ this.properties = {
+ enabled: true,
+ 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.getInputOrProperty("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 }
+ );
+
+ var avg = this.getInputData(1);
+ if (avg == null) avg = this.properties.average_lum;
+
+ var uniforms = this._uniforms;
+ var shader = null;
+
+ if (avg.constructor === Number) {
+ this.properties.average_lum = avg;
+ uniforms.u_average_lum = this.properties.average_lum;
+ shader = LGraphToneMapping._shader;
+ if (!shader)
+ shader = LGraphToneMapping._shader = new GL.Shader(
+ GL.Shader.SCREEN_VERTEX_SHADER,
+ LGraphToneMapping.pixel_shader
+ );
+ } else if (avg.constructor === GL.Texture) {
+ uniforms.u_average_texture = avg.bind(1);
+ shader = LGraphToneMapping._shader_texture;
+ if (!shader)
+ shader = LGraphToneMapping._shader_texture = new GL.Shader(
+ GL.Shader.SCREEN_VERTEX_SHADER,
+ LGraphToneMapping.pixel_shader,
+ { AVG_TEXTURE: "" }
+ );
+ }
+
+ uniforms.u_lumwhite2 =
+ this.properties.lum_white * this.properties.lum_white;
+ uniforms.u_scale = this.properties.scale;
+ 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\
+ #ifdef AVG_TEXTURE\n\
+ uniform sampler2D u_average_texture;\n\
+ #else\n\
+ uniform float u_average_lum;\n\
+ #endif\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\
+ float average_lum = 0.0;\n\
+ #ifdef AVG_TEXTURE\n\
+ vec3 pixel = texture2D(u_average_texture,vec2(0.5)).xyz;\n\
+ average_lum = (pixel.x + pixel.y + pixel.z) / 3.0;\n\
+ #else\n\
+ average_lum = u_average_lum;\n\
+ #endif\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 / 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._texture = null;
+ 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.onGetInputs = function() {
+ return [
+ ["seed", "Number"],
+ ["persistence", "Number"],
+ ["octaves", "Number"],
+ ["scale", "Number"],
+ ["amplitude", "Number"],
+ ["offset", "vec2"]
+ ];
+ };
+
+ 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._texture;
+ if (
+ !temp ||
+ temp.width != w ||
+ temp.height != h ||
+ temp.type != type
+ )
+ temp = this._texture = new GL.Texture(w, h, {
+ type: type,
+ format: gl.RGB,
+ filter: gl.LINEAR
+ });
+
+ var persistence = this.getInputOrProperty("persistence");
+ var octaves = this.getInputOrProperty("octaves");
+ var offset = this.getInputOrProperty("offset");
+ var scale = this.getInputOrProperty("scale");
+ var amplitude = this.getInputOrProperty("amplitude");
+ var seed = this.getInputOrProperty("seed");
+
+ //reusing old texture
+ var key =
+ "" +
+ w +
+ h +
+ type +
+ persistence +
+ octaves +
+ scale +
+ seed +
+ offset[0] +
+ offset[1] +
+ amplitude;
+ if (key == this._key) {
+ this.setOutputData(0, temp);
+ return;
+ }
+ this._key = key;
+
+ //gather uniforms
+ var uniforms = this._uniforms;
+ uniforms.u_persistence = persistence;
+ uniforms.u_octaves = octaves;
+ uniforms.u_offset.set(offset);
+ uniforms.u_scale = scale;
+ uniforms.u_amplitude = amplitude;
+ uniforms.u_seed = seed * 128;
+ uniforms.u_viewport[0] = w;
+ uniforms.u_viewport[1] = h;
+
+ //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 LGraphTextureCanvas2D() {
+ this.addOutput("out", "Texture");
+ this.properties = {
+ code: "",
+ width: 512,
+ height: 512,
+ precision: LGraphTexture.DEFAULT
+ };
+ this._func = null;
+ this._temp_texture = null;
+ }
+
+ LGraphTextureCanvas2D.title = "Canvas2D";
+ LGraphTextureCanvas2D.desc =
+ "Executes Canvas2D code inside a texture or the viewport";
+
+ LGraphTextureCanvas2D.widgets_info = {
+ precision: { widget: "combo", values: LGraphTexture.MODE_VALUES },
+ code: { type: "code" },
+ width: { type: "Number", precision: 0, step: 1 },
+ height: { type: "Number", precision: 0, step: 1 }
+ };
+
+ LGraphTextureCanvas2D.prototype.onPropertyChanged = function(
+ name,
+ value
+ ) {
+ if (name == "code" && LiteGraph.allow_scripts) {
+ this._func = null;
+ try {
+ this._func = new Function(
+ "canvas",
+ "ctx",
+ "time",
+ "script",
+ value
+ );
+ this.boxcolor = "#00FF00";
+ } catch (err) {
+ this.boxcolor = "#FF0000";
+ console.error("Error parsing script");
+ console.error(err);
+ }
+ }
+ };
+
+ LGraphTextureCanvas2D.prototype.onExecute = function() {
+ var func = this._func;
+ if (!func || !this.isOutputConnected(0)) return;
+
+ if (!global.enableWebGLCanvas) {
+ console.warn(
+ "cannot use LGraphTextureCanvas2D if Canvas2DtoWebGL is not included"
+ );
+ return;
+ }
+
+ var width = this.properties.width || gl.canvas.width;
+ var height = this.properties.height || gl.canvas.height;
+ var temp = this._temp_texture;
+ if (!temp || temp.width != width || temp.height != height)
+ temp = this._temp_texture = new GL.Texture(width, height, {
+ format: gl.RGBA,
+ filter: gl.LINEAR
+ });
+
+ var that = this;
+ var time = this.graph.getTime();
+ temp.drawTo(function() {
+ gl.start2D();
+ try {
+ if (func.draw)
+ func.draw.call(that, gl.canvas, gl, time, func);
+ else func.call(that, gl.canvas, gl, time, func);
+ that.boxcolor = "#00FF00";
+ } catch (err) {
+ that.boxcolor = "#FF0000";
+ console.error("Error executing script");
+ console.error(err);
+ }
+ gl.finish2D();
+ });
+
+ this.setOutputData(0, temp);
+ };
+
+ LiteGraph.registerNodeType("texture/canvas2D", LGraphTextureCanvas2D);
+
+ 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
+ };
+ }
+
+ LGraphTextureMatte.title = "Matte";
+ LGraphTextureMatte.desc = "Extracts background";
+
+ LGraphTextureMatte.widgets_info = {
+ key_color: { widget: "color" },
+ precision: { widget: "combo", values: LGraphTexture.MODE_VALUES }
+ };
+
+ LGraphTextureMatte.prototype.onExecute = function() {
+ if (!this.isOutputConnected(0)) return; //saves work
+
+ var tex = this.getInputData(0);
+
+ if (this.properties.precision === LGraphTexture.PASS_THROUGH) {
+ this.setOutputData(0, tex);
+ return;
+ }
+
+ if (!tex) return;
+
+ this._tex = LGraphTexture.getTargetTexture(
+ tex,
+ this._tex,
+ this.properties.precision
+ );
+
+ gl.disable(gl.BLEND);
+ gl.disable(gl.DEPTH_TEST);
+
+ if (!this._uniforms)
+ this._uniforms = {
+ u_texture: 0,
+ u_key_color: this.properties.key_color,
+ u_threshold: 1,
+ u_slope: 1
+ };
+ var uniforms = this._uniforms;
+
+ 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;
+ uniforms.u_slope = this.properties.slope;
+
+ this._tex.drawTo(function() {
+ tex.bind(0);
+ shader.uniforms(uniforms).draw(mesh);
+ });
+
+ this.setOutputData(0, this._tex);
+ };
+
+ LGraphTextureMatte.pixel_shader =
+ "precision highp float;\n\
+ varying vec2 v_coord;\n\
+ uniform sampler2D u_texture;\n\
+ uniform vec3 u_key_color;\n\
+ uniform float u_threshold;\n\
+ uniform float u_slope;\n\
+ \n\
+ void main() {\n\
+ vec3 color = texture2D( u_texture, v_coord ).xyz;\n\
+ float diff = length( normalize(color) - normalize(u_key_color) );\n\
+ float edge = u_threshold * (1.0 - u_slope);\n\
+ float alpha = smoothstep( edge, u_threshold, diff);\n\
+ gl_FragColor = vec4( color, alpha );\n\
+ }";
+
+ LiteGraph.registerNodeType("texture/matte", LGraphTextureMatte);
+
+ //***********************************
+ //Cubemap reader (to pass a cubemap to a node that requires cubemaps and no images)
+ function LGraphCubemap() {
+ this.addOutput("Cubemap", "Cubemap");
+ this.properties = { name: "" };
+ this.size = [
+ LGraphTexture.image_preview_size,
+ LGraphTexture.image_preview_size
+ ];
+ }
+
+ LGraphCubemap.title = "Cubemap";
+
+ LGraphCubemap.prototype.onDropFile = function(data, filename, file) {
+ if (!data) {
+ this._drop_texture = null;
+ this.properties.name = "";
+ } else {
+ if (typeof data == "string")
+ this._drop_texture = GL.Texture.fromURL(data);
+ else this._drop_texture = GL.Texture.fromDDSInMemory(data);
+ this.properties.name = filename;
+ }
+ };
+
+ LGraphCubemap.prototype.onExecute = function() {
+ if (this._drop_texture) {
+ this.setOutputData(0, this._drop_texture);
+ return;
+ }
+
+ if (!this.properties.name) return;
+
+ var tex = LGraphTexture.getTexture(this.properties.name);
+ if (!tex) return;
+
+ this._last_tex = tex;
+ this.setOutputData(0, tex);
+ };
+
+ LGraphCubemap.prototype.onDrawBackground = function(ctx) {
+ if (this.flags.collapsed || this.size[1] <= 20) return;
+
+ if (!ctx.webgl) return;
+
+ var cube_mesh = gl.meshes["cube"];
+ if (!cube_mesh)
+ cube_mesh = gl.meshes["cube"] = GL.Mesh.cube({ size: 1 });
+
+ //var view = mat4.lookAt( mat4.create(), [0,0
+ };
+
LiteGraph.registerNodeType("texture/cubemap", LGraphCubemap);
} //litegl.js defined
})(this);
-
+
(function(global) {
var LiteGraph = global.LiteGraph;
@@ -17294,7 +18618,7 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
global.LGraphFXVigneting = LGraphFXVigneting;
}
})(this);
-
+
(function(global) {
var LiteGraph = global.LiteGraph;
var MIDI_COLOR = "#243";
@@ -18624,7 +19948,7 @@ if (typeof exports != "undefined") exports.LiteGraph = this.LiteGraph;
return window.performance.now();
}
})(this);
-
+
(function(global) {
var LiteGraph = global.LiteGraph;
@@ -19906,7 +21230,7 @@ LiteGraph.registerNodeType("audio/waveShaper", LGAudioWaveShaper);
LGAudioDestination.desc = "Audio output";
LiteGraph.registerNodeType("audio/destination", LGAudioDestination);
})(this);
-
+
//event related nodes
(function(global) {
var LiteGraph = global.LiteGraph;
@@ -20195,3 +21519,4 @@ LiteGraph.registerNodeType("audio/waveShaper", LGAudioWaveShaper);
LiteGraph.registerNodeType("network/sillyclient", LGSillyClient);
})(this);
+
diff --git a/build/litegraph.min.js b/build/litegraph.min.js
index 99416667d..81dfea519 100755
--- a/build/litegraph.min.js
+++ b/build/litegraph.min.js
@@ -1,9483 +1,597 @@
-var $jscomp = $jscomp || {};
-$jscomp.scope = {};
-$jscomp.ASSUME_ES5 = !1;
-$jscomp.ASSUME_NO_NATIVE_MAP = !1;
-$jscomp.ASSUME_NO_NATIVE_SET = !1;
-$jscomp.defineProperty = $jscomp.ASSUME_ES5 || "function" == typeof Object.defineProperties ? Object.defineProperty : function(w, e, q) {
- w != Array.prototype && w != Object.prototype && (w[e] = q.value);
-};
-$jscomp.getGlobal = function(w) {
- return "undefined" != typeof window && window === w ? w : "undefined" != typeof global && null != global ? global : w;
-};
-$jscomp.global = $jscomp.getGlobal(this);
-$jscomp.polyfill = function(w, e, q, k) {
- if (e) {
- q = $jscomp.global;
- w = w.split(".");
- for (k = 0; k < w.length - 1; k++) {
- var h = w[k];
- h in q || (q[h] = {});
- q = q[h];
- }
- w = w[w.length - 1];
- k = q[w];
- e = e(k);
- e != k && null != e && $jscomp.defineProperty(q, w, {configurable:!0, writable:!0, value:e});
- }
-};
-$jscomp.polyfill("Array.prototype.fill", function(w) {
- return w ? w : function(e, q, k) {
- var h = this.length || 0;
- 0 > q && (q = Math.max(0, h + q));
- if (null == k || k > h) {
- k = h;
- }
- k = Number(k);
- 0 > k && (k = Math.max(0, h + k));
- for (q = Number(q || 0); q < k; q++) {
- this[q] = e;
- }
- return this;
- };
-}, "es6", "es3");
-$jscomp.SYMBOL_PREFIX = "jscomp_symbol_";
-$jscomp.initSymbol = function() {
- $jscomp.initSymbol = function() {
- };
- $jscomp.global.Symbol || ($jscomp.global.Symbol = $jscomp.Symbol);
-};
-$jscomp.Symbol = function() {
- var w = 0;
- return function(e) {
- return $jscomp.SYMBOL_PREFIX + (e || "") + w++;
- };
-}();
-$jscomp.initSymbolIterator = function() {
- $jscomp.initSymbol();
- var w = $jscomp.global.Symbol.iterator;
- w || (w = $jscomp.global.Symbol.iterator = $jscomp.global.Symbol("iterator"));
- "function" != typeof Array.prototype[w] && $jscomp.defineProperty(Array.prototype, w, {configurable:!0, writable:!0, value:function() {
- return $jscomp.arrayIterator(this);
- }});
- $jscomp.initSymbolIterator = function() {
- };
-};
-$jscomp.arrayIterator = function(w) {
- var e = 0;
- return $jscomp.iteratorPrototype(function() {
- return e < w.length ? {done:!1, value:w[e++]} : {done:!0};
- });
-};
-$jscomp.iteratorPrototype = function(w) {
- $jscomp.initSymbolIterator();
- w = {next:w};
- w[$jscomp.global.Symbol.iterator] = function() {
- return this;
- };
- return w;
-};
-$jscomp.iteratorFromArray = function(w, e) {
- $jscomp.initSymbolIterator();
- w instanceof String && (w += "");
- var q = 0, k = {next:function() {
- if (q < w.length) {
- var h = q++;
- return {value:e(h, w[h]), done:!1};
- }
- k.next = function() {
- return {done:!0, value:void 0};
- };
- return k.next();
- }};
- k[Symbol.iterator] = function() {
- return k;
- };
- return k;
-};
-$jscomp.polyfill("Array.prototype.values", function(w) {
- return w ? w : function() {
- return $jscomp.iteratorFromArray(this, function(e, q) {
- return q;
- });
- };
-}, "es8", "es3");
-$jscomp.polyfill("Array.prototype.keys", function(w) {
- return w ? w : function() {
- return $jscomp.iteratorFromArray(this, function(e) {
- return e;
- });
- };
-}, "es6", "es3");
-(function(w) {
- function e(a) {
- c.debug && console.log("Graph created");
- this.list_of_graphcanvas = null;
- this.clear();
- a && this.configure(a);
- }
- function q(a, b, d, p, c, g) {
- this.id = a;
- this.type = b;
- this.origin_id = d;
- this.origin_slot = p;
- this.target_id = c;
- this.target_slot = g;
- this._data = null;
- this._pos = new Float32Array(2);
- }
- function k(a) {
- this._ctor(a);
- }
- function h(a) {
- this._ctor(a);
- }
- function n(a, b) {
- this.offset = new Float32Array([0, 0]);
- this.scale = 1;
- this.max_scale = 10;
- this.min_scale = 0.1;
- this.onredraw = null;
- this.enabled = !0;
- this.last_mouse = [0, 0];
- this.element = null;
- this.visible_area = new Float32Array(4);
- a && (this.element = a, b || this.bindEvents(a));
- }
- function f(a, b, d) {
- d = d || {};
- this.background_image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII=";
- a && a.constructor === String && (a = document.querySelector(a));
- this.ds = new n;
- this.zoom_modify_alpha = !0;
- this.title_text_font = "" + c.NODE_TEXT_SIZE + "px Arial";
- this.inner_text_font = "normal " + c.NODE_SUBTEXT_SIZE + "px Arial";
- this.node_title_color = c.NODE_TITLE_COLOR;
- this.default_link_color = c.LINK_COLOR;
- this.default_connection_color = {input_off:"#778", input_on:"#7F7", output_off:"#778", output_on:"#7F7"};
- this.highquality_render = !0;
- this.use_gradients = !1;
- this.editor_alpha = 1;
- this.pause_rendering = !1;
- this.render_only_selected = this.clear_background = !0;
- this.live_mode = !1;
- this.allow_searchbox = this.allow_interaction = this.allow_dragnodes = this.allow_dragcanvas = this.show_info = !0;
- this.drag_mode = this.allow_reconnect_links = !1;
- this.filter = this.dragging_rectangle = null;
- this.always_render_background = !1;
- this.render_canvas_border = this.render_shadows = !0;
- this.render_connections_shadows = !1;
- this.render_connections_border = !0;
- this.render_connection_arrows = this.render_curved_connections = !1;
- this.render_collapsed_slots = !0;
- this.render_execution_order = !1;
- this.render_title_colored = !0;
- this.links_render_mode = c.SPLINE_LINK;
- this.canvas_mouse = [0, 0];
- this.onDrawOverlay = this.onDrawForeground = this.onDrawBackground = this.onMouse = this.onSearchBoxSelection = this.onSearchBox = null;
- this.connections_width = 3;
- this.round_radius = 8;
- this.node_widget = this.current_node = null;
- this.last_mouse_position = [0, 0];
- this.visible_area = this.ds.visible_area;
- this.visible_links = [];
- b && b.attachCanvas(this);
- this.setCanvas(a);
- this.clear();
- d.skip_render || this.startRendering();
- this.autoresize = d.autoresize;
- }
- function y(a, b) {
- return Math.sqrt((b[0] - a[0]) * (b[0] - a[0]) + (b[1] - a[1]) * (b[1] - a[1]));
- }
- function B(a, b, d, p, c, g) {
- return d < a && d + c > a && p < b && p + g > b ? !0 : !1;
- }
- function z(a, b) {
- var d = a[0] + a[2], p = a[1] + a[3], c = b[1] + b[3];
- return a[0] > b[0] + b[2] || a[1] > c || d < b[0] || p < b[1] ? !1 : !0;
- }
- function C(a, b) {
- function d(a) {
- var d = parseInt(c.style.top);
- c.style.top = (d + a.deltaY * b.scroll_speed).toFixed() + "px";
- a.preventDefault();
- return !0;
- }
- this.options = b = b || {};
- var p = this;
- b.parentMenu && (b.parentMenu.constructor !== this.constructor ? (console.error("parentMenu must be of class ContextMenu, ignoring it"), b.parentMenu = null) : (this.parentMenu = b.parentMenu, this.parentMenu.lock = !0, this.parentMenu.current_submenu = this));
- b.event && b.event.constructor !== MouseEvent && b.event.constructor !== CustomEvent && (console.error("Event passed to ContextMenu is not of type MouseEvent or CustomEvent. Ignoring it."), b.event = null);
- var c = document.createElement("div");
- c.className = "litegraph litecontextmenu litemenubar-panel";
- b.className && (c.className += " " + b.className);
- c.style.minWidth = 100;
- c.style.minHeight = 100;
- c.style.pointerEvents = "none";
- setTimeout(function() {
- c.style.pointerEvents = "auto";
- }, 100);
- c.addEventListener("mouseup", function(a) {
- a.preventDefault();
- return !0;
- }, !0);
- c.addEventListener("contextmenu", function(a) {
- if (2 != a.button) {
- return !1;
- }
- a.preventDefault();
- return !1;
- }, !0);
- c.addEventListener("mousedown", function(a) {
- if (2 == a.button) {
- return p.close(), a.preventDefault(), !0;
- }
- }, !0);
- b.scroll_speed || (b.scroll_speed = 0.1);
- c.addEventListener("wheel", d, !0);
- c.addEventListener("mousewheel", d, !0);
- this.root = c;
- if (b.title) {
- var g = document.createElement("div");
- g.className = "litemenu-title";
- g.innerHTML = b.title;
- c.appendChild(g);
- }
- g = 0;
- for (var e in a) {
- var f = a.constructor == Array ? a[e] : e;
- null != f && f.constructor !== String && (f = void 0 === f.content ? String(f) : f.content);
- this.addItem(f, a[e], b);
- g++;
- }
- c.addEventListener("mouseleave", function(a) {
- p.lock || (c.closing_timer && clearTimeout(c.closing_timer), c.closing_timer = setTimeout(p.close.bind(p, a), 500));
- });
- c.addEventListener("mouseenter", function(a) {
- c.closing_timer && clearTimeout(c.closing_timer);
- });
- a = document;
- b.event && (a = b.event.target.ownerDocument);
- a || (a = document);
- a.body.appendChild(c);
- e = b.left || 0;
- a = b.top || 0;
- b.event && (e = b.event.clientX - 10, a = b.event.clientY - 10, b.title && (a -= 20), b.parentMenu && (e = b.parentMenu.root.getBoundingClientRect(), e = e.left + e.width), g = document.body.getBoundingClientRect(), f = c.getBoundingClientRect(), e > g.width - f.width - 10 && (e = g.width - f.width - 10), a > g.height - f.height - 10 && (a = g.height - f.height - 10));
- c.style.left = e + "px";
- c.style.top = a + "px";
- b.scale && (c.style.transform = "scale(" + b.scale + ")");
- }
- var c = w.LiteGraph = {VERSION:0.4, CANVAS_GRID_SIZE:10, NODE_TITLE_HEIGHT:30, NODE_TITLE_TEXT_Y:20, NODE_SLOT_HEIGHT:20, NODE_WIDGET_HEIGHT:20, NODE_WIDTH:140, NODE_MIN_WIDTH:50, NODE_COLLAPSED_RADIUS:10, NODE_COLLAPSED_WIDTH:80, NODE_TITLE_COLOR:"#999", NODE_TEXT_SIZE:14, NODE_TEXT_COLOR:"#AAA", NODE_SUBTEXT_SIZE:12, NODE_DEFAULT_COLOR:"#333", NODE_DEFAULT_BGCOLOR:"#353535", NODE_DEFAULT_BOXCOLOR:"#666", NODE_DEFAULT_SHAPE:"box", DEFAULT_SHADOW_COLOR:"rgba(0,0,0,0.5)", DEFAULT_GROUP_FONT:24,
- LINK_COLOR:"#9A9", EVENT_LINK_COLOR:"#A86", CONNECTING_LINK_COLOR:"#AFA", MAX_NUMBER_OF_NODES:1000, DEFAULT_POSITION:[100, 100], VALID_SHAPES:["default", "box", "round", "card"], BOX_SHAPE:1, ROUND_SHAPE:2, CIRCLE_SHAPE:3, CARD_SHAPE:4, ARROW_SHAPE:5, INPUT:1, OUTPUT:2, EVENT:-1, ACTION:-1, ALWAYS:0, ON_EVENT:1, NEVER:2, ON_TRIGGER:3, UP:1, DOWN:2, LEFT:3, RIGHT:4, CENTER:5, STRAIGHT_LINK:0, LINEAR_LINK:1, SPLINE_LINK:2, NORMAL_TITLE:0, NO_TITLE:1, TRANSPARENT_TITLE:2, AUTOHIDE_TITLE:3, proxy:null,
- node_images_path:"", debug:!1, catch_exceptions:!0, throw_errors:!0, allow_scripts:!1, registered_node_types:{}, node_types_by_file_extension:{}, Nodes:{}, searchbox_extras:{}, registerNodeType:function(a, b) {
- if (!b.prototype) {
- throw "Cannot register a simple object, it must be a class with a prototype";
- }
- b.type = a;
- c.debug && console.log("Node registered: " + a);
- a.split("/");
- var d = b.name, p = a.lastIndexOf("/");
- b.category = a.substr(0, p);
- b.title || (b.title = d);
- if (b.prototype) {
- for (var m in k.prototype) {
- b.prototype[m] || (b.prototype[m] = k.prototype[m]);
- }
- }
- Object.defineProperty(b.prototype, "shape", {set:function(a) {
- switch(a) {
- case "default":
- delete this._shape;
- break;
- case "box":
- this._shape = c.BOX_SHAPE;
- break;
- case "round":
- this._shape = c.ROUND_SHAPE;
- break;
- case "circle":
- this._shape = c.CIRCLE_SHAPE;
- break;
- case "card":
- this._shape = c.CARD_SHAPE;
- break;
- default:
- this._shape = a;
- }
- }, get:function(a) {
- return this._shape;
- }, enumerable:!0});
- this.registered_node_types[a] = b;
- b.constructor.name && (this.Nodes[d] = b);
- b.prototype.onPropertyChange && console.warn("LiteGraph node class " + a + " has onPropertyChange method, it must be called onPropertyChanged with d at the end");
- if (b.supported_extensions) {
- for (m in b.supported_extensions) {
- this.node_types_by_file_extension[b.supported_extensions[m].toLowerCase()] = b;
- }
- }
- }, wrapFunctionAsNode:function(a, b, d, p, m) {
- for (var g = Array(b.length), e = "", f = c.getParameterNames(b), l = 0; l < f.length; ++l) {
- e += "this.addInput('" + f[l] + "'," + (d && d[l] ? "'" + d[l] + "'" : "0") + ");\n";
- }
- e += "this.addOutput('out'," + (p ? "'" + p + "'" : 0) + ");\n";
- m && (e += "this.properties = " + JSON.stringify(m) + ";\n");
- d = Function(e);
- d.title = a.split("/").pop();
- d.desc = "Generated from " + b.name;
- d.prototype.onExecute = function() {
- for (var a = 0; a < g.length; ++a) {
- g[a] = this.getInputData(a);
- }
- a = b.apply(this, g);
- this.setOutputData(0, a);
- };
- this.registerNodeType(a, d);
- }, addNodeMethod:function(a, b) {
- k.prototype[a] = b;
- for (var d in this.registered_node_types) {
- var c = this.registered_node_types[d];
- c.prototype[a] && (c.prototype["_" + a] = c.prototype[a]);
- c.prototype[a] = b;
- }
- }, createNode:function(a, b, d) {
- var p = this.registered_node_types[a];
- if (!p) {
- return c.debug && console.log('GraphNode type "' + a + '" not registered.'), null;
- }
- b = b || p.title || a;
- var m = null;
- if (c.catch_exceptions) {
- try {
- m = new p(b);
- } catch (E) {
- return console.error(E), null;
- }
- } else {
- m = new p(b);
- }
- m.type = a;
- !m.title && b && (m.title = b);
- m.properties || (m.properties = {});
- m.properties_info || (m.properties_info = []);
- m.flags || (m.flags = {});
- m.size || (m.size = m.computeSize());
- m.pos || (m.pos = c.DEFAULT_POSITION.concat());
- m.mode || (m.mode = c.ALWAYS);
- if (d) {
- for (var g in d) {
- m[g] = d[g];
- }
- }
- return m;
- }, getNodeType:function(a) {
- return this.registered_node_types[a];
- }, getNodeTypesInCategory:function(a, b) {
- var d = [], c;
- for (c in this.registered_node_types) {
- var m = this.registered_node_types[c];
- b && m.filter && m.filter != b || ("" == a ? null == m.category && d.push(m) : m.category == a && d.push(m));
- }
- return d;
- }, getNodeTypesCategories:function() {
- var a = {"":1}, b;
- for (b in this.registered_node_types) {
- this.registered_node_types[b].category && !this.registered_node_types[b].skip_list && (a[this.registered_node_types[b].category] = 1);
- }
- var d = [];
- for (b in a) {
- d.push(b);
- }
- return d;
- }, reloadNodes:function(a) {
- var b = document.getElementsByTagName("script"), d = [], p;
- for (p in b) {
- d.push(b[p]);
- }
- b = document.getElementsByTagName("head")[0];
- a = document.location.href + a;
- for (p in d) {
- var m = d[p].src;
- if (m && m.substr(0, a.length) == a) {
- try {
- c.debug && console.log("Reloading: " + m);
- var g = document.createElement("script");
- g.type = "text/javascript";
- g.src = m;
- b.appendChild(g);
- b.removeChild(d[p]);
- } catch (E) {
- if (c.throw_errors) {
- throw E;
- }
- c.debug && console.log("Error while reloading " + m);
- }
- }
- }
- c.debug && console.log("Nodes reloaded");
- }, cloneObject:function(a, b) {
- if (null == a) {
- return null;
- }
- a = JSON.parse(JSON.stringify(a));
- if (!b) {
- return a;
- }
- for (var d in a) {
- b[d] = a[d];
- }
- return b;
- }, isValidConnection:function(a, b) {
- if (!a || !b || a == b || a == c.EVENT && b == c.ACTION) {
- return !0;
- }
- a = String(a);
- b = String(b);
- a = a.toLowerCase();
- b = b.toLowerCase();
- if (-1 == a.indexOf(",") && -1 == b.indexOf(",")) {
- return a == b;
- }
- a = a.split(",");
- b = b.split(",");
- for (var d = 0; d < a.length; ++d) {
- for (var p = 0; p < b.length; ++p) {
- if (a[d] == b[p]) {
- return !0;
- }
- }
- }
- return !1;
- }, registerSearchboxExtra:function(a, b, d) {
- this.searchbox_extras[b] = {type:a, desc:b, data:d};
- }};
- c.getTime = "undefined" != typeof performance ? performance.now.bind(performance) : "undefined" != typeof Date && Date.now ? Date.now.bind(Date) : "undefined" != typeof process ? function() {
- var a = process.hrtime();
- return 0.001 * a[0] + 1e-6 * a[1];
- } : function() {
- return (new Date).getTime();
- };
- w.LGraph = c.LGraph = e;
- e.supported_types = ["number", "string", "boolean"];
- e.prototype.getSupportedTypes = function() {
- return this.supported_types || e.supported_types;
- };
- e.STATUS_STOPPED = 1;
- e.STATUS_RUNNING = 2;
- e.prototype.clear = function() {
- this.stop();
- this.status = e.STATUS_STOPPED;
- this.last_link_id = this.last_node_id = 1;
- this._version = -1;
- if (this._nodes) {
- for (var a = 0; a < this._nodes.length; ++a) {
- var b = this._nodes[a];
- if (b.onRemoved) {
- b.onRemoved();
- }
- }
- }
- this._nodes = [];
- this._nodes_by_id = {};
- this._nodes_in_order = [];
- this._nodes_executable = null;
- this._groups = [];
- this.links = {};
- this.iteration = 0;
- this.config = {};
- this.fixedtime = this.runningtime = this.globaltime = 0;
- this.elapsed_time = this.fixedtime_lapse = 0.01;
- this.starttime = this.last_update_time = 0;
- this.catch_errors = !0;
- this.inputs = {};
- this.outputs = {};
- this.change();
- this.sendActionToCanvas("clear");
- };
- e.prototype.attachCanvas = function(a) {
- if (a.constructor != f) {
- throw "attachCanvas expects a LGraphCanvas instance";
- }
- a.graph && a.graph != this && a.graph.detachCanvas(a);
- a.graph = this;
- this.list_of_graphcanvas || (this.list_of_graphcanvas = []);
- this.list_of_graphcanvas.push(a);
- };
- e.prototype.detachCanvas = function(a) {
- if (this.list_of_graphcanvas) {
- var b = this.list_of_graphcanvas.indexOf(a);
- -1 != b && (a.graph = null, this.list_of_graphcanvas.splice(b, 1));
- }
- };
- e.prototype.start = function(a) {
- if (this.status != e.STATUS_RUNNING) {
- this.status = e.STATUS_RUNNING;
- if (this.onPlayEvent) {
- this.onPlayEvent();
- }
- this.sendEventToAllNodes("onStart");
- this.last_update_time = this.starttime = c.getTime();
- a = a || 0;
- var b = this;
- if (0 == a && "undefined" != typeof window && window.requestAnimationFrame) {
- var d = function() {
- -1 == b.execution_timer_id && (window.requestAnimationFrame(d), b.runStep(1, !this.catch_errors));
- };
- this.execution_timer_id = -1;
- d();
- } else {
- this.execution_timer_id = setInterval(function() {
- b.runStep(1, !this.catch_errors);
- }, a);
- }
- }
- };
- e.prototype.stop = function() {
- if (this.status != e.STATUS_STOPPED) {
- this.status = e.STATUS_STOPPED;
- if (this.onStopEvent) {
- this.onStopEvent();
- }
- null != this.execution_timer_id && (-1 != this.execution_timer_id && clearInterval(this.execution_timer_id), this.execution_timer_id = null);
- this.sendEventToAllNodes("onStop");
- }
- };
- e.prototype.runStep = function(a, b) {
- a = a || 1;
- var d = c.getTime();
- this.globaltime = 0.001 * (d - this.starttime);
- var p = this._nodes_executable ? this._nodes_executable : this._nodes;
- if (p) {
- if (b) {
- for (var m = 0; m < a; m++) {
- for (var g = 0, e = p.length; g < e; ++g) {
- var f = p[g];
- if (f.mode == c.ALWAYS && f.onExecute) {
- f.onExecute();
- }
- }
- this.fixedtime += this.fixedtime_lapse;
- if (this.onExecuteStep) {
- this.onExecuteStep();
- }
- }
- if (this.onAfterExecute) {
- this.onAfterExecute();
- }
- } else {
- try {
- for (m = 0; m < a; m++) {
- g = 0;
- for (e = p.length; g < e; ++g) {
- if (f = p[g], f.mode == c.ALWAYS && f.onExecute) {
- f.onExecute();
- }
- }
- this.fixedtime += this.fixedtime_lapse;
- if (this.onExecuteStep) {
- this.onExecuteStep();
- }
- }
- if (this.onAfterExecute) {
- this.onAfterExecute();
- }
- this.errors_in_execution = !1;
- } catch (I) {
- this.errors_in_execution = !0;
- if (c.throw_errors) {
- throw I;
- }
- c.debug && console.log("Error during execution: " + I);
- this.stop();
- }
- }
- a = c.getTime();
- d = a - d;
- 0 == d && (d = 1);
- this.execution_time = 0.001 * d;
- this.globaltime += 0.001 * d;
- this.iteration += 1;
- this.elapsed_time = 0.001 * (a - this.last_update_time);
- this.last_update_time = a;
- }
- };
- e.prototype.updateExecutionOrder = function() {
- this._nodes_in_order = this.computeExecutionOrder(!1);
- this._nodes_executable = [];
- for (var a = 0; a < this._nodes_in_order.length; ++a) {
- this._nodes_in_order[a].onExecute && this._nodes_executable.push(this._nodes_in_order[a]);
- }
- };
- e.prototype.computeExecutionOrder = function(a, b) {
- for (var d = [], p = [], m = {}, g = {}, e = {}, f = 0, l = this._nodes.length; f < l; ++f) {
- var k = this._nodes[f];
- if (!a || k.onExecute) {
- m[k.id] = k;
- var v = 0;
- if (k.inputs) {
- for (var h = 0, t = k.inputs.length; h < t; h++) {
- k.inputs[h] && null != k.inputs[h].link && (v += 1);
- }
- }
- 0 == v ? (p.push(k), b && (k._level = 1)) : (b && (k._level = 0), e[k.id] = v);
- }
- }
- for (; 0 != p.length;) {
- if (k = p.shift(), d.push(k), delete m[k.id], k.outputs) {
- for (f = 0; f < k.outputs.length; f++) {
- if (a = k.outputs[f], null != a && null != a.links && 0 != a.links.length) {
- for (h = 0; h < a.links.length; h++) {
- (l = this.links[a.links[h]]) && !g[l.id] && (v = this.getNodeById(l.target_id), null == v ? g[l.id] = !0 : (b && (!v._level || v._level <= k._level) && (v._level = k._level + 1), g[l.id] = !0, --e[v.id], 0 == e[v.id] && p.push(v)));
- }
- }
- }
- }
- }
- for (f in m) {
- d.push(m[f]);
- }
- d.length != this._nodes.length && c.debug && console.warn("something went wrong, nodes missing");
- l = d.length;
- for (f = 0; f < l; ++f) {
- d[f].order = f;
- }
- d = d.sort(function(a, b) {
- var d = a.constructor.priority || a.priority || 0, c = b.constructor.priority || b.priority || 0;
- return d == c ? a.order - b.order : d - c;
- });
- for (f = 0; f < l; ++f) {
- d[f].order = f;
- }
- return d;
- };
- e.prototype.getAncestors = function(a) {
- for (var b = [], d = [a], c = {}; d.length;) {
- var m = d.shift();
- if (m.inputs) {
- c[m.id] || m == a || (c[m.id] = !0, b.push(m));
- for (var g = 0; g < m.inputs.length; ++g) {
- var e = m.getInputNode(g);
- e && -1 == b.indexOf(e) && d.push(e);
- }
- }
- }
- b.sort(function(a, b) {
- return a.order - b.order;
- });
- return b;
- };
- e.prototype.arrange = function(a) {
- a = a || 40;
- for (var b = this.computeExecutionOrder(!1, !0), d = [], c = 0; c < b.length; ++c) {
- var m = b[c], g = m._level || 1;
- d[g] || (d[g] = []);
- d[g].push(m);
- }
- b = a;
- for (c = 0; c < d.length; ++c) {
- if (g = d[c]) {
- for (var e = 100, f = a, l = 0; l < g.length; ++l) {
- m = g[l], m.pos[0] = b, m.pos[1] = f, m.size[0] > e && (e = m.size[0]), f += m.size[1] + a;
- }
- b += e + a;
- }
- }
- this.setDirtyCanvas(!0, !0);
- };
- e.prototype.getTime = function() {
- return this.globaltime;
- };
- e.prototype.getFixedTime = function() {
- return this.fixedtime;
- };
- e.prototype.getElapsedTime = function() {
- return this.elapsed_time;
- };
- e.prototype.sendEventToAllNodes = function(a, b, d) {
- d = d || c.ALWAYS;
- var p = this._nodes_in_order ? this._nodes_in_order : this._nodes;
- if (p) {
- for (var m = 0, g = p.length; m < g; ++m) {
- var e = p[m];
- if (e.constructor === c.Subgraph && "onExecute" != a) {
- e.mode == d && e.sendEventToAllNodes(a, b, d);
- } else {
- if (e[a] && e.mode == d) {
- if (void 0 === b) {
- e[a]();
- } else {
- if (b && b.constructor === Array) {
- e[a].apply(e, b);
- } else {
- e[a](b);
- }
- }
- }
- }
- }
- }
- };
- e.prototype.sendActionToCanvas = function(a, b) {
- if (this.list_of_graphcanvas) {
- for (var d = 0; d < this.list_of_graphcanvas.length; ++d) {
- var c = this.list_of_graphcanvas[d];
- c[a] && c[a].apply(c, b);
- }
- }
- };
- e.prototype.add = function(a, b) {
- if (a) {
- if (a.constructor === h) {
- this._groups.push(a), this.setDirtyCanvas(!0), this.change(), a.graph = this, this._version++;
- } else {
- -1 != a.id && null != this._nodes_by_id[a.id] && (console.warn("LiteGraph: there is already a node with this ID, changing it"), a.id = ++this.last_node_id);
- if (this._nodes.length >= c.MAX_NUMBER_OF_NODES) {
- throw "LiteGraph: max number of nodes in a graph reached";
- }
- null == a.id || -1 == a.id ? a.id = ++this.last_node_id : this.last_node_id < a.id && (this.last_node_id = a.id);
- a.graph = this;
- this._version++;
- this._nodes.push(a);
- this._nodes_by_id[a.id] = a;
- if (a.onAdded) {
- a.onAdded(this);
- }
- this.config.align_to_grid && a.alignToGrid();
- b || this.updateExecutionOrder();
- if (this.onNodeAdded) {
- this.onNodeAdded(a);
- }
- this.setDirtyCanvas(!0);
- this.change();
- return a;
- }
- }
- };
- e.prototype.remove = function(a) {
- if (a.constructor === c.LGraphGroup) {
- var b = this._groups.indexOf(a);
- -1 != b && this._groups.splice(b, 1);
- a.graph = null;
- this._version++;
- this.setDirtyCanvas(!0, !0);
- this.change();
- } else {
- if (null != this._nodes_by_id[a.id] && !a.ignore_remove) {
- if (a.inputs) {
- for (b = 0; b < a.inputs.length; b++) {
- var d = a.inputs[b];
- null != d.link && a.disconnectInput(b);
- }
- }
- if (a.outputs) {
- for (b = 0; b < a.outputs.length; b++) {
- d = a.outputs[b], null != d.links && d.links.length && a.disconnectOutput(b);
- }
- }
- if (a.onRemoved) {
- a.onRemoved();
- }
- a.graph = null;
- this._version++;
- if (this.list_of_graphcanvas) {
- for (b = 0; b < this.list_of_graphcanvas.length; ++b) {
- d = this.list_of_graphcanvas[b], d.selected_nodes[a.id] && delete d.selected_nodes[a.id], d.node_dragged == a && (d.node_dragged = null);
- }
- }
- b = this._nodes.indexOf(a);
- -1 != b && this._nodes.splice(b, 1);
- delete this._nodes_by_id[a.id];
- if (this.onNodeRemoved) {
- this.onNodeRemoved(a);
- }
- this.setDirtyCanvas(!0, !0);
- this.change();
- this.updateExecutionOrder();
- }
- }
- };
- e.prototype.getNodeById = function(a) {
- return null == a ? null : this._nodes_by_id[a];
- };
- e.prototype.findNodesByClass = function(a, b) {
- b = b || [];
- for (var d = b.length = 0, c = this._nodes.length; d < c; ++d) {
- this._nodes[d].constructor === a && b.push(this._nodes[d]);
- }
- return b;
- };
- e.prototype.findNodesByType = function(a, b) {
- a = a.toLowerCase();
- b = b || [];
- for (var d = b.length = 0, c = this._nodes.length; d < c; ++d) {
- this._nodes[d].type.toLowerCase() == a && b.push(this._nodes[d]);
- }
- return b;
- };
- e.prototype.findNodeByTitle = function(a) {
- for (var b = 0, d = this._nodes.length; b < d; ++b) {
- if (this._nodes[b].title == a) {
- return this._nodes[b];
- }
- }
- return null;
- };
- e.prototype.findNodesByTitle = function(a) {
- for (var b = [], d = 0, c = this._nodes.length; d < c; ++d) {
- this._nodes[d].title == a && b.push(this._nodes[d]);
- }
- return b;
- };
- e.prototype.getNodeOnPos = function(a, b, d, c) {
- d = d || this._nodes;
- for (var p = d.length - 1; 0 <= p; p--) {
- var g = d[p];
- if (g.isPointInside(a, b, c)) {
- return g;
- }
- }
- return null;
- };
- e.prototype.getGroupOnPos = function(a, b) {
- for (var d = this._groups.length - 1; 0 <= d; d--) {
- var c = this._groups[d];
- if (c.isPointInside(a, b, 2, !0)) {
- return c;
- }
- }
- return null;
- };
- e.prototype.onAction = function(a, b) {
- this._input_nodes = this.findNodesByClass(c.GraphInput, this._input_nodes);
- for (var d = 0; d < this._input_nodes.length; ++d) {
- var p = this._input_nodes[d];
- if (p.properties.name == a) {
- p.onAction(a, b);
- break;
- }
- }
- };
- e.prototype.trigger = function(a, b) {
- if (this.onTrigger) {
- this.onTrigger(a, b);
- }
- };
- e.prototype.addInput = function(a, b, d) {
- if (!this.inputs[a]) {
- this.inputs[a] = {name:a, type:b, value:d};
- this._version++;
- if (this.onInputAdded) {
- this.onInputAdded(a, b);
- }
- if (this.onInputsOutputsChange) {
- this.onInputsOutputsChange();
- }
- }
- };
- e.prototype.setInputData = function(a, b) {
- if (a = this.inputs[a]) {
- a.value = b;
- }
- };
- e.prototype.getInputData = function(a) {
- return (a = this.inputs[a]) ? a.value : null;
- };
- e.prototype.renameInput = function(a, b) {
- if (b != a) {
- if (!this.inputs[a]) {
- return !1;
- }
- if (this.inputs[b]) {
- return console.error("there is already one input with that name"), !1;
- }
- this.inputs[b] = this.inputs[a];
- delete this.inputs[a];
- this._version++;
- if (this.onInputRenamed) {
- this.onInputRenamed(a, b);
- }
- if (this.onInputsOutputsChange) {
- this.onInputsOutputsChange();
- }
- }
- };
- e.prototype.changeInputType = function(a, b) {
- if (!this.inputs[a]) {
- return !1;
- }
- if (!this.inputs[a].type || String(this.inputs[a].type).toLowerCase() != String(b).toLowerCase()) {
- if (this.inputs[a].type = b, this._version++, this.onInputTypeChanged) {
- this.onInputTypeChanged(a, b);
- }
- }
- };
- e.prototype.removeInput = function(a) {
- if (!this.inputs[a]) {
- return !1;
- }
- delete this.inputs[a];
- this._version++;
- if (this.onInputRemoved) {
- this.onInputRemoved(a);
- }
- if (this.onInputsOutputsChange) {
- this.onInputsOutputsChange();
- }
- return !0;
- };
- e.prototype.addOutput = function(a, b, d) {
- this.outputs[a] = {name:a, type:b, value:d};
- this._version++;
- if (this.onOutputAdded) {
- this.onOutputAdded(a, b);
- }
- if (this.onInputsOutputsChange) {
- this.onInputsOutputsChange();
- }
- };
- e.prototype.setOutputData = function(a, b) {
- if (a = this.outputs[a]) {
- a.value = b;
- }
- };
- e.prototype.getOutputData = function(a) {
- return (a = this.outputs[a]) ? a.value : null;
- };
- e.prototype.renameOutput = function(a, b) {
- if (!this.outputs[a]) {
- return !1;
- }
- if (this.outputs[b]) {
- return console.error("there is already one output with that name"), !1;
- }
- this.outputs[b] = this.outputs[a];
- delete this.outputs[a];
- this._version++;
- if (this.onOutputRenamed) {
- this.onOutputRenamed(a, b);
- }
- if (this.onInputsOutputsChange) {
- this.onInputsOutputsChange();
- }
- };
- e.prototype.changeOutputType = function(a, b) {
- if (!this.outputs[a]) {
- return !1;
- }
- if (!this.outputs[a].type || String(this.outputs[a].type).toLowerCase() != String(b).toLowerCase()) {
- if (this.outputs[a].type = b, this._version++, this.onOutputTypeChanged) {
- this.onOutputTypeChanged(a, b);
- }
- }
- };
- e.prototype.removeOutput = function(a) {
- if (!this.outputs[a]) {
- return !1;
- }
- delete this.outputs[a];
- this._version++;
- if (this.onOutputRemoved) {
- this.onOutputRemoved(a);
- }
- if (this.onInputsOutputsChange) {
- this.onInputsOutputsChange();
- }
- return !0;
- };
- e.prototype.triggerInput = function(a, b) {
- a = this.findNodesByTitle(a);
- for (var d = 0; d < a.length; ++d) {
- a[d].onTrigger(b);
- }
- };
- e.prototype.setCallback = function(a, b) {
- a = this.findNodesByTitle(a);
- for (var d = 0; d < a.length; ++d) {
- a[d].setTrigger(b);
- }
- };
- e.prototype.connectionChange = function(a, b) {
- this.updateExecutionOrder();
- if (this.onConnectionChange) {
- this.onConnectionChange(a);
- }
- this._version++;
- this.sendActionToCanvas("onConnectionChange");
- };
- e.prototype.isLive = function() {
- if (!this.list_of_graphcanvas) {
- return !1;
- }
- for (var a = 0; a < this.list_of_graphcanvas.length; ++a) {
- if (this.list_of_graphcanvas[a].live_mode) {
- return !0;
- }
- }
- return !1;
- };
- e.prototype.clearTriggeredSlots = function() {
- for (var a in this.links) {
- var b = this.links[a];
- b && b._last_time && (b._last_time = 0);
- }
- };
- e.prototype.change = function() {
- c.debug && console.log("Graph changed");
- this.sendActionToCanvas("setDirty", [!0, !0]);
- if (this.on_change) {
- this.on_change(this);
- }
- };
- e.prototype.setDirtyCanvas = function(a, b) {
- this.sendActionToCanvas("setDirty", [a, b]);
- };
- e.prototype.removeLink = function(a) {
- if (a = this.links[a]) {
- var b = this.getNodeById(a.target_id);
- b && b.disconnectInput(a.target_slot);
- }
- };
- e.prototype.serialize = function() {
- for (var a = [], b = 0, d = this._nodes.length; b < d; ++b) {
- a.push(this._nodes[b].serialize());
- }
- d = [];
- for (b in this.links) {
- var p = this.links[b];
- d.push([p.id, p.origin_id, p.origin_slot, p.target_id, p.target_slot, p.type]);
- }
- p = [];
- for (b = 0; b < this._groups.length; ++b) {
- p.push(this._groups[b].serialize());
- }
- return {last_node_id:this.last_node_id, last_link_id:this.last_link_id, nodes:a, links:d, groups:p, config:this.config, version:c.VERSION};
- };
- e.prototype.configure = function(a, b) {
- if (a) {
- b || this.clear();
- b = a.nodes;
- if (a.links && a.links.constructor === Array) {
- for (var d = [], p = 0; p < a.links.length; ++p) {
- var m = a.links[p], g = new q;
- g.configure(m);
- d[g.id] = g;
- }
- a.links = d;
- }
- for (p in a) {
- this[p] = a[p];
- }
- d = !1;
- this._nodes = [];
- if (b) {
- p = 0;
- for (m = b.length; p < m; ++p) {
- g = b[p];
- var e = c.createNode(g.type, g.title);
- e || (c.debug && console.log("Node not found or has errors: " + g.type), e = new k, e.last_serialization = g, d = e.has_errors = !0);
- e.id = g.id;
- this.add(e, !0);
- }
- p = 0;
- for (m = b.length; p < m; ++p) {
- g = b[p], (e = this.getNodeById(g.id)) && e.configure(g);
- }
- }
- this._groups.length = 0;
- if (a.groups) {
- for (p = 0; p < a.groups.length; ++p) {
- b = new c.LGraphGroup, b.configure(a.groups[p]), this.add(b);
- }
- }
- this.updateExecutionOrder();
- this._version++;
- this.setDirtyCanvas(!0, !0);
- return d;
- }
- };
- e.prototype.load = function(a) {
- var b = this, d = new XMLHttpRequest;
- d.open("GET", a, !0);
- d.send(null);
- d.onload = function(a) {
- 200 !== d.status ? console.error("Error loading graph:", d.status, d.response) : (a = JSON.parse(d.response), b.configure(a));
- };
- d.onerror = function(a) {
- console.error("Error loading graph:", a);
- };
- };
- e.prototype.onNodeTrace = function(a, b, d) {
- };
- q.prototype.configure = function(a) {
- a.constructor === Array ? (this.id = a[0], this.origin_id = a[1], this.origin_slot = a[2], this.target_id = a[3], this.target_slot = a[4], this.type = a[5]) : (this.id = a.id, this.type = a.type, this.origin_id = a.origin_id, this.origin_slot = a.origin_slot, this.target_id = a.target_id, this.target_slot = a.target_slot);
- };
- q.prototype.serialize = function() {
- return [this.id, this.type, this.origin_id, this.origin_slot, this.target_id, this.target_slot];
- };
- c.LLink = q;
- w.LGraphNode = c.LGraphNode = k;
- k.prototype._ctor = function(a) {
- this.title = a || "Unnamed";
- this.size = [c.NODE_WIDTH, 60];
- this.graph = null;
- this._pos = new Float32Array(10, 10);
- Object.defineProperty(this, "pos", {set:function(a) {
- !a || 2 > a.length || (this._pos[0] = a[0], this._pos[1] = a[1]);
- }, get:function() {
- return this._pos;
- }, enumerable:!0});
- this.id = -1;
- this.type = null;
- this.inputs = [];
- this.outputs = [];
- this.connections = [];
- this.properties = {};
- this.properties_info = [];
- this.flags = {};
- };
- k.prototype.configure = function(a) {
- this.graph && this.graph._version++;
- for (var b in a) {
- if ("properties" == b) {
- for (var d in a.properties) {
- if (this.properties[d] = a.properties[d], this.onPropertyChanged) {
- this.onPropertyChanged(d, a.properties[d]);
- }
- }
- } else {
- null != a[b] && ("object" == typeof a[b] ? this[b] && this[b].configure ? this[b].configure(a[b]) : this[b] = c.cloneObject(a[b], this[b]) : this[b] = a[b]);
- }
- }
- a.title || (this.title = this.constructor.title);
- if (this.onConnectionsChange) {
- if (this.inputs) {
- for (d = 0; d < this.inputs.length; ++d) {
- b = this.inputs[d];
- var p = this.graph ? this.graph.links[b.link] : null;
- this.onConnectionsChange(c.INPUT, d, !0, p, b);
- }
- }
- if (this.outputs) {
- for (d = 0; d < this.outputs.length; ++d) {
- var m = this.outputs[d];
- if (m.links) {
- for (b = 0; b < m.links.length; ++b) {
- p = this.graph ? this.graph.links[m.links[b]] : null, this.onConnectionsChange(c.OUTPUT, d, !0, p, m);
- }
- }
- }
- }
- }
- if (a.widgets_values && this.widgets) {
- for (d = 0; d < a.widgets_values.length; ++d) {
- this.widgets[d] && (this.widgets[d].value = a.widgets_values[d]);
- }
- }
- if (this.onConfigure) {
- this.onConfigure(a);
- }
- };
- k.prototype.serialize = function() {
- var a = {id:this.id, type:this.type, pos:this.pos, size:this.size, flags:c.cloneObject(this.flags), mode:this.mode};
- if (this.constructor === k && this.last_serialization) {
- return this.last_serialization;
- }
- this.inputs && (a.inputs = this.inputs);
- if (this.outputs) {
- for (var b = 0; b < this.outputs.length; b++) {
- delete this.outputs[b]._data;
- }
- a.outputs = this.outputs;
- }
- this.title && this.title != this.constructor.title && (a.title = this.title);
- this.properties && (a.properties = c.cloneObject(this.properties));
- if (this.widgets && this.serialize_widgets) {
- for (a.widgets_values = [], b = 0; b < this.widgets.length; ++b) {
- a.widgets_values[b] = this.widgets[b].value;
- }
- }
- a.type || (a.type = this.constructor.type);
- this.color && (a.color = this.color);
- this.bgcolor && (a.bgcolor = this.bgcolor);
- this.boxcolor && (a.boxcolor = this.boxcolor);
- this.shape && (a.shape = this.shape);
- this.onSerialize && this.onSerialize(a) && console.warn("node onSerialize shouldnt return anything, data should be stored in the object pass in the first parameter");
- return a;
- };
- k.prototype.clone = function() {
- var a = c.createNode(this.type);
- if (!a) {
- return null;
- }
- var b = c.cloneObject(this.serialize());
- if (b.inputs) {
- for (var d = 0; d < b.inputs.length; ++d) {
- b.inputs[d].link = null;
- }
- }
- if (b.outputs) {
- for (d = 0; d < b.outputs.length; ++d) {
- b.outputs[d].links && (b.outputs[d].links.length = 0);
- }
- }
- delete b.id;
- a.configure(b);
- return a;
- };
- k.prototype.toString = function() {
- return JSON.stringify(this.serialize());
- };
- k.prototype.getTitle = function() {
- return this.title || this.constructor.title;
- };
- k.prototype.setOutputData = function(a, b) {
- if (this.outputs && !(-1 == a || a >= this.outputs.length)) {
- var d = this.outputs[a];
- if (d && (d._data = b, this.outputs[a].links)) {
- for (d = 0; d < this.outputs[a].links.length; d++) {
- this.graph.links[this.outputs[a].links[d]].data = b;
- }
- }
- }
- };
- k.prototype.setOutputDataType = function(a, b) {
- if (this.outputs && !(-1 == a || a >= this.outputs.length)) {
- var d = this.outputs[a];
- if (d && (d.type = b, this.outputs[a].links)) {
- for (d = 0; d < this.outputs[a].links.length; d++) {
- this.graph.links[this.outputs[a].links[d]].type = b;
- }
- }
- }
- };
- k.prototype.getInputData = function(a, b) {
- if (this.inputs && !(a >= this.inputs.length || null == this.inputs[a].link)) {
- a = this.graph.links[this.inputs[a].link];
- if (!a) {
- return null;
- }
- if (!b) {
- return a.data;
- }
- b = this.graph.getNodeById(a.origin_id);
- if (!b) {
- return a.data;
- }
- if (b.updateOutputData) {
- b.updateOutputData(a.origin_slot);
- } else {
- if (b.onExecute) {
- b.onExecute();
- }
- }
- return a.data;
- }
- };
- k.prototype.getInputDataType = function(a) {
- if (!this.inputs || a >= this.inputs.length || null == this.inputs[a].link) {
- return null;
- }
- a = this.graph.links[this.inputs[a].link];
- if (!a) {
- return null;
- }
- var b = this.graph.getNodeById(a.origin_id);
- return b ? (a = b.outputs[a.origin_slot]) ? a.type : null : a.type;
- };
- k.prototype.getInputDataByName = function(a, b) {
- a = this.findInputSlot(a);
- return -1 == a ? null : this.getInputData(a, b);
- };
- k.prototype.isInputConnected = function(a) {
- return this.inputs ? a < this.inputs.length && null != this.inputs[a].link : !1;
- };
- k.prototype.getInputInfo = function(a) {
- return this.inputs ? a < this.inputs.length ? this.inputs[a] : null : null;
- };
- k.prototype.getInputNode = function(a) {
- if (!this.inputs || a >= this.inputs.length) {
- return null;
- }
- a = this.inputs[a];
- return a && null !== a.link ? (a = this.graph.links[a.link]) ? this.graph.getNodeById(a.origin_id) : null : null;
- };
- k.prototype.getInputOrProperty = function(a) {
- if (!this.inputs || !this.inputs.length) {
- return this.properties ? this.properties[a] : null;
- }
- for (var b = 0, d = this.inputs.length; b < d; ++b) {
- var c = this.inputs[b];
- if (a == c.name && null != c.link && (c = this.graph.links[c.link])) {
- return c.data;
- }
- }
- return this.properties[a];
- };
- k.prototype.getOutputData = function(a) {
- return !this.outputs || a >= this.outputs.length ? null : this.outputs[a]._data;
- };
- k.prototype.getOutputInfo = function(a) {
- return this.outputs ? a < this.outputs.length ? this.outputs[a] : null : null;
- };
- k.prototype.isOutputConnected = function(a) {
- return this.outputs ? a < this.outputs.length && this.outputs[a].links && this.outputs[a].links.length : !1;
- };
- k.prototype.isAnyOutputConnected = function() {
- if (!this.outputs) {
- return !1;
- }
- for (var a = 0; a < this.outputs.length; ++a) {
- if (this.outputs[a].links && this.outputs[a].links.length) {
- return !0;
- }
- }
- return !1;
- };
- k.prototype.getOutputNodes = function(a) {
- if (!this.outputs || 0 == this.outputs.length || a >= this.outputs.length) {
- return null;
- }
- a = this.outputs[a];
- if (!a.links || 0 == a.links.length) {
- return null;
- }
- for (var b = [], d = 0; d < a.links.length; d++) {
- var c = this.graph.links[a.links[d]];
- c && (c = this.graph.getNodeById(c.target_id)) && b.push(c);
- }
- return b;
- };
- k.prototype.trigger = function(a, b) {
- if (this.outputs && this.outputs.length) {
- this.graph && (this.graph._last_trigger_time = c.getTime());
- for (var d = 0; d < this.outputs.length; ++d) {
- var p = this.outputs[d];
- !p || p.type !== c.EVENT || a && p.name != a || this.triggerSlot(d, b);
- }
- }
- };
- k.prototype.triggerSlot = function(a, b, d) {
- if (this.outputs && (a = this.outputs[a]) && (a = a.links) && a.length) {
- this.graph && (this.graph._last_trigger_time = c.getTime());
- for (var p = 0; p < a.length; ++p) {
- var m = a[p];
- if (null == d || d == m) {
- var g = this.graph.links[a[p]];
- if (g && (g._last_time = c.getTime(), m = this.graph.getNodeById(g.target_id))) {
- if (g = m.inputs[g.target_slot], m.onAction) {
- m.onAction(g.name, b);
- } else {
- if (m.mode === c.ON_TRIGGER && m.onExecute) {
- m.onExecute(b);
- }
- }
- }
- }
- }
- }
- };
- k.prototype.clearTriggeredSlot = function(a, b) {
- if (this.outputs && (a = this.outputs[a]) && (a = a.links) && a.length) {
- for (var d = 0; d < a.length; ++d) {
- var c = a[d];
- if (null == b || b == c) {
- if (c = this.graph.links[a[d]]) {
- c._last_time = 0;
- }
- }
- }
- }
- };
- k.prototype.addProperty = function(a, b, d, c) {
- d = {name:a, type:d, default_value:b};
- if (c) {
- for (var p in c) {
- d[p] = c[p];
- }
- }
- this.properties_info || (this.properties_info = []);
- this.properties_info.push(d);
- this.properties || (this.properties = {});
- this.properties[a] = b;
- return d;
- };
- k.prototype.addOutput = function(a, b, d) {
- a = {name:a, type:b, links:null};
- if (d) {
- for (var c in d) {
- a[c] = d[c];
- }
- }
- this.outputs || (this.outputs = []);
- this.outputs.push(a);
- if (this.onOutputAdded) {
- this.onOutputAdded(a);
- }
- this.size = this.computeSize();
- this.setDirtyCanvas(!0, !0);
- return a;
- };
- k.prototype.addOutputs = function(a) {
- for (var b = 0; b < a.length; ++b) {
- var d = a[b], c = {name:d[0], type:d[1], link:null};
- if (a[2]) {
- for (var m in d[2]) {
- c[m] = d[2][m];
- }
- }
- this.outputs || (this.outputs = []);
- this.outputs.push(c);
- if (this.onOutputAdded) {
- this.onOutputAdded(c);
- }
- }
- this.size = this.computeSize();
- this.setDirtyCanvas(!0, !0);
- };
- k.prototype.removeOutput = function(a) {
- this.disconnectOutput(a);
- this.outputs.splice(a, 1);
- for (var b = a; b < this.outputs.length; ++b) {
- if (this.outputs[b] && this.outputs[b].links) {
- for (var d = this.outputs[b].links, c = 0; c < d.length; ++c) {
- var m = this.graph.links[d[c]];
- m && --m.origin_slot;
- }
- }
- }
- this.size = this.computeSize();
- if (this.onOutputRemoved) {
- this.onOutputRemoved(a);
- }
- this.setDirtyCanvas(!0, !0);
- };
- k.prototype.addInput = function(a, b, d) {
- a = {name:a, type:b || 0, link:null};
- if (d) {
- for (var c in d) {
- a[c] = d[c];
- }
- }
- this.inputs || (this.inputs = []);
- this.inputs.push(a);
- this.size = this.computeSize();
- if (this.onInputAdded) {
- this.onInputAdded(a);
- }
- this.setDirtyCanvas(!0, !0);
- return a;
- };
- k.prototype.addInputs = function(a) {
- for (var b = 0; b < a.length; ++b) {
- var d = a[b], c = {name:d[0], type:d[1], link:null};
- if (a[2]) {
- for (var m in d[2]) {
- c[m] = d[2][m];
- }
- }
- this.inputs || (this.inputs = []);
- this.inputs.push(c);
- if (this.onInputAdded) {
- this.onInputAdded(c);
- }
- }
- this.size = this.computeSize();
- this.setDirtyCanvas(!0, !0);
- };
- k.prototype.removeInput = function(a) {
- this.disconnectInput(a);
- this.inputs.splice(a, 1);
- for (var b = a; b < this.inputs.length; ++b) {
- if (this.inputs[b]) {
- var d = this.graph.links[this.inputs[b].link];
- d && --d.target_slot;
- }
- }
- this.size = this.computeSize();
- if (this.onInputRemoved) {
- this.onInputRemoved(a);
- }
- this.setDirtyCanvas(!0, !0);
- };
- k.prototype.addConnection = function(a, b, d, c) {
- a = {name:a, type:b, pos:d, direction:c, links:null};
- this.connections.push(a);
- return a;
- };
- k.prototype.computeSize = function(a, b) {
- function d(a) {
- return a ? p * a.length * 0.6 : 0;
- }
- if (this.constructor.size) {
- return this.constructor.size.concat();
- }
- a = Math.max(this.inputs ? this.inputs.length : 1, this.outputs ? this.outputs.length : 1);
- b = b || new Float32Array([0, 0]);
- a = Math.max(a, 1);
- var p = c.NODE_TEXT_SIZE;
- b[1] = (this.constructor.slot_start_y || 0) + a * c.NODE_SLOT_HEIGHT;
- a = 0;
- this.widgets && this.widgets.length && (a = this.widgets.length * (c.NODE_WIDGET_HEIGHT + 4) + 8);
- b[1] = this.widgets_up ? Math.max(b[1], a) : b[1] + a;
- a = d(this.title);
- var m = 0, g = 0;
- if (this.inputs) {
- for (var e = 0, f = this.inputs.length; e < f; ++e) {
- var l = this.inputs[e];
- l = l.label || l.name || "";
- l = d(l);
- m < l && (m = l);
- }
- }
- if (this.outputs) {
- for (e = 0, f = this.outputs.length; e < f; ++e) {
- l = this.outputs[e], l = l.label || l.name || "", l = d(l), g < l && (g = l);
- }
- }
- b[0] = Math.max(m + g + 10, a);
- b[0] = Math.max(b[0], c.NODE_WIDTH);
- this.widgets && this.widgets.length && (b[0] = Math.max(b[0], 1.5 * c.NODE_WIDTH));
- if (this.onResize) {
- this.onResize(b);
- }
- this.constructor.min_height && b[1] < this.constructor.min_height && (b[1] = this.constructor.min_height);
- b[1] += 6;
- return b;
- };
- k.prototype.addWidget = function(a, b, d, c, m) {
- this.widgets || (this.widgets = []);
- b = {type:a.toLowerCase(), name:b, value:d, callback:c, options:m || {}};
- void 0 !== b.options.y && (b.y = b.options.y);
- c || console.warn("LiteGraph addWidget(...) without a callback");
- if ("combo" == a && !b.options.values) {
- throw "LiteGraph addWidget('combo',...) requires to pass values in options: { values:['red','blue'] }";
- }
- this.widgets.push(b);
- return b;
- };
- k.prototype.addCustomWidget = function(a) {
- this.widgets || (this.widgets = []);
- this.widgets.push(a);
- return a;
- };
- k.prototype.getBounding = function(a) {
- a = a || new Float32Array(4);
- a[0] = this.pos[0] - 4;
- a[1] = this.pos[1] - c.NODE_TITLE_HEIGHT;
- a[2] = this.size[0] + 4;
- a[3] = this.size[1] + c.NODE_TITLE_HEIGHT;
- if (this.onBounding) {
- this.onBounding(a);
- }
- return a;
- };
- k.prototype.isPointInside = function(a, b, d, p) {
- d = d || 0;
- var m = this.graph && this.graph.isLive() ? 0 : 20;
- p && (m = 0);
- if (this.flags && this.flags.collapsed) {
- if (B(a, b, this.pos[0] - d, this.pos[1] - c.NODE_TITLE_HEIGHT - d, (this._collapsed_width || c.NODE_COLLAPSED_WIDTH) + 2 * d, c.NODE_TITLE_HEIGHT + 2 * d)) {
- return !0;
- }
- } else {
- if (this.pos[0] - 4 - d < a && this.pos[0] + this.size[0] + 4 + d > a && this.pos[1] - m - d < b && this.pos[1] + this.size[1] + d > b) {
- return !0;
- }
- }
- return !1;
- };
- k.prototype.getSlotInPosition = function(a, b) {
- var d = new Float32Array(2);
- if (this.inputs) {
- for (var c = 0, m = this.inputs.length; c < m; ++c) {
- var g = this.inputs[c];
- this.getConnectionPos(!0, c, d);
- if (B(a, b, d[0] - 10, d[1] - 5, 20, 10)) {
- return {input:g, slot:c, link_pos:d};
- }
- }
- }
- if (this.outputs) {
- for (c = 0, m = this.outputs.length; c < m; ++c) {
- if (g = this.outputs[c], this.getConnectionPos(!1, c, d), B(a, b, d[0] - 10, d[1] - 5, 20, 10)) {
- return {output:g, slot:c, link_pos:d};
- }
- }
- }
- return null;
- };
- k.prototype.findInputSlot = function(a) {
- if (!this.inputs) {
- return -1;
- }
- for (var b = 0, d = this.inputs.length; b < d; ++b) {
- if (a == this.inputs[b].name) {
- return b;
- }
- }
- return -1;
- };
- k.prototype.findOutputSlot = function(a) {
- if (!this.outputs) {
- return -1;
- }
- for (var b = 0, d = this.outputs.length; b < d; ++b) {
- if (a == this.outputs[b].name) {
- return b;
- }
- }
- return -1;
- };
- k.prototype.connect = function(a, b, d) {
- d = d || 0;
- if (!this.graph) {
- return console.log("Connect: Error, node doesn't belong to any graph. Nodes must be added first to a graph before connecting them."), null;
- }
- if (a.constructor === String) {
- if (a = this.findOutputSlot(a), -1 == a) {
- return c.debug && console.log("Connect: Error, no slot of name " + a), null;
- }
- } else {
- if (!this.outputs || a >= this.outputs.length) {
- return c.debug && console.log("Connect: Error, slot number not found"), null;
- }
- }
- b && b.constructor === Number && (b = this.graph.getNodeById(b));
- if (!b) {
- throw "target node is null";
- }
- if (b == this) {
- return null;
- }
- if (d.constructor === String) {
- if (d = b.findInputSlot(d), -1 == d) {
- return c.debug && console.log("Connect: Error, no slot of name " + d), null;
- }
- } else {
- if (d === c.EVENT) {
- return null;
- }
- if (!b.inputs || d >= b.inputs.length) {
- return c.debug && console.log("Connect: Error, slot number not found"), null;
- }
- }
- null != b.inputs[d].link && b.disconnectInput(d);
- var g = this.outputs[a];
- if (b.onConnectInput && !1 === b.onConnectInput(d, g.type, g)) {
- return null;
- }
- var m = b.inputs[d], e = null;
- if (c.isValidConnection(g.type, m.type)) {
- e = new q(this.graph.last_link_id++, m.type, this.id, a, b.id, d);
- this.graph.links[e.id] = e;
- null == g.links && (g.links = []);
- g.links.push(e.id);
- b.inputs[d].link = e.id;
- this.graph && this.graph._version++;
- if (this.onConnectionsChange) {
- this.onConnectionsChange(c.OUTPUT, a, !0, e, g);
- }
- if (b.onConnectionsChange) {
- b.onConnectionsChange(c.INPUT, d, !0, e, m);
- }
- this.graph && this.graph.onNodeConnectionChange && (this.graph.onNodeConnectionChange(c.INPUT, b, d, this, a), this.graph.onNodeConnectionChange(c.OUTPUT, this, a, b, d));
- }
- this.setDirtyCanvas(!1, !0);
- this.graph.connectionChange(this, e);
- return e;
- };
- k.prototype.disconnectOutput = function(a, b) {
- if (a.constructor === String) {
- if (a = this.findOutputSlot(a), -1 == a) {
- return c.debug && console.log("Connect: Error, no slot of name " + a), !1;
- }
- } else {
- if (!this.outputs || a >= this.outputs.length) {
- return c.debug && console.log("Connect: Error, slot number not found"), !1;
- }
- }
- var d = this.outputs[a];
- if (!d || !d.links || 0 == d.links.length) {
- return !1;
- }
- if (b) {
- b.constructor === Number && (b = this.graph.getNodeById(b));
- if (!b) {
- throw "Target Node not found";
- }
- for (var g = 0, m = d.links.length; g < m; g++) {
- var e = d.links[g], f = this.graph.links[e];
- if (f.target_id == b.id) {
- d.links.splice(g, 1);
- var l = b.inputs[f.target_slot];
- l.link = null;
- delete this.graph.links[e];
- this.graph && this.graph._version++;
- if (b.onConnectionsChange) {
- b.onConnectionsChange(c.INPUT, f.target_slot, !1, f, l);
- }
- if (this.onConnectionsChange) {
- this.onConnectionsChange(c.OUTPUT, a, !1, f, d);
- }
- if (this.graph && this.graph.onNodeConnectionChange) {
- this.graph.onNodeConnectionChange(c.OUTPUT, this, a);
- }
- this.graph && this.graph.onNodeConnectionChange && (this.graph.onNodeConnectionChange(c.OUTPUT, this, a), this.graph.onNodeConnectionChange(c.INPUT, b, f.target_slot));
- break;
- }
- }
- } else {
- g = 0;
- for (m = d.links.length; g < m; g++) {
- if (e = d.links[g], f = this.graph.links[e]) {
- b = this.graph.getNodeById(f.target_id);
- this.graph && this.graph._version++;
- if (b) {
- l = b.inputs[f.target_slot];
- l.link = null;
- if (b.onConnectionsChange) {
- b.onConnectionsChange(c.INPUT, f.target_slot, !1, f, l);
- }
- if (this.graph && this.graph.onNodeConnectionChange) {
- this.graph.onNodeConnectionChange(c.INPUT, b, f.target_slot);
- }
- }
- delete this.graph.links[e];
- if (this.onConnectionsChange) {
- this.onConnectionsChange(c.OUTPUT, a, !1, f, d);
- }
- this.graph && this.graph.onNodeConnectionChange && (this.graph.onNodeConnectionChange(c.OUTPUT, this, a), this.graph.onNodeConnectionChange(c.INPUT, b, f.target_slot));
- }
- }
- d.links = null;
- }
- this.setDirtyCanvas(!1, !0);
- this.graph.connectionChange(this);
- return !0;
- };
- k.prototype.disconnectInput = function(a) {
- if (a.constructor === String) {
- if (a = this.findInputSlot(a), -1 == a) {
- return c.debug && console.log("Connect: Error, no slot of name " + a), !1;
- }
- } else {
- if (!this.inputs || a >= this.inputs.length) {
- return c.debug && console.log("Connect: Error, slot number not found"), !1;
- }
- }
- var b = this.inputs[a];
- if (!b) {
- return !1;
- }
- var d = this.inputs[a].link;
- this.inputs[a].link = null;
- var g = this.graph.links[d];
- if (g) {
- var m = this.graph.getNodeById(g.origin_id);
- if (!m) {
- return !1;
- }
- var e = m.outputs[g.origin_slot];
- if (!e || !e.links || 0 == e.links.length) {
- return !1;
- }
- for (var f = 0, l = e.links.length; f < l; f++) {
- if (e.links[f] == d) {
- e.links.splice(f, 1);
- break;
- }
- }
- delete this.graph.links[d];
- this.graph && this.graph._version++;
- if (this.onConnectionsChange) {
- this.onConnectionsChange(c.INPUT, a, !1, g, b);
- }
- if (m.onConnectionsChange) {
- m.onConnectionsChange(c.OUTPUT, f, !1, g, e);
- }
- this.graph && this.graph.onNodeConnectionChange && (this.graph.onNodeConnectionChange(c.OUTPUT, m, f), this.graph.onNodeConnectionChange(c.INPUT, this, a));
- }
- this.setDirtyCanvas(!1, !0);
- this.graph.connectionChange(this);
- return !0;
- };
- k.prototype.getConnectionPos = function(a, b, d) {
- d = d || new Float32Array(2);
- var g = 0;
- a && this.inputs && (g = this.inputs.length);
- !a && this.outputs && (g = this.outputs.length);
- var m = 0.5 * c.NODE_SLOT_HEIGHT;
- if (this.flags.collapsed) {
- return b = this._collapsed_width || c.NODE_COLLAPSED_WIDTH, this.horizontal ? (d[0] = this.pos[0] + 0.5 * b, d[1] = a ? this.pos[1] - c.NODE_TITLE_HEIGHT : this.pos[1]) : (d[0] = a ? this.pos[0] : this.pos[0] + b, d[1] = this.pos[1] - 0.5 * c.NODE_TITLE_HEIGHT), d;
- }
- if (a && -1 == b) {
- return d[0] = this.pos[0] + 0.5 * c.NODE_TITLE_HEIGHT, d[1] = this.pos[1] + 0.5 * c.NODE_TITLE_HEIGHT, d;
- }
- if (a && g > b && this.inputs[b].pos) {
- return d[0] = this.pos[0] + this.inputs[b].pos[0], d[1] = this.pos[1] + this.inputs[b].pos[1], d;
- }
- if (!a && g > b && this.outputs[b].pos) {
- return d[0] = this.pos[0] + this.outputs[b].pos[0], d[1] = this.pos[1] + this.outputs[b].pos[1], d;
- }
- if (this.horizontal) {
- return d[0] = this.pos[0] + this.size[0] / g * (b + 0.5), d[1] = a ? this.pos[1] - c.NODE_TITLE_HEIGHT : this.pos[1] + this.size[1], d;
- }
- d[0] = a ? this.pos[0] + m : this.pos[0] + this.size[0] + 1 - m;
- d[1] = this.pos[1] + (b + 0.7) * c.NODE_SLOT_HEIGHT + (this.constructor.slot_start_y || 0);
- return d;
- };
- k.prototype.alignToGrid = function() {
- this.pos[0] = c.CANVAS_GRID_SIZE * Math.round(this.pos[0] / c.CANVAS_GRID_SIZE);
- this.pos[1] = c.CANVAS_GRID_SIZE * Math.round(this.pos[1] / c.CANVAS_GRID_SIZE);
- };
- k.prototype.trace = function(a) {
- this.console || (this.console = []);
- this.console.push(a);
- this.console.length > k.MAX_CONSOLE && this.console.shift();
- this.graph.onNodeTrace(this, a);
- };
- k.prototype.setDirtyCanvas = function(a, b) {
- this.graph && this.graph.sendActionToCanvas("setDirty", [a, b]);
- };
- k.prototype.loadImage = function(a) {
- var b = new Image;
- b.src = c.node_images_path + a;
- b.ready = !1;
- var d = this;
- b.onload = function() {
- this.ready = !0;
- d.setDirtyCanvas(!0);
- };
- return b;
- };
- k.prototype.captureInput = function(a) {
- if (this.graph && this.graph.list_of_graphcanvas) {
- for (var b = this.graph.list_of_graphcanvas, d = 0; d < b.length; ++d) {
- var c = b[d];
- if (a || c.node_capturing_input == this) {
- c.node_capturing_input = a ? this : null;
- }
- }
- }
- };
- k.prototype.collapse = function(a) {
- this.graph._version++;
- if (!1 !== this.constructor.collapsable || a) {
- this.flags.collapsed = this.flags.collapsed ? !1 : !0, this.setDirtyCanvas(!0, !0);
- }
- };
- k.prototype.pin = function(a) {
- this.graph._version++;
- this.flags.pinned = void 0 === a ? !this.flags.pinned : a;
- };
- k.prototype.localToScreen = function(a, b, d) {
- return [(a + this.pos[0]) * d.scale + d.offset[0], (b + this.pos[1]) * d.scale + d.offset[1]];
- };
- w.LGraphGroup = c.LGraphGroup = h;
- h.prototype._ctor = function(a) {
- this.title = a || "Group";
- this.font_size = 24;
- this.color = f.node_colors.pale_blue ? f.node_colors.pale_blue.groupcolor : "#AAA";
- this._bounding = new Float32Array([10, 10, 140, 80]);
- this._pos = this._bounding.subarray(0, 2);
- this._size = this._bounding.subarray(2, 4);
- this._nodes = [];
- this.graph = null;
- Object.defineProperty(this, "pos", {set:function(a) {
- !a || 2 > a.length || (this._pos[0] = a[0], this._pos[1] = a[1]);
- }, get:function() {
- return this._pos;
- }, enumerable:!0});
- Object.defineProperty(this, "size", {set:function(a) {
- !a || 2 > a.length || (this._size[0] = Math.max(140, a[0]), this._size[1] = Math.max(80, a[1]));
- }, get:function() {
- return this._size;
- }, enumerable:!0});
- };
- h.prototype.configure = function(a) {
- this.title = a.title;
- this._bounding.set(a.bounding);
- this.color = a.color;
- this.font = a.font;
- };
- h.prototype.serialize = function() {
- var a = this._bounding;
- return {title:this.title, bounding:[Math.round(a[0]), Math.round(a[1]), Math.round(a[2]), Math.round(a[3])], color:this.color, font:this.font};
- };
- h.prototype.move = function(a, b, d) {
- this._pos[0] += a;
- this._pos[1] += b;
- if (!d) {
- for (d = 0; d < this._nodes.length; ++d) {
- var c = this._nodes[d];
- c.pos[0] += a;
- c.pos[1] += b;
- }
- }
- };
- h.prototype.recomputeInsideNodes = function() {
- this._nodes.length = 0;
- for (var a = this.graph._nodes, b = new Float32Array(4), d = 0; d < a.length; ++d) {
- var c = a[d];
- c.getBounding(b);
- z(this._bounding, b) && this._nodes.push(c);
- }
- };
- h.prototype.isPointInside = k.prototype.isPointInside;
- h.prototype.setDirtyCanvas = k.prototype.setDirtyCanvas;
- c.DragAndScale = n;
- n.prototype.bindEvents = function(a) {
- this.last_mouse = new Float32Array(2);
- this._binded_mouse_callback = this.onMouse.bind(this);
- a.addEventListener("mousedown", this._binded_mouse_callback);
- a.addEventListener("mousemove", this._binded_mouse_callback);
- a.addEventListener("mousewheel", this._binded_mouse_callback, !1);
- a.addEventListener("wheel", this._binded_mouse_callback, !1);
- };
- n.prototype.computeVisibleArea = function() {
- if (this.element) {
- var a = -this.offset[0], b = -this.offset[1], d = a + this.element.width / this.scale, c = b + this.element.height / this.scale;
- this.visible_area[0] = a;
- this.visible_area[1] = b;
- this.visible_area[2] = d - a;
- this.visible_area[3] = c - b;
- } else {
- this.visible_area[0] = this.visible_area[1] = this.visible_area[2] = this.visible_area[3] = 0;
- }
- };
- n.prototype.onMouse = function(a) {
- if (this.enabled) {
- var b = this.element, d = b.getBoundingClientRect(), c = a.clientX - d.left;
- d = a.clientY - d.top;
- a.canvasx = c;
- a.canvasy = d;
- a.dragging = this.dragging;
- var g = !1;
- this.onmouse && (g = this.onmouse(a));
- if ("mousedown" == a.type) {
- this.dragging = !0, b.removeEventListener("mousemove", this._binded_mouse_callback), document.body.addEventListener("mousemove", this._binded_mouse_callback), document.body.addEventListener("mouseup", this._binded_mouse_callback);
- } else {
- if ("mousemove" == a.type) {
- g || (b = c - this.last_mouse[0], g = d - this.last_mouse[1], this.dragging && this.mouseDrag(b, g));
- } else {
- if ("mouseup" == a.type) {
- this.dragging = !1, document.body.removeEventListener("mousemove", this._binded_mouse_callback), document.body.removeEventListener("mouseup", this._binded_mouse_callback), b.addEventListener("mousemove", this._binded_mouse_callback);
- } else {
- if ("mousewheel" == a.type || "wheel" == a.type || "DOMMouseScroll" == a.type) {
- a.eventType = "mousewheel", a.wheel = "wheel" == a.type ? -a.deltaY : null != a.wheelDeltaY ? a.wheelDeltaY : -60 * a.detail, a.delta = a.wheelDelta ? a.wheelDelta / 40 : a.deltaY ? -a.deltaY / 3 : 0, this.changeDeltaScale(1.0 + 0.05 * a.delta);
- }
- }
- }
- }
- this.last_mouse[0] = c;
- this.last_mouse[1] = d;
- a.preventDefault();
- a.stopPropagation();
- return !1;
- }
- };
- n.prototype.toCanvasContext = function(a) {
- a.scale(this.scale, this.scale);
- a.translate(this.offset[0], this.offset[1]);
- };
- n.prototype.convertOffsetToCanvas = function(a) {
- return [(a[0] + this.offset[0]) * this.scale, (a[1] + this.offset[1]) * this.scale];
- };
- n.prototype.convertCanvasToOffset = function(a, b) {
- b = b || [0, 0];
- b[0] = a[0] / this.scale - this.offset[0];
- b[1] = a[1] / this.scale - this.offset[1];
- return b;
- };
- n.prototype.mouseDrag = function(a, b) {
- this.offset[0] += a / this.scale;
- this.offset[1] += b / this.scale;
- if (this.onredraw) {
- this.onredraw(this);
- }
- };
- n.prototype.changeScale = function(a, b) {
- a < this.min_scale ? a = this.min_scale : a > this.max_scale && (a = this.max_scale);
- if (a != this.scale && this.element) {
- var d = this.element.getBoundingClientRect();
- if (d && (b = b || [0.5 * d.width, 0.5 * d.height], d = this.convertCanvasToOffset(b), this.scale = a, 0.01 > Math.abs(this.scale - 1) && (this.scale = 1), a = this.convertCanvasToOffset(b), a = [a[0] - d[0], a[1] - d[1]], this.offset[0] += a[0], this.offset[1] += a[1], this.onredraw)) {
- this.onredraw(this);
- }
- }
- };
- n.prototype.changeDeltaScale = function(a, b) {
- this.changeScale(this.scale * a, b);
- };
- n.prototype.reset = function() {
- this.scale = 1;
- this.offset[0] = 0;
- this.offset[1] = 0;
- };
- w.LGraphCanvas = c.LGraphCanvas = f;
- f.link_type_colors = {"-1":c.EVENT_LINK_COLOR, number:"#AAA", node:"#DCA"};
- f.gradients = {};
- f.prototype.clear = function() {
- this.fps = this.render_time = this.last_draw_time = this.frame = 0;
- this.dragging_rectangle = null;
- this.selected_nodes = {};
- this.selected_group = null;
- this.visible_nodes = [];
- this.connecting_node = this.node_capturing_input = this.node_over = this.node_dragged = null;
- this.highlighted_links = {};
- this.dirty_bgcanvas = this.dirty_canvas = !0;
- this.node_widget = this.node_in_panel = this.dirty_area = null;
- this.last_mouse = [0, 0];
- this.last_mouseclick = 0;
- this.visible_area.set([0, 0, 0, 0]);
- if (this.onClear) {
- this.onClear();
- }
- };
- f.prototype.setGraph = function(a, b) {
- this.graph != a && (b || this.clear(), !a && this.graph ? this.graph.detachCanvas(this) : (a.attachCanvas(this), this.setDirty(!0, !0)));
- };
- f.prototype.openSubgraph = function(a) {
- if (!a) {
- throw "graph cannot be null";
- }
- if (this.graph == a) {
- throw "graph cannot be the same";
- }
- this.clear();
- this.graph && (this._graph_stack || (this._graph_stack = []), this._graph_stack.push(this.graph));
- a.attachCanvas(this);
- this.setDirty(!0, !0);
- };
- f.prototype.closeSubgraph = function() {
- if (this._graph_stack && 0 != this._graph_stack.length) {
- var a = this.graph._subgraph_node, b = this._graph_stack.pop();
- this.selected_nodes = {};
- this.highlighted_links = {};
- b.attachCanvas(this);
- this.setDirty(!0, !0);
- a && (this.centerOnNode(a), this.selectNodes([a]));
- }
- };
- f.prototype.setCanvas = function(a, b) {
- if (a && a.constructor === String && (a = document.getElementById(a), !a)) {
- throw "Error creating LiteGraph canvas: Canvas not found";
- }
- if (a !== this.canvas && (!a && this.canvas && (b || this.unbindEvents()), this.canvas = a, this.ds.element = a)) {
- a.className += " lgraphcanvas";
- a.data = this;
- a.tabindex = "1";
- this.bgcanvas = null;
- this.bgcanvas || (this.bgcanvas = document.createElement("canvas"), this.bgcanvas.width = this.canvas.width, this.bgcanvas.height = this.canvas.height);
- if (null == a.getContext) {
- if ("canvas" != a.localName) {
- throw "Element supplied for LGraphCanvas must be a