xForm_nodes_ui.py 13 KB

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