Просмотр исходного кода

allowed init of @param variables directly in shader code (instead of shader class constructor)

Nicolas Cannasse 7 лет назад
Родитель
Сommit
1d612d653a
2 измененных файлов с 57 добавлено и 4 удалено
  1. 27 1
      hxsl/Checker.hx
  2. 30 3
      hxsl/Macros.hx

+ 27 - 1
hxsl/Checker.hx

@@ -27,6 +27,7 @@ class Checker {
 	var globals : Map<String,{ g : TGlobal, t : Type }>;
 	var globals : Map<String,{ g : TGlobal, t : Type }>;
 	var curFun : TFunction;
 	var curFun : TFunction;
 	var inLoop : Bool;
 	var inLoop : Bool;
+	public var inits : Array<{ v : TVar, e : TExpr }>;
 
 
 	public function new() {
 	public function new() {
 		globals = new Map();
 		globals = new Map();
@@ -141,6 +142,7 @@ class Checker {
 
 
 	public function check( name : String, shader : Expr ) : ShaderData {
 	public function check( name : String, shader : Expr ) : ShaderData {
 		vars = new Map();
 		vars = new Map();
+		inits = [];
 		inLoop = false;
 		inLoop = false;
 
 
 		var funs = [];
 		var funs = [];
@@ -586,12 +588,25 @@ class Checker {
 						default:
 						default:
 						}
 						}
 				}
 				}
-				if( v.expr != null ) error("Cannot initialize variable declaration", v.expr.pos);
+				var einit = null;
+				if( v.expr != null ) {
+					if( v.kind != Param )
+						error("Cannot initialize variable declaration if not @param", v.expr.pos);
+					var e = typeExpr(v.expr, v.type == null ? Value : With(v.type));
+					if( v.type == null )
+						v.type = e.t;
+					else
+						unify(e.t, v.type, v.expr.pos);
+					checkConst(e);
+					einit = e;
+				}
 				if( v.type == null ) error("Type required for variable declaration", e.pos);
 				if( v.type == null ) error("Type required for variable declaration", e.pos);
 				if( vars.exists(v.name) ) error("Duplicate var decl '" + v.name + "'", e.pos);
 				if( vars.exists(v.name) ) error("Duplicate var decl '" + v.name + "'", e.pos);
 				var v = makeVar(v, e.pos);
 				var v = makeVar(v, e.pos);
 				if( isImport && v.kind == Param )
 				if( isImport && v.kind == Param )
 					continue;
 					continue;
+				if( einit != null )
+					inits.push({ v : v, e : einit });
 				vars.set(v.name, v);
 				vars.set(v.name, v);
 			}
 			}
 		case ECall( { expr : EIdent("import") }, [e]):
 		case ECall( { expr : EIdent("import") }, [e]):
@@ -630,6 +645,17 @@ class Checker {
 		}
 		}
 	}
 	}
 
 
+	function checkConst( e : TExpr ) {
+		switch( e.e ) {
+		case TConst(_):
+		case TParenthesis(e): checkConst(e);
+		case TCall({ e : TGlobal(Vec2 | Vec3 | Vec4) }, args):
+			for( a in args ) checkConst(a);
+		default:
+			error("This expression should be constant", e.p);
+		}
+	}
+
 	function makeVar( v : VarDecl, pos : Position, ?parent : TVar ) {
 	function makeVar( v : VarDecl, pos : Position, ?parent : TVar ) {
 		var tv : TVar = {
 		var tv : TVar = {
 			id : Tools.allocVarId(),
 			id : Tools.allocVarId(),

+ 30 - 3
hxsl/Macros.hx

@@ -73,6 +73,29 @@ class Macros {
 		}
 		}
 	}
 	}
 
 
+	static function makeInit( e : Ast.TExpr ) : haxe.macro.Expr {
+		return switch( e.e ) {
+		case TConst(c):
+			{
+				expr : EConst(switch( c ) {
+					case CNull: CIdent("null");
+					case CBool(b): CIdent(b?"true":"false");
+					case CFloat(f): CFloat("" + f);
+					case CInt(i): CInt(""+i);
+					case CString(s): CString(s);
+				}),
+				pos : e.p,
+			};
+		case TCall({ e : TGlobal(Vec2 | Vec3 | Vec4) }, args):
+			{
+				expr : ENew({ pack : ["h3d"], name : "Vector" }, [for( a in args ) makeInit(a)]),
+				pos : e.p,
+			}
+		default:
+			Error.t("Unsupported init expr", e.p);
+		}
+	}
+
 	static function getConsts( v : TVar, p : Position, consts : Array<{ pos : Int, bits : Int, v : TVar }> ) {
 	static function getConsts( v : TVar, p : Position, consts : Array<{ pos : Int, bits : Int, v : TVar }> ) {
 		switch( v.type ) {
 		switch( v.type ) {
 		case TStruct(vl):
 		case TStruct(vl):
@@ -103,7 +126,7 @@ class Macros {
 		}
 		}
 	}
 	}
 
 
-	static function buildFields( shader : ShaderData, pos : Position ) {
+	static function buildFields( shader : ShaderData, inits : Array<{ v : TVar, e : Ast.TExpr }>, pos : Position ) {
 		var fields = new Array<Field>();
 		var fields = new Array<Field>();
 		var globals = [], consts = [], params = [], eparams = [], tparams = [];
 		var globals = [], consts = [], params = [], eparams = [], tparams = [];
 		for( v in shader.vars ) {
 		for( v in shader.vars ) {
@@ -119,10 +142,14 @@ class Macros {
 					access : [APublic],
 					access : [APublic],
 				};
 				};
 				var name = v.name + "__";
 				var name = v.name + "__";
+				var initVal = null;
+				for( i in inits )
+					if( i.v == v )
+						initVal = i.e;
 				var f2 : Field = {
 				var f2 : Field = {
 					name : name,
 					name : name,
 					pos : pos,
 					pos : pos,
-					kind : FVar(t, makeDef(v.type, pos)),
+					kind : FVar(t, initVal != null ? makeInit(initVal) : makeDef(v.type, pos)),
 					meta : [{ name : ":noCompletion", pos : pos }],
 					meta : [{ name : ":noCompletion", pos : pos }],
 				};
 				};
 				var fget : Field = {
 				var fget : Field = {
@@ -357,7 +384,7 @@ class Macros {
 							name : ":keep",
 							name : ":keep",
 							pos : pos,
 							pos : pos,
 						});
 						});
-						for( f in buildFields(shader, pos) )
+						for( f in buildFields(shader, check.inits, pos) )
 							if( !supFields.exists(f.name) )
 							if( !supFields.exists(f.name) )
 								fields.push(f);
 								fields.push(f);
 					} catch( e : Ast.Error ) {
 					} catch( e : Ast.Error ) {