xForm_definitions.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. import bpy
  2. from .base_definitions import xFormNode
  3. from bpy.types import Node
  4. from mantis.utilities import (prRed, prGreen, prPurple, prWhite,
  5. prOrange,
  6. wrapRed, wrapGreen, wrapPurple, wrapWhite,
  7. wrapOrange,)
  8. from .base_definitions import get_signature_from_edited_tree, get_is_name_unique
  9. def TellClasses():
  10. return [
  11. # xFormNullNode,
  12. xFormBoneNode,
  13. xFormRootNode,
  14. xFormArmatureNode,
  15. xFormGeometryObjectNode,
  16. ]
  17. def default_traverse(self, socket):
  18. if (socket == self.outputs["xForm Out"]):
  19. return self.inputs["Relationship"]
  20. if (socket == self.inputs["Relationship"]):
  21. return self.outputs["xForm Out"]
  22. return None
  23. # Representing an Empty or non-armature-Object
  24. # class xFormNullNode(Node, xFormNode):
  25. # '''A node representing a Null node'''
  26. # bl_idname = 'xFormNullNode'
  27. # bl_label = "Null"
  28. # bl_icon = 'EMPTY_AXIS'
  29. # # === Optional Functions ===
  30. # def init(self, context):
  31. # self.inputs.new('StringSocket', "Name")
  32. # self.inputs.new('RelationshipSocket', "Relationship")
  33. # self.inputs.new('RotationOrderSocket', "Rotation Order")
  34. # self.inputs.new('MatrixSocket', "Matrix")
  35. # self.outputs.new('xFormSocket', "xForm Out")
  36. def check_if_connected(start, end, line):
  37. started=False
  38. for path_nc in line:
  39. prWhite(" ", path_nc.signature)
  40. if path_nc.signature == start.signature:
  41. started = True
  42. elif path_nc.signature == end.signature:
  43. break
  44. if started:
  45. if path_nc.inputs.get("Connected"):
  46. if path_nc.evaluate_input("Connected") == False:
  47. return False
  48. else:
  49. return False
  50. return True
  51. class xFormRootNode(Node, xFormNode):
  52. '''A node representing the world node'''
  53. bl_idname = 'xFormRootNode'
  54. bl_label = "World Root"
  55. bl_icon = 'WORLD'
  56. def init(self, context):
  57. self.outputs.new('RelationshipSocket', "World Out")
  58. class xFormBoneNode(Node, xFormNode):
  59. '''A node representing a Bone'''
  60. bl_idname = 'xFormBoneNode'
  61. bl_label = "Bone"
  62. bl_icon = 'BONE_DATA'
  63. display_ik_settings : bpy.props.BoolProperty(default=False)
  64. display_vp_settings : bpy.props.BoolProperty(default=False)
  65. display_def_settings : bpy.props.BoolProperty(default=False)
  66. socket_count : bpy.props.IntProperty() # not needed anymore, right?
  67. error : bpy.props.BoolProperty(default=False)
  68. error_msg : bpy.props.StringProperty(default="")
  69. error_icon : bpy.props.StringProperty(default="NONE")
  70. def init(self, context):
  71. context = bpy.context
  72. if context.space_data:
  73. node_tree = context.space_data.path[0].node_tree
  74. from mantis import readtree
  75. prOrange("Updating from xFormBone init callback")
  76. node_tree.update_tree(context)
  77. self.inputs.new('StringSocket', "Name")
  78. self.inputs.new('RotationOrderSocket', "Rotation Order")
  79. self.inputs.new('RelationshipSocket', "Relationship")
  80. self.inputs.new('MatrixSocket', "Matrix")
  81. # IK SETTINGS
  82. a = []
  83. # a.append(self.inputs.new ('LabelSocket', "IK Settings"))
  84. a.append(self.inputs.new ('FloatFactorSocket', "IK Stretch"))
  85. a.append(self.inputs.new ('BooleanThreeTupleSocket', "Lock IK"))
  86. a.append(self.inputs.new ('NodeSocketVector', "IK Stiffness"))
  87. a.append(self.inputs.new ('BooleanThreeTupleSocket', "Limit IK"))
  88. a.append(self.inputs.new ('NodeSocketFloatAngle', "X Min"))
  89. a.append(self.inputs.new ('NodeSocketFloatAngle', "X Max"))
  90. a.append(self.inputs.new ('NodeSocketFloatAngle', "Y Min"))
  91. a.append(self.inputs.new ('NodeSocketFloatAngle', "Y Max"))
  92. a.append(self.inputs.new ('NodeSocketFloatAngle', "Z Min"))
  93. a.append(self.inputs.new ('NodeSocketFloatAngle', "Z Max"))
  94. #4-14
  95. # visual settings:
  96. b = []
  97. b.append(self.inputs.new ('LayerMaskSocket', "Layer Mask"))
  98. b.append(self.inputs.new ('xFormSocket', "Custom Object"))
  99. b.append(self.inputs.new ('xFormSocket', "Custom Object xForm Override"))
  100. b.append(self.inputs.new ('BooleanSocket', "Custom Object Scale to Bone Length"))
  101. b.append(self.inputs.new ('BooleanSocket', "Custom Object Wireframe"))
  102. b.append(self.inputs.new ('VectorScaleSocket', "Custom Object Scale"))
  103. b.append(self.inputs.new ('VectorSocket', "Custom Object Translation"))
  104. b.append(self.inputs.new ('VectorEulerSocket', "Custom Object Rotation"))
  105. b.append(self.inputs.new ('StringSocket', "Bone Group"))
  106. # 16-22
  107. # Deform Settings:
  108. c = []
  109. c.append(self.inputs.new ('BooleanSocket', "Deform"))
  110. c.append(self.inputs.new ('FloatPositiveSocket', "Envelope Distance"))
  111. c.append(self.inputs.new ('FloatFactorSocket', "Envelope Weight"))
  112. c.append(self.inputs.new ('BooleanSocket', "Envelope Multiply"))
  113. c.append(self.inputs.new ('FloatPositiveSocket', "Envelope Head Radius"))
  114. c.append(self.inputs.new ('FloatPositiveSocket', "Envelope Tail Radius"))
  115. #24-28
  116. # c[0].default_value=False
  117. # Hide should be last
  118. b.append(self.inputs.new ('HideSocket', "Hide"))
  119. for sock in a:
  120. sock.hide = True
  121. for sock in b:
  122. if sock.name in ['Custom Object', 'Layer Mask']:
  123. continue
  124. sock.hide = True
  125. for sock in c:
  126. if sock.name == 'Deform':
  127. continue
  128. sock.hide = True
  129. # Thinking about using colors for nodes, why not?
  130. # cxForm = (0.443137, 0.242157, 0.188235,) #could even fetch the theme colors...
  131. # self.color=cxForm
  132. # self.use_custom_color=True
  133. self.socket_count = len(self.inputs)
  134. #
  135. self.outputs.new('xFormSocket', "xForm Out")
  136. def draw_buttons(self, context, layout):
  137. layout.label(text=self.error_msg, icon = self.error_icon)
  138. layout.operator("mantis.add_custom_property", text='+Add Custom Parameter')
  139. # layout.label(text="Edit Parameter ... not implemented")
  140. if (len(self.inputs) > self.socket_count):
  141. layout.operator("mantis.remove_custom_property", text='-Remove Custom Parameter')
  142. else:
  143. layout.label(text="")
  144. # def draw_label(self):
  145. # if not self.error:
  146. # return self.label
  147. # else:
  148. # return self.error_msg
  149. def display_update(self, parsed_tree, context):
  150. errors = []
  151. self.error_msg = ""
  152. self.error_icon = "NONE"
  153. self.error=False
  154. if context.space_data:
  155. node_tree = context.space_data.path[0].node_tree
  156. nc = parsed_tree.get(get_signature_from_edited_tree(self, context))
  157. other_nc = None
  158. if len(self.inputs.get("Relationship").links)>0:
  159. prev_node = self.inputs.get("Relationship").links[0].from_node
  160. if prev_node:
  161. other_nc = parsed_tree.get(get_signature_from_edited_tree(prev_node, context))
  162. if nc and other_nc:
  163. self.display_vp_settings = nc.inputs["Custom Object"].is_connected
  164. self.display_def_settings = nc.evaluate_input("Deform")
  165. self.display_ik_settings = False
  166. #
  167. from .node_container_common import ( trace_all_lines_up,
  168. trace_single_line)
  169. trace = trace_all_lines_up(nc, "xForm Out")
  170. for key in trace.keys():
  171. if (ik_nc:= parsed_tree.get(key)):
  172. if ik_nc.__class__.__name__ in ["LinkInverseKinematics"]:
  173. # if the tree is invalid? This shouldn't be necessary.
  174. if ik_nc.inputs["Input Relationship"].is_connected:
  175. chain_count = ik_nc.evaluate_input("Chain Length")
  176. if chain_count == 0:
  177. self.display_ik_settings = True
  178. else:
  179. if ik_nc.evaluate_input("Use Tail") == False:
  180. chain_count+=1
  181. for line in trace[key]:
  182. # preprocess it to get rid of non-xForms:
  183. xForm_line=[]
  184. for path_nc in line:
  185. if path_nc == ik_nc:
  186. if ik_nc.inputs["Input Relationship"].links[0].from_node != prev_path_nc:
  187. break # not a constraint connection
  188. if path_nc.node_type == 'XFORM':
  189. xForm_line.append(path_nc)
  190. prev_path_nc = path_nc
  191. else:
  192. if len(xForm_line) < chain_count:
  193. self.display_ik_settings = True
  194. inp = nc.inputs["Relationship"]
  195. link = None
  196. if inp.is_connected:
  197. link = inp.links[0]
  198. while(link):
  199. if link.from_node.__class__.__name__ in ["LinkInverseKinematics"]:
  200. self.display_ik_settings = link.from_node.evaluate_input("Use Tail")
  201. break
  202. inp = link.from_node.outputs[link.from_socket]
  203. inp = inp.traverse_target
  204. if not inp:
  205. break
  206. if inp.links:
  207. link = inp.links[0]
  208. else:
  209. link = None
  210. if get_is_name_unique(nc, parsed_tree) == False:
  211. errors.append("Bone name is not unique.")
  212. self.error_icon = "ERROR"
  213. self.color=(1.0,0.0,0.0)
  214. self.error=True
  215. else:
  216. errors.append("Bone is not connected to the tree.")
  217. self.color=(0.7,0.35,0.0)
  218. self.error_icon = "CANCEL"
  219. self.error=True
  220. #
  221. if self.display_ik_settings == True:
  222. for inp in self.inputs[4:14]:
  223. inp.hide = False
  224. else:
  225. for inp in self.inputs[4:14]:
  226. inp.hide = True
  227. if self.display_vp_settings == True:
  228. for inp in self.inputs[16:22]:
  229. inp.hide = False
  230. else:
  231. for inp in self.inputs[16:22]:
  232. inp.hide = True
  233. #
  234. if self.display_def_settings == True:
  235. for inp in self.inputs[24:29]:
  236. inp.hide = False
  237. else:
  238. for inp in self.inputs[24:29]:
  239. inp.hide = True
  240. if self.error:
  241. print (errors)
  242. self.use_custom_color=True
  243. self.error_msg= " and ".join(errors)
  244. else:
  245. self.color=(0.3,0.3,0.3)
  246. self.use_custom_color=False
  247. # def copy(ectype, archtype):
  248. # tree = ectype.id_data.parsed_tree
  249. # n = get_unique_name(ectype.name, tree)
  250. # ectype.name = "boink!"
  251. # # TODO: automatically avoid duplicating names
  252. # ectype.inputs["Name"].default_value = ""
  253. class xFormArmatureNode(Node, xFormNode):
  254. '''A node representing an Armature object node'''
  255. bl_idname = 'xFormArmatureNode'
  256. bl_label = "Armature"
  257. bl_icon = 'OUTLINER_OB_ARMATURE'
  258. def init(self, context):
  259. self.inputs.new('StringSocket', "Name")
  260. self.inputs.new('RelationshipSocket', "Relationship")
  261. self.inputs.new('RotationOrderSocket', "Rotation Order")
  262. self.inputs.new('MatrixSocket', "Matrix")
  263. self.outputs.new('xFormSocket', "xForm Out")
  264. class xFormGeometryObjectNode(Node, xFormNode):
  265. """Represents a curve or mesh object."""
  266. bl_idname = "xFormGeometryObject"
  267. bl_label = "Geometry Object"
  268. bl_icon = "EMPTY_AXIS"
  269. def init(self, context):
  270. self.inputs.new('StringSocket', "Name")
  271. self.inputs.new('GeometrySocket', "Geometry")
  272. self.inputs.new('MatrixSocket', "Matrix")
  273. self.inputs.new('RelationshipSocket', "Relationship")
  274. self.outputs.new('xFormSocket', "xForm Out")