Pārlūkot izejas kodu

Added const params to hxsl shader nodes, and added clamp and nearest filtering for samplers

Clement Espeute 1 gadu atpakaļ
vecāks
revīzija
18f0fb161d

+ 2 - 1
hide.hxml

@@ -11,4 +11,5 @@ common.hxml
 --macro include("hrt.prefab")
 --macro include("hrt.shgraph.nodes")
 -dce no
--debug
+-debug
+#-D shader_debug_dump

+ 24 - 1
hide/view/shadereditor/ShaderEditor.hx

@@ -765,7 +765,7 @@ class ShaderEditor extends hide.view.Graph {
 				});*/
 				typeName = "Color";
 			case TSampler2D:
-				var parentSampler = new Element('<input type="texturepath" field="sampler2d" />').appendTo(defaultValue);
+				var parentSampler = new Element('<input type="texturepath" field="sampler2d"/>').appendTo(defaultValue);
 
 				var tselect = new hide.comp.TextureChoice(null, parentSampler);
 				tselect.value = value;
@@ -778,6 +778,29 @@ class ShaderEditor extends hide.view.Graph {
 					updateParam(parameter.id);
 				}
 				typeName = "Texture";
+
+				var texWrap = new Element('<div><select name="texWrap" id="texwrap"></select><label for="texWrap">Texture Wrap</label></div>').appendTo(defaultValue).find("#texwrap");
+				for (i => wrap in ShaderGraph.wraps) {
+					texWrap.append(new Element('<option value="$i">$wrap</option>'));
+					if (shaderGraph.getParameterSetting(parameter.id, "wrap") == wrap) {
+						texWrap.val(""+wrap);
+					}
+				}
+				texWrap.on("change", (e) -> {
+					shaderGraph.setParameterSetting(parameter.id, "wrap", texWrap.val());
+				});
+
+				var texfilter = new Element('<div><select name="texfilter" id="texfilter"></select><label for="texfilter">Texture filter</label></div>').appendTo(defaultValue).find("#texfilter");
+				for (i => filter in ShaderGraph.filters) {
+					texfilter.append(new Element('<option value="$i">$filter</option>'));
+					if (shaderGraph.getParameterSetting(parameter.id, "filter") == filter) {
+						texfilter.val(""+filter);
+					}
+				}
+				texfilter.on("change", (e) -> {
+					shaderGraph.setParameterSetting(parameter.id, "filter", texfilter.val());
+				});
+
 			default:
 		}
 

+ 13 - 0
hrt/shgraph/Macros.hx

@@ -31,6 +31,7 @@ class Macros {
 
 							var inVars : Array<String> = [];
 							var outVars : Array<String> = [];
+							var constVars : Array<String> = [];
 							var defValues : Array<String> = [];
 							var dynamicValues : Array<String> = [];
 
@@ -98,6 +99,16 @@ class Macros {
 													default:
 														throw "sgoutput must be used with variables only";
 												}
+											case "sgconst":
+												switch(subexpr.expr) {
+													case EVars(vars):
+														for (v in vars) {
+															constVars.push(v.name);
+														}
+														e.expr = subexpr.expr;
+													default:
+														throw "sgconst must be used with variables only";
+												}
 											default:
 										}
 									default:
@@ -144,6 +155,8 @@ class Macros {
 							fields.push(makeField("_outVars", outVars));
 							fields.push(makeField("_defValues", defValues));
 							fields.push(makeField("_dynamicValues", dynamicValues));
+							fields.push(makeField("_constVars", constVars));
+
 
 						} catch( e : hxsl.Ast.Error ) {
 							fields.remove(f);

+ 49 - 0
hrt/shgraph/ShaderGraph.hx

@@ -58,6 +58,7 @@ typedef Parameter = {
 	?id : Int,
 	?variable : TVar,
 	?internal: Bool,
+	?settings: Dynamic,
 	index : Int
 };
 
@@ -66,6 +67,35 @@ enum Domain {
 	Fragment;
 }
 
+enum abstract TexFilter(String) from String to String {
+	var Nearest;
+	var Linear;
+}
+
+var filters = [Nearest, Linear];
+
+function TexFilterToFilter(t: TexFilter) : h3d.mat.Data.Filter {
+	return switch (t) {
+		case Nearest: Nearest;
+		case Linear: Linear;
+	}
+}
+
+enum abstract TexWrap(String) from String to String {
+	var Clamp;
+	var Repeat;
+}
+
+var wraps = [Clamp, Repeat];
+
+function TexWrapToWrap(t: TexWrap) : h3d.mat.Data.Wrap {
+	return switch (t) {
+		case Clamp: Clamp;
+		case Repeat: Repeat;
+	}
+}
+
+
 class ShaderGraph extends hrt.prefab.Prefab {
 
 	var graphs : Array<Graph>;
@@ -466,6 +496,25 @@ class ShaderGraph extends hrt.prefab.Prefab {
 		return false;
 	}
 
+	public function getParameterSetting(id : Int, name: String) : Null<Dynamic> {
+		var p = parametersAvailable.get(id);
+		if (p?.settings != null) {
+			return Reflect.getProperty(p.settings, name);
+		}
+		return null;
+	}
+
+	public function setParameterSetting(id : Int, name: String, value:Dynamic) {
+		var p = parametersAvailable.get(id);
+		if (p == null)
+			throw "invalid parameter";
+
+		if (p?.settings == null) {
+			p.settings = {};
+		}
+		Reflect.setField(p.settings, name, value);
+	}
+
 	public function removeParameter(id : Int) {
 		parametersAvailable.remove(id);
 		parametersKeys.remove(id);

+ 26 - 0
hrt/shgraph/ShaderNodeHxsl.hx

@@ -102,10 +102,36 @@ class ShaderNodeHxsl extends ShaderNode {
 				}
 			}
 
+			var classConstVars : Array<String> = cast (cl:Dynamic)._constVars;
+
+			// Const replacement
+			for (const in classConstVars) {
+				var value = getConstValue(const);
+				if (value == null)
+					throw "unhandled const value " + const;
+
+				function patchExprConst(expr : TExpr) {
+					switch (expr.e) {
+						case TVar(v):
+							if (v.name == const) {
+								expr.e = TConst(CInt(value));
+							}
+						default:
+							expr.map(patchExprConst);
+					}
+					return expr;
+				}
+				expr.map(patchExprConst);
+			}
+
 			def = {expr: expr, inVars: inVars, outVars: outVars, externVars: externVars, inits: [], functions: funs};
 			nodeCache.set(className, def);
 		}
 
 		return def;
 	}
+
+	function getConstValue(name: String) : Null<Int> {
+		return null;
+	}
 }

+ 109 - 1
hrt/shgraph/nodes/Sampler.hx

@@ -2,11 +2,30 @@ package hrt.shgraph.nodes;
 
 using hxsl.Ast;
 
+
+enum abstract TexFilter(String) from String to String {
+	var Nearest;
+	var Linear;
+}
+
+var filters = [Nearest, Linear];
+
+enum abstract TexWrap(String) from String to String {
+	var Clamp;
+	var Repeat;
+}
+
+var wraps = [Clamp, Repeat];
+
 @name("Sample Texture 2D")
 @description("Get color from texture and UV")
 @group("Property")
 class Sampler extends ShaderNodeHxsl {
 
+	@prop() var filter : TexFilter = Linear;
+	@prop() var wrap : TexWrap = Repeat;
+
+
 	static var SRC = {
 		@sginput var texture : Sampler2D;
 		@sginput(calculatedUV) var uv : Vec2;
@@ -16,9 +35,24 @@ class Sampler extends ShaderNodeHxsl {
 		@sgoutput var B : Float;
 		@sgoutput var A : Float;
 
+		@sgconst var wrap : Int;
+		@sgconst var filter : Int;
+
+
 
 		function fragment() {
-			RGBA = texture.get(uv);
+			var uv2 = uv;
+			if (wrap == 0) {
+				var size = texture.size();
+				uv2 = saturate(uv2);
+				uv2 = clamp(uv2, 0.5 / size, (size - vec2(0.5)) / size);
+			}
+
+			if (filter == 0) {
+				var size = texture.size();
+				uv2 = (floor( size * uv2 ) + 0.5) / size ;
+			}
+			RGBA = texture.get(uv2);
 			R = RGBA.r;
 			G = RGBA.g;
 			B = RGBA.b;
@@ -26,6 +60,80 @@ class Sampler extends ShaderNodeHxsl {
 		}
 	}
 
+	override function getConstValue(name: String) : Null<Int> {
+		switch (name) {
+			case "wrap":
+				return wrap == Clamp ? 0 : 1;
+			case "filter":
+				return filter == Nearest ? 0 : 1;
+			default:
+				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: ${width * 0.8}px; height: 40px"></div>');
+			element.append('<span>Wrap</span>');
+			element.append(new hide.Element('<select id="wrap"></select>'));
+
+			if (this.wrap == null) {
+				this.wrap = wraps[1];
+			}
+			var input = element.children("#wrap");
+			var indexOption = 0;
+			for (i => currentWrap in wraps) {
+				input.append(new hide.Element('<option value="${i}">${currentWrap}</option>'));
+				if (this.wrap == currentWrap) {
+					input.val(i);
+				}
+				indexOption++;
+			}
+
+			input.on("change", function(e) {
+				var value = input.val();
+				this.wrap = wraps[value];
+			});
+
+			elements.push(element);
+		}
+
+		{
+			var element = new hide.Element('<div style="width: ${width * 0.8}px; height: 40px"></div>');
+			element.append('<span>Filter</span>');
+			element.append(new hide.Element('<select id="filter"></select>'));
+
+			if (this.filter == null) {
+				this.filter = filters[1];
+			}
+			var input = element.children("#filter");
+			var indexOption = 0;
+			for (i => currentfilter in filters) {
+				input.append(new hide.Element('<option value="${i}">${currentfilter}</option>'));
+				if (this.filter == currentfilter) {
+					input.val(i);
+				}
+				indexOption++;
+			}
+
+			input.on("change", function(e) {
+				var value = input.val();
+				this.filter = filters[value];
+			});
+
+			elements.push(element);
+		}
+
+
+		return elements;
+	}
+	#end
+
 	// @input("Texture") var texture = SType.Sampler;
 	// @input("UV") var uv = SType.Vec2;