xForm_nodes_ui.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. import bpy
  2. from .base_definitions import xFormNode
  3. from bpy.types import Node
  4. from .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
  9. from .xForm_socket_templates import *
  10. def TellClasses():
  11. return [
  12. # xFormNullNode,
  13. xFormBoneNode,
  14. xFormArmatureNode,
  15. xFormGeometryObjectNode,
  16. xFormObjectInstance,
  17. xFormCurvePin,
  18. xFormGetBone,
  19. ]
  20. def default_traverse(self, socket):
  21. if (socket == self.outputs["xForm Out"]):
  22. return self.inputs["Relationship"]
  23. if (socket == self.inputs["Relationship"]):
  24. return self.outputs["xForm Out"]
  25. return None
  26. # Representing an Empty or non-armature-Object
  27. # class xFormNullNode(Node, xFormNode):
  28. # '''A node representing a Null node'''
  29. # bl_idname = 'xFormNullNode'
  30. # bl_label = "Null"
  31. # bl_icon = 'EMPTY_AXIS'
  32. # # === Optional Functions ===
  33. # def init(self, context):
  34. # self.inputs.new('StringSocket', "Name")
  35. # self.inputs.new('RelationshipSocket', "Relationship")
  36. # self.inputs.new('RotationOrderSocket', "Rotation Order")
  37. # self.inputs.new('MatrixSocket', "Matrix")
  38. # self.outputs.new('xFormSocket', "xForm Out")
  39. def check_if_connected(start, end, line):
  40. started=False
  41. for path_mantis_node in line:
  42. prWhite(" ", path_mantis_node.signature)
  43. if path_mantis_node.signature == start.signature:
  44. started = True
  45. elif path_mantis_node.signature == end.signature:
  46. break
  47. if started:
  48. if path_mantis_node.inputs.get("Connected"):
  49. if path_mantis_node.evaluate_input("Connected") == False:
  50. return False
  51. else:
  52. return False
  53. return True
  54. def main_draw_label(self): # this will prefer a user-set label, or return the evaluated name
  55. if self.label:
  56. return self.label
  57. if self.inputs['Name'].display_text:
  58. return self.inputs['Name'].display_text
  59. return self.name
  60. def custom_prop_display_update(self, mantis_node = None):
  61. custom_props = {}
  62. type_map = {
  63. 'BOOL' : 'ParameterBoolSocket',
  64. 'INT' : 'ParameterIntSocket',
  65. 'FLOAT' : 'ParameterFloatSocket',
  66. 'VECTOR' : 'ParameterVectorSocket',
  67. 'STRING' : 'ParameterStringSocket',
  68. }
  69. cant_read=0
  70. if not mantis_node:
  71. links = [link for link in self.inputs['Custom Properties'].links]
  72. links.sort(key=lambda a : -a.multi_input_sort_id)
  73. for link in links:
  74. if link.from_node.bl_idname == 'UtilityCustomProperty':
  75. if (link.from_node.inputs['Name'].is_linked or
  76. link.from_node.inputs['Type'].is_linked):
  77. cant_read+=1 # we can't eval this without the Mantis data
  78. continue # but we need to count it
  79. else:
  80. custom_props[link.from_node.inputs['Name'].default_value] = \
  81. type_map[link.from_node.inputs['Type'].default_value]
  82. else:
  83. cant_read+=1
  84. for name, type in custom_props.items():
  85. if self.outputs.get(name): continue # already there
  86. else:
  87. self.outputs.new(type, name)
  88. else:
  89. from .misc_nodes import UtilityCustomProperty
  90. from .mantis_dataclasses import custom_prop_template
  91. mantis_node.inputs['Custom Properties'].flush_links() # clean/sort the links
  92. if len(mantis_node.inputs['Custom Properties'].links) != len(self.inputs['Custom Properties'].links):
  93. return # there is a problem somewhere
  94. for i, link in enumerate(mantis_node.inputs['Custom Properties'].links):
  95. from .node_common import trace_single_line
  96. node_line, _last_socket = trace_single_line(mantis_node, 'Custom Properties', i)
  97. if not node_line[-1].prepared:
  98. return
  99. custom_prop_data = mantis_node.evaluate_input('Custom Property', i)
  100. if isinstance(node_line[-1], UtilityCustomProperty) and \
  101. not isinstance(custom_prop_data, custom_prop_template):
  102. return
  103. elif not isinstance(custom_prop_data, custom_prop_template):
  104. continue # wrong connection
  105. name = custom_prop_data.name
  106. type = custom_prop_data.prop_type
  107. custom_props[name] = type_map[type]
  108. from .utilities import get_socket_maps, do_relink
  109. _socket_map_in, socket_map_out = get_socket_maps(self)
  110. for name, type in custom_props.items():
  111. if socket_map_out.get(name) is None:
  112. socket_map_out[name] = None # initialize the new ones
  113. # remove and replace sockets
  114. if cant_read == 0:
  115. remove_me = self.outputs[1:]
  116. while remove_me:
  117. remove_socket = remove_me.pop()
  118. self.outputs.remove(remove_socket)
  119. for name, type in custom_props.items():
  120. socket = self.outputs.new(type, name)
  121. do_relink(self, socket, socket_map_out, in_out='OUTPUT')
  122. from mathutils import Color
  123. xFormColor = Color((0.093172, 0.047735, 0.028036)).from_scene_linear_to_srgb()
  124. class xFormBoneNode(Node, xFormNode):
  125. '''A node representing a Bone'''
  126. bl_idname = 'xFormBoneNode'
  127. bl_label = "Bone"
  128. bl_icon = 'BONE_DATA'
  129. display_ik_settings : bpy.props.BoolProperty(default=False)
  130. display_vp_settings : bpy.props.BoolProperty(default=False)
  131. display_def_settings : bpy.props.BoolProperty(default=False)
  132. display_bb_settings : bpy.props.BoolProperty(default=False)
  133. socket_count : bpy.props.IntProperty()
  134. initialized : bpy.props.BoolProperty(default = False)
  135. mantis_node_class_name=bl_idname[:-4]
  136. socket_templates = xFormBoneSockets
  137. def init(self, context):
  138. self.init_sockets(self.__class__.socket_templates)
  139. self.socket_count = len(self.inputs)
  140. self.use_custom_color = True
  141. self.color = xFormColor
  142. self.initialized=True
  143. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  144. return main_draw_label(self)
  145. def display_update(self, parsed_tree, context):
  146. # let's setup the outputs for the custom properties:
  147. # we'll start by trying to do it without the special mantis data
  148. if self.id_data.mantis_version[1] < 13: return #or the old custom properties will get wiped.
  149. custom_prop_display_update(self)
  150. if context.space_data:
  151. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  152. if mantis_node and mantis_node.prepared:
  153. custom_prop_display_update(self, mantis_node)
  154. self.display_ik_settings = False
  155. if mantis_node and (pb := mantis_node.bGetObject(mode='POSE')):
  156. self.display_ik_settings = pb.is_in_ik_chain
  157. self.inputs['Name'].display_text = ""
  158. if mantis_node and mantis_node.prepared:
  159. try:
  160. self.inputs['Name'].display_text = mantis_node.evaluate_input("Name")
  161. self.display_vp_settings = mantis_node.inputs["Custom Object"].is_connected
  162. self.display_def_settings = mantis_node.evaluate_input("Deform")
  163. self.display_bb_settings = mantis_node.evaluate_input("BBone Segments") > 1
  164. except KeyError:
  165. return # the tree isn't ready yet.
  166. for template in self.socket_templates:
  167. name = template.name
  168. category = template.category
  169. if category == "IK":
  170. self.inputs[name].hide = not self.display_ik_settings
  171. if category == "Display":
  172. if name in ['Custom Object', 'Bone Collection']: continue
  173. self.inputs[name].hide = not self.display_vp_settings
  174. if category == "Deform":
  175. if name in ['Deform']: continue
  176. self.inputs[name].hide = not self.display_def_settings
  177. if category == "bbone":
  178. if name in ['BBone Segments']: continue
  179. self.inputs[name].hide = not self.display_bb_settings
  180. def object_displaty_update(self, parsed_tree, context):
  181. custom_prop_display_update(self)
  182. if context.space_data:
  183. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  184. self.inputs['Name'].display_text = ""
  185. if mantis_node and mantis_node.prepared:
  186. self.inputs['Name'].display_text = mantis_node.evaluate_input("Name")
  187. custom_prop_display_update(self, mantis_node)
  188. class xFormArmatureNode(Node, xFormNode):
  189. '''A node representing an Armature object node'''
  190. bl_idname = 'xFormArmatureNode'
  191. bl_label = "Armature"
  192. bl_icon = 'OUTLINER_OB_ARMATURE'
  193. initialized : bpy.props.BoolProperty(default = False)
  194. mantis_node_class_name=bl_idname[:-4]
  195. def init(self, context):
  196. self.init_sockets(xFormArmatureSockets)
  197. self.use_custom_color = True
  198. self.color = xFormColor
  199. self.initialized=True
  200. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  201. return main_draw_label(self)
  202. def display_update(self, parsed_tree, context):
  203. object_displaty_update(self, parsed_tree, context)
  204. class xFormGeometryObjectNode(Node, xFormNode):
  205. """Represents a curve or mesh object."""
  206. bl_idname = "xFormGeometryObject"
  207. bl_label = "Geometry Object"
  208. bl_icon = "EMPTY_AXIS"
  209. initialized : bpy.props.BoolProperty(default = False)
  210. mantis_node_class_name=bl_idname
  211. def init(self, context):
  212. self.init_sockets(xFormGeometryObjectSockets)
  213. self.use_custom_color = True
  214. self.color = xFormColor
  215. self.initialized=True
  216. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  217. return main_draw_label(self)
  218. def display_update(self, parsed_tree, context):
  219. object_displaty_update(self, parsed_tree, context)
  220. class xFormObjectInstance(Node, xFormNode):
  221. """Represents an instance of an existing geometry object."""
  222. bl_idname = "xFormObjectInstance"
  223. bl_label = "Object Instance"
  224. bl_icon = "EMPTY_AXIS"
  225. initialized : bpy.props.BoolProperty(default = False)
  226. mantis_node_class_name=bl_idname
  227. def init(self, context):
  228. self.init_sockets(xFormGeometryObjectInstanceSockets)
  229. self.use_custom_color = True
  230. self.color = xFormColor
  231. self.initialized=True
  232. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  233. return main_draw_label(self)
  234. def display_update(self, parsed_tree, context):
  235. object_displaty_update(self, parsed_tree, context)
  236. from .xForm_nodes import xFormCurvePinSockets
  237. class xFormCurvePin(Node, xFormNode):
  238. """"A node representing a curve pin"""
  239. bl_idname = "xFormCurvePin"
  240. bl_label = "Curve Pin"
  241. bl_icon = "FORCE_CURVE"
  242. initialized : bpy.props.BoolProperty(default = False)
  243. mantis_node_class_name=bl_idname
  244. def init(self, context):
  245. self.init_sockets(xFormCurvePinSockets)
  246. self.use_custom_color = True
  247. self.color = xFormColor
  248. self.initialized = True
  249. class xFormGetBone(Node, xFormNode):
  250. """"A node representing an existing bone"""
  251. bl_idname = "xFormGetBone"
  252. bl_label = "Existing Bone"
  253. bl_icon = "BONE_DATA"
  254. initialized : bpy.props.BoolProperty(default = False)
  255. armature : bpy.props.StringProperty(default="")
  256. mantis_node_class_name=bl_idname
  257. def init(self, context):
  258. self.init_sockets(xFormGetBoneSockets)
  259. self.use_custom_color = True
  260. self.color = xFormColor
  261. self.initialized = True
  262. def display_update(self, parsed_tree, context):
  263. if context.space_data:
  264. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  265. if mantis_node:
  266. # need this parent armature to use the bone picker.
  267. self.inputs["Bone"].armature = mantis_node.bGetParentArmature()
  268. for cls in TellClasses():
  269. cls.set_mantis_class()