xForm_definitions.py 13 KB

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