xForm_definitions.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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. mantis_node_class_name=bl_idname[:-4]
  144. def init(self, context):
  145. for name, sock_type in main_names.items():
  146. self.inputs.new(sock_type, name)
  147. for name, sock_type in ik_names.items():
  148. s = self.inputs.new(sock_type, name)
  149. s.hide = True
  150. for name, sock_type in display_names.items():
  151. s = self.inputs.new(sock_type, name)
  152. if s.name in ['Custom Object', 'Bone Collection']:
  153. continue
  154. s.hide = True
  155. for name, sock_type in deform_names.items():
  156. s = self.inputs.new(sock_type, name)
  157. if s.name == 'Deform':
  158. continue
  159. s.hide = True
  160. for name, sock_type in bbone_names.items():
  161. s = self.inputs.new(sock_type, name)
  162. if s.name == "BBone Segments":
  163. continue
  164. s.hide = True
  165. for name, sock_type in other_names.items():
  166. self.inputs.new(sock_type, name)
  167. # could probably simplify this further with iter_tools.chain() but meh
  168. self.socket_count = len(self.inputs)
  169. #
  170. self.outputs.new('xFormSocket', "xForm Out")
  171. # set up some defaults...
  172. self.inputs['Rotation Order'].default_value = "XYZ"
  173. self.inputs['Lock Location'].default_value[0] = True
  174. self.inputs['Lock Location'].default_value[1] = True
  175. self.inputs['Lock Location'].default_value[2] = True
  176. self.inputs['Lock Rotation'].default_value[0] = True
  177. self.inputs['Lock Rotation'].default_value[1] = True
  178. self.inputs['Lock Rotation'].default_value[2] = True
  179. self.inputs['Lock Scale'].default_value[0] = True
  180. self.inputs['Lock Scale'].default_value[1] = True
  181. self.inputs['Lock Scale'].default_value[2] = True
  182. # color
  183. self.use_custom_color = True
  184. self.color = xFormColor
  185. #
  186. self.initialized=True
  187. def draw_buttons(self, context, layout):
  188. # return
  189. layout.operator("mantis.add_custom_property", text='+Add Custom Parameter')
  190. # layout.label(text="Edit Parameter ... not implemented")
  191. if (len(self.inputs) > self.socket_count):
  192. layout.operator("mantis.edit_custom_property", text=' Edit Custom Parameter')
  193. layout.operator("mantis.remove_custom_property", text='-Remove Custom Parameter')
  194. else:
  195. layout.label(text="")
  196. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  197. return main_draw_label(self)
  198. def display_update(self, parsed_tree, context):
  199. if context.space_data:
  200. nc = parsed_tree.get(get_signature_from_edited_tree(self, context))
  201. self.display_ik_settings = False
  202. if nc and (pb := nc.bGetObject(mode='POSE')):
  203. self.display_ik_settings = pb.is_in_ik_chain
  204. self.inputs['Name'].display_text = ""
  205. if nc:
  206. try:
  207. self.inputs['Name'].display_text = nc.evaluate_input("Name")
  208. self.display_vp_settings = nc.inputs["Custom Object"].is_connected
  209. self.display_def_settings = nc.evaluate_input("Deform")
  210. self.display_bb_settings = nc.evaluate_input("BBone Segments") > 1
  211. except KeyError:
  212. return # the tree isn't ready yet.
  213. for name in ik_names.keys():
  214. self.inputs[name].hide = not self.display_ik_settings
  215. for name in display_names.keys():
  216. if name in ['Custom Object', 'Bone Collection']: continue
  217. self.inputs[name].hide = not self.display_vp_settings
  218. for name in deform_names.keys():
  219. if name in ['Deform']: continue
  220. self.inputs[name].hide = not self.display_def_settings
  221. for name in bbone_names.keys():
  222. if name in ['BBone Segments']: continue
  223. self.inputs[name].hide = not self.display_bb_settings
  224. class xFormArmatureNode(Node, xFormNode):
  225. '''A node representing an Armature object node'''
  226. bl_idname = 'xFormArmatureNode'
  227. bl_label = "Armature"
  228. bl_icon = 'OUTLINER_OB_ARMATURE'
  229. initialized : bpy.props.BoolProperty(default = False)
  230. mantis_node_class_name=bl_idname[:-4]
  231. def init(self, context):
  232. self.inputs.new('StringSocket', "Name")
  233. self.inputs.new('RelationshipSocket', "Relationship")
  234. self.inputs.new('RotationOrderSocket', "Rotation Order")
  235. self.inputs.new('MatrixSocket', "Matrix")
  236. self.outputs.new('xFormSocket', "xForm Out")
  237. # color
  238. self.use_custom_color = True
  239. self.color = xFormColor
  240. self.initialized=True
  241. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  242. return main_draw_label(self)
  243. def display_update(self, parsed_tree, context):
  244. if context.space_data:
  245. nc = parsed_tree.get(get_signature_from_edited_tree(self, context))
  246. self.inputs['Name'].display_text = ""
  247. if nc:
  248. self.inputs['Name'].display_text = nc.evaluate_input("Name")
  249. class xFormGeometryObjectNode(Node, xFormNode):
  250. """Represents a curve or mesh object."""
  251. bl_idname = "xFormGeometryObject"
  252. bl_label = "Geometry Object"
  253. bl_icon = "EMPTY_AXIS"
  254. initialized : bpy.props.BoolProperty(default = False)
  255. mantis_node_class_name=bl_idname
  256. def init(self, context):
  257. self.inputs.new('StringSocket', "Name")
  258. self.inputs.new('GeometrySocket', "Geometry")
  259. self.inputs.new('MatrixSocket', "Matrix")
  260. self.inputs.new('RelationshipSocket', "Relationship")
  261. self.inputs.new('DeformerSocket', "Deformer")
  262. self.inputs.new ("HideSocket", "Hide in Viewport")
  263. self.inputs.new ("BooleanSocket", "Hide in Render")
  264. self.outputs.new('xFormSocket', "xForm Out")
  265. # color
  266. self.use_custom_color = True
  267. self.color = xFormColor
  268. self.initialized=True
  269. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  270. return main_draw_label(self)
  271. def display_update(self, parsed_tree, context):
  272. if context.space_data:
  273. nc = parsed_tree.get(get_signature_from_edited_tree(self, context))
  274. self.inputs['Name'].display_text = ""
  275. if nc:
  276. self.inputs['Name'].display_text = nc.evaluate_input("Name")
  277. class xFormObjectInstance(Node, xFormNode):
  278. """Represents an instance of an existing geometry object."""
  279. bl_idname = "xFormObjectInstance"
  280. bl_label = "Object Instance"
  281. bl_icon = "EMPTY_AXIS"
  282. initialized : bpy.props.BoolProperty(default = False)
  283. mantis_node_class_name=bl_idname
  284. def init(self, context):
  285. self.inputs.new('StringSocket', "Name")
  286. self.inputs.new('xFormSocket', "Source Object")
  287. self.inputs.new('BooleanSocket', "As Instance",)
  288. self.inputs.new('MatrixSocket', "Matrix")
  289. self.inputs.new('RelationshipSocket', "Relationship")
  290. self.inputs.new('DeformerSocket', "Deformer")
  291. self.inputs.new ("HideSocket", "Hide in Viewport")
  292. self.inputs.new ("BooleanSocket", "Hide in Render")
  293. self.outputs.new('xFormSocket', "xForm Out")
  294. # color
  295. self.use_custom_color = True
  296. self.color = xFormColor
  297. self.initialized=True
  298. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  299. return main_draw_label(self)
  300. def display_update(self, parsed_tree, context):
  301. if context.space_data:
  302. nc = parsed_tree.get(get_signature_from_edited_tree(self, context))
  303. self.inputs['Name'].display_text = ""
  304. if nc:
  305. self.inputs['Name'].display_text = nc.evaluate_input("Name")
  306. for cls in TellClasses():
  307. cls.set_mantis_class()