Browse Source

glsl output started

Nicolas Cannasse 11 years ago
parent
commit
e2bab7307f
8 changed files with 390 additions and 23 deletions
  1. 2 0
      .gitignore
  2. 6 0
      hxsl.html
  3. 1 4
      hxsl.hxml
  4. 10 10
      hxsl.hxproj
  5. 23 7
      hxsl/Flatten.hx
  6. 305 0
      hxsl/GlslOut.hx
  7. 1 1
      hxsl/Printer.hx
  8. 42 1
      test/Test.hx

+ 2 - 0
.gitignore

@@ -1,3 +1,5 @@
 /Render.hx
 /Shaders.hx
 /*.swf
+/hxsl.js
+/hxsl.js.map

+ 6 - 0
hxsl.html

@@ -0,0 +1,6 @@
+<html>
+	<body>
+		<pre id="haxe:trace"></pre>
+		<script src="hxsl.js"></script>
+	</body>
+</html>

+ 1 - 4
hxsl.hxml

@@ -1,8 +1,5 @@
 -cp test
--swf hxsl.swf
--swf-header 800:1000:60:FFFFFF
---flash-strict
--swf-version 11.6
+-js hxsl.js
 -main Test
 -dce full
 -lib h3d

+ 10 - 10
hxsl.hxproj

@@ -4,13 +4,13 @@
   <output>
     <movie outputType="Application" />
     <movie input="" />
-    <movie path="hxsl.swf" />
+    <movie path="hxsl.js" />
     <movie fps="60" />
     <movie width="800" />
     <movie height="1000" />
-    <movie version="11" />
-    <movie minorVersion="6" />
-    <movie platform="Flash Player" />
+    <movie version="1" />
+    <movie minorVersion="0" />
+    <movie platform="JavaScript" />
     <movie background="#FFFFFF" />
   </output>
   <!-- Other classes to be compiled into your SWF -->
@@ -33,13 +33,13 @@
   <compileTargets>
     <!-- example: <compile path="..." /> -->
   </compileTargets>
-  <!-- Assets to embed into the output SWF -->
-  <library>
-    <!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->
-  </library>
   <!-- Paths to exclude from the Project Explorer tree -->
   <hiddenPaths>
     <hidden path="obj" />
+    <hidden path="hxsl.js.map" />
+    <hidden path="hxsl.swf" />
+    <hidden path="hxsl.js" />
+    <hidden path="hxsl.hxml" />
   </hiddenPaths>
   <!-- Executed before build -->
   <preBuildCommand />
@@ -48,8 +48,8 @@
   <!-- Other project options -->
   <options>
     <option showHiddenPaths="False" />
-    <option testMovie="Default" />
-    <option testMovieCommand="" />
+    <option testMovie="OpenDocument" />
+    <option testMovieCommand="hxsl.html" />
   </options>
   <!-- Plugin storage -->
   <storage />

+ 23 - 7
hxsl/Flatten.hx

@@ -21,6 +21,7 @@ class Flatten {
 	var params : Array<TVar>;
 	var outVars : Array<TVar>;
 	var varMap : Map<TVar,Alloc>;
+	var varNames : Map<String,TVar>;
 	
 	public function new() {
 	}
@@ -30,6 +31,7 @@ class Flatten {
 		params = [];
 		outVars = [];
 		varMap = new Map();
+		varNames = new Map();
 		for( v in s.vars )
 			gatherVar(v);
 		pack("globals", Global, globals, VFloat);
@@ -54,7 +56,10 @@ class Flatten {
 			if( a == null )
 				e
 			else
-				access(a,v.type, e.p);
+				access(a, v.type, e.p);
+		case TVarDecl(v, _):
+			uniqueVar(v);
+			e.map(mapExpr);
 		default:
 			e.map(mapExpr);
 		};
@@ -137,7 +142,9 @@ class Flatten {
 		};
 		for( v in vars ) {
 			switch( v.type ) {
-			case TSampler2D, TSamplerCube: continue;
+			case TSampler2D, TSamplerCube:
+				outVars.push(v);
+				continue;
 			default:
 			}
 			var size = varSize(v.type, t);
@@ -191,17 +198,26 @@ class Flatten {
 		}
 	}
 	
+	function uniqueVar( v : TVar ) {
+		var v2 = varNames.get(v.name);
+		if( v2 == v ) return;
+		if( v2 == null ) {
+			varNames.set(v.name, v);
+			return;
+		}
+		var k = 2;
+		while( varNames.exists(v.name + k) ) k++;
+		v.name += k;
+		varNames.set(v.name, v);
+	}
+	
 	function gatherVar( v : TVar ) {
 		switch( v.type ) {
 		case TStruct(vl):
-			var keep = v.kind == Input || v.name == "output";
-			if( keep ) {
-				outVars.push(v);
-				return;
-			}
 			for( v in vl )
 				gatherVar(v);
 		default:
+			uniqueVar(v);
 			switch( v.kind ) {
 			case Global:
 				if( v.hasQualifier(PerObject) )

+ 305 - 0
hxsl/GlslOut.hx

@@ -0,0 +1,305 @@
+package hxsl;
+import hxsl.Ast;
+
+class GlslOut {
+
+	var buf : StringBuf;
+	var prec : String;
+	var keywords : Map<String,Bool>;
+	var exprValues : Array<String>;
+	var globalNames : Map<TGlobal,String>;
+	
+	public function new() {
+		keywords = [ "input" => true, "output" => true, "discard" => true ];
+		globalNames = new Map();
+		for( g in hxsl.Ast.TGlobal.createAll() ) {
+			var n = "" + g;
+			n = n.charAt(0).toLowerCase() + n.substr(1);
+			globalNames.set(g, n);
+		}
+	}
+	
+	public function run( s : ShaderData ) : { vertex : String, fragment : String } {
+		return {
+			vertex : make(s, "vertex"),
+			fragment : make(s,"fragment"),
+		};
+	}
+	
+	inline function add( v : Dynamic ) {
+		buf.add(v);
+	}
+	
+	function ident( i : String ) {
+		add(keywords.exists(i) ? "_" + i : i);
+	}
+	
+	function addType( t : Type ) {
+		switch( t ) {
+		case TVoid:
+			add("void");
+		case TInt:
+			add("int");
+		case TBool:
+			add("bool");
+		case TFloat:
+			add(prec);
+			add("float");
+		case TString:
+			add("string");
+		case TVec(size, k):
+			switch( k ) {
+			case VFloat: add(prec);
+			case VInt: add("i");
+			case VBool: add("b");
+			}
+			add("vec");
+			add(size);
+		case TMat3:
+			add("mat3");
+		case TMat4:
+			add("mat4");
+		case TMat3x4:
+			add("mat3x4");
+		case TSampler2D:
+			add("sampler2D");
+		case TSamplerCube:
+			add("samplerCube");
+		case TStruct(vl):
+			add("struct { ");
+			for( v in vl ) {
+				addVar(v);
+				add(";");
+			}
+			add(" }");
+		case TFun(_):
+			add("function");
+		case TArray(t, size):
+			addType(t);
+			add("[");
+			switch( size ) {
+			case SVar(v):
+				ident(v.name);
+			case SConst(v):
+				add(v);
+			}
+			add("]");
+		}
+	}
+	
+	function addVar( v : TVar ) {
+		switch( v.type ) {
+		case TArray(t, size):
+			var old = v.type;
+			v.type = t;
+			addVar(v);
+			v.type = old;
+			add("[");
+			switch( size ) {
+			case SVar(v): ident(v.name);
+			case SConst(n): add(n);
+			}
+			add("]");
+		default:
+			addType(v.type);
+			add(" ");
+			ident(v.name);
+		}
+	}
+	
+	function addValue( e : TExpr, tabs : String ) {
+		switch( e.e ) {
+		case TBlock(el):
+			var name = "val" + exprValues.length;
+			var tmp = buf;
+			buf = new StringBuf();
+			addType(e.t);
+			add(" ");
+			add(name);
+			add("(void)");
+			var el2 = el.copy();
+			var last = el2[el2.length - 1];
+			el2[el2.length - 1] = { e : TReturn(last), t : e.t, p : last.p };
+			var e2 = {
+				t : TVoid,
+				e : TBlock(el2),
+				p : e.p,
+			};
+			addExpr(e2, "");
+			exprValues.push(buf.toString());
+			buf = tmp;
+			add(name);
+			add("()");
+		default:
+			addExpr(e, tabs);
+		}
+	}
+	
+	function addExpr( e : TExpr, tabs : String ) {
+		switch( e.e ) {
+		case TConst(c):
+			switch( c ) {
+			case CInt(v): add(v);
+			case CFloat(f):
+				var str = "" + f;
+				add(str);
+				if( str.indexOf(".") == -1 && str.indexOf("e") == -1 )
+					add(".");
+			case CString(v): add('"' + v + '"');
+			case CNull: add("null");
+			case CBool(b): add(b);
+			}
+		case TVar(v):
+			ident(v.name);
+		case TGlobal(g):
+			add(globalNames.get(g));
+		case TParenthesis(e):
+			add("(");
+			addValue(e,tabs);
+			add(")");
+		case TBlock(el):
+			add("{\n");
+			var t2 = tabs + "\t";
+			for( e in el ) {
+				add(t2);
+				addExpr(e, t2);
+				add(";\n");
+			}
+			add(tabs);
+			add("}");
+		case TBinop(op, e1, e2):
+			switch( [op, e1.t, e2.t] ) {
+			case [OpMult, TMat3x4, TVec(3,VFloat)]:
+				add("m3x4mult(");
+				addValue(e1, tabs);
+				add(",");
+				addValue(e2, tabs);
+				add(")");
+			default:
+				addValue(e1, tabs);
+				add(Printer.opStr(op));
+				addValue(e2, tabs);
+			}
+		case TUnop(op, e1):
+			add(switch(op) {
+			case OpNot: "!";
+			case OpNeg: "-";
+			case OpIncrement: "++";
+			case OpDecrement: "--";
+			case OpNegBits: "~";
+			});
+			addValue(e1, tabs);
+		case TVarDecl(v, init):
+			addVar(v);
+			if( init != null ) {
+				add(" = ");
+				addValue(init, tabs);
+			}
+		case TCall(e, args):
+			addValue(e, tabs);
+			add("(");
+			var first = true;
+			for( e in args ) {
+				if( first ) first = false else add(", ");
+				addValue(e, tabs);
+			}
+			add(")");
+		case TSwiz(e, regs):
+			addValue(e, tabs);
+			add(".");
+			for( r in regs )
+				add(switch(r) {
+				case X: "x";
+				case Y: "y";
+				case Z: "z";
+				case W: "w";
+				});
+		case TIf(econd, eif, eelse):
+			add("if( ");
+			addValue(econd, tabs);
+			add(") ");
+			addExpr(eif, tabs);
+			if( eelse != null ) {
+				add(" else ");
+				addExpr(eelse, tabs);
+			}
+		case TDiscard:
+			add("discard");
+		case TReturn(e):
+			if( e == null )
+				add("return");
+			else {
+				add("return ");
+				addValue(e, tabs);
+			}
+		case TFor(v, it, loop):
+			add("for(...)");
+		case TContinue:
+			add("continue");
+		case TBreak:
+			add("break");
+		case TArray(e, index):
+			addValue(e, tabs);
+			add("[");
+			addValue(index, tabs);
+			add("]");
+		case TArrayDecl(el):
+			add("[");
+			var first = true;
+			for( e in el ) {
+				if( first ) first = false else add(", ");
+				addValue(e,tabs);
+			}
+			add("]");
+		}
+	}
+	
+	function make( s : ShaderData, func : String ) {
+		prec = "mediump ";
+		buf = new StringBuf();
+		exprValues = [];
+		add("struct mat3x4 { "+prec+"vec4 a; "+prec+"vec4 b; "+prec+"vec4 c; };\n");
+		add(prec+"vec3 m3x4mult( mat3x4 m, "+prec+"vec3 v ) { "+prec+"vec4 ve = vec4(v,1.0); return vec3(dot(m.a,ve),dot(m.b,ve),dot(m.c,ve)); }\n");
+		for( v in s.vars ) {
+			switch( v.kind ) {
+			case Param, Global:
+				add("uniform ");
+			case Input:
+				if( func == "fragment" ) continue;
+				add("attribute ");
+			case Var:
+				add("varying ");
+			case Function: continue;
+			case Local: throw "assert";
+			}
+			addVar(v);
+			add(";\n");
+		}
+		add("\n");
+		var found = false;
+		for( f in s.funs ) {
+			if( f.ref.name == func ) {
+				var tmp = buf;
+				buf = new StringBuf();
+				found = true;
+				add("void main(void) ");
+				addExpr(f.expr, "");
+				exprValues.push(buf.toString());
+				buf = tmp;
+			}
+		}
+		for( e in exprValues ) {
+			add(e);
+			add("\n\n");
+		}
+		if( !found ) throw func + " not found in shader";
+		var content = buf.toString();
+		buf = null;
+		return content;
+	}
+	
+	public static function toGlsl( s : ShaderData ) {
+		return new GlslOut().run(s);
+	}
+	
+}

+ 1 - 1
hxsl/Printer.hx

@@ -219,7 +219,7 @@ class Printer {
 		}
 	}
 	
-	function opStr( op : Ast.Binop ) {
+	public static function opStr( op : Ast.Binop ) {
 		return switch(op) {
 		case OpAdd:"+";
 		case OpSub:"-";

+ 42 - 1
test/Test.hx

@@ -350,7 +350,48 @@ class Test {
 		var instances = [for( s in shaders ) { s.updateConstants(globals); s.instance; }];
 		var cache = hxsl.Cache.get();
 		var s = cache.link(instances, cache.allocOutputVars(["output.position", "output.color"]));
-		trace("\n"+hxsl.Printer.shaderToString(s));
+		//trace("\n" + hxsl.Printer.shaderToString(s));
+		#if js
+		haxe.Log.trace("START");
+		try {
+		
+		var glSrc = hxsl.GlslOut.toGlsl(s);
+		
+		var canvas = js.Browser.document.createCanvasElement();
+		var gl = canvas.getContextWebGL();
+		var GL = js.html.webgl.GL;
+		
+		function compile(kind, code) {
+			trace(code);
+			var s = gl.createShader(kind);
+			gl.shaderSource(s, code);
+			gl.compileShader(s);
+			if( gl.getShaderParameter(s, GL.COMPILE_STATUS) != cast 1 ) {
+				var log = gl.getShaderInfoLog(s);
+				var line = code.split("\n")[Std.parseInt(log.substr(9)) - 1];
+				if( line == null ) line = "" else line = "(" + StringTools.trim(line) + ")";
+				throw log + line;
+			}
+			return s;
+		}
+			
+		var vs = compile(GL.VERTEX_SHADER, glSrc.vertex);
+		var fs = compile(GL.FRAGMENT_SHADER, glSrc.fragment);
+		
+		var p = gl.createProgram();
+		gl.attachShader(p, vs);
+		gl.attachShader(p, fs);
+		gl.linkProgram(p);
+		if( gl.getProgramParameter(p, GL.LINK_STATUS) != cast 1 ) {
+			var log = gl.getProgramInfoLog(p);
+			throw "Program linkage failure: "+log;
+		}
+		
+		} catch( e : Dynamic ) {
+			trace(e);
+		}
+
+		#end
 	}
 		
 }