Преглед изворни кода

ShaderGraph: subgraph node properties + some fix

Tom SPIRA пре 6 година
родитељ
комит
e05b776747

+ 4 - 0
bin/style.css

@@ -1362,6 +1362,10 @@ input[type=checkbox]:checked:after {
   height: 100px;
   width: 100px;
 }
+.graph-view .heaps-scene svg .properties-group .propertySubShader span {
+  float: left;
+  margin-right: 10px;
+}
 .graph-view .heaps-scene svg .edge {
   stroke-width: 2;
   stroke: #c8c8c8;

+ 7 - 0
bin/style.less

@@ -1537,6 +1537,13 @@ input[type=checkbox] {
 					height: 100px;
 					width: 100px;
 				}
+
+				.propertySubShader {
+					span {
+						float: left;
+						margin-right: 10px;
+					}
+				}
 			}
 
 			.edge {

+ 5 - 0
hide/view/shadereditor/Box.hx

@@ -181,6 +181,11 @@ class Box {
 			element.addClass("not-selected");
 		}
 	}
+	public function setTitle(str : String) {
+		if (hasHeader) {
+			element.find(".title-box").html(str);
+		}
+	}
 	public function getId() {
 		return this.nodeInstance.id;
 	}

+ 14 - 5
hide/view/shadereditor/ShaderEditor.hx

@@ -1,5 +1,6 @@
 package hide.view.shadereditor;
 
+import hrt.shgraph.nodes.SubGraph;
 import hxsl.DynamicShader;
 import h3d.Vector;
 import hrt.shgraph.ShaderParam;
@@ -49,7 +50,7 @@ class ShaderEditor extends hide.view.Graph {
 	override function onDisplay() {
 		super.onDisplay();
 		saveDisplayKey = "ShaderGraph:" + getPath().split("\\").join("/").substr(0,-1);
-		shaderGraph = new ShaderGraph(getPath());
+		shaderGraph = new ShaderGraph(state.path);
 		addMenu = null;
 
 		element.find("#rightPanel").html('
@@ -232,6 +233,9 @@ class ShaderEditor extends hide.view.Graph {
 					if (b.getId() == idBox) {
 						var subGraph = Std.instance(b.getInstance(), hrt.shgraph.nodes.SubGraph);
 						if (subGraph != null) {
+							if (ev.currentTarget.getAttribute('field') != "filesubgraph") {
+								break;
+							}
 							var length = listOfEdges.length;
 							for (i in 0...length) {
 								var edge = listOfEdges[length-i-1];
@@ -466,7 +470,7 @@ class ShaderEditor extends hide.view.Graph {
 		var typeName = "";
 		switch(type) {
 			case TFloat:
-				var parentRange = new Element('<input type="range" type="range" min="-1" max="1" />').appendTo(defaultValue);
+				var parentRange = new Element('<input type="range" min="-1" max="1" />').appendTo(defaultValue);
 				var range = new hide.comp.Range(null, parentRange);
 				var rangeInput = @:privateAccess range.f;
 				rangeInput.on("mousedown", function(e) {
@@ -728,7 +732,6 @@ class ShaderEditor extends hide.view.Graph {
 							m.mainPass.addShader(currentShader);
 						}
 					}
-					throw e;
 					return;
 				}
 			} else if (Std.is(e, ShaderException)) {
@@ -744,7 +747,6 @@ class ShaderEditor extends hide.view.Graph {
 					m.mainPass.addShader(currentShader);
 				}
 			}
-			throw e;
 		}
 	}
 
@@ -1134,6 +1136,12 @@ class ShaderEditor extends hide.view.Graph {
 					parametersList.scrollTop(parametersList.scrollTop() + offsetScroll);
 				}
 			});
+		} else if (nodeClass == SubGraph) {
+			var subGraphNode = Std.instance(node, SubGraph);
+			if (subGraphNode.pathShaderGraph != null) {
+				var filename = subGraphNode.pathShaderGraph.split("/").pop();
+				box.setTitle("SubGraph: " + filename.split(".")[0]);
+			}
 		}
 
 		return box;
@@ -1141,13 +1149,14 @@ class ShaderEditor extends hide.view.Graph {
 
 	override function removeBox(box : Box) {
 		beforeChange();
+		var isSubShader = Std.is(box.getInstance(), SubGraph);
 		var length = listOfEdges.length;
 		for (i in 0...length) {
 			var edge = listOfEdges[length-i-1];
 			if (edge.from == box || edge.to == box) {
 				super.removeEdge(edge);
 				removeShaderGraphEdge(edge);
-				removeEdgeSubGraphUpdate(edge);
+				if (!isSubShader) removeEdgeSubGraphUpdate(edge);
 			}
 		}
 		shaderGraph.removeNode(box.getId());

+ 13 - 14
hrt/prefab/ShaderGraph.hx

@@ -7,22 +7,8 @@ class ShaderGraph extends Shader {
 		type = "shadergraph";
 	}
 
-	override function fixSourcePath() {
-		#if editor
-		var ide = hide.Ide.inst;
-		var shadersPath = ide.projectDir + "/res";
-
-		var path = source.split("\\").join("/");
-		if( StringTools.startsWith(path.toLowerCase(), shadersPath.toLowerCase()+"/") ) {
-			path = path.substr(shadersPath.length + 1);
-		}
-		source = shadersPath + "/" + path;
-		#end
-	}
-
 	override public function loadShaderDef(ctx: Context) {
 		if(shaderDef == null) {
-			fixSourcePath();
 			var shaderGraph = new hrt.shgraph.ShaderGraph(source);
 			shaderDef = shaderGraph.compile();
 		}
@@ -42,6 +28,19 @@ class ShaderGraph extends Shader {
 	override function getHideProps() : HideProps {
 		return { icon : "cog", name : "Shader Graph", fileSource : ["hlshader"], allowParent : function(p) return p.to(Object3D) != null };
 	}
+
+	override function edit( ctx : EditContext ) {
+		super.edit(ctx);
+
+		var btn = new hide.Element("<input type='submit' style='width: 100%; margin-top: 10px;' value='Open Shader Graph' />");
+		btn.on("click", function() {
+ 			ctx.ide.openFile(source);
+		});
+
+		ctx.properties.add(btn,this.props, function(pname) {
+			ctx.onChange(this, pname);
+		});
+	}
 	#end
 
 	static var _ = Library.register("hlshader", ShaderGraph);

+ 22 - 1
hrt/shgraph/ShaderConst.hx

@@ -4,7 +4,7 @@ using hxsl.Ast;
 
 class ShaderConst extends ShaderNode {
 
-	var const : TExpr;
+	@prop() public var name : String = "";
 
 	override public function getOutputType(key : String) : Type {
 		return getOutputTExpr(key).t;
@@ -13,4 +13,25 @@ class ShaderConst extends ShaderNode {
 	override public function build(key : String) : TExpr {
 		return null;
 	}
+
+	#if editor
+	override public function getPropertiesHTML(width : Float) : Array<hide.Element> {
+		var elements = super.getPropertiesHTML(width);
+
+		var element = new hide.Element('<div style="width: 75px; height: 20px"></div>');
+		element.append(new hide.Element('<input type="text" id="value" style="width: ${width*0.75}px" placeholder="Name" value="${this.name}" />'));
+
+		var input = element.children("input");
+		input.on("keydown", function(e) {
+			e.stopPropagation();
+		});
+		input.on("change", function(e) {
+			this.name = input.val();
+		});
+
+		elements.push(element);
+
+		return elements;
+	}
+	#end
 }

+ 12 - 7
hrt/shgraph/ShaderGraph.hx

@@ -6,7 +6,6 @@ using hxsl.Ast;
 typedef Node = {
 	x : Float,
 	y : Float,
-	comment : String,
 	id : Int,
 	type : String,
 	?properties : Dynamic,
@@ -48,9 +47,9 @@ class ShaderGraph {
 		if (filepath == null) return;
 		this.filepath = filepath;
 
-		var json;
+		var json : Dynamic;
 		try {
-			var content = sys.io.File.getContent(this.filepath);
+			var content = hxd.Res.load(this.filepath).toText();
 			if (content.length == 0) return;
 			json = haxe.Json.parse(content);
 		} catch( e : Dynamic ) {
@@ -61,7 +60,7 @@ class ShaderGraph {
 
 	}
 
-	public function load(json : haxe.Json) {
+	public function load(json : Dynamic) {
 		nodes = [];
 		parametersAvailable = [];
 		generate(Reflect.getProperty(json, "nodes"), Reflect.getProperty(json, "edges"), Reflect.getProperty(json, "parameters"));
@@ -159,6 +158,10 @@ class ShaderGraph {
 		return this.nodes;
 	}
 
+	public function getNode(id : Int) {
+		return this.nodes.get(id);
+	}
+
 	function generateParameter(name : String, type : Type) : TVar {
 		return {
 				parent: null,
@@ -275,7 +278,9 @@ class ShaderGraph {
 			}
 			if (!variableNamesAlreadyUpdated && subShaderId != null && !Std.is(n.instance, ShaderInput)) {
 				for (outputKey in n.instance.getOutputInfoKeys()) {
-					n.instance.getOutput(outputKey).name = "sub_" + subShaderId + "_" + n.instance.getOutput(outputKey).name;
+					var output = n.instance.getOutput(outputKey);
+					if (output != null)
+						output.name = "sub_" + subShaderId + "_" + output.name;
 				}
 			}
 			n.instance.outputCompiled = [];
@@ -389,7 +394,7 @@ class ShaderGraph {
 
 	#if editor
 	public function addNode(x : Float, y : Float, nameClass : Class<ShaderNode>) {
-		var node : Node = { x : x, y : y, comment: "", id : current_node_id, type: std.Type.getClassName(nameClass) };
+		var node : Node = { x : x, y : y, id : current_node_id, type: std.Type.getClassName(nameClass) };
 
 		node.instance = std.Type.createInstance(nameClass, []);
 		node.instance.setId(current_node_id);
@@ -486,7 +491,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, properties : n.instance.savePropertiesNode() }
+				for (n in nodes) { x : Std.int(n.x), y : Std.int(n.y), id: n.id, type: n.type, properties : n.instance.savePropertiesNode() }
 			],
 			edges: edgesJson,
 			parameters: [

+ 2 - 1
hrt/shgraph/nodes/BoolConst.hx

@@ -5,7 +5,8 @@ using hxsl.Ast;
 @name("Bool")
 @description("Boolean input, it's static")
 @group("Input")
-@width(75)
+@width(100)
+@noheader()
 class BoolConst extends ShaderConst {
 
 	@output() var fakeOutput = SType.Bool;

+ 2 - 1
hrt/shgraph/nodes/Color.hx

@@ -6,7 +6,8 @@ using hxsl.Ast;
 @description("Color input, it's static")
 @group("Input")
 @width(100)
-class Color extends ShaderNode {
+@noheader()
+class Color extends ShaderConst {
 
 	@output() var output = SType.Vec4;
 

+ 1 - 0
hrt/shgraph/nodes/FloatConst.hx

@@ -6,6 +6,7 @@ using hxsl.Ast;
 @description("Number input, it's static")
 @group("Input")
 @width(100)
+@noheader()
 class FloatConst extends ShaderConst {
 
 	@output() var output = SType.Float;

+ 89 - 11
hrt/shgraph/nodes/SubGraph.hx

@@ -9,7 +9,7 @@ using hxsl.Ast;
 @alwaysshowinputs()
 class SubGraph extends ShaderNode {
 
-	@prop() var pathShaderGraph : String;
+	@prop() public var pathShaderGraph : String;
 
 	var inputsInfo : Map<String, ShaderNode.InputInfo>;
 	var inputInfoKeys : Array<String> = [];
@@ -25,7 +25,7 @@ class SubGraph extends ShaderNode {
 	public function loadGraphShader() {
 		if (this.pathShaderGraph != null) {
 			try {
-				subShaderGraph = new ShaderGraph("E:/Projects/arena/trunk/res/" + pathShaderGraph);
+				subShaderGraph = new ShaderGraph(pathShaderGraph);
 			} catch (e : Dynamic) {
 				trace("The shader doesn't not exist.");
 				return;
@@ -62,11 +62,11 @@ class SubGraph extends ShaderNode {
 						var shaderConst = Std.instance(node.instance, ShaderConst);
 						if (shaderConst != null) { // input static become properties
 							if (Std.is(shaderConst, BoolConst)) {
-								parameters.push({ name : "Bool", type : TBool, defaultValue : null, id : shaderConst.id });
+								parameters.push({ name : shaderConst.name, type : TBool, defaultValue : null, id : shaderConst.id });
 							} else if (Std.is(shaderConst, FloatConst)) {
-								parameters.push({ name : "Number", type : TFloat, defaultValue : null, id : shaderConst.id });
+								parameters.push({ name : shaderConst.name, type : TFloat, defaultValue : null, id : shaderConst.id });
 							} else if (Std.is(shaderConst, Color)) {
-								parameters.push({ name : "Color", type : TVec(4, VFloat), defaultValue : null, id : shaderConst.id });
+								parameters.push({ name : shaderConst.name, type : TVec(4, VFloat), defaultValue : null, id : shaderConst.id });
 							}
 						}
 				}
@@ -96,10 +96,33 @@ class SubGraph extends ShaderNode {
 			}
 		}
 
+		for (p in parameters) {
+			if (p.defaultValue != null) {
+				var node = subShaderGraph.getNode(p.id);
+				switch (p.type) {
+					case TBool:
+						var boolConst = Std.instance(node.instance, BoolConst);
+						@:privateAccess boolConst.value = p.defaultValue;
+					case TVec(4, VFloat):
+						var colorConst = Std.instance(node.instance, Color);
+						@:privateAccess {
+							colorConst.r = p.defaultValue.x;
+							colorConst.g = p.defaultValue.y;
+							colorConst.b = p.defaultValue.z;
+							colorConst.a = p.defaultValue.w;
+						}
+					case TFloat:
+						var floatConst = Std.instance(node.instance, FloatConst);
+						@:privateAccess floatConst.value = p.defaultValue;
+					default:
+				}
+			}
+		}
+
 		var shaderDef;
 		try {
 			shaderDef = subShaderGraph.generateShader(null, id);
-		} catch (e : Dynamic) {
+		} catch (e : ShaderException) {
 			throw ShaderException.t(e.msg, id);
 		}
 		if (shaderDef.funs.length > 1) {
@@ -156,11 +179,32 @@ class SubGraph extends ShaderNode {
 	override public function loadProperties(props : Dynamic) {
 		this.pathShaderGraph = Reflect.field(props, "pathShaderGraph");
 		loadGraphShader();
+
+		var parametersValues : Array<hrt.shgraph.ShaderGraph.Parameter> = Reflect.field(props, "parametersValues");
+		if (parametersValues == null) return;
+		var index = 0;
+		for (p in this.parameters) {
+			if (parametersValues.length <= index) break;
+			if (p.id != parametersValues[index].id) {
+				continue;
+			}
+			p.defaultValue = parametersValues[index].defaultValue;
+			index++;
+		}
 	}
 
 	override public function saveProperties() : Dynamic {
+
+		var parametersValues = [];
+		for (p in this.parameters) {
+			if (p.defaultValue != null) {
+				parametersValues.push({id: p.id, defaultValue : p.defaultValue});
+			}
+		}
+
 		var properties = {
-			pathShaderGraph: this.pathShaderGraph
+			pathShaderGraph: this.pathShaderGraph,
+			parametersValues : parametersValues
 		};
 
 		return properties;
@@ -187,17 +231,51 @@ class SubGraph extends ShaderNode {
 		elements.push(new hide.Element('<div style="background: #202020; height: 1px; margin-bottom: 5px;"></div>'));
 
 		for (p in parameters) {
-			var element = new hide.Element('<div style="width: 100px; height: 25px"></div>');
+			var element = new hide.Element('<div class="propertySubShader" style="width: 200px;"></div>');
 			element.on("mousedown", function(e) {
 				e.stopPropagation();
 			});
 			switch (p.type) {
 				case TBool:
-					element.append(new hide.Element('<input type="checkbox" id="value" />'));
+					new hide.Element('<span>${p.name}</span>').appendTo(element);
+					var inputBool = new hide.Element('<input type="checkbox" id="value" />').appendTo(element);
+					inputBool.on("change", function(e) {
+						p.defaultValue = (inputBool.is(":checked")) ? true : false;
+					});
+					if (p.defaultValue) {
+						inputBool.prop("checked", true);
+					}
+					element.css("height", 20);
 				case TFloat:
-					element.append(new hide.Element('<input type="text" id="value" style="width: ${width*0.65}px" value="" />'));
+					new hide.Element('<span>${p.name}</span>').appendTo(element);
+					var parentRange = new hide.Element('<input type="range" min="-1" max="1" value="" />').appendTo(element);
+					var range = new hide.comp.Range(null, parentRange);
+					var rangeInput = @:privateAccess range.f;
+					rangeInput.on("mousedown", function(e) {
+						e.stopPropagation();
+					});
+					rangeInput.on("mouseup", function(e) {
+						e.stopPropagation();
+					});
+					parentRange.parent().css("width", 50);
+					range.onChange = function(moving) {
+						p.defaultValue = range.value;
+					};
+					element.css("height", 40);
 				case TVec(4, VFloat):
-					new hide.comp.ColorPicker(true, element);
+					new hide.Element('<span>${p.name}</span>').appendTo(element);
+					var inputColor = new hide.comp.ColorPicker(true, element);
+
+					if (p.defaultValue != null) {
+						var start = h3d.Vector.fromArray([p.defaultValue.x, p.defaultValue.y, p.defaultValue.z, p.defaultValue.w]);
+						inputColor.value = start.toColor();
+					}
+
+					inputColor.onChange = function(move) {
+						var vec = h3d.Vector.fromColor(inputColor.value);
+						p.defaultValue = vec;
+					};
+					element.css("height", 25);
 				default:
 
 			}