xForm_definitions.py 14 KB

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