Logic.hx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. package arm.node;
  2. import zui.Nodes;
  3. class Logic {
  4. static var nodes: Array<TNode>;
  5. static var links: Array<TNodeLink>;
  6. static var parsed_nodes: Array<String> = null;
  7. static var parsed_labels: Map<String, String> = null;
  8. static var nodeMap: Map<String, LogicNode>;
  9. public static var packageName = "arm.node.logic";
  10. public static function getNode(id: Int): TNode {
  11. for (n in nodes) if (n.id == id) return n;
  12. return null;
  13. }
  14. public static function getLink(id: Int): TNodeLink {
  15. for (l in links) if (l.id == id) return l;
  16. return null;
  17. }
  18. public static function getInputLink(inp: TNodeSocket): TNodeLink {
  19. for (l in links) {
  20. if (l.to_id == inp.node_id) {
  21. var node = getNode(inp.node_id);
  22. if (node.inputs.length <= l.to_socket) return null;
  23. if (node.inputs[l.to_socket] == inp) return l;
  24. }
  25. }
  26. return null;
  27. }
  28. public static function getOutputLinks(out: TNodeSocket): Array<TNodeLink> {
  29. var res: Array<TNodeLink> = [];
  30. for (l in links) {
  31. if (l.from_id == out.node_id) {
  32. var node = getNode(out.node_id);
  33. if (node.outputs.length <= l.from_socket) continue;
  34. if (node.outputs[l.from_socket] == out) res.push(l);
  35. }
  36. }
  37. return res;
  38. }
  39. static function safesrc(s:String):String {
  40. return StringTools.replace(s, " ", "");
  41. }
  42. static function node_name(node: TNode): String {
  43. var s = safesrc(node.name) + node.id;
  44. return s;
  45. }
  46. static var tree: LogicTree;
  47. public static function parse(canvas: TNodeCanvas, onAdd = true): LogicTree {
  48. nodes = canvas.nodes;
  49. links = canvas.links;
  50. parsed_nodes = [];
  51. parsed_labels = new Map();
  52. nodeMap = new Map();
  53. var root_nodes = get_root_nodes(canvas);
  54. tree = new LogicTree();
  55. if (onAdd) {
  56. tree.notifyOnAdd(function() {
  57. for (node in root_nodes) build_node(node);
  58. });
  59. }
  60. else {
  61. for (node in root_nodes) build_node(node);
  62. }
  63. return tree;
  64. }
  65. static function build_node(node: TNode): String {
  66. // Get node name
  67. var name = node_name(node);
  68. // Check if node already exists
  69. if (parsed_nodes.indexOf(name) != -1) {
  70. return name;
  71. }
  72. parsed_nodes.push(name);
  73. // Create node
  74. var v = createClassInstance(node.type, [tree]);
  75. nodeMap.set(name, v);
  76. // Expose button values in node class
  77. for (b in node.buttons) {
  78. if (b.type == "ENUM") {
  79. var arrayData = Std.is(b.data, Array);
  80. var texts = arrayData ? b.data : Nodes.enumTexts(node.type);
  81. Reflect.setProperty(v, b.name, texts[b.default_value]);
  82. }
  83. else {
  84. Reflect.setProperty(v, b.name, b.default_value);
  85. }
  86. }
  87. // Create inputs
  88. var inp_node: LogicNode = null;
  89. var inp_from = 0;
  90. for (i in 0...node.inputs.length) {
  91. var inp = node.inputs[i];
  92. // Is linked - find node
  93. var l = getInputLink(inp);
  94. if (l != null) {
  95. var n = getNode(l.from_id);
  96. var socket = n.outputs[l.from_socket];
  97. inp_node = nodeMap.get(build_node(n));
  98. for (i in 0...n.outputs.length) {
  99. if (n.outputs[i] == socket) {
  100. inp_from = i;
  101. break;
  102. }
  103. }
  104. }
  105. // Not linked - create node with default values
  106. else {
  107. inp_node = build_default_node(inp);
  108. inp_from = 0;
  109. }
  110. // Add input
  111. v.addInput(inp_node, inp_from);
  112. }
  113. // Create outputs
  114. for (out in node.outputs) {
  115. var outNodes:Array<LogicNode> = [];
  116. var ls = getOutputLinks(out);
  117. if (ls != null && ls.length > 0) {
  118. for (l in ls) {
  119. var n = getNode(l.to_id);
  120. var out_name = build_node(n);
  121. outNodes.push(nodeMap.get(out_name));
  122. }
  123. }
  124. // Not linked - create node with default values
  125. else {
  126. outNodes.push(build_default_node(out));
  127. }
  128. // Add outputs
  129. v.addOutputs(outNodes);
  130. }
  131. return name;
  132. }
  133. static function get_root_nodes(node_group: TNodeCanvas): Array<TNode> {
  134. var roots: Array<TNode> = [];
  135. for (node in node_group.nodes) {
  136. // if (node.bl_idname == 'NodeUndefined') {
  137. // arm.log.warn('Undefined logic nodes in ' + node_group.name)
  138. // return []
  139. // }
  140. var linked = false;
  141. for (out in node.outputs) {
  142. var ls = getOutputLinks(out);
  143. if (ls != null && ls.length > 0) {
  144. linked = true;
  145. break;
  146. }
  147. }
  148. if (!linked) { // Assume node with no connected outputs as roots
  149. roots.push(node);
  150. }
  151. }
  152. return roots;
  153. }
  154. static function build_default_node(inp: TNodeSocket): LogicNode {
  155. var v: LogicNode = null;
  156. if (inp.type == "OBJECT") {
  157. v = createClassInstance("ObjectNode", [tree, inp.default_value]);
  158. }
  159. else if (inp.type == "ANIMACTION") {
  160. v = createClassInstance("StringNode", [tree, inp.default_value]);
  161. }
  162. else if (inp.type == "VECTOR") {
  163. if (inp.default_value == null) inp.default_value = [0, 0, 0]; // TODO
  164. v = createClassInstance("VectorNode", [tree, inp.default_value[0], inp.default_value[1], inp.default_value[2]]);
  165. }
  166. else if (inp.type == "RGBA") {
  167. if (inp.default_value == null) inp.default_value = [0, 0, 0]; // TODO
  168. v = createClassInstance("ColorNode", [tree, inp.default_value[0], inp.default_value[1], inp.default_value[2], inp.default_value[3]]);
  169. }
  170. else if (inp.type == "RGB") {
  171. if (inp.default_value == null) inp.default_value = [0, 0, 0]; // TODO
  172. v = createClassInstance("ColorNode", [tree, inp.default_value[0], inp.default_value[1], inp.default_value[2]]);
  173. }
  174. else if (inp.type == "VALUE") {
  175. v = createClassInstance("FloatNode", [tree, inp.default_value]);
  176. }
  177. else if (inp.type == "INT") {
  178. v = createClassInstance("IntegerNode", [tree, inp.default_value]);
  179. }
  180. else if (inp.type == "BOOLEAN") {
  181. v = createClassInstance("BooleanNode", [tree, inp.default_value]);
  182. }
  183. else if (inp.type == "STRING") {
  184. v = createClassInstance("StringNode", [tree, inp.default_value]);
  185. }
  186. else { // ACTION, ARRAY
  187. v = createClassInstance("NullNode", [tree]);
  188. }
  189. return v;
  190. }
  191. static function createClassInstance(className: String, args: Array<Dynamic>): Dynamic {
  192. var cname = Type.resolveClass(packageName + "." + className);
  193. if (cname == null) return null;
  194. return Type.createInstance(cname, args);
  195. }
  196. }