Browse Source

Add custom outputs to shadergraphs

Leonardo Jeanteur 4 years ago
parent
commit
1458a8801b
5 changed files with 146 additions and 6 deletions
  1. 11 0
      bin/style.css
  2. 11 0
      bin/style.less
  3. 74 0
      hrt/shgraph/CustomVarChooser.hx
  4. 48 5
      hrt/shgraph/ShaderOutput.hx
  5. 2 1
      hrt/shgraph/nodes/SubGraph.hx

+ 11 - 0
bin/style.css

@@ -1640,6 +1640,17 @@ input[type=checkbox]:checked:after {
   float: left;
   margin-right: 10px;
 }
+.graph-view .heaps-scene svg .properties-group .custom-var {
+  display: table;
+  width: 100%;
+}
+.graph-view .heaps-scene svg .properties-group .custom-var div.custom-var-row {
+  display: table-row;
+}
+.graph-view .heaps-scene svg .properties-group .custom-var div.custom-var-row label,
+.graph-view .heaps-scene svg .properties-group .custom-var div.custom-var-row span {
+  display: table-cell;
+}
 .graph-view .heaps-scene svg .edge {
   stroke-width: 2;
   stroke: #c8c8c8;

+ 11 - 0
bin/style.less

@@ -1874,6 +1874,17 @@ input[type=checkbox] {
 						margin-right: 10px;
 					}
 				}
+
+				.custom-var {
+					display: table;
+					width: 100%;
+					div.custom-var-row {
+						display: table-row;
+						label, span {
+							display: table-cell;
+						}
+					}
+				}
 			}
 
 			.edge {

+ 74 - 0
hrt/shgraph/CustomVarChooser.hx

@@ -0,0 +1,74 @@
+package hrt.shgraph;
+
+using hxsl.Ast;
+
+#if editor
+// TODO block or raise an error on illegal names
+class CustomVarChooser extends hide.comp.Component {
+	public var variable : TVar = null;
+
+	public function new(?parent : hide.Element, ?initialName : String, ?initialType : Type, onChange : (TVar) -> Void) {
+		var el = new hide.Element('<div class="custom-var">
+			<div class="custom-var-row">
+				<label for="customName">Name</label><span><input type="text" id="customName"/></span>
+			</div>
+			<div class="custom-var-row">
+				<label for="customType">Type</label><span><select id="customType"></select></span>
+			</div>
+		</div>');
+		super(parent, el);
+
+		var textInput = element.find("#customName");
+		var select = element.find("#customType");
+		var availableTypes = [
+			"Color" => TVec( 4, VFloat ),
+			"Int" => TInt,
+			"Bool" => TBool,
+			"Float" => TFloat,
+			"String" => TString,
+			"Vec2" => TVec( 2, VFloat ),
+			"Vec3" => TVec( 3, VFloat ),
+		];
+		for( key => value in availableTypes ) {
+			select.append(new hide.Element('<option value="${key}">${key}</option>'));
+			if( value == initialType )
+				select.val(key);
+		}
+		if( initialName != null ) {
+			textInput.val(initialName);
+		}
+		if( initialName != null && initialName != "" && initialType != null ) {
+			variable = {
+				parent: null,
+				id: 0,
+				kind: Local,
+				name: initialName,
+				type: availableTypes[select.val()],
+			};
+		}
+		function changedFun(_) {
+			var name = textInput.val();
+			if( name == "" )
+				return;
+			variable = {
+				parent: null,
+				id: 0,
+				kind: Local,
+				name: name,
+				type: availableTypes[select.val()],
+			};
+			onChange(variable);
+		}
+		select.on("change", changedFun);
+		textInput.on("change", changedFun);
+	}
+
+	public function show() {
+		element.show();
+	}
+
+	public function hide() {
+		element.hide();
+	}
+}
+#end

+ 48 - 5
hrt/shgraph/ShaderOutput.hx

@@ -19,7 +19,6 @@ class ShaderOutput extends ShaderNode {
 	}
 
 	override public function build(key : String) : TExpr {
-
 		return {
 				p : null,
 				t : TVoid,
@@ -71,7 +70,9 @@ class ShaderOutput extends ShaderNode {
 	];
 
 	override public function loadProperties(props : Dynamic) {
-		var paramVariable : Array<String> = Reflect.field(props, "variable");
+		var paramVariable : Array<Dynamic> = Reflect.field(props, "variable");
+		if( paramVariable[0] == null)
+			return;
 
 		for (c in ShaderNode.availableVariables) {
 			if (c.name == paramVariable[0]) {
@@ -85,11 +86,23 @@ class ShaderOutput extends ShaderNode {
 				return;
 			}
 		}
+		this.variable = {
+			parent: null,
+			id: 0,
+			kind: Local,
+			name: paramVariable[0],
+			type: haxe.EnumTools.createByName(Type, paramVariable[1], paramVariable[2]),
+		};
 	}
 
 	override public function saveProperties() : Dynamic {
+		var content : Array<Dynamic> = (variable == null) ? [null] : [
+			variable.name,
+			variable.type.getName(),
+			variable.type.getParameters()
+		];
 		var parameters = {
-			variable: (variable == null) ? [null] : [variable.name, variable.type.getName()]
+			variable: content,
 		};
 
 		return parameters;
@@ -99,7 +112,7 @@ class ShaderOutput extends ShaderNode {
 	#if editor
 	override public function getPropertiesHTML(width : Float) : Array<hide.Element> {
 		var elements = super.getPropertiesHTML(width);
-		var element = new hide.Element('<div style="width: 110px; height: 30px"></div>');
+		var element = new hide.Element('<div style="width: 110px; height: 70px"></div>');
 		element.append(new hide.Element('<select id="variable"></select>'));
 
 		if (this.variable == null) {
@@ -107,10 +120,12 @@ class ShaderOutput extends ShaderNode {
 		}
 		var input = element.children("select");
 		var indexOption = 0;
+		var selectingDefault = false;
 		for (c in ShaderNode.availableVariables) {
 			input.append(new hide.Element('<option value="${indexOption}">${c.name}</option>'));
 			if (this.variable.name == c.name) {
 				input.val(indexOption);
+				selectingDefault = true;
 			}
 			indexOption++;
 		}
@@ -118,16 +133,44 @@ class ShaderOutput extends ShaderNode {
 			input.append(new hide.Element('<option value="${indexOption}">${c.name}</option>'));
 			if (this.variable.name == c.name) {
 				input.val(indexOption);
+				selectingDefault = true;
 			}
 			indexOption++;
 		}
+		var maxIndex = indexOption;
+		input.append(new hide.Element('<option value="${maxIndex}">Other...</option>'));
+		var initialName : String = null;
+		var initialType : Type = null;
+		if( !selectingDefault ) {
+			input.val(maxIndex);
+			initialName = this.variable.name;
+			initialType = this.variable.type;
+		}
+
+		var customVarChooser = new CustomVarChooser(element, initialName, initialType, function(val) {
+			this.variable = val;
+		});
+
+		if( !selectingDefault )
+			customVarChooser.show();
+		else
+			customVarChooser.hide();
+
 		input.on("change", function(e) {
 			var value = input.val();
 			if (value < ShaderNode.availableVariables.length) {
 				this.variable = ShaderNode.availableVariables[value];
-			} else {
+			} else if (value < maxIndex) {
 				this.variable = ShaderOutput.availableOutputs[value-ShaderNode.availableVariables.length];
 			}
+			if (value == maxIndex) {
+				customVarChooser.show();
+				if (customVarChooser.variable != null) {
+					this.variable = customVarChooser.variable;
+				}
+			} else {
+				customVarChooser.hide();
+			}
 		});
 
 		elements.push(element);

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

@@ -65,8 +65,9 @@ class SubGraph extends ShaderNode {
 						inputInfoKeys.push(prefixSubGraph+node.id);
 					case "ShaderOutput":
 						var shaderOutput = Std.downcast(node.instance, ShaderOutput);
+						var prefix = shaderOutput.variable.kind == Local ? "" : "*";
 
-						outputsInfo.set(prefixSubGraph+node.id, { name : shaderOutput.variable.name , type: ShaderType.getSType(shaderOutput.variable.type), id : node.id });
+						outputsInfo.set(prefixSubGraph+node.id, { name : prefix + shaderOutput.variable.name , type: ShaderType.getSType(shaderOutput.variable.type), id : node.id });
 						outputInfoKeys.push(prefixSubGraph+node.id);
 
 						addOutput(prefixSubGraph+node.id, shaderOutput.variable.type);