ShaderGraph.hx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package hrt.shgraph;
  2. using hxsl.Ast;
  3. private typedef Node = {
  4. x : Float,
  5. y : Float,
  6. comment : String,
  7. id : Int,
  8. type : String,
  9. ?parameters : Dynamic,
  10. ?instance : ShaderNode
  11. };
  12. private typedef Edge = {
  13. idOutput : Int,
  14. nameOutput : String,
  15. idInput : Int,
  16. nameInput : String
  17. };
  18. class ShaderGraph {
  19. var id = 0;
  20. var filepath : String;
  21. var nodes : Map<Int, Node> = [];
  22. var allVariables : Array<TVar> = [];
  23. public function new(filepath : String) {
  24. if (filepath == null) return;
  25. this.filepath = filepath;
  26. var json;
  27. try {
  28. json = haxe.Json.parse(sys.io.File.getContent(this.filepath));
  29. } catch( e : Dynamic ) {
  30. throw "Invalid shader graph parsing ("+e+")";
  31. }
  32. generate(Reflect.getProperty(json, "nodes"), Reflect.getProperty(json, "edges"));
  33. }
  34. public function generate(nodes : Array<Node>, edges : Array<Edge>) {
  35. for (n in nodes) {
  36. n.instance = std.Type.createInstance(std.Type.resolveClass(n.type), []);
  37. n.instance.loadParameters(n.parameters);
  38. n.instance.setId(n.id);
  39. this.nodes.set(n.id, n);
  40. }
  41. if (nodes[nodes.length-1] != null)
  42. this.id = nodes[nodes.length-1].id+1;
  43. for (e in edges) {
  44. addEdge(e);
  45. }
  46. }
  47. public function addNode(x : Float, y : Float, nameClass : Class<ShaderNode>) {
  48. var node : Node = { x : x, y : y, comment: "", id : id, type: std.Type.getClassName(nameClass) };
  49. id++;
  50. node.instance = std.Type.createInstance(nameClass, []);
  51. node.instance.createOutputs();
  52. this.nodes.set(node.id, node);
  53. return node.instance;
  54. }
  55. public function removeNode(idNode : Int) {
  56. this.nodes.remove(idNode);
  57. }
  58. public function addEdge(edge : Edge) {
  59. this.nodes.get(edge.idInput).instance.setInput(edge.nameInput, new NodeVar(this.nodes.get(edge.idOutput).instance, edge.nameOutput));
  60. this.nodes.get(edge.idInput).instance.createOutputs();
  61. }
  62. public function removeEdge(idNode, nameInput) {
  63. this.nodes.get(idNode).instance.setInput(nameInput, null);
  64. }
  65. public function setPosition(idNode : Int, x : Float, y : Float) {
  66. var node = this.nodes.get(idNode);
  67. node.x = x;
  68. node.y = y;
  69. }
  70. public function getNodes() {
  71. return this.nodes;
  72. }
  73. function buildNodeVar(nodeVar : NodeVar) : Array<TExpr>{
  74. var node = nodeVar.node;
  75. if (node == null)
  76. return [];
  77. var res = [];
  78. var inputs = node.getInputs();
  79. for (k in inputs) {
  80. res = res.concat(buildNodeVar(k));
  81. }
  82. var build = nodeVar.getExpr();
  83. res = res.concat(build);
  84. return res;
  85. }
  86. static function alreadyAddVariable(array : Array<TVar>, variable : TVar) {
  87. for (v in array) {
  88. if (v.name == variable.name && v.type == variable.type) {
  89. return true;
  90. }
  91. }
  92. return false;
  93. }
  94. public function buildFragment() : ShaderData {
  95. allVariables = [];
  96. var content = [];
  97. for (n in nodes) {
  98. n.instance.outputCompiled = [];
  99. }
  100. for (n in nodes) {
  101. if (Std.is(n.instance, ShaderInput)) {
  102. var variable = Std.instance(n.instance, ShaderInput).variable;
  103. if ((variable.kind == Param || variable.kind == Global || variable.kind == Input) && !alreadyAddVariable(allVariables, variable)) {
  104. allVariables.push(variable);
  105. }
  106. }
  107. if (Std.is(n.instance, ShaderOutput)) {
  108. var variable = Std.instance(n.instance, ShaderOutput).variable;
  109. if ( !alreadyAddVariable(allVariables, variable) ) {
  110. allVariables.push(variable);
  111. }
  112. var nodeVar = new NodeVar(n.instance, "input");
  113. content = content.concat(buildNodeVar(nodeVar));
  114. }
  115. }
  116. return {
  117. funs : [{
  118. ret : TVoid, kind : Fragment,
  119. ref : {
  120. name : "fragment",
  121. id : 0,
  122. kind : Function,
  123. type : TFun([{ ret : TVoid, args : [] }])
  124. },
  125. expr : {
  126. p : null,
  127. t : TVoid,
  128. e : TBlock(content)
  129. },
  130. args : []
  131. }],
  132. name: "MON_FRAGMENT",
  133. vars: allVariables
  134. };
  135. }
  136. public function save() {
  137. var edgesJson : Array<Edge> = [];
  138. for (n in nodes) {
  139. for (k in n.instance.getInputsKey()) {
  140. var output = n.instance.getInput(k);
  141. edgesJson.push({ idOutput: output.node.id, nameOutput: output.keyOutput, idInput: n.id, nameInput: k });
  142. }
  143. }
  144. var json = haxe.Json.stringify({
  145. nodes: [
  146. for (n in nodes) { x : n.x, y : n.y, comment: n.comment, id: n.id, type: n.type, parameters : n.instance.saveParameters() }
  147. ],
  148. edges: edgesJson
  149. });
  150. sys.io.File.saveContent(this.filepath, json);
  151. }
  152. }