DynamicShader.hx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package hrt.prefab;
  2. class DynamicShader extends Shader {
  3. var shaderDef : hrt.prefab.ContextShared.ShaderDef;
  4. var shaderClass : Class<hxsl.Shader>;
  5. @:s var isInstance : Bool;
  6. public function new(?parent) {
  7. super(parent);
  8. type = "shader";
  9. }
  10. override function setShaderParam(shader:hxsl.Shader, v:hxsl.Ast.TVar, value:Dynamic) {
  11. if( isInstance ) {
  12. super.setShaderParam(shader,v,value);
  13. return;
  14. }
  15. cast(shader,hxsl.DynamicShader).setParamValue(v, value);
  16. }
  17. override function getShaderDefinition(ctx:Context):hxsl.SharedShader {
  18. if( shaderDef == null && ctx != null )
  19. loadShaderDef(ctx);
  20. return shaderDef == null ? null : shaderDef.shader;
  21. }
  22. override function makeShader( ?ctx:Context ) {
  23. if( getShaderDefinition(ctx) == null )
  24. return null;
  25. var shader;
  26. if( isInstance )
  27. shader = Type.createInstance(shaderClass,[]);
  28. else {
  29. var dshader = new hxsl.DynamicShader(shaderDef.shader);
  30. for( v in shaderDef.inits ) {
  31. #if !hscript
  32. throw "hscript required";
  33. #else
  34. dshader.hscriptSet(v.variable.name, v.value);
  35. #end
  36. }
  37. shader = dshader;
  38. }
  39. syncShaderVars(shader, shaderDef.shader);
  40. return shader;
  41. }
  42. override function makeInstance(ctx:Context):Context {
  43. if( source == null )
  44. return ctx;
  45. return super.makeInstance(ctx);
  46. }
  47. function fixSourcePath() {
  48. #if editor
  49. // shader source is loaded with ../src/path/to/Shader.hx
  50. // but we want the path relative to source path path/to/Shader.hx only
  51. var ide = hide.Ide.inst;
  52. var shadersPath = ide.projectDir + "/src"; // TODO: serach in haxe.classPath?
  53. var path = ide.getPath(source);
  54. var fpath = sys.FileSystem.fullPath(path);
  55. if( fpath != null ) path = fpath;
  56. path = path.split("\\").join("/");
  57. if( StringTools.startsWith(path.toLowerCase(), shadersPath.toLowerCase()+"/") ) {
  58. path = path.substr(shadersPath.length + 1);
  59. source = path;
  60. }
  61. #end
  62. }
  63. function loadShaderClass(opt=false) : Class<hxsl.Shader> {
  64. var path = source;
  65. if(StringTools.endsWith(path, ".hx")) path = path.substr(0, -3);
  66. var cpath = path.split("/").join(".");
  67. var cl = cast Type.resolveClass(cpath);
  68. if( cl == null && !opt ) throw "Missing shader class"+cpath;
  69. return cl;
  70. }
  71. public function loadShaderDef(ctx: Context) {
  72. if(shaderDef == null) {
  73. fixSourcePath();
  74. if( isInstance ) {
  75. shaderClass = loadShaderClass();
  76. var shared : hxsl.SharedShader = (shaderClass:Dynamic)._SHADER;
  77. if( shared == null ) {
  78. @:privateAccess Type.createEmptyInstance(shaderClass).initialize();
  79. shared = (shaderClass:Dynamic)._SHADER;
  80. }
  81. shaderDef = { shader : shared, inits : [] };
  82. } else {
  83. var path = source;
  84. if(StringTools.endsWith(path, ".hx")) path = path.substr(0, -3);
  85. shaderDef = ctx.loadShader(path);
  86. }
  87. }
  88. if(shaderDef == null)
  89. return;
  90. #if editor
  91. // TODO: Where to init prefab default values?
  92. for( v in shaderDef.inits ) {
  93. if(!Reflect.hasField(props, v.variable.name)) {
  94. Reflect.setField(props, v.variable.name, v.value);
  95. }
  96. }
  97. for(v in shaderDef.shader.data.vars) {
  98. if(v.kind != Param)
  99. continue;
  100. if(!Reflect.hasField(props, v.name)) {
  101. Reflect.setField(props, v.name, getDefault(v.type));
  102. }
  103. }
  104. #end
  105. }
  106. #if editor
  107. override function edit( ectx ) {
  108. super.edit(ectx);
  109. if( isInstance || loadShaderClass(true) != null ) {
  110. ectx.properties.add(hide.comp.PropsEditor.makePropsList([{
  111. name : "isInstance",
  112. t : PBool,
  113. }]), this);
  114. }
  115. }
  116. #end
  117. public static function evalConst( e : hxsl.Ast.TExpr ) : Dynamic {
  118. return switch( e.e ) {
  119. case TConst(c):
  120. switch( c ) {
  121. case CNull: null;
  122. case CBool(b): b;
  123. case CInt(i): i;
  124. case CFloat(f): f;
  125. case CString(s): s;
  126. }
  127. case TCall({ e : TGlobal(Vec2 | Vec3 | Vec4) }, args):
  128. var vals = [for( a in args ) evalConst(a)];
  129. if( vals.length == 1 )
  130. switch( e.t ) {
  131. case TVec(n, _):
  132. for( i in 0...n - 1 ) vals.push(vals[0]);
  133. return vals;
  134. default:
  135. throw "assert";
  136. }
  137. return vals;
  138. default:
  139. throw "Unhandled constant init " + hxsl.Printer.toString(e);
  140. }
  141. }
  142. public static function getDefault(type: hxsl.Ast.Type): Dynamic {
  143. switch(type) {
  144. case TBool:
  145. return false;
  146. case TInt:
  147. return 0;
  148. case TFloat:
  149. return 0.0;
  150. case TVec( size, VFloat ):
  151. return [for(i in 0...size) 0];
  152. default:
  153. return null;
  154. }
  155. return null;
  156. }
  157. static var _ = Library.register("shader", DynamicShader);
  158. }