xForm_definitions.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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. def TellClasses():
  10. return [
  11. # xFormNullNode,
  12. xFormBoneNode,
  13. xFormArmatureNode,
  14. xFormGeometryObjectNode,
  15. xFormObjectInstance,
  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. # I had chat gpt flip these so they may be a little innacurate
  52. # always visible
  53. main_names = {
  54. "Name":'StringSocket',
  55. "Rotation Order":'RotationOrderSocket',
  56. "Relationship":'RelationshipSocket',
  57. "Matrix":'MatrixSocket',}
  58. # IK SETTINGS
  59. ik_names = {
  60. "IK Stretch":'FloatFactorSocket',
  61. "Lock IK":'BooleanThreeTupleSocket',
  62. "IK Stiffness":'NodeSocketVector',
  63. "Limit IK":'BooleanThreeTupleSocket',
  64. "X Min":'NodeSocketFloatAngle',
  65. "X Max":'NodeSocketFloatAngle',
  66. "Y Min":'NodeSocketFloatAngle',
  67. "Y Max":'NodeSocketFloatAngle',
  68. "Z Min":'NodeSocketFloatAngle',
  69. "Z Max":'NodeSocketFloatAngle',
  70. }
  71. #display settings
  72. display_names = {
  73. "Bone Collection":'BoneCollectionSocket',
  74. "Custom Object":'xFormSocket',
  75. "Custom Object xForm Override":'xFormSocket',
  76. "Custom Object Scale to Bone Length":'BooleanSocket',
  77. "Custom Object Wireframe":'BooleanSocket',
  78. "Custom Object Scale":'VectorScaleSocket',
  79. "Custom Object Translation":'VectorSocket',
  80. "Custom Object Rotation":'VectorEulerSocket',
  81. }
  82. # deform_names
  83. deform_names = {
  84. "Deform":'BooleanSocket',
  85. "Envelope Distance":'FloatPositiveSocket',
  86. "Envelope Weight":'FloatFactorSocket',
  87. "Envelope Multiply":'BooleanSocket',
  88. "Envelope Head Radius":'FloatPositiveSocket',
  89. "Envelope Tail Radius":'FloatPositiveSocket',
  90. }
  91. bbone_names = {
  92. "BBone Segments":"IntSocket", # BONE
  93. "BBone X Size":"FloatSocket", # BONE
  94. "BBone Z Size":"FloatSocket", # BONE
  95. # "bbone_mapping_mode":"StringSocket", <== BONE
  96. "BBone HQ Deformation":"BooleanSocket", # BONE bbone_mapping_mode
  97. "BBone X Curve-In":"FloatSocket", # BONE AND POSE
  98. "BBone Z Curve-In":"FloatSocket", # BONE AND POSE
  99. "BBone X Curve-Out":"FloatSocket", # BONE AND POSE
  100. "BBone Z Curve-Out":"FloatSocket", # BONE AND POSE
  101. "BBone Roll-In":"FloatSocket", # BONE AND POSE
  102. "BBone Roll-Out":"FloatSocket", # BONE AND POSE
  103. "BBone Inherit End Roll":"BooleanSocket", # BONE
  104. "BBone Scale-In":"VectorSocket", # BONE AND POSE
  105. "BBone Scale-Out":"VectorSocket", # BONE AND POSE
  106. "BBone Ease-In":"FloatSocket", # BONE AND POSE
  107. "BBone Ease-Out":"FloatSocket", # BONE AND POSE
  108. "BBone Easing":"BooleanSocket", # BONE
  109. "BBone Start Handle Type":"EnumBBoneHandleType", # BONE
  110. "BBone Custom Start Handle":"StringSocket", # BONE
  111. "BBone Start Handle Scale":"BooleanThreeTupleSocket", # BONE
  112. "BBone Start Handle Ease":"BooleanSocket", # BONE
  113. "BBone End Handle Type":"EnumBBoneHandleType", # BONE
  114. "BBone Custom End Handle":"StringSocket", # BONE
  115. "BBone End Handle Scale":"BooleanThreeTupleSocket", # BONE
  116. "BBone End Handle Ease":"BooleanSocket", # BONE
  117. }
  118. other_names = {
  119. "Lock Location":'BooleanThreeTupleSocket',
  120. "Lock Rotation":'BooleanThreeTupleSocket',
  121. "Lock Scale":'BooleanThreeTupleSocket',
  122. "Hide":'HideSocket',
  123. }
  124. from mathutils import Color
  125. xFormColor = Color((0.093172, 0.047735, 0.028036)).from_scene_linear_to_srgb()
  126. class xFormBoneNode(Node, xFormNode):
  127. '''A node representing a Bone'''
  128. bl_idname = 'xFormBoneNode'
  129. bl_label = "Bone"
  130. bl_icon = 'BONE_DATA'
  131. display_ik_settings : bpy.props.BoolProperty(default=False)
  132. display_vp_settings : bpy.props.BoolProperty(default=False)
  133. display_def_settings : bpy.props.BoolProperty(default=False)
  134. display_bb_settings : bpy.props.BoolProperty(default=False)
  135. socket_count : bpy.props.IntProperty()
  136. initialized : bpy.props.BoolProperty(default = False)
  137. def init(self, context):
  138. for name, sock_type in main_names.items():
  139. self.inputs.new(sock_type, name)
  140. for name, sock_type in ik_names.items():
  141. s = self.inputs.new(sock_type, name)
  142. s.hide = True
  143. for name, sock_type in display_names.items():
  144. s = self.inputs.new(sock_type, name)
  145. if s.name in ['Custom Object', 'Bone Collection']:
  146. continue
  147. s.hide = True
  148. for name, sock_type in deform_names.items():
  149. s = self.inputs.new(sock_type, name)
  150. if s.name == 'Deform':
  151. continue
  152. s.hide = True
  153. for name, sock_type in bbone_names.items():
  154. s = self.inputs.new(sock_type, name)
  155. if s.name == "BBone Segments":
  156. continue
  157. s.hide = True
  158. for name, sock_type in other_names.items():
  159. self.inputs.new(sock_type, name)
  160. # could probably simplify this further with iter_tools.chain() but meh
  161. self.socket_count = len(self.inputs)
  162. #
  163. self.outputs.new('xFormSocket', "xForm Out")
  164. # set up some defaults...
  165. self.inputs['Rotation Order'].default_value = "XYZ"
  166. self.inputs['Lock Location'].default_value[0] = True
  167. self.inputs['Lock Location'].default_value[1] = True
  168. self.inputs['Lock Location'].default_value[2] = True
  169. self.inputs['Lock Rotation'].default_value[0] = True
  170. self.inputs['Lock Rotation'].default_value[1] = True
  171. self.inputs['Lock Rotation'].default_value[2] = True
  172. self.inputs['Lock Scale'].default_value[0] = True
  173. self.inputs['Lock Scale'].default_value[1] = True
  174. self.inputs['Lock Scale'].default_value[2] = True
  175. # color
  176. self.use_custom_color = True
  177. self.color = xFormColor
  178. #
  179. self.initialized=True
  180. def draw_buttons(self, context, layout):
  181. # return
  182. layout.operator("mantis.add_custom_property", text='+Add Custom Parameter')
  183. # layout.label(text="Edit Parameter ... not implemented")
  184. if (len(self.inputs) > self.socket_count):
  185. layout.operator("mantis.edit_custom_property", text=' Edit Custom Parameter')
  186. layout.operator("mantis.remove_custom_property", text='-Remove Custom Parameter')
  187. else:
  188. layout.label(text="")
  189. def display_update(self, parsed_tree, context):
  190. if context.space_data:
  191. nc = parsed_tree.get(get_signature_from_edited_tree(self, context))
  192. other_nc = None
  193. if len(self.inputs.get("Relationship").links)>0:
  194. prev_node = self.inputs.get("Relationship").links[0].from_node
  195. if prev_node:
  196. other_nc = parsed_tree.get(get_signature_from_edited_tree(prev_node, context))
  197. if nc and other_nc:
  198. self.display_vp_settings = nc.inputs["Custom Object"].is_connected
  199. self.display_def_settings = nc.evaluate_input("Deform")
  200. self.display_bb_settings = nc.evaluate_input("BBone Segments") > 1
  201. self.display_ik_settings = False
  202. #
  203. from .node_container_common import ( trace_all_lines_up,
  204. trace_single_line)
  205. #TODO find a much faster way to do this
  206. if False and self.id_data.do_live_update: #TODO this is extremely freaking slow
  207. trace = trace_all_lines_up(nc, "xForm Out")
  208. for key in trace.keys():
  209. if (ik_nc:= parsed_tree.get(key)):
  210. if ik_nc.__class__.__name__ in ["LinkInverseKinematics"]:
  211. # if the tree is invalid? This shouldn't be necessary.
  212. if ik_nc.inputs["Input Relationship"].is_connected:
  213. chain_count = ik_nc.evaluate_input("Chain Length")
  214. # if chain_count == 0: # this is wrong
  215. # self.display_ik_settings = True
  216. # else:
  217. if ik_nc.evaluate_input("Use Tail") == False:
  218. chain_count+=1
  219. for line in trace[key]:
  220. # preprocess it to get rid of non-xForms:
  221. xForm_line=[]
  222. for path_nc in line:
  223. if path_nc == ik_nc:
  224. if ik_nc.inputs["Input Relationship"].links[0].from_node != prev_path_nc:
  225. break # not a constraint connection
  226. if path_nc.node_type == 'XFORM':
  227. xForm_line.append(path_nc)
  228. prev_path_nc = path_nc
  229. else: # if it can finish cleaning the line of non-xForms and still has a connection
  230. if (len(xForm_line) < chain_count) or (chain_count == 0):
  231. self.display_ik_settings = True
  232. inp = nc.inputs["Relationship"]
  233. link = None
  234. if inp.is_connected:
  235. link = inp.links[0]
  236. while(link):
  237. if link.from_node.__class__.__name__ in ["LinkInverseKinematics"]:
  238. self.display_ik_settings = link.from_node.evaluate_input("Use Tail")
  239. break
  240. inp = link.from_node.outputs[link.from_socket]
  241. inp = inp.traverse_target
  242. if not inp:
  243. break
  244. if inp.links:
  245. link = inp.links[0]
  246. else:
  247. link = None
  248. for name in ik_names.keys():
  249. self.inputs[name].hide = not self.display_ik_settings
  250. for name in display_names.keys():
  251. if name in ['Custom Object', 'Bone Collection']: continue
  252. self.inputs[name].hide = not self.display_vp_settings
  253. for name in deform_names.keys():
  254. if name in ['Deform']: continue
  255. self.inputs[name].hide = not self.display_def_settings
  256. for name in bbone_names.keys():
  257. if name in ['BBone Segments']: continue
  258. self.inputs[name].hide = not self.display_bb_settings
  259. class xFormArmatureNode(Node, xFormNode):
  260. '''A node representing an Armature object node'''
  261. bl_idname = 'xFormArmatureNode'
  262. bl_label = "Armature"
  263. bl_icon = 'OUTLINER_OB_ARMATURE'
  264. initialized : bpy.props.BoolProperty(default = False)
  265. def init(self, context):
  266. self.inputs.new('StringSocket', "Name")
  267. self.inputs.new('RelationshipSocket', "Relationship")
  268. self.inputs.new('RotationOrderSocket', "Rotation Order")
  269. self.inputs.new('MatrixSocket', "Matrix")
  270. self.outputs.new('xFormSocket', "xForm Out")
  271. # color
  272. self.use_custom_color = True
  273. self.color = xFormColor
  274. self.initialized=True
  275. class xFormGeometryObjectNode(Node, xFormNode):
  276. """Represents a curve or mesh object."""
  277. bl_idname = "xFormGeometryObject"
  278. bl_label = "Geometry Object"
  279. bl_icon = "EMPTY_AXIS"
  280. initialized : bpy.props.BoolProperty(default = False)
  281. def init(self, context):
  282. self.inputs.new('StringSocket', "Name")
  283. self.inputs.new('GeometrySocket', "Geometry")
  284. self.inputs.new('MatrixSocket', "Matrix")
  285. self.inputs.new('RelationshipSocket', "Relationship")
  286. self.inputs.new('DeformerSocket', "Deformer")
  287. self.inputs.new ("HideSocket", "Hide in Viewport")
  288. self.inputs.new ("BooleanSocket", "Hide in Render")
  289. self.outputs.new('xFormSocket', "xForm Out")
  290. # color
  291. self.use_custom_color = True
  292. self.color = xFormColor
  293. self.initialized=True
  294. class xFormObjectInstance(Node, xFormNode):
  295. """Represents an instance of an existing geometry object."""
  296. bl_idname = "xFormObjectInstance"
  297. bl_label = "Object Instance"
  298. bl_icon = "EMPTY_AXIS"
  299. initialized : bpy.props.BoolProperty(default = False)
  300. def init(self, context):
  301. self.inputs.new('StringSocket', "Name")
  302. self.inputs.new('xFormSocket', "Source Object")
  303. self.inputs.new('BooleanSocket', "As Instance",)
  304. self.inputs.new('MatrixSocket', "Matrix")
  305. self.inputs.new('RelationshipSocket', "Relationship")
  306. self.inputs.new('DeformerSocket', "Deformer")
  307. self.inputs.new ("HideSocket", "Hide in Viewport")
  308. self.inputs.new ("BooleanSocket", "Hide in Render")
  309. self.outputs.new('xFormSocket', "xForm Out")
  310. # color
  311. self.use_custom_color = True
  312. self.color = xFormColor
  313. self.initialized=True