link_nodes_ui.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. import bpy
  2. from bpy.types import NodeTree, Node, NodeSocket
  3. from .base_definitions import LinkNode, GraphError
  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 .link_socket_templates import *
  10. def TellClasses():
  11. return [ LinkInheritNode,
  12. LinkInverseKinematics,
  13. LinkCopyLocationNode,
  14. LinkCopyRotationNode,
  15. LinkCopyScaleNode,
  16. LinkInheritConstraintNode,
  17. LinkCopyTransformNode,
  18. LinkStretchToNode,
  19. LinkDampedTrackNode,
  20. LinkLockedTrackNode,
  21. LinkTrackToNode,
  22. LinkLimitLocationNode,
  23. LinkLimitScaleNode,
  24. LinkLimitRotationNode,
  25. LinkLimitDistanceNode,
  26. LinkDrivenParameterNode,
  27. LinkArmatureNode,
  28. LinkSplineIKNode,
  29. LinkFloorNode,
  30. LinkShrinkWrapNode,
  31. LinkGeometryAttribute,
  32. LinkTransformationNode,
  33. ]
  34. from mathutils import Color # these colors were sampled from Blender's UI
  35. # TODO: maybe read the relevant colors from the Theme
  36. linkTransformColor = Color((0.028034, 0.093164, 0.070379)).from_scene_linear_to_srgb()
  37. inheritColor = Color((0.083213, 0.131242, 0.116497)).from_scene_linear_to_srgb()
  38. trackingColor = Color((0.033114, 0.049013, 0.131248)).from_scene_linear_to_srgb()
  39. ikColor = Color((0.131117, 0.131248, 0.006971)).from_scene_linear_to_srgb()
  40. driverColor = Color((0.043782, 0.014745, 0.131248,)).from_scene_linear_to_srgb()
  41. class LinkInheritNode(Node, LinkNode):
  42. '''A node representing inheritance'''
  43. # cuss, messed this up
  44. bl_idname = 'linkInherit' # l should be L
  45. # need to fix this
  46. bl_label = "Inherit"
  47. bl_icon = 'CONSTRAINT_BONE'
  48. initialized : bpy.props.BoolProperty(default = False)
  49. mantis_node_class_name="LinkInherit"
  50. def init(self, context):
  51. self.init_sockets(LinkInheritSockets)
  52. self.initialized = True
  53. self.use_custom_color = True
  54. self.color = inheritColor
  55. def display_update(self, parsed_tree, context):
  56. node_tree = context.space_data.path[0].node_tree
  57. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  58. if mantis_node:
  59. bone_prev, bone_next = False, False
  60. if (inp := mantis_node.inputs["Parent"]).is_connected:
  61. if from_node := inp.links[0].from_node:
  62. if from_node.__class__.__name__ in ["xFormBone"]:
  63. bone_prev=True
  64. bone_next=True
  65. try:
  66. xForm = mantis_node.GetxForm()
  67. if xForm.__class__.__name__ not in "xFormBone":
  68. bone_next=False
  69. except GraphError:
  70. bone_next=False
  71. # print(bone_prev, bone_next )
  72. if bone_next and bone_prev:
  73. self.inputs["Inherit Rotation"].hide = False
  74. self.inputs["Inherit Scale"].hide = False
  75. self.inputs["Connected"].hide = False
  76. else:
  77. self.inputs["Inherit Rotation"].hide = True or self.inputs["Inherit Rotation"].is_connected
  78. self.inputs["Inherit Scale"].hide = True or self.inputs["Inherit Scale"].is_connected
  79. self.inputs["Connected"].hide = True or self.inputs["Connected"].is_connected
  80. # the node_groups on the way here ought to be active if there
  81. # is no funny business going on.
  82. # DO: make another node for ITASC IK, eh?
  83. class LinkInverseKinematics(Node, LinkNode):
  84. '''A node representing inverse kinematics'''
  85. bl_idname = 'LinkInverseKinematics'
  86. bl_label = "Inverse Kinematics"
  87. bl_icon = 'CON_KINEMATIC'
  88. initialized : bpy.props.BoolProperty(default = False)
  89. mantis_node_class_name=bl_idname
  90. def init(self, context):
  91. self.init_sockets(LinkInverseKinematicsSockets)
  92. self.initialized = True
  93. self.use_custom_color = True
  94. self.color = ikColor
  95. class LinkCopyLocationNode(Node, LinkNode):
  96. '''A node representing Copy Location'''
  97. bl_idname = 'LinkCopyLocation'
  98. bl_label = "Copy Location"
  99. bl_icon = 'CON_LOCLIKE'
  100. initialized : bpy.props.BoolProperty(default = False)
  101. mantis_node_class_name=bl_idname
  102. def init(self, context):
  103. self.init_sockets(LinkCopyLocationSockets)
  104. self.use_custom_color = True
  105. self.color = linkTransformColor
  106. self.initialized = True
  107. class LinkCopyRotationNode(Node, LinkNode):
  108. '''A node representing Copy Rotation'''
  109. bl_idname = 'LinkCopyRotation'
  110. bl_label = "Copy Rotation"
  111. bl_icon = 'CON_ROTLIKE'
  112. initialized : bpy.props.BoolProperty(default = False)
  113. mantis_node_class_name=bl_idname
  114. def init(self, context):
  115. self.init_sockets(LinkCopyRotationSockets)
  116. self.use_custom_color = True
  117. self.color = linkTransformColor
  118. self.initialized = True
  119. class LinkCopyScaleNode(Node, LinkNode):
  120. '''A node representing Copy Scale'''
  121. bl_idname = 'LinkCopyScale'
  122. bl_label = "Copy Scale"
  123. bl_icon = 'CON_SIZELIKE'
  124. initialized : bpy.props.BoolProperty(default = False)
  125. mantis_node_class_name=bl_idname
  126. def init(self, context):
  127. self.init_sockets(LinkCopyScaleSockets)
  128. self.use_custom_color = True
  129. self.color = linkTransformColor
  130. self.initialized = True
  131. class LinkInheritConstraintNode(Node, LinkNode):
  132. # === Basics ===
  133. # Description string
  134. '''A node representing a parent constraint'''
  135. bl_idname = 'LinkInheritConstraint'
  136. bl_label = "Inherit (constraint)"
  137. bl_icon = 'CON_CHILDOF'
  138. initialized : bpy.props.BoolProperty(default = False)
  139. mantis_node_class_name=bl_idname
  140. # === Optional Functions ===
  141. def init(self, context):
  142. self.init_sockets(LinkInheritConstraintSockets)
  143. self.use_custom_color = True
  144. self.color = inheritColor
  145. self.initialized = True
  146. class LinkCopyTransformNode(Node, LinkNode):
  147. # === Basics ===
  148. # Description string
  149. '''A node representing Copy Transform'''
  150. bl_idname = 'LinkCopyTransforms'
  151. bl_label = "Copy Transform"
  152. bl_icon = 'CON_TRANSLIKE'
  153. initialized : bpy.props.BoolProperty(default = False)
  154. mantis_node_class_name=bl_idname
  155. # === Optional Functions ===
  156. def init(self, context):
  157. self.init_sockets(LinkCopyTransformsSockets)
  158. self.use_custom_color = True
  159. self.color = linkTransformColor
  160. self.initialized = True
  161. class LinkStretchToNode(Node, LinkNode):
  162. '''A node representing Stretch-To'''
  163. bl_idname = 'LinkStretchTo'
  164. bl_label = "Stretch To"
  165. bl_icon = 'CON_STRETCHTO'
  166. initialized : bpy.props.BoolProperty(default = False)
  167. mantis_node_class_name=bl_idname
  168. def init(self, context):
  169. self.init_sockets(LinkStretchToSockets)
  170. self.initialized = True
  171. self.use_custom_color = True
  172. self.color = trackingColor
  173. class LinkDampedTrackNode(Node, LinkNode):
  174. '''A node representing Stretch-To'''
  175. bl_idname = 'LinkDampedTrack'
  176. bl_label = "Damped Track"
  177. bl_icon = 'CON_TRACKTO'
  178. initialized : bpy.props.BoolProperty(default = False)
  179. mantis_node_class_name=bl_idname
  180. def init(self, context):
  181. self.init_sockets(LinkDampedTrackSockets)
  182. self.initialized = True
  183. self.use_custom_color = True
  184. self.color = trackingColor
  185. class LinkLockedTrackNode(Node, LinkNode):
  186. '''A node representing Stretch-To'''
  187. bl_idname = 'LinkLockedTrack'
  188. bl_label = "Locked Track"
  189. bl_icon = 'CON_LOCKTRACK'
  190. initialized : bpy.props.BoolProperty(default = False)
  191. mantis_node_class_name=bl_idname
  192. def init(self, context):
  193. self.init_sockets(LinkLockedTrackSockets)
  194. self.initialized = True
  195. self.use_custom_color = True
  196. self.color = trackingColor
  197. class LinkTrackToNode(Node, LinkNode):
  198. '''A node representing Stretch-To'''
  199. bl_idname = 'LinkTrackTo'
  200. bl_label = "Track To"
  201. bl_icon = 'CON_TRACKTO'
  202. initialized : bpy.props.BoolProperty(default = False)
  203. mantis_node_class_name=bl_idname
  204. def init(self, context):
  205. self.init_sockets(LinkTrackToSockets)
  206. self.initialized = True
  207. self.use_custom_color = True
  208. self.color = trackingColor
  209. class LinkLimitLocationNode(Node, LinkNode):
  210. '''A node representing Limit Location'''
  211. bl_idname = 'LinkLimitLocation'
  212. bl_label = "Limit Location"
  213. bl_icon = 'CON_LOCLIMIT'
  214. mantis_node_class_name=bl_idname
  215. initialized : bpy.props.BoolProperty(default = False)
  216. def init(self, context):
  217. self.init_sockets(LinkLimitLocationScaleSockets)
  218. self.initialized = True
  219. self.use_custom_color = True
  220. self.color = linkTransformColor
  221. class LinkLimitScaleNode(Node, LinkNode):
  222. '''A node representing Limit Scale'''
  223. bl_idname = 'LinkLimitScale'
  224. bl_label = "Limit Scale"
  225. bl_icon = 'CON_SIZELIMIT'
  226. initialized : bpy.props.BoolProperty(default = False)
  227. mantis_node_class_name=bl_idname
  228. def init(self, context):
  229. self.init_sockets(LinkLimitLocationScaleSockets)
  230. self.initialized = True
  231. self.use_custom_color = True
  232. self.color = linkTransformColor
  233. class LinkLimitRotationNode(Node, LinkNode):
  234. '''A node representing Limit Rotation'''
  235. bl_idname = 'LinkLimitRotation'
  236. bl_label = "Limit Rotation"
  237. bl_icon = 'CON_ROTLIMIT'
  238. initialized : bpy.props.BoolProperty(default = False)
  239. mantis_node_class_name=bl_idname
  240. def init(self, context):
  241. self.init_sockets(LinkLimitRotationSockets)
  242. self.initialized = True
  243. # color
  244. self.use_custom_color = True
  245. self.color = linkTransformColor
  246. class LinkLimitDistanceNode(Node, LinkNode):
  247. '''A node representing Limit Distance'''
  248. bl_idname = 'LinkLimitDistance'
  249. bl_label = "Limit Distance"
  250. bl_icon = 'CON_DISTLIMIT'
  251. initialized : bpy.props.BoolProperty(default = False)
  252. mantis_node_class_name=bl_idname
  253. def init(self, context):
  254. self.init_sockets(LinkLimitDistanceSockets)
  255. self.use_custom_color = True
  256. self.color = linkTransformColor
  257. self.initialized = True
  258. class LinkTransformationNode(Node, LinkNode):
  259. '''A node representing Transformation (Constraint)'''
  260. bl_idname = 'LinkTransformation'
  261. bl_label = "Transformation"
  262. bl_icon = 'CON_TRANSFORM'
  263. initialized : bpy.props.BoolProperty(default = False)
  264. mantis_node_class_name=bl_idname
  265. def init(self, context):
  266. self.init_sockets(LinkTransformationSockets)
  267. self.use_custom_color = True
  268. self.color = linkTransformColor
  269. self.initialized = True
  270. def display_update(self, parsed_tree, context):
  271. node_tree = context.space_data.path[0].node_tree
  272. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  273. if mantis_node:
  274. if mantis_node.evaluate_input("Map From") == "ROTATION":
  275. self.inputs["Rotation Mode"].hide=False
  276. else:
  277. self.inputs["Rotation Mode"].hide=True
  278. if mantis_node.evaluate_input("Map To") == "TRANSLATION":
  279. self.inputs["Rotation Order"].hide=True
  280. self.inputs["Mix Mode (Translation)"].hide=False
  281. self.inputs["Mix Mode (Rotation)"].hide=True
  282. self.inputs["Mix Mode (Scale)"].hide=True
  283. elif mantis_node.evaluate_input("Map To") == "ROTATION":
  284. self.inputs["Rotation Order"].hide=False
  285. self.inputs["Mix Mode (Translation)"].hide=True
  286. self.inputs["Mix Mode (Rotation)"].hide=False
  287. self.inputs["Mix Mode (Scale)"].hide=True
  288. elif mantis_node.evaluate_input("Map To") == "SCALE":
  289. self.inputs["Rotation Order"].hide=True
  290. self.inputs["Mix Mode (Translation)"].hide=True
  291. self.inputs["Mix Mode (Rotation)"].hide=True
  292. self.inputs["Mix Mode (Scale)"].hide=False
  293. class LinkArmatureNode(Node, LinkNode):
  294. """A node representing Blender's Armature Constraint"""
  295. bl_idname = "LinkArmature"
  296. bl_label = "Armature (Constraint)"
  297. bl_icon = "CON_ARMATURE"
  298. initialized : bpy.props.BoolProperty(default = False)
  299. mantis_node_class_name=bl_idname
  300. def init(self, context):
  301. self.init_sockets(LinkArmatureSockets)
  302. self.use_custom_color = True
  303. self.color = inheritColor
  304. self.initialized = True
  305. def draw_buttons(self, context, layout):
  306. # return
  307. layout.operator( 'mantis.link_armature_node_add_target' )
  308. if (len(self.inputs) > 6):
  309. layout.operator( 'mantis.link_armature_node_remove_target' )
  310. else:
  311. layout.label(text="")
  312. class LinkSplineIKNode(Node, LinkNode):
  313. """"A node representing Spline IK"""
  314. bl_idname = "LinkSplineIK"
  315. bl_label = "Spline IK"
  316. bl_icon = "CON_SPLINEIK"
  317. initialized : bpy.props.BoolProperty(default = False)
  318. mantis_node_class_name=bl_idname
  319. def init(self, context):
  320. self.init_sockets(LinkSplineIKSockets)
  321. self.use_custom_color = True
  322. self.color = ikColor
  323. self.initialized = True
  324. class LinkFloorNode(Node, LinkNode):
  325. """A node representing Blender's Floor Constraint"""
  326. bl_idname = "LinkFloor"
  327. bl_label = "Floor"
  328. bl_icon = "CON_FLOOR"
  329. initialized : bpy.props.BoolProperty(default = False)
  330. mantis_node_class_name=bl_idname
  331. def init(self, context):
  332. self.init_sockets(LinkFloorSockets)
  333. self.use_custom_color = True
  334. self.color = linkTransformColor
  335. self.initialized = True
  336. class LinkShrinkWrapNode(Node, LinkNode):
  337. """A node representing Blender's Shrinkwrap Constraint"""
  338. bl_idname = "LinkShrinkWrap"
  339. bl_label = "Shrinkwrap"
  340. bl_icon = "CON_SHRINKWRAP"
  341. initialized : bpy.props.BoolProperty(default = False)
  342. mantis_node_class_name=bl_idname
  343. def init(self, context):
  344. self.init_sockets(LinkShrinkWrapSockets)
  345. self.use_custom_color = True
  346. self.color = trackingColor
  347. self.initialized = True
  348. def display_update(self, parsed_tree, context):
  349. # vast majority of the time user doesn't link this.
  350. shrink_type = self.inputs['Mode'].default_value
  351. if self.inputs['Mode'].is_linked:# 1% or less of cases
  352. node_tree = context.space_data.path[0].node_tree
  353. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  354. shrink_is_project = False
  355. if mantis_node:
  356. shrink_type = mantis_node.evaluate_input("Mode")
  357. if shrink_type != "PROJECT":
  358. self.inputs['Project Axis'].hide=True
  359. self.inputs['Space'].hide=True
  360. self.inputs['Project Distance'].hide=True
  361. self.inputs['Project Opposite'].hide=True
  362. self.inputs['Face Cull'].hide=True
  363. self.inputs['Invert Cull'].hide=True
  364. else:
  365. for inp in self.inputs:
  366. inp.hide=False
  367. if shrink_type == 'NEAREST_VERTEX':
  368. self.inputs['Snap Mode'].hide=True
  369. self.inputs['Align to Normal'].hide=True
  370. self.inputs['Align Normal Axis'].hide=True
  371. else:
  372. self.inputs['Snap Mode'].hide=False
  373. self.inputs['Align to Normal'].hide=False
  374. self.inputs['Align Normal Axis'].hide=False
  375. # TODO: this stuff should be handled by input tags
  376. # once I get that working.
  377. class LinkGeometryAttribute(Node, LinkNode):
  378. """A node representing Blender's Geometry Attribute Constraint"""
  379. bl_idname = "LinkGeometryAttribute"
  380. bl_label = "Geometry Attribute"
  381. bl_icon = "CON_GEOMETRYATTRIBUTE"
  382. initialized : bpy.props.BoolProperty(default = False)
  383. mantis_node_class_name=bl_idname
  384. def init(self, context):
  385. self.init_sockets(LinkGeometryAttributeSockets)
  386. self.use_custom_color = True
  387. self.color = linkTransformColor
  388. self.initialized = True
  389. def display_update(self, parsed_tree, context):
  390. data_type = self.inputs['Data Type'].default_value
  391. if self.inputs['Data Type'].is_linked:
  392. node_tree = context.space_data.path[0].node_tree
  393. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  394. if mantis_node: data_type = mantis_node.evaluate_input("Data Type")
  395. not_matrix_mode = (data_type != 'FLOAT4X4')
  396. self.inputs['Enabled Location'].hide=not_matrix_mode
  397. self.inputs['Enabled Rotation'].hide=not_matrix_mode
  398. self.inputs['Enabled Scale'].hide=not_matrix_mode
  399. # DRIVERS!!
  400. class LinkDrivenParameterNode(Node, LinkNode):
  401. """Represents a driven parameter in the downstream xForm node."""
  402. bl_idname = "LinkDrivenParameter"
  403. bl_label = "Driven Parameter"
  404. bl_icon = "CONSTRAINT_BONE"
  405. initialized : bpy.props.BoolProperty(default = False)
  406. mantis_node_class_name=bl_idname
  407. def init(self, context):
  408. self.init_sockets(LinkDrivenParameterSockets)
  409. self.use_custom_color = True
  410. self.color = linkTransformColor
  411. self.initialized = True
  412. # Set up the class property that ties the UI classes to the Mantis classes.
  413. for cls in TellClasses():
  414. cls.set_mantis_class()