SubGraph.hx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. package hrt.shgraph.nodes;
  2. using hxsl.Ast;
  3. @name("SubGraph")
  4. @description("Include a subgraph")
  5. @width(250)
  6. @alwaysshowinputs()
  7. class SubGraph extends ShaderNode {
  8. @prop() public var pathShaderGraph : String;
  9. var inputsInfo : Map<String, ShaderNode.InputInfo>;
  10. var inputInfoKeys : Array<String> = [];
  11. var outputsInfo : Map<String, ShaderNode.OutputInfo>;
  12. var outputInfoKeys : Array<String> = [];
  13. var parameters : Array<ShaderGraph.Parameter> = [];
  14. var propertiesSubGraph : Map<Int, Dynamic>;
  15. public var subShaderGraph : ShaderGraph;
  16. public var varsSubGraph : Array<TVar> = [];
  17. public function loadGraphShader() {
  18. if (this.pathShaderGraph != null) {
  19. try {
  20. subShaderGraph = new ShaderGraph(pathShaderGraph);
  21. } catch (e : Dynamic) {
  22. trace("The shader does not exist.");
  23. return;
  24. }
  25. inputsInfo = new Map<String, ShaderNode.InputInfo>();
  26. inputInfoKeys = [];
  27. outputsInfo = new Map<String, ShaderNode.OutputInfo>();
  28. outputInfoKeys = [];
  29. parameters = [];
  30. propertiesSubGraph = new Map<Int, Dynamic>();
  31. var prefixSubGraph = "shgraph_" + id + "_";
  32. for (node in subShaderGraph.getNodes()) {
  33. switch (node.type.split(".").pop()) {
  34. case "ShaderParam": // params become inputs
  35. var shaderParam = Std.downcast(node.instance, ShaderParam);
  36. var paramName = subShaderGraph.getParameter(shaderParam.parameterId).name;
  37. var paramId = "param_" + shaderParam.parameterId;
  38. var paramInfo = inputsInfo.get(prefixSubGraph+paramId);
  39. var ids = [];
  40. if (paramInfo != null && paramInfo.ids != null)
  41. ids = paramInfo.ids;
  42. ids.push(node.id);
  43. if (!inputsInfo.exists(prefixSubGraph + paramId)) {
  44. inputInfoKeys.push(prefixSubGraph+paramId);
  45. }
  46. inputsInfo.set(prefixSubGraph+paramId, { name : paramName , type: ShaderType.getSType(shaderParam.variable.type), hasProperty: false, isRequired : false, ids : ids });
  47. case "ShaderInput":
  48. var shaderInput = Std.downcast(node.instance, ShaderInput);
  49. var inputId = "input_" + shaderInput.variable.name;
  50. var inputInfo = inputsInfo.get(prefixSubGraph+inputId);
  51. var ids = [];
  52. if (inputInfo != null && inputInfo.ids != null)
  53. ids = inputInfo.ids;
  54. ids.push(node.id);
  55. if (!inputsInfo.exists(prefixSubGraph+inputId)) {
  56. inputInfoKeys.push(prefixSubGraph+inputId);
  57. }
  58. inputsInfo.set(prefixSubGraph+inputId, { name : "*" + shaderInput.variable.name , type: ShaderType.getSType(shaderInput.variable.type), hasProperty: false, isRequired : false, ids : ids });
  59. case "ShaderGlobalInput":
  60. var shaderInput = Std.downcast(node.instance, ShaderGlobalInput);
  61. var inputId = "globalInput_" + shaderInput.variable.name;
  62. var inputInfo = inputsInfo.get(prefixSubGraph+inputId);
  63. var ids = [];
  64. if (inputInfo != null && inputInfo.ids != null)
  65. ids = inputInfo.ids;
  66. ids.push(node.id);
  67. if (!inputsInfo.exists(prefixSubGraph+inputId)) {
  68. inputInfoKeys.push(prefixSubGraph+inputId);
  69. }
  70. inputsInfo.set(prefixSubGraph+inputId, { name : "*" + shaderInput.variable.name , type: ShaderType.getSType(shaderInput.variable.type), hasProperty: false, isRequired : false, ids : ids });
  71. case "ShaderCameraInput":
  72. var shaderInput = Std.downcast(node.instance, ShaderCameraInput);
  73. var inputId = "cameraInput_" + shaderInput.variable.name;
  74. var inputInfo = inputsInfo.get(prefixSubGraph+inputId);
  75. var ids = [];
  76. if (inputInfo != null && inputInfo.ids != null)
  77. ids = inputInfo.ids;
  78. ids.push(node.id);
  79. if (!inputsInfo.exists(prefixSubGraph+inputId)) {
  80. inputInfoKeys.push(prefixSubGraph+inputId);
  81. }
  82. inputsInfo.set(prefixSubGraph+inputId, { name : "*" + shaderInput.variable.name , type: ShaderType.getSType(shaderInput.variable.type), hasProperty: false, isRequired : false, ids : ids });
  83. case "ShaderOutput":
  84. var shaderOutput = Std.downcast(node.instance, ShaderOutput);
  85. var prefix = shaderOutput.variable.kind == Local ? "" : "*";
  86. outputsInfo.set(prefixSubGraph+node.id, { name : prefix + shaderOutput.variable.name , type: ShaderType.getSType(shaderOutput.variable.type), id : node.id });
  87. outputInfoKeys.push(prefixSubGraph+node.id);
  88. addOutput(prefixSubGraph+node.id, shaderOutput.variable.type);
  89. default:
  90. var shaderConst = Std.downcast(node.instance, ShaderConst);
  91. if (shaderConst != null) { // input static become properties
  92. if (shaderConst.name.length == 0) continue;
  93. if (Std.is(shaderConst, BoolConst)) {
  94. parameters.push({ name : shaderConst.name, type : TBool, defaultValue : null, id : shaderConst.id });
  95. } else if (Std.is(shaderConst, FloatConst)) {
  96. parameters.push({ name : shaderConst.name, type : TFloat, defaultValue : null, id : shaderConst.id });
  97. } else if (Std.is(shaderConst, Color)) {
  98. parameters.push({ name : shaderConst.name, type : TVec(4, VFloat), defaultValue : null, id : shaderConst.id });
  99. }
  100. }
  101. }
  102. }
  103. }
  104. }
  105. override public function build(key : String) : TExpr {
  106. for (inputKey in inputInfoKeys) {
  107. var inputInfo = inputsInfo.get(inputKey);
  108. var inputTVar = getInput(inputKey);
  109. if (inputTVar != null) {
  110. for (id in inputInfo.ids) {
  111. var nodeToReplace = subShaderGraph.getNodes().get(id);
  112. for (i in 0...nodeToReplace.outputs.length) {
  113. var inputNode = nodeToReplace.outputs[i];
  114. for (inputKey in inputNode.instance.getInputsKey()) {
  115. var input = inputNode.instance.getInput(inputKey);
  116. if (input.node == nodeToReplace.instance) {
  117. inputNode.instance.setInput(inputKey, inputTVar);
  118. }
  119. }
  120. }
  121. }
  122. }
  123. }
  124. for (p in parameters) {
  125. if (p.defaultValue != null) {
  126. var node = subShaderGraph.getNode(p.id);
  127. switch (p.type) {
  128. case TBool:
  129. var boolConst = Std.downcast(node.instance, BoolConst);
  130. @:privateAccess boolConst.value = p.defaultValue;
  131. case TVec(4, VFloat):
  132. var colorConst = Std.downcast(node.instance, Color);
  133. @:privateAccess {
  134. colorConst.r = p.defaultValue.x;
  135. colorConst.g = p.defaultValue.y;
  136. colorConst.b = p.defaultValue.z;
  137. colorConst.a = p.defaultValue.w;
  138. }
  139. case TFloat:
  140. var floatConst = Std.downcast(node.instance, FloatConst);
  141. @:privateAccess floatConst.value = p.defaultValue;
  142. default:
  143. }
  144. }
  145. }
  146. var shaderDef;
  147. try {
  148. shaderDef = subShaderGraph.generateShader(null, id);
  149. } catch (e : ShaderException) {
  150. throw ShaderException.t(e.msg, id);
  151. }
  152. if (shaderDef.funs.length > 1) {
  153. throw ShaderException.t("The sub shader is vertex and fragment.", id);
  154. }
  155. varsSubGraph = shaderDef.vars;
  156. var arrayExpr : Array<TExpr> = [];
  157. switch (shaderDef.funs[0].expr.e) {
  158. case TBlock(block):
  159. arrayExpr = block;
  160. default:
  161. }
  162. for (outputKey in outputInfoKeys) {
  163. var outputInfo = outputsInfo.get(outputKey);
  164. var outputTVar = getOutput(outputKey);
  165. if (outputTVar != null) {
  166. arrayExpr.push({
  167. p : null,
  168. t : outputTVar.type,
  169. e : TBinop(OpAssign, {
  170. e: TVar(outputTVar),
  171. p: null,
  172. t: outputTVar.type
  173. }, subShaderGraph.getNodes().get(outputInfo.id).instance.getInput("input").getVar(outputTVar.type))
  174. });
  175. }
  176. }
  177. return {
  178. p : null,
  179. t : TVoid,
  180. e : TBlock(arrayExpr)
  181. };
  182. }
  183. override public function getInputInfo(key : String) : ShaderNode.InputInfo {
  184. return inputsInfo.get(key);
  185. }
  186. override public function getInputInfoKeys() : Array<String> {
  187. return inputInfoKeys;
  188. }
  189. override public function getOutputInfo(key : String) : ShaderNode.OutputInfo {
  190. return outputsInfo.get(key);
  191. }
  192. override public function getOutputInfoKeys() : Array<String> {
  193. return outputInfoKeys;
  194. }
  195. override public function loadProperties(props : Dynamic) {
  196. this.pathShaderGraph = Reflect.field(props, "pathShaderGraph");
  197. loadGraphShader();
  198. var parametersValues : Array<hrt.shgraph.ShaderGraph.Parameter> = Reflect.field(props, "parametersValues");
  199. if (parametersValues == null) return;
  200. var index = 0;
  201. for (p in this.parameters) {
  202. if (parametersValues.length <= index) break;
  203. if (p.id != parametersValues[index].id) {
  204. continue;
  205. }
  206. p.defaultValue = parametersValues[index].defaultValue;
  207. index++;
  208. }
  209. }
  210. override public function saveProperties() : Dynamic {
  211. var parametersValues = [];
  212. for (p in this.parameters) {
  213. if (p.defaultValue != null) {
  214. parametersValues.push({id: p.id, defaultValue : p.defaultValue});
  215. }
  216. }
  217. var properties = {
  218. pathShaderGraph: this.pathShaderGraph,
  219. parametersValues : parametersValues
  220. };
  221. return properties;
  222. }
  223. #if editor
  224. override public function getPropertiesHTML(width : Float) : Array<hide.Element> {
  225. var elements = super.getPropertiesHTML(width);
  226. for (p in parameters) {
  227. var element = new hide.Element('<div class="propertySubShader" style="width: 200px;"></div>');
  228. element.on("mousedown", function(e) {
  229. e.stopPropagation();
  230. });
  231. switch (p.type) {
  232. case TBool:
  233. new hide.Element('<span>${p.name}</span>').appendTo(element);
  234. var inputBool = new hide.Element('<input type="checkbox" id="value" />').appendTo(element);
  235. inputBool.on("change", function(e) {
  236. p.defaultValue = (inputBool.is(":checked")) ? true : false;
  237. });
  238. if (p.defaultValue) {
  239. inputBool.prop("checked", true);
  240. }
  241. element.css("height", 20);
  242. case TFloat:
  243. new hide.Element('<span>${p.name}</span>').appendTo(element);
  244. var parentRange = new hide.Element('<input type="range" min="-1" max="1" value="" />').appendTo(element);
  245. var range = new hide.comp.Range(null, parentRange);
  246. var rangeInput = @:privateAccess range.f;
  247. rangeInput.on("mousedown", function(e) {
  248. e.stopPropagation();
  249. });
  250. rangeInput.on("mouseup", function(e) {
  251. e.stopPropagation();
  252. });
  253. parentRange.parent().css("width", 50);
  254. if (p.defaultValue != null) {
  255. range.value = p.defaultValue;
  256. }
  257. range.onChange = function(moving) {
  258. p.defaultValue = range.value;
  259. };
  260. element.css("height", 40);
  261. case TVec(4, VFloat):
  262. new hide.Element('<span>${p.name}</span>').appendTo(element);
  263. var inputColor = new hide.comp.ColorPicker(true, element);
  264. if (p.defaultValue != null) {
  265. var start = h3d.Vector.fromArray([p.defaultValue.x, p.defaultValue.y, p.defaultValue.z, p.defaultValue.w]);
  266. inputColor.value = start.toColor();
  267. }
  268. inputColor.onChange = function(move) {
  269. var vec = h3d.Vector.fromColor(inputColor.value);
  270. p.defaultValue = vec;
  271. };
  272. element.css("height", 25);
  273. default:
  274. }
  275. elements.push(element);
  276. }
  277. return elements;
  278. }
  279. #end
  280. }