Forráskód Böngészése

prefabs: settings shader params, added blur, fixes

ncannasse 7 éve
szülő
commit
820f938b63

+ 4 - 1
hide/comp/PropsEditor.hx

@@ -4,6 +4,7 @@ enum PropType {
 	PInt( ?min : Int, ?max : Int );
 	PInt( ?min : Int, ?max : Int );
 	PFloat( ?min : Float, ?max : Float );
 	PFloat( ?min : Float, ?max : Float );
 	PBool;
 	PBool;
+	PTexture;
 	PUnsupported( debug : String );
 	PUnsupported( debug : String );
 }
 }
 
 
@@ -48,13 +49,15 @@ class PropsEditor extends Component {
 			case PInt(min, max):
 			case PInt(min, max):
 				var e = new Element('<input type="range" field="${p.name}" step="1">').appendTo(def);
 				var e = new Element('<input type="range" field="${p.name}" step="1">').appendTo(def);
 				if( min != null ) e.attr("min", "" + min);
 				if( min != null ) e.attr("min", "" + min);
-				if( max != null ) e.attr("max", "" + max);
+				e.attr("max", "" + (max == null ? 100 : max));
 			case PFloat(min, max):
 			case PFloat(min, max):
 				var e = new Element('<input type="range" field="${p.name}">').appendTo(def);
 				var e = new Element('<input type="range" field="${p.name}">').appendTo(def);
 				if( min != null ) e.attr("min", "" + min);
 				if( min != null ) e.attr("min", "" + min);
 				if( max != null ) e.attr("max", "" + max);
 				if( max != null ) e.attr("max", "" + max);
 			case PBool:
 			case PBool:
 				new Element('<input type="checkbox" field="${p.name}">').appendTo(def);
 				new Element('<input type="checkbox" field="${p.name}">').appendTo(def);
+			case PTexture:
+				new Element('<input type="texturepath" field="${p.name}">').appendTo(def);
 			case PUnsupported(text):
 			case PUnsupported(text):
 				new Element('<font color="red">'+StringTools.htmlEscape(text)+'</font>').appendTo(def);
 				new Element('<font color="red">'+StringTools.htmlEscape(text)+'</font>').appendTo(def);
 			}
 			}

+ 110 - 0
hide/prefab/Blur.hx

@@ -0,0 +1,110 @@
+package hide.prefab;
+
+class Blur extends Prefab {
+
+	public var size : Int = 0;
+	public var quality : Int = 1;
+	public var passes : Int = 1;
+	public var sigma : Float = 1.;
+	public var gain : Float = 1.;
+
+	// mostly testing
+	public var image : String;
+	public var zoom : Int = 1;
+
+	override function load(o:Dynamic) {
+		size = o.size;
+		quality = o.quality;
+		passes = o.passes;
+		sigma = o.sigma;
+		gain = o.gain;
+		image = o.image;
+		zoom = o.zoom;
+	}
+
+	override function save() {
+		return {
+			size:size,
+			quality:quality,
+			passes:passes,
+			sigma:sigma,
+			gain:gain,
+			image : image,
+			zoom : zoom,
+		};
+	}
+
+	override function getHideProps() : HideProps {
+		return { name : "Blur", icon : "bullseye" };
+	}
+
+	public function makeFilter() {
+		var f = new h2d.filter.Blur(quality, passes, sigma);
+		f.gain = gain;
+		f.reduceSize = size;
+		return f;
+	}
+
+	override function makeInstance( ctx : Context ) {
+		ctx = ctx.clone(this);
+		var bmp = new h2d.Bitmap(null, ctx.local2d);
+		syncBitmap(bmp, ctx);
+		bmp.visible = false;
+		ctx.local2d = bmp;
+		return ctx;
+	}
+
+	function syncBitmap( bmp : h2d.Bitmap, ctx : Context ) {
+		var t;
+		if( image != null )
+			t = h2d.Tile.fromTexture(ctx.loadTexture(image));
+		else {
+			t = h2d.Tile.fromTexture(h3d.mat.Texture.genChecker(16));
+			t.setSize(256, 256);
+		}
+		bmp.tile = t;
+		bmp.filter = makeFilter();
+		bmp.smooth = true;
+		bmp.tileWrap = image == null;
+		bmp.setScale(zoom);
+		bmp.x = -(t.width * zoom) >> 1;
+		bmp.y = -(t.height * zoom) >> 1;
+	}
+
+	override function edit( ctx : EditContext ) {
+		#if editor
+		var e : hide.Element;
+		function sync() {
+			e.find("[name=fetches]").text( "" + hxd.Math.fmt(quality * (passes * 2 + 1) * 2 * passes / Math.pow(2, size)) );
+		}
+		e = ctx.properties.add(new hide.Element('
+			<dl>
+				<dt>Reduce Size</dt><dd><input type="range" min="0" max="8" step="1" field="size"/></dd>
+				<dt>Quality</dt><dd><input type="range" min="1" max="4" step="1" field="quality"/></dd>
+				<dt>Passes</dt><dd><input type="range" min="0" max="10" step="1" field="passes"/></dd>
+				<dt>Sigma</dt><dd><input type="range" min="0" max="5" field="sigma"/></dd>
+				<dt>Gain</dt><dd><input type="range" min="0.5" max="1.5" field="gain"/></dd>
+			</dl>
+			<br/>
+			<dl>
+				<dt>Fetches</dt><dd name="fetches"></dd>
+				<dt>Test Texture</dt><dd><input type="texturepath" field="image"/></dd>
+				<dt>Display zoom</dt><dd><input type="range" min="1" max="8" step="1" field="zoom"/></dd>
+			</dl>
+		'),this,function(f) {
+			var ctx = ctx.getContext(this);
+			var bmp = cast(ctx.local2d, h2d.Bitmap);
+			syncBitmap(bmp, ctx);
+			sync();
+		});
+		var bmp = cast(ctx.getContext(this).local2d, h2d.Bitmap);
+		bmp.visible = true;
+		ctx.cleanups.push(function() bmp.visible = false);
+		sync();
+		#end
+	}
+
+
+	static var _ = Library.register("blur", Blur);
+
+}

+ 8 - 0
hide/prefab/Context.hx

@@ -62,6 +62,14 @@ class Context {
 		#end
 		#end
 	}
 	}
 
 
+	public function loadTexture( path : String ) {
+		#if editor
+		return hide.comp.Scene.getCurrent().loadTexture("",path);
+		#else
+		return @:privateAccess shared.cache.loadTexture("", path);
+		#end
+	}
+
 	public function locateObject( path : String ) {
 	public function locateObject( path : String ) {
 		if( path == null )
 		if( path == null )
 			return null;
 			return null;

+ 1 - 1
hide/prefab/Noise.hx

@@ -141,7 +141,7 @@ class Noise extends Prefab {
 	}
 	}
 
 
 	override function getHideProps() : HideProps {
 	override function getHideProps() : HideProps {
-		return { icon : "chess-board", name : "Noise Generator" };
+		return { icon : "cloud", name : "Noise Generator" };
 	}
 	}
 
 
 	override function edit( ctx : EditContext ) {
 	override function edit( ctx : EditContext ) {

+ 33 - 14
hide/tools/ShaderLoader.hx

@@ -1,10 +1,18 @@
 package hide.tools;
 package hide.tools;
 
 
+typedef CachedShader = {
+	var file : String;
+	var name : String;
+	var shader : hxsl.SharedShader;
+	var inits : Array<{ v : hxsl.Ast.TVar, e : hxsl.Ast.TExpr }>;
+	var watch : Void -> Void;
+}
+
 class ShaderLoader {
 class ShaderLoader {
 
 
 	var ide : hide.ui.Ide;
 	var ide : hide.ui.Ide;
 	var shaderPath : Array<String>;
 	var shaderPath : Array<String>;
-	var shaderCache = new Map<String, hxsl.SharedShader>();
+	var shaderCache = new Map<String, CachedShader>();
 
 
 	public function new() {
 	public function new() {
 		ide = hide.ui.Ide.inst;
 		ide = hide.ui.Ide.inst;
@@ -15,51 +23,64 @@ class ShaderLoader {
 		var s = loadSharedShader(name);
 		var s = loadSharedShader(name);
 		if( s == null )
 		if( s == null )
 			return null;
 			return null;
-		return new hxsl.DynamicShader(s);
+		var d = new hxsl.DynamicShader(s.shader);
+		for( v in s.inits )
+			d.hscriptSet(v.v.name, hxsl.Ast.Tools.evalConst(v.e));
+		return d;
 	}
 	}
 
 
-	function loadSharedShader( name : String ) {
+	public function loadSharedShader( name : String, ?file : String ) {
 		var s = shaderCache.get(name);
 		var s = shaderCache.get(name);
 		if( s != null )
 		if( s != null )
 			return s;
 			return s;
-		var e = loadShaderExpr(name);
+		var e = loadShaderExpr(name, file);
 		if( e == null )
 		if( e == null )
 			return null;
 			return null;
 		var chk = new hxsl.Checker();
 		var chk = new hxsl.Checker();
 		chk.loadShader = function(iname) {
 		chk.loadShader = function(iname) {
-			var e = loadShaderExpr(iname);
+			var e = loadShaderExpr(iname, null);
 			if( e == null )
 			if( e == null )
 				throw "Could not @:import " + iname + " (referenced from " + name+")";
 				throw "Could not @:import " + iname + " (referenced from " + name+")";
-			return e;
+			return e.expr;
 		};
 		};
 		var s = new hxsl.SharedShader("");
 		var s = new hxsl.SharedShader("");
-		s.data = chk.check(name, e);
+		s.data = chk.check(name, e.expr);
 		@:privateAccess s.initialize();
 		@:privateAccess s.initialize();
+		var s : CachedShader = { file : e.file, name : name, shader : s, inits : chk.inits, watch : null };
+		s.watch = onShaderChanged.bind(s);
+		ide.fileWatcher.register(s.file, s.watch);
 		shaderCache.set(name, s);
 		shaderCache.set(name, s);
 		return s;
 		return s;
 	}
 	}
 
 
-	function loadShaderExpr( name : String ) : hxsl.Ast.Expr {
+	function onShaderChanged( s : CachedShader ) {
+		shaderCache.remove(s.name);
+		ide.fileWatcher.unregister(s.file, s.watch);
+	}
+
+	function loadShaderExpr( name : String, file : String ) : { file : String, expr : hxsl.Ast.Expr } {
+		if( file != null && sys.FileSystem.exists(file) )
+			return { file : file, expr : loadShaderString(file,sys.io.File.getContent(file), name) };
 		var path = name.split(".").join("/")+".hx";
 		var path = name.split(".").join("/")+".hx";
 		for( s in shaderPath ) {
 		for( s in shaderPath ) {
 			var file = ide.projectDir + "/" + s + "/" + path;
 			var file = ide.projectDir + "/" + s + "/" + path;
 			if( sys.FileSystem.exists(file) )
 			if( sys.FileSystem.exists(file) )
-				return loadShaderString(file,sys.io.File.getContent(file));
+				return { file : file, expr : loadShaderString(file, sys.io.File.getContent(file), null) };
 		}
 		}
 		if( StringTools.startsWith(name,"h3d.shader.") ) {
 		if( StringTools.startsWith(name,"h3d.shader.") ) {
 			var r = haxe.Resource.getString("shader/" + name.substr(11));
 			var r = haxe.Resource.getString("shader/" + name.substr(11));
-			if( r != null ) return loadShaderString(path, r);
+			if( r != null ) return { file : null, expr : loadShaderString(path, r, null) };
 		}
 		}
 		return null;
 		return null;
 	}
 	}
 
 
-	function loadShaderString( file : String, content : String ) {
+	function loadShaderString( file : String, content : String, name : String ) {
 		var parser = new hscript.Parser();
 		var parser = new hscript.Parser();
 		var decls = parser.parseModule(content, file);
 		var decls = parser.parseModule(content, file);
 		var cl = null, cf = null;
 		var cl = null, cf = null;
 		for( d in decls ) {
 		for( d in decls ) {
 			switch( d ) {
 			switch( d ) {
-			case DClass(c):
+			case DClass(c) if( name == null || c.name == name.split(".").pop() ):
 				for( f in c.fields )
 				for( f in c.fields )
 					if( f.name == "SRC" ) {
 					if( f.name == "SRC" ) {
 						cl = c;
 						cl = c;
@@ -81,7 +102,6 @@ class ShaderLoader {
 
 
 		var e = new hscript.Macro({ min : 0, max : 0, file : file }).convert(expr);
 		var e = new hscript.Macro({ min : 0, max : 0, file : file }).convert(expr);
 		var e = new hxsl.MacroParser().parseExpr(e);
 		var e = new hxsl.MacroParser().parseExpr(e);
-
 		switch( cl.extend ) {
 		switch( cl.extend ) {
 		case CTPath(p,_):
 		case CTPath(p,_):
 			var path = p.join(".");
 			var path = p.join(".");
@@ -91,7 +111,6 @@ class ShaderLoader {
 			}
 			}
 		default:
 		default:
 		}
 		}
-
 		return e;
 		return e;
 	}
 	}
 
 

+ 61 - 4
hide/tools/TypesCache.hx

@@ -1,4 +1,5 @@
 package hide.tools;
 package hide.tools;
+import hide.comp.PropsEditor.PropType;
 
 
 enum ModelKind {
 enum ModelKind {
 	PrefabDef;
 	PrefabDef;
@@ -17,6 +18,7 @@ typedef TypeFile = {
 	var watch : Void -> Void;
 	var watch : Void -> Void;
 	var models : Array<TypeModel>;
 	var models : Array<TypeModel>;
 	var files : Array<TypeFile>;
 	var files : Array<TypeFile>;
+	var error : String;
 }
 }
 
 
 class TypesCache {
 class TypesCache {
@@ -60,8 +62,17 @@ class TypesCache {
 				continue;
 				continue;
 			browseRec(path,old);
 			browseRec(path,old);
 		}
 		}
-		for( f in old )
+		for( f in old ) {
+			var fnew = hfiles.get(f.path);
+			if( fnew != null && fnew.error != null ) {
+				fnew.models = [for( m in f.models ) { id : m.id, kind : m.kind, fields : [{ t : PUnsupported(fnew.error), name : "", def : null }], file : fnew }];
+				for( m in fnew.models ) {
+					types.push(m);
+					htype.set(m.id, m);
+				}
+			}
 			ide.fileWatcher.unregister(f.path, f.watch);
 			ide.fileWatcher.unregister(f.path, f.watch);
+		}
 	}
 	}
 
 
 	function browseRec( path : String, old : Map<String,TypeFile> ) {
 	function browseRec( path : String, old : Map<String,TypeFile> ) {
@@ -70,6 +81,7 @@ class TypesCache {
 			watch : null,
 			watch : null,
 			files : [],
 			files : [],
 			models : [],
 			models : [],
+			error : null,
 		};
 		};
 		addFile(dir);
 		addFile(dir);
 
 
@@ -101,6 +113,7 @@ class TypesCache {
 			watch : null,
 			watch : null,
 			files : [],
 			files : [],
 			models : [],
 			models : [],
+			error : null,
 		};
 		};
 		var content = sys.io.File.getContent(path);
 		var content = sys.io.File.getContent(path);
 		var scan = content.indexOf("hxsl.Shader") >= 0 || content.indexOf("h3d.shader.ScreenShader") >= 0 || content.indexOf("@:prefab") >= 0;
 		var scan = content.indexOf("hxsl.Shader") >= 0 || content.indexOf("h3d.shader.ScreenShader") >= 0 || content.indexOf("@:prefab") >= 0;
@@ -114,8 +127,27 @@ class TypesCache {
 				switch( d ) {
 				switch( d ) {
 				case DPackage(p):
 				case DPackage(p):
 					pack = p.length == 0 ? "" : p.join(".") + ".";
 					pack = p.length == 0 ? "" : p.join(".") + ".";
-				case DClass(c) if( c.extend != null && (c.extend.match(CTPath(["hxsl","Shader"])) || c.extend.match(CTPath(["h3d","shader","ScreenShader"]))) ):
-					file.models.push({ id : pack + c.name, kind : Shader, file : file, fields : [] });
+				case DClass(c) if( c.extend != null && (c.extend.match(CTPath(["hxsl", "Shader"])) || c.extend.match(CTPath(["h3d", "shader", "ScreenShader"]))) ):
+					var shader = try ide.shaderLoader.loadSharedShader(pack + c.name) catch( e : hxsl.Ast.Error ) null;
+					var fields = [];
+					var fmap = new Map();
+					if( shader == null )
+						fields.push({ name : "", t : PUnsupported("Failed to load this shader"), def : null });
+					else {
+						for( v in shader.shader.data.vars ) {
+							if( v.kind != Param ) continue;
+							if( v.qualifiers != null && v.qualifiers.indexOf(Ignore) >= 0 ) continue;
+							var t = makeShaderType(v);
+							var fl = { name : v.name, t : t, def : defType(t) };
+							fields.push(fl);
+							fmap.set(v.name, fl);
+						}
+						for( i in shader.inits ) {
+							var fl = fmap.get(i.v.name);
+							fl.def = hxsl.Ast.Tools.evalConst(i.e);
+						}
+					}
+					file.models.push({ id : pack + c.name, kind : Shader, file : file, fields : fields });
 				case DTypedef(t) if( Lambda.exists(t.meta, function(m) return m.name == ":prefab") ):
 				case DTypedef(t) if( Lambda.exists(t.meta, function(m) return m.name == ":prefab") ):
 					var fields = [];
 					var fields = [];
 					switch( t.t ) {
 					switch( t.t ) {
@@ -130,7 +162,7 @@ class TypesCache {
 				default:
 				default:
 				}
 				}
 		} catch( e : hscript.Expr.Error ) {
 		} catch( e : hscript.Expr.Error ) {
-			ide.error(e.toString());
+			file.error = e.toString();
 		}
 		}
 		return file;
 		return file;
 	}
 	}
@@ -191,10 +223,13 @@ class TypesCache {
 			return min == null ? 0 : min;
 			return min == null ? 0 : min;
 		case PBool:
 		case PBool:
 			return false;
 			return false;
+		case PTexture:
+			return null;
 		case PUnsupported(_):
 		case PUnsupported(_):
 			return null;
 			return null;
 		}
 		}
 	}
 	}
+
 	function makeType( t : hscript.Expr.CType ) : hide.comp.PropsEditor.PropType {
 	function makeType( t : hscript.Expr.CType ) : hide.comp.PropsEditor.PropType {
 		return switch( t ) {
 		return switch( t ) {
 		case CTPath(["Int"]):
 		case CTPath(["Int"]):
@@ -208,4 +243,26 @@ class TypesCache {
 		}
 		}
 	}
 	}
 
 
+	function makeShaderType( v : hxsl.Ast.TVar ) : hide.comp.PropsEditor.PropType {
+		var min : Null<Float> = null, max : Null<Float> = null;
+		if( v.qualifiers != null )
+			for( q in v.qualifiers )
+				switch( q ) {
+				case Range(rmin, rmax): min = rmin; max = rmax;
+				default:
+				}
+		return switch( v.type ) {
+		case TInt:
+			PInt(min == null ? null : Std.int(min), max == null ? null : Std.int(max));
+		case TFloat:
+			PFloat(min, max);
+		case TBool:
+			PBool;
+		case TSampler2D:
+			PTexture;
+		default:
+			PUnsupported(hxsl.Ast.Tools.toString(v.type));
+		}
+	}
+
 }
 }