Browse Source

Add property when input is empty + some fix

Tom SPIRA 6 years ago
parent
commit
41c7512255

+ 6 - 3
bin/style.css

@@ -1122,7 +1122,7 @@ input[type=checkbox]:checked:after {
   fill: none;
 }
 .shader-view .heaps-scene svg .head-box {
-  fill: #424242;
+  fill: #3e3e3e;
 }
 .shader-view .heaps-scene svg .title-box {
   fill: #ffffff;
@@ -1134,13 +1134,16 @@ input[type=checkbox]:checked:after {
 }
 .shader-view .heaps-scene svg .nodes,
 .shader-view .heaps-scene svg .properties {
-  fill: #5c5c5c;
+  fill: #737373;
   opacity: 0.75;
 }
+.shader-view .heaps-scene svg .hasLink .input-field {
+  display: none;
+}
 .shader-view .heaps-scene svg .input-node,
 .shader-view .heaps-scene svg .output-node {
   fill: #c8c8c8;
-  stroke-width: 15px;
+  stroke-width: 13px;
   stroke-opacity: 0;
 }
 .shader-view .heaps-scene svg .input-node.nodeMatch,

+ 9 - 3
bin/style.less

@@ -1261,7 +1261,7 @@ input[type=checkbox] {
 			}
 
 			.head-box {
-				fill: #424242;
+				fill: #3e3e3e;
 			}
 
 			.title-box {
@@ -1274,13 +1274,19 @@ input[type=checkbox] {
 			}
 
 			.nodes, .properties {
-				fill: #5c5c5c;
+				fill: #737373;
 				opacity: 0.75;
 			}
 
+			.hasLink {
+				.input-field {
+					display: none;
+				}
+			}
+
 			.input-node, .output-node {
 				fill: rgb(200, 200, 200);
-				stroke-width: 15px;
+				stroke-width: 13px;
 				stroke-opacity: 0;
 
 				&.nodeMatch {

+ 56 - 18
hide/view/ShaderEditor.hx

@@ -1,5 +1,7 @@
 package hide.view;
 
+import h3d.shader.LineShader;
+import h3d.shader.ColorAdd;
 using hxsl.Ast.Type;
 
 import haxe.rtti.Rtti;
@@ -29,7 +31,7 @@ class ShaderEditor extends FileView {
 	var editorMatrix : JQuery;
 
 
-	var listOfClasses = new Map<String, Array<NodeInfo>>();
+	var listOfClasses : Map<String, Array<NodeInfo>>;
 	var addMenu : JQuery;
 	var selectedNode : JQuery;
 
@@ -168,7 +170,8 @@ class ShaderEditor extends FileView {
 			}
 			// Edit rectangle selection
 			if (startRecSelection != null) {
-				var endRecSelection = new h2d.col.IPoint(e.offsetX, e.offsetY);
+				var screenOffset = editor.element.offset();
+				var endRecSelection = new h2d.col.IPoint(Std.int(e.clientX - screenOffset.left), Std.int(e.clientY - screenOffset.top));
 				var xMin = startRecSelection.x;
 				var xMax = endRecSelection.x;
 				var yMin = startRecSelection.y;
@@ -288,6 +291,8 @@ class ShaderEditor extends FileView {
 					clearSelectionBoxes();
 				}
 			} else if (e.keyCode == 32) {
+				var test = new LineShader();
+				trace(test);
 				var s = new SharedShader("");
 				s.data = shaderGraph.buildFragment();
 				s.initialize();
@@ -302,9 +307,13 @@ class ShaderEditor extends FileView {
 				}
 			} else if (e.keyCode == 83 && e.ctrlKey) { // CTRL+S : save
 				shaderGraph.save();
+			} else if (e.keyCode == 74 && e.ctrlKey) { // CTRL+S : save
+				trace(shaderGraph.hasCycle());
 			}
 		});
 
+		addMenu = null;
+		listOfClasses = new Map<String, Array<NodeInfo>>();
 		var mapOfNodes = ShaderNode.registeredNodes;
 		for (key in mapOfNodes.keys()) {
 			var metas = haxe.rtti.Meta.getType(mapOfNodes[key]);
@@ -330,29 +339,34 @@ class ShaderEditor extends FileView {
 		listOfBoxes = [];
 		listOfEdges = [];
 
-		new Element("svg").ready(function(e) {
+		updateMatrix();
+
+		new Element("body").ready(function(e) {
 
 			for (node in shaderGraph.getNodes()) {
 				addBox(new Point(node.x, node.y), std.Type.getClass(node.instance), node.instance);
 			}
 
-			for (box in listOfBoxes) {
-				for (key in box.getShaderNode().getInputsKey()) {
-					var input = box.getShaderNode().getInput(key);
-					if (input != null) {
-						var fromBox : Box = null;
-						for (boxFrom in listOfBoxes) {
-							if (boxFrom.getId() == input.node.id) {
-								fromBox = boxFrom;
-								break;
+			new Element(".nodes").ready(function(e) {
+
+				for (box in listOfBoxes) {
+					for (key in box.getShaderNode().getInputsKey()) {
+						var input = box.getShaderNode().getInput(key);
+						if (input != null) {
+							var fromBox : Box = null;
+							for (boxFrom in listOfBoxes) {
+								if (boxFrom.getId() == input.node.id) {
+									fromBox = boxFrom;
+									break;
+								}
 							}
+							var nodeFrom = fromBox.getElement().find('[field=${input.getKey()}]');
+							var nodeTo = box.getElement().find('[field=${key}]');
+							createEdgeInEditorGraph({from: fromBox, nodeFrom: nodeFrom, to : box, nodeTo: nodeTo, elt : createCurve(nodeFrom, nodeTo) });
 						}
-						var nodeFrom = fromBox.getElement().find('[field=${input.getKey()}]');
-						var nodeTo = box.getElement().find('[field=${key}]');
-						createEdgeInEditorGraph({from: fromBox, nodeFrom: nodeFrom, to : box, nodeTo: nodeTo, elt : createCurve(nodeFrom, nodeTo) });
 					}
 				}
-			}
+			});
 		});
 
 	}
@@ -431,8 +445,30 @@ class ShaderEditor extends FileView {
 				if (m == null) continue;
 			}
 			if (Reflect.hasField(m, "input")) {
-				var name : String = (m.input != null && m.input.length > 0) ? Reflect.field(m, "input")[0] : "input";
-				var grNode = box.addInput(editor, name);
+				var inputMeta : Array<Dynamic> = Reflect.field(m, "input");
+				var name : String = (m.input != null && m.input.length > 0) ? inputMeta[0] : "input";
+
+				var defaultValue = null;
+				if (m.input.length >= 2 && inputMeta[1]) {
+					defaultValue = Reflect.field(box.getShaderNode(), 'prop_${f}');
+					if (defaultValue == null) {
+						defaultValue = "0";
+					}
+				}
+				var grNode = box.addInput(editor, name, defaultValue);
+				if (defaultValue != null) {
+					var fieldEditInput = grNode.find("input");
+					fieldEditInput.on("change", function(ev) {
+						var tmpValue = Std.parseFloat(fieldEditInput.val());
+						if (Math.isNaN(tmpValue) ) {
+							fieldEditInput.addClass("error");
+						} else {
+							Reflect.setField(box.getShaderNode(), 'prop_${f}', tmpValue);
+							fieldEditInput.val(tmpValue);
+							fieldEditInput.removeClass("error");
+						}
+					});
+				}
 				grNode.find(".node").attr("field", f);
 				grNode.on("mousedown", function(e : js.jquery.Event) {
 					e.stopPropagation();
@@ -487,6 +523,7 @@ class ShaderEditor extends FileView {
 	function removeEdge(edge : Edge) {
 		edge.elt.remove();
 		edge.nodeTo.removeAttr("hasLink");
+		edge.nodeTo.parent().removeClass("hasLink");
 		shaderGraph.removeEdge(edge.to.getId(), edge.nodeTo.attr("field"));
 		listOfEdges.remove(edge);
 	}
@@ -561,6 +598,7 @@ class ShaderEditor extends FileView {
 	function createEdgeInEditorGraph(edge) {
 		listOfEdges.push(edge);
 		edge.nodeTo.attr("hasLink", "true");
+		edge.nodeTo.parent().addClass("hasLink");
 
 		edge.elt.on("mousedown", function(e) {
 			e.stopPropagation();

+ 12 - 7
hide/view/shadereditor/Box.hx

@@ -16,7 +16,7 @@ class Box {
 	var propsHeight : Int = 0;
 
 	var HEADER_HEIGHT = 27;
-	@const var NODE_MARGIN = 20;
+	@const var NODE_MARGIN = 17;
 	public static var NODE_RADIUS = 5;
 	@const var NODE_TITLE_PADDING = 10;
 	public var selected : Bool = false;
@@ -58,13 +58,18 @@ class Box {
 		editor.line(element, width/2, HEADER_HEIGHT, width/2, 0, {display: "none"}).addClass("nodes-separator");
 	}
 
-	public function addInput(editor : SVG, name : String) {
+	public function addInput(editor : SVG, name : String, valueDefault : String = null) {
 		var node = editor.group(element).addClass("input-node-group");
-		var nodeHeight = HEADER_HEIGHT + (NODE_MARGIN + NODE_RADIUS) * (inputs.length+1);
+		var nodeHeight = HEADER_HEIGHT + NODE_MARGIN * (inputs.length+1) + NODE_RADIUS * inputs.length;
 		var nodeCircle = editor.circle(node, 0, nodeHeight, NODE_RADIUS).addClass("node input-node");
 
 		if (name.length > 0)
 			editor.text(node, NODE_TITLE_PADDING, nodeHeight + 4, name).addClass("title-node");
+		if (valueDefault != null) {
+			var widthInput = width / 2 * 0.7;
+			var fObject = editor.foreignObject(node, NODE_TITLE_PADDING, nodeHeight - 9, widthInput, 20).addClass("input-field");
+			new Element('<input type="text" style="width: ${widthInput - 7}px" value="${valueDefault}" />').appendTo(fObject);
+		}
 
 		inputs.push(nodeCircle);
 		refreshHeight();
@@ -74,7 +79,7 @@ class Box {
 
 	public function addOutput(editor : SVG, name : String) {
 		var node = editor.group(element).addClass("output-node-group");
-		var nodeHeight = HEADER_HEIGHT + (NODE_MARGIN + NODE_RADIUS) * (outputs.length+1);
+		var nodeHeight = HEADER_HEIGHT + NODE_MARGIN * (outputs.length+1) + NODE_RADIUS * outputs.length;
 		var nodeCircle = editor.circle(node, width, nodeHeight, NODE_RADIUS).addClass("node output-node");
 
 		if (name.length > 0)
@@ -99,7 +104,7 @@ class Box {
 
 			// create properties box
 		editor.rect(propertiesGroup, 0, 0, this.width, 0).addClass("properties");
-		propsHeight = 10;
+		propsHeight = 5;
 
 		for (p in props) {
 			var prop = editor.group(propertiesGroup).addClass("prop-group");
@@ -108,7 +113,7 @@ class Box {
 			var propWidth = (p.width() > 0 ? p.width() : this.width);
 			var fObject = editor.foreignObject(prop, (this.width - propWidth) / 2, 5, propWidth, p.height());
 			p.appendTo(fObject);
-			propsHeight += Std.int(p.height()) + 10;
+			propsHeight += Std.int(p.height()) + 5;
 		}
 
 		refreshHeight();
@@ -170,7 +175,7 @@ class Box {
 		if (maxNb == 1 && propsHeight > 0) {
 			return 0;
 		}
-		return (NODE_MARGIN + NODE_RADIUS) * (maxNb+1);
+		return NODE_MARGIN * (maxNb+1) + NODE_RADIUS * maxNb;
 	}
 	public function getHeight() {
 		return HEADER_HEIGHT + getNodesHeight() + propsHeight;

+ 67 - 0
hrt/shgraph/NodeVar.hx

@@ -31,6 +31,73 @@ class NodeVar {
 		}
 
 		switch(currentType) {
+			case TBool:
+				var tExprBool = node.getOutputTExpr(keyOutput);
+				switch(type) {
+					case TVec(size, VBool):
+						if (size == 2) {
+							return {
+								e: TCall({
+									e: TGlobal(Vec2),
+									p: null,
+									t: TFun([
+										{
+											ret: type,
+											args: [
+											{ name: "u", type : TBool },
+											{ name: "v", type : TBool }]
+										}
+									])
+								}, [tExprBool,
+									tExprBool]),
+								p: null,
+								t: type
+							};
+						} else if (size == 3) {
+							return {
+								e: TCall({
+									e: TGlobal(Vec3),
+									p: null,
+									t: TFun([
+										{
+											ret: type,
+											args: [
+											{ name: "x", type : TBool },
+											{ name: "y", type : TBool },
+											{ name: "z", type : TBool }]
+										}
+									])
+								}, [tExprBool,
+									tExprBool,
+									tExprBool]),
+								p: null,
+								t: type
+							};
+						} else {
+							return {
+								e: TCall({
+									e: TGlobal(Vec4),
+									p: null,
+									t: TFun([
+										{
+											ret: type,
+											args: [
+											{ name: "r", type : TBool },
+											{ name: "g", type : TBool },
+											{ name: "b", type : TBool },
+											{ name: "a", type : TBool }]
+										}
+									])
+								}, [tExprBool,
+									tExprBool,
+									tExprBool,
+									tExprBool]),
+								p: null,
+								t: type
+							};
+						}
+					default:
+				};
 			case TFloat:
 				var tExprFloat = node.getOutputTExpr(keyOutput);
 				switch(type) {

+ 2 - 2
hrt/shgraph/Operation.hx

@@ -6,8 +6,8 @@ using hxsl.Ast;
 
 class Operation extends ShaderNode {
 
-	@input("A") var a = SType.Number;
-	@input("B") var b = SType.Number;
+	@input("A", true) var a = SType.Number;
+	@input("B", true) var b = SType.Number;
 
 	@output() var output = SType.Number;
 

+ 38 - 5
hrt/shgraph/ParseFieldsMacro.hx

@@ -29,17 +29,50 @@ class ParseFieldsMacro {
 							hasInputs = true;
 							var sel = f.name;
 							var get_sel = "get_" + sel;
-							var sfields = macro class {
-								inline function $get_sel() : NodeVar return getInput($v{sel});
-							};
-							for( field in sfields.fields )
-								fields.push(field);
+							var propSel = "prop_" + sel;
+							var hasProperty = false;
+							if (m.params.length >= 2) {
+								switch(m.params[1].expr) {
+									case EConst(CIdent(b)):
+										if (b == "true") {
+											hasProperty = true;
+											fields.push({
+												name: propSel,
+												access: [Access.APrivate],
+												kind: FieldType.FVar(macro:Float),
+												pos: Context.currentPos(),
+												meta: [{name: "prop", params: [{expr: EConst(CString("macro")), pos: Context.currentPos() }], pos: Context.currentPos()}]
+											});
+										}
+									default:
+								}
+							}
+							if (hasProperty) {
+								var sfields = macro class {
+									inline function $get_sel() : NodeVar {
+										var input = getInput($v{sel});
+										if (input == null)
+											return new NodeVar(new hrt.shgraph.nodes.FloatConst($i{propSel}), "output");
+										else
+											return getInput($v{sel});
+									}
+								};
+								for( field in sfields.fields )
+									fields.push(field);
+							} else {
+								var sfields = macro class {
+									inline function $get_sel() : NodeVar return getInput($v{sel});
+								};
+								for( field in sfields.fields )
+									fields.push(field);
+							}
 							if (e == null)
 								Context.error('Input ${sel} has not affectation', f.pos);
 							var enumValue = ["ShaderType", "SType", e.toString().split(".").pop()];
 							mapInputs.push(macro $v{sel} => ${enumValue.toFieldExpr()});
 							f.kind = FProp("get", "null", TPath({ pack: ["hrt", "shgraph"], name: "NodeVar" }));
 							f.meta = saveMeta;
+
 							break;
 						}
 						if (m.name == "output") {

+ 53 - 5
hrt/shgraph/ShaderGraph.hx

@@ -9,7 +9,9 @@ private typedef Node = {
 	id : Int,
 	type : String,
 	?parameters : Dynamic,
-	?instance : ShaderNode
+	?instance : ShaderNode,
+	?outputs: Array<Node>,
+	?indegree : Int
 };
 
 private typedef Edge = {
@@ -44,6 +46,7 @@ class ShaderGraph {
 	public function generate(nodes : Array<Node>, edges : Array<Edge>) {
 
 		for (n in nodes) {
+			n.outputs = [];
 			n.instance = std.Type.createInstance(std.Type.resolveClass(n.type), []);
 			n.instance.loadProperties(n.parameters);
 			n.instance.setId(n.id);
@@ -63,6 +66,7 @@ class ShaderGraph {
 
 		node.instance = std.Type.createInstance(nameClass, []);
 		node.instance.createOutputs();
+		node.outputs = [];
 
 		this.nodes.set(node.id, node);
 
@@ -74,12 +78,25 @@ class ShaderGraph {
 	}
 
 	public function addEdge(edge : Edge) {
-		this.nodes.get(edge.idInput).instance.setInput(edge.nameInput, new NodeVar(this.nodes.get(edge.idOutput).instance, edge.nameOutput));
-		this.nodes.get(edge.idInput).instance.createOutputs();
+		var node = this.nodes.get(edge.idInput);
+		var output = this.nodes.get(edge.idOutput);
+		node.instance.setInput(edge.nameInput, new NodeVar(output.instance, edge.nameOutput));
+		output.outputs.push(node);
+		updateOutputs(output);
+	}
+
+	function updateOutputs(node : Node) {
+		node.instance.createOutputs();
+		for (o in node.outputs) {
+			updateOutputs(o);
+		}
 	}
 
 	public function removeEdge(idNode, nameInput) {
-		this.nodes.get(idNode).instance.setInput(nameInput, null);
+		var node = this.nodes.get(idNode);
+		this.nodes.get(node.instance.getInput(nameInput).node.id).outputs.remove(node);
+		node.instance.setInput(nameInput, null);
+		updateOutputs(node);
 	}
 
 	public function setPosition(idNode : Int, x : Float, y : Float) {
@@ -92,6 +109,37 @@ class ShaderGraph {
 		return this.nodes;
 	}
 
+	public function hasCycle() : Bool {
+		var queue : Array<Node> = [];
+
+		var counter = 0;
+		var nbInDegree = 0;
+		for (n in nodes) {
+			n.indegree = n.outputs.length;
+			if (n.indegree == 0) {
+				queue.push(n);
+			}
+			nbInDegree += n.indegree;
+		}
+
+		var currentIndex = 0;
+		while (currentIndex < queue.length) {
+			var node = queue[currentIndex];
+			currentIndex++;
+
+			for (input in node.instance.getInputs()) {
+				var nodeInput = nodes.get(input.node.id);
+				nodeInput.indegree -= 1;
+				if (nodeInput.indegree == 0) {
+					queue.push(nodeInput);
+				}
+			}
+			counter++;
+		}
+		trace(counter, nbInDegree);
+		return counter != nbInDegree;
+	}
+
 	function buildNodeVar(nodeVar : NodeVar) : Array<TExpr>{
 		var node = nodeVar.node;
 		if (node == null)
@@ -173,7 +221,7 @@ class ShaderGraph {
 
 		var json = haxe.Json.stringify({
 			nodes: [
-				for (n in nodes) { x : n.x, y : n.y, comment: n.comment, id: n.id, type: n.type, parameters : n.instance.saveProperties() }
+				for (n in nodes) { x : n.x, y : n.y, comment: n.comment, id: n.id, type: n.type, parameters : n.instance.savePropertiesNode() }
 			],
 			edges: edgesJson
 		});

+ 1 - 1
hrt/shgraph/ShaderInput.hx

@@ -34,7 +34,7 @@ class ShaderInput extends ShaderNode {
 						parent: null,
 						id: 0,
 						kind: Input,
-						name: "input.uv",
+						name: "uv",
 						type: TVec(2, VFloat)
 					}];
 

+ 39 - 8
hrt/shgraph/ShaderNode.hx

@@ -7,9 +7,7 @@ using hxsl.Ast;
 @:keepSub
 class ShaderNode {
 
-	static public var current_id : Int = 0; // TODO : check concurrency
-
-	public var id : Int = current_id++;
+	public var id : Int;
 
 	static var availableVariables = [{
 						parent: null,
@@ -25,7 +23,6 @@ class ShaderNode {
 
 	public function setId(id : Int) {
 		this.id = id;
-		ShaderNode.current_id = id+1;
 	}
 
 	public function setInput(key : String, s : NodeVar) {
@@ -117,19 +114,53 @@ class ShaderNode {
 		}
 	}
 
+	public function savePropertiesNode() : Dynamic {
+		var parameters = saveProperties();
+
+		var thisClass = std.Type.getClass(this);
+		var fields = std.Type.getInstanceFields(thisClass);
+		var metas = haxe.rtti.Meta.getFields(thisClass);
+		var metaSuperClass = haxe.rtti.Meta.getFields(std.Type.getSuperClass(thisClass));
+
+		for (f in fields) {
+			var m = Reflect.field(metas, f);
+			if (m == null) {
+				m = Reflect.field(metaSuperClass, f);
+				if (m == null)
+					continue;
+			}
+
+			if (Reflect.hasField(m, "prop")) {
+				var metaData : Array<String> = Reflect.field(m, "prop");
+				if (metaData != null && metaData.length >= 1 && metaData[0] == "macro") {
+					Reflect.setField(parameters, f, Reflect.getProperty(this, f));
+				}
+			}
+		}
+
+		return parameters;
+	}
+
 	public function saveProperties() : Dynamic {
 		var parameters = {};
 
-		var fields = std.Type.getInstanceFields(std.Type.getClass(this));
-		var metas = haxe.rtti.Meta.getFields(std.Type.getClass(this));
+		var thisClass = std.Type.getClass(this);
+		var fields = std.Type.getInstanceFields(thisClass);
+		var metas = haxe.rtti.Meta.getFields(thisClass);
+		var metaSuperClass = haxe.rtti.Meta.getFields(std.Type.getSuperClass(thisClass));
 
 		for (f in fields) {
 			var m = Reflect.field(metas, f);
 			if (m == null) {
-				continue;
+				m = Reflect.field(metaSuperClass, f);
+				if (m == null)
+					continue;
 			}
 			if (Reflect.hasField(m, "prop")) {
-				Reflect.setField(parameters, f, Reflect.getProperty(this, f));
+				var metaData : Array<String> = Reflect.field(m, "prop");
+				if (metaData == null || metaData.length == 0 || metaData[0] != "macro") {
+					Reflect.setField(parameters, f, Reflect.getProperty(this, f));
+				}
 			}
 		}
 		return parameters;

+ 18 - 0
hrt/shgraph/ShaderType.hx

@@ -5,6 +5,12 @@ import hxsl.Ast.Type;
 enum SType {
 	/** Bool **/
 	Bool;
+	/** Vector of bools of size 2 **/
+	VecBool2;
+	/** Vector of bools of size 3 **/
+	VecBool3;
+	/** Vector of bools of size 4 **/
+	VecBool4;
 	/** Float **/
 	Float;
 	/** Vector of size 2 **/
@@ -31,6 +37,12 @@ class ShaderType {
 				return Vec3;
 			case TVec(4, VFloat):
 				return Vec4;
+			case TVec(2, VBool):
+				return VecBool2;
+			case TVec(3, VBool):
+				return VecBool3;
+			case TVec(4, VBool):
+				return VecBool4;
 			case TBool:
 				return Bool;
 			case TFloat:
@@ -56,6 +68,12 @@ class ShaderType {
 				return (from == Float || from == Vec2 || from == Vec3 || from == Vec4);
 			case Bool:
 				return (from == Bool);
+			case VecBool2:
+				return (from == Bool || from == VecBool2);
+			case VecBool3:
+				return (from == Bool || from == VecBool3);
+			case VecBool4:
+				return (from == Bool || from == VecBool4);
 			case Float:
 				return (from == Float);
 			case Number:

+ 16 - 5
hrt/shgraph/nodes/Cond.hx

@@ -8,8 +8,8 @@ using hxsl.Ast;
 @group("Condition")
 class Cond extends ShaderNode {
 
-	@input("left") var leftVar = SType.Variant;
-	@input("right") var rightVar = SType.Variant;
+	@input("left") var leftVar = SType.Number;
+	@input("right") var rightVar = SType.Number;
 
 	@output("boolean") var output = SType.Bool;
 
@@ -27,7 +27,18 @@ class Cond extends ShaderNode {
 	}
 
 	override public function createOutputs() {
-		addOutput("output", TBool);
+		if (leftVar != null && leftVar.getType() != null && rightVar != null && rightVar.getType() != null) {
+			var type = leftVar.getVar(rightVar.getType()).t;
+			switch(type) {
+				case TVec(s, t):
+					throw "Vector of bools not supported";//addOutput("output", TVec(s, VBool));
+				case TFloat:
+					addOutput("output", TBool);
+				default:
+					removeOutput("output");
+			}
+		} else
+			removeOutput("output");
 	}
 
 	override public function build(key : String) : TExpr {
@@ -40,8 +51,8 @@ class Cond extends ShaderNode {
 						p: null,
 						t: output.type
 					}, {e: TBinop(this.condition,
-							leftVar.getVar(),
-							rightVar.getVar()),
+							leftVar.getVar(rightVar.getType()),
+							rightVar.getVar(leftVar.getType())),
 						p: null, t: output.type })
 			};
 	}

+ 8 - 3
hrt/shgraph/nodes/FloatConst.hx

@@ -3,15 +3,20 @@ package hrt.shgraph.nodes;
 import hide.Element;
 using hxsl.Ast;
 
-@name("Float")
-@description("Float input, it's static")
+@name("Number")
+@description("Number input, it's static")
 @group("Input")
 @width(100)
 class FloatConst extends ShaderConst {
 
 	@output() var output = SType.Float;
 
-	@prop() var value : Float = 0.5;
+	@prop() var value : Float = 0.;
+
+	public function new(?value : Float) {
+		if (value != null)
+			this.value = value;
+	}
 
 	override public function getOutputTExpr(key : String) : TExpr {
 		return {

+ 6 - 13
hrt/shgraph/nodes/Sampler.hx

@@ -4,27 +4,20 @@ import hxsl.*;
 
 using hxsl.Ast;
 
-/*
 @name("Sampler")
 @description("Get color from texture and UV")
 @group("AAAAA")
-*/
-class Sampler extends ShaderNode {
+class Sampler extends ShaderFunction {
 
-	@input("u") var u = SType.Float;
-	@input("v") var v = SType.Float;
+	@input("texture") var texture = SType.Sampler;
+	@input("uv") var uv = SType.Vec2;
 
-	@output("rgba") var rgba = SType.Vec4;
-
-	var components = [X, Y, Z, W];
-	var componentsString = ["r", "g", "b", "a"];
+	public function new() {
+		super(Texture);
+	}
 
 	override public function createOutputs() {
 		addOutput("rgba", TVec(4, VFloat));
 	}
 
-	override public function build(key : String) : TExpr {
-		return null;
-	}
-
 }

+ 24 - 0
hrt/shgraph/nodes/Texture.hx

@@ -0,0 +1,24 @@
+package hrt.shgraph.nodes;
+
+import hxsl.*;
+
+using hxsl.Ast;
+
+@name("Texture")
+@description("Create a texture from a file")
+@group("AAAA")
+class Texture extends ShaderNode {
+
+	@output("texture") var texture = SType.Sampler;
+
+	@prop() var fileTexture : String;
+
+	override public function createOutputs() {
+		addOutput("rgba", TSampler2D);
+	}
+
+	override public function build(key : String) : TExpr {
+		return null;
+	}
+
+}