ScreenShaderGraph.hx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. package hrt.prefab.rfx;
  2. import hrt.prefab.rfx.RendererFX;
  3. import hrt.prefab.Library;
  4. import hxd.Math;
  5. private class GraphShader extends h3d.shader.ScreenShader {
  6. static var SRC = {
  7. @param var source : Sampler2D;
  8. function fragment() {
  9. pixelColor = source.get(calculatedUV);
  10. }
  11. }
  12. }
  13. class ScreenShaderGraph extends RendererFX {
  14. var shaderPass = new h3d.pass.ScreenFx(new GraphShader());
  15. var shaderGraph : hrt.shgraph.ShaderGraph;
  16. var shaderDef : hrt.prefab.ContextShared.ShaderDef;
  17. var shader : hxsl.DynamicShader;
  18. override function end(r:h3d.scene.Renderer, step:h3d.impl.RendererFX.Step) {
  19. if( !checkEnabled() ) return;
  20. if( step == AfterTonemapping ) {
  21. r.mark("ScreenShaderGraph");
  22. if (shader != null) {
  23. var ctx = r.ctx;
  24. var target = r.allocTarget("ppTarget", false);
  25. shaderPass.shader.source = ctx.getGlobal("ldrMap");
  26. ctx.engine.pushTarget(target);
  27. shaderPass.render();
  28. ctx.engine.popTarget();
  29. ctx.setGlobal("ldrMap", target);
  30. r.setTarget(target);
  31. }
  32. }
  33. if( step == BeforeTonemapping ) {
  34. r.mark("ScreenShaderGraph");
  35. if (shader != null) {
  36. var ctx = r.ctx;
  37. var target = r.allocTarget("ppTarget", false);
  38. shaderPass.shader.source = ctx.getGlobal("hdrMap");
  39. ctx.engine.pushTarget(target);
  40. shaderPass.render();
  41. ctx.engine.popTarget();
  42. ctx.setGlobal("hdrMap", target);
  43. r.setTarget(target);
  44. }
  45. }
  46. }
  47. override function load( obj : Dynamic ) {
  48. loadSerializedFields(obj);
  49. }
  50. public function loadShaderDef() {
  51. shaderDef = shaderGraph.compile();
  52. if(shaderDef == null)
  53. return;
  54. #if editor
  55. for( v in shaderDef.inits ) {
  56. if (props == null)
  57. props = {};
  58. if(!Reflect.hasField(props, v.variable.name)) {
  59. Reflect.setField(props, v.variable.name, v.value);
  60. }
  61. }
  62. #end
  63. }
  64. function getShaderDefinition():hxsl.SharedShader {
  65. if( shaderDef == null )
  66. loadShaderDef();
  67. return shaderDef == null ? null : shaderDef.shader;
  68. }
  69. function setShaderParam(shader:hxsl.Shader, v:hxsl.Ast.TVar, value:Dynamic) {
  70. cast(shader,hxsl.DynamicShader).setParamValue(v, value);
  71. }
  72. function syncShaderVars() {
  73. for(v in shaderDef.shader.data.vars) {
  74. if(v.kind != Param)
  75. continue;
  76. var val : Dynamic = Reflect.field(props, v.name);
  77. switch(v.type) {
  78. case TVec(_, VFloat):
  79. if(val != null) {
  80. if( Std.is(val,Int) ) {
  81. var v = new h3d.Vector();
  82. v.setColor(val);
  83. val = v;
  84. } else
  85. val = h3d.Vector.fromArray(val);
  86. } else
  87. val = new h3d.Vector();
  88. case TSampler2D:
  89. if( val != null )
  90. val = hxd.res.Loader.currentInstance.load(val).toTexture();
  91. else {
  92. var childNoise = getOpt(hrt.prefab.l2d.NoiseGenerator, v.name);
  93. if(childNoise != null)
  94. val = childNoise.toTexture();
  95. }
  96. default:
  97. }
  98. if(val == null)
  99. continue;
  100. setShaderParam(shader,v,val);
  101. }
  102. }
  103. function makeShader() {
  104. if( getShaderDefinition() == null )
  105. return null;
  106. var dshader = new hxsl.DynamicShader(shaderDef.shader);
  107. for( v in shaderDef.inits ) {
  108. #if !hscript
  109. throw "hscript required";
  110. #else
  111. dshader.hscriptSet(v.variable.name, v.value);
  112. #end
  113. }
  114. shader = dshader;
  115. syncShaderVars();
  116. shaderPass.addShader(shader);
  117. return shader;
  118. }
  119. override function makeInstance(ctx: Context) : Context {
  120. ctx = super.makeInstance(ctx);
  121. updateInstance(ctx);
  122. return ctx;
  123. }
  124. override function updateInstance( ctx: Context, ?propName : String ) {
  125. var p = resolveRef(ctx.shared);
  126. if(p == null)
  127. return;
  128. if (shader == null)
  129. shader = makeShader();
  130. else
  131. syncShaderVars();
  132. }
  133. public function resolveRef(shared : hrt.prefab.ContextShared) {
  134. if(shaderGraph != null)
  135. return shaderGraph;
  136. if(source == null)
  137. return null;
  138. #if editor
  139. shaderGraph = new hrt.shgraph.ShaderGraph(source);
  140. #else
  141. return null;
  142. #end
  143. return shaderGraph;
  144. }
  145. function makeShaderParam( v : hxsl.Ast.TVar ) : hrt.prefab.Props.PropType {
  146. var min : Null<Float> = null, max : Null<Float> = null;
  147. if( v.qualifiers != null )
  148. for( q in v.qualifiers )
  149. switch( q ) {
  150. case Range(rmin, rmax): min = rmin; max = rmax;
  151. default:
  152. }
  153. return switch( v.type ) {
  154. case TInt:
  155. PInt(min == null ? null : Std.int(min), max == null ? null : Std.int(max));
  156. case TFloat:
  157. PFloat(min != null ? min : 0.0, max != null ? max : 1.0);
  158. case TBool:
  159. PBool;
  160. case TSampler2D:
  161. PTexture;
  162. case TVec(n, VFloat):
  163. PVec(n);
  164. default:
  165. PUnsupported(hxsl.Ast.Tools.toString(v.type));
  166. }
  167. }
  168. #if editor
  169. override function edit( ectx : hide.prefab.EditContext ) {
  170. var element = new hide.Element('
  171. <div class="group" name="Reference">
  172. <dl>
  173. <dt>Reference</dt><dd><input type="fileselect" extensions="shgraph" field="source"/></dd>
  174. </dl>
  175. </div>');
  176. function updateProps() {
  177. var input = element.find("input");
  178. updateInstance(ectx.rootContext);
  179. var found = shaderGraph != null;
  180. input.toggleClass("error", !found);
  181. }
  182. updateProps();
  183. ectx.properties.add(element, this, function(pname) {
  184. ectx.onChange(this, pname);
  185. if(pname == "source") {
  186. shaderGraph = null;
  187. shaderPass.removeShader(shader);
  188. shader = null;
  189. if (shaderDef != null) {
  190. for(v in shaderDef.inits) {
  191. if (Reflect.hasField(props, v.variable.name))
  192. Reflect.deleteField(props, v.variable.name);
  193. }
  194. shaderDef = null;
  195. }
  196. updateProps();
  197. ectx.properties.clear();
  198. edit(ectx);
  199. }
  200. });
  201. super.edit(ectx);
  202. if (shaderGraph == null)
  203. return;
  204. getShaderDefinition();
  205. var group = new hide.Element('<div class="group" name="Shader"></div>');
  206. var props = [];
  207. for(v in shaderDef.shader.data.vars) {
  208. if( v.kind != Param )
  209. continue;
  210. if( v.qualifiers != null && v.qualifiers.contains(Ignore) )
  211. continue;
  212. var prop = makeShaderParam(v);
  213. if( prop == null ) continue;
  214. props.push({name: v.name, t: prop, def: Reflect.field(this.props, v.name)});
  215. }
  216. group.append(hide.comp.PropsEditor.makePropsList(props));
  217. ectx.properties.add(group, this.props, function(pname) {
  218. ectx.onChange(this, pname);
  219. updateInstance(ectx.rootContext, pname);
  220. });
  221. var btn = new hide.Element("<input type='submit' style='width: 100%; margin-top: 10px;' value='Open Shader Graph' />");
  222. btn.on("click", function() {
  223. ectx.ide.openFile(source);
  224. });
  225. ectx.properties.add(btn, this, function(pname) {
  226. ectx.onChange(this, pname);
  227. });
  228. }
  229. #end
  230. static var _ = Library.register("rfx.ScreenShaderGraph", ScreenShaderGraph);
  231. }